@swmansion/react-native-bottom-sheet 0.10.0-next.3 → 0.10.0-next.4

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.
@@ -85,6 +85,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
85
85
  private var scrimColor = Color.TRANSPARENT
86
86
  private var scrimProgress = 0f
87
87
  private var suppressScrimForClosingTarget = false
88
+ private var scrimPinnedFull = false
88
89
  private var maxDetentHeight = Float.NaN
89
90
  private var contentHeightMarker: View? = null
90
91
 
@@ -294,6 +295,13 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
294
295
  }
295
296
 
296
297
  val previousMaxHeight = detentSpecs.maxOfOrNull { it.height } ?: resolvedMaxDetentHeight()
298
+ // Whether the scrim is currently fully opaque, i.e. the sheet is settled at
299
+ // or above the first non-zero detent. If so, a detent resize must not dip
300
+ // the scrim while the sheet re-anchors to the new geometry.
301
+ val wasScrimFull =
302
+ modal &&
303
+ firstNonZeroDetentHeight > 0f &&
304
+ currentSheetHeight() + 0.5f >= firstNonZeroDetentHeight
297
305
  detentSpecs = resolvedDetents
298
306
  if (width > 0 && height > 0 && detentSpecs.isNotEmpty()) {
299
307
  layoutSheetContainer(width, height)
@@ -317,8 +325,15 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
317
325
  // sheet surface keeps the same on-screen height across the resize.
318
326
  val visibleHeight = previousMaxHeight - currentTy
319
327
  sheetContainer.translationY = (newMaxHeight - visibleHeight).coerceIn(0f, newMaxHeight)
328
+ scrimPinnedFull = scrimPinnedFull || wasScrimFull
320
329
  emitPosition()
321
- snapToIndex(targetIndex, 0f, emitIndexChange = false, emitSettle = shouldEmitSettle)
330
+ snapToIndex(
331
+ targetIndex,
332
+ 0f,
333
+ emitIndexChange = false,
334
+ emitSettle = shouldEmitSettle,
335
+ preserveScrimPin = true,
336
+ )
322
337
  } else {
323
338
  val currentVisibleHeight = previousMaxHeight - sheetContainer.translationY
324
339
  val targetHeight = detentSpecs.getOrNull(targetIndex)?.height ?: 0f
@@ -332,8 +347,15 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
332
347
  // up to the taller detent.
333
348
  sheetContainer.translationY =
334
349
  (newMaxHeight - currentVisibleHeight).coerceIn(0f, newMaxHeight)
350
+ scrimPinnedFull = scrimPinnedFull || wasScrimFull
335
351
  emitPosition()
336
- snapToIndex(targetIndex, 0f, emitIndexChange = false, emitSettle = false)
352
+ snapToIndex(
353
+ targetIndex,
354
+ 0f,
355
+ emitIndexChange = false,
356
+ emitSettle = false,
357
+ preserveScrimPin = true,
358
+ )
337
359
  }
338
360
  }
339
361
  }
@@ -474,12 +496,16 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
474
496
  velocity: Float,
475
497
  emitIndexChange: Boolean = true,
476
498
  emitSettle: Boolean = true,
499
+ preserveScrimPin: Boolean = false,
477
500
  ) {
478
501
  if (index < 0 || index >= detentSpecs.size) return
479
502
  targetIndex = index
480
503
  if (!isTargetingClosedDetent) {
481
504
  suppressScrimForClosingTarget = false
482
505
  }
506
+ if (!preserveScrimPin) {
507
+ scrimPinnedFull = false
508
+ }
483
509
 
484
510
  val targetTy = translationY(index)
485
511
  val currentTy = sheetContainer.translationY
@@ -504,6 +530,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
504
530
  activeAnimation = null
505
531
  activeAnimationEmitsSettle = false
506
532
  suppressScrimForClosingTarget = false
533
+ scrimPinnedFull = false
507
534
  if (closedIndex == index) {
508
535
  sheetContainer.translationY = translationY(index)
509
536
  hideScrim()
@@ -693,6 +720,7 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
693
720
 
694
721
  private fun beginPan(event: MotionEvent) {
695
722
  isPanning = true
723
+ scrimPinnedFull = false
696
724
  panStartingIndex = targetIndex
697
725
  activePointerId = event.getPointerId(0)
698
726
  lastTouchY = event.y
@@ -818,6 +846,15 @@ class BottomSheetView(context: Context) : ReactViewGroup(context) {
818
846
  return
819
847
  }
820
848
 
849
+ // While the sheet is fully open and only its content/detent geometry is
850
+ // resizing, the position momentarily lags the grown detent height. Keep the
851
+ // scrim at full opacity instead of dipping it until the re-anchor settles.
852
+ if (scrimPinnedFull) {
853
+ scrimProgress = 1f
854
+ invalidate()
855
+ return
856
+ }
857
+
821
858
  val threshold = firstNonZeroDetentHeight
822
859
  scrimProgress = if (threshold <= 0f) 0f else (position / threshold).coerceIn(0f, 1f)
823
860
  invalidate()
@@ -55,6 +55,7 @@ public final class RNSBottomSheetHostingView: UIView {
55
55
  private var panGesture: UIPanGestureRecognizer!
56
56
  private var activeAnimator: UIViewPropertyAnimator?
57
57
  private var activeAnimatorEmitsSettle = false
58
+ private var scrimPinnedFull = false
58
59
  private var displayLink: CADisplayLink?
59
60
  private var pendingIndex: Int?
60
61
  private var hasLaidOut = false
@@ -364,10 +365,14 @@ public final class RNSBottomSheetHostingView: UIView {
364
365
  _ index: Int,
365
366
  velocity: CGFloat,
366
367
  emitIndexChange: Bool = true,
367
- emitSettle: Bool = true
368
+ emitSettle: Bool = true,
369
+ preserveScrimPin: Bool = false
368
370
  ) {
369
371
  guard index >= 0, index < detentSpecs.count else { return }
370
372
  targetIndex = index
373
+ if !preserveScrimPin {
374
+ scrimPinnedFull = false
375
+ }
371
376
 
372
377
  let currentTy = sheetContainer.transform.ty
373
378
  let targetTy = translationY(for: index)
@@ -391,6 +396,7 @@ public final class RNSBottomSheetHostingView: UIView {
391
396
  self.emitPosition()
392
397
  self.activeAnimator = nil
393
398
  self.activeAnimatorEmitsSettle = false
399
+ self.scrimPinnedFull = false
394
400
  self.setContentInteractionEnabled(true)
395
401
  self.updateInteractionState()
396
402
  if emitIndexChange {
@@ -411,6 +417,7 @@ public final class RNSBottomSheetHostingView: UIView {
411
417
  switch gesture.state {
412
418
  case .began:
413
419
  isPanning = true
420
+ scrimPinnedFull = false
414
421
  panStartingIndex = targetIndex
415
422
  sheetContainer.endEditing(true)
416
423
  setContentInteractionEnabled(false)
@@ -609,6 +616,12 @@ public final class RNSBottomSheetHostingView: UIView {
609
616
  }
610
617
 
611
618
  let previousMaxHeight = maximumResolvedDetentHeight ?? resolvedMaxDetentHeight
619
+ // Whether the scrim is currently fully opaque, i.e. the sheet is settled at
620
+ // or above the first non-zero detent. If so, a detent resize must not dip
621
+ // the scrim while the sheet re-anchors to the new geometry.
622
+ let wasScrimFull = modal
623
+ && firstNonZeroDetentHeight > 0
624
+ && currentSheetHeight + 0.5 >= firstNonZeroDetentHeight
612
625
  detentSpecs = resolvedDetents
613
626
 
614
627
  guard bounds.width > 0, bounds.height > 0, !detentSpecs.isEmpty else {
@@ -632,8 +645,15 @@ public final class RNSBottomSheetHostingView: UIView {
632
645
  let visibleHeight = previousMaxHeight - visualTy
633
646
  let reanchoredTy = min(max(newMaxHeight - visibleHeight, 0), newMaxHeight)
634
647
  sheetContainer.transform = CGAffineTransform(translationX: 0, y: reanchoredTy)
648
+ scrimPinnedFull = scrimPinnedFull || wasScrimFull
635
649
  emitPosition()
636
- snapToIndex(targetIndex, velocity: 0, emitIndexChange: false, emitSettle: shouldEmitSettle)
650
+ snapToIndex(
651
+ targetIndex,
652
+ velocity: 0,
653
+ emitIndexChange: false,
654
+ emitSettle: shouldEmitSettle,
655
+ preserveScrimPin: true
656
+ )
637
657
  } else {
638
658
  let currentVisibleHeight = previousMaxHeight - currentTranslationY
639
659
  let targetHeight = detent(at: targetIndex).height
@@ -647,8 +667,15 @@ public final class RNSBottomSheetHostingView: UIView {
647
667
  // up to the taller detent.
648
668
  let startTy = min(max(newMaxHeight - currentVisibleHeight, 0), newMaxHeight)
649
669
  sheetContainer.transform = CGAffineTransform(translationX: 0, y: startTy)
670
+ scrimPinnedFull = scrimPinnedFull || wasScrimFull
650
671
  emitPosition()
651
- snapToIndex(targetIndex, velocity: 0, emitIndexChange: false, emitSettle: false)
672
+ snapToIndex(
673
+ targetIndex,
674
+ velocity: 0,
675
+ emitIndexChange: false,
676
+ emitSettle: false,
677
+ preserveScrimPin: true
678
+ )
652
679
  }
653
680
  }
654
681
  }
@@ -786,6 +813,15 @@ private extension RNSBottomSheetHostingView {
786
813
  return
787
814
  }
788
815
 
816
+ // While the sheet is fully open and only its content/detent geometry is
817
+ // resizing, the position momentarily lags the grown detent height. Keep the
818
+ // scrim at full opacity instead of dipping it until the re-anchor settles.
819
+ if scrimPinnedFull {
820
+ scrimView.alpha = 1
821
+ scrimView.isHidden = false
822
+ return
823
+ }
824
+
789
825
  let threshold = firstNonZeroDetentHeight
790
826
  let progress: CGFloat
791
827
  if threshold <= 0 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swmansion/react-native-bottom-sheet",
3
- "version": "0.10.0-next.3",
3
+ "version": "0.10.0-next.4",
4
4
  "description": "Provides bottom-sheet components for React Native.",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",