@lodev09/react-native-true-sheet 3.5.1-beta.4 → 3.5.1

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.
@@ -309,13 +309,15 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
309
309
  // ==================== Sheet Stack Translation ====================
310
310
 
311
311
  /**
312
- * Updates this sheet's translation based on its child sheet's position.
313
- * When a child sheet is presented, parent sheets slide down to create a stacked appearance.
312
+ * Updates this sheet's translation and disables dragging when a child sheet is presented.
313
+ * Parent sheets slide down to create a stacked appearance.
314
314
  * Propagates additional translation to parent so the entire stack stays visually consistent.
315
315
  */
316
316
  fun updateTranslationForChild(childSheetTop: Int) {
317
317
  if (!viewController.isSheetVisible || viewController.isExpanded) return
318
318
 
319
+ viewController.sheetView?.behavior?.isDraggable = false
320
+
319
321
  val mySheetTop = viewController.detentCalculator.getSheetTopForDetentIndex(viewController.currentDetentIndex)
320
322
  val newTranslation = maxOf(0, childSheetTop - mySheetTop)
321
323
  val additionalTranslation = newTranslation - viewController.currentTranslationY
@@ -332,17 +334,18 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
332
334
  * Recursively adds translation to this sheet and all parent sheets.
333
335
  */
334
336
  private fun addTranslation(amount: Int) {
335
- if (!viewController.isSheetVisible || viewController.isExpanded) return
337
+ if (viewController.isExpanded) return
336
338
 
337
339
  viewController.translateSheet(viewController.currentTranslationY + amount)
338
340
  TrueSheetStackManager.getParentSheet(this)?.addTranslation(amount)
339
341
  }
340
342
 
341
343
  /**
342
- * Resets this sheet's translation and updates parent sheets.
343
- * This sheet resets to 0 (it's now topmost), but parent recalculates based on this sheet's position.
344
+ * Resets this sheet's translation and restores dragging when it becomes topmost.
345
+ * Parent recalculates its translation based on this sheet's position.
344
346
  */
345
347
  fun resetTranslation() {
348
+ viewController.sheetView?.behavior?.isDraggable = viewController.draggable
346
349
  viewController.translateSheet(0)
347
350
 
348
351
  // Parent should recalculate its translation based on this sheet's position
@@ -66,12 +66,11 @@ interface TrueSheetViewControllerDelegate {
66
66
  // =============================================================================
67
67
 
68
68
  /**
69
- * Manages the bottom sheet using CoordinatorLayout + BottomSheetBehavior.
69
+ * Controls the presentation and behavior of a bottom sheet.
70
70
  *
71
- * This approach keeps the sheet in the same activity window (no separate dialog window),
72
- * which allows touch events to pass through to underlying views when the sheet is not
73
- * covering them. This solves the touch lag issue when sheets are presented over
74
- * interactive components like Maps.
71
+ * Uses CoordinatorLayout with BottomSheetBehavior to manage the sheet within the activity window,
72
+ * enabling touch pass-through to underlying views. Handles detent configuration, drag interactions,
73
+ * keyboard avoidance, dimmed backgrounds, back button, and lifecycle events for stacked sheets.
75
74
  */
76
75
  @SuppressLint("ClickableViewAccessibility", "ViewConstructor")
77
76
  class TrueSheetViewController(private val reactContext: ThemedReactContext) :
@@ -89,6 +88,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
89
88
  private const val DEFAULT_CORNER_RADIUS = 16 // dp
90
89
  private const val TRANSLATE_ANIMATION_DURATION = 200L
91
90
  private const val DISMISS_DURATION = 200L
91
+ private const val MODAL_FADE_DURATION = 150L
92
92
  }
93
93
 
94
94
  // =============================================================================
@@ -190,6 +190,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
190
190
  if (isPresented) sheetView?.setupGrabber()
191
191
  }
192
192
 
193
+ val isDimmedAtCurrentDetent: Boolean
194
+ get() = dimmed && currentDetentIndex >= dimmedDetentIndex
195
+
193
196
  // =============================================================================
194
197
  // MARK: - Computed Properties
195
198
  // =============================================================================
@@ -336,9 +339,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
336
339
  backCallback = object : OnBackPressedCallback(true) {
337
340
  override fun handleOnBackPressed() {
338
341
  delegate?.viewControllerDidBackPress()
339
- if (dismissible) {
340
- dismiss(animated = true)
341
- }
342
+ dismissOrCollapseToLowest()
342
343
  }
343
344
  }
344
345
 
@@ -366,26 +367,26 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
366
367
  // =============================================================================
367
368
 
368
369
  override fun dimViewDidTap() {
369
- val hostView = delegate as? TrueSheetView
370
- if (hostView == null) {
371
- RNLog.e(reactContext, "TrueSheet: Expected delegate to be TrueSheetView")
372
- return
373
- }
370
+ val hostView = delegate as? TrueSheetView ?: return
371
+
372
+ val children = TrueSheetStackManager.getSheetsAbove(hostView)
373
+ val topmostChild = children.firstOrNull()?.viewController
374
374
 
375
- // If there's a child sheet on top, handle it instead
376
- val topmostChild = TrueSheetStackManager.getSheetsAbove(hostView).firstOrNull()
377
- if (topmostChild != null) {
378
- if (topmostChild.viewController.dismissible) {
379
- topmostChild.viewController.dismiss(animated = true)
375
+ // If topmost child is dimmed, only handle that child
376
+ if (topmostChild?.isDimmedAtCurrentDetent == true) {
377
+ if (topmostChild.dismissible) {
378
+ topmostChild.dismiss(animated = true)
380
379
  }
381
380
  return
382
381
  }
383
382
 
384
- if (dismissible) {
385
- dismiss(animated = true)
386
- } else if (parentSheetView == null && currentDetentIndex > 0) {
387
- setStateForDetentIndex(0)
383
+ // Pass through to parent - dismiss all if possible
384
+ val allDismissible = dismissible && children.all { it.viewController.dismissible }
385
+ if (allDismissible) {
386
+ children.forEach { it.viewController.dismiss(animated = true) }
388
387
  }
388
+
389
+ dismissOrCollapseToLowest()
389
390
  }
390
391
 
391
392
  // =============================================================================
@@ -533,16 +534,31 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
533
534
  }
534
535
 
535
536
  private fun hideForModal() {
537
+ val sheet = sheetView ?: run {
538
+ RNLog.e(reactContext, "TrueSheet: sheetView is null in hideForModal")
539
+ return
540
+ }
541
+
536
542
  isSheetVisible = false
537
543
  wasHiddenByModal = true
538
- dimViews.forEach { it.alpha = 0f }
539
- setSheetVisibility(false)
544
+
545
+ dimViews.forEach { it.animate().alpha(0f).setDuration(MODAL_FADE_DURATION).start() }
546
+ sheet.animate()
547
+ .alpha(0f)
548
+ .setDuration(MODAL_FADE_DURATION)
549
+ .withEndAction {
550
+ setSheetVisibility(false)
551
+ }
552
+ .start()
553
+
554
+ // This will hide parent sheets first
540
555
  parentSheetView?.viewController?.hideForModal()
541
556
  }
542
557
 
543
558
  private fun showAfterModal() {
544
559
  isSheetVisible = true
545
560
  setSheetVisibility(true)
561
+ sheetView?.alpha = 1f
546
562
  updateDimAmount(animated = true)
547
563
  }
548
564
 
@@ -659,6 +675,14 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
659
675
  }
660
676
  }
661
677
 
678
+ private fun dismissOrCollapseToLowest() {
679
+ if (dismissible) {
680
+ dismiss(animated = true)
681
+ } else if (parentSheetView == null && isDimmedAtCurrentDetent && dimmedDetentIndex > 0) {
682
+ setStateForDetentIndex(dimmedDetentIndex - 1)
683
+ }
684
+ }
685
+
662
686
  private fun animateDismiss() {
663
687
  val sheet = sheetView ?: run {
664
688
  finishDismiss()
@@ -2,11 +2,13 @@ package com.lodev09.truesheet.core
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.graphics.Color
5
+ import android.graphics.Outline
5
6
  import android.graphics.drawable.ShapeDrawable
6
7
  import android.graphics.drawable.shapes.RoundRectShape
7
8
  import android.util.TypedValue
8
9
  import android.view.Gravity
9
10
  import android.view.View
11
+ import android.view.ViewOutlineProvider
10
12
  import android.widget.FrameLayout
11
13
  import androidx.coordinatorlayout.widget.CoordinatorLayout
12
14
  import com.facebook.react.uimanager.PixelUtil.dpToPx
@@ -113,6 +115,12 @@ class TrueSheetBottomSheetView(private val reactContext: ThemedReactContext) : F
113
115
  background = ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply {
114
116
  paint.color = color
115
117
  }
118
+
119
+ outlineProvider = object : ViewOutlineProvider() {
120
+ override fun getOutline(view: View, outline: Outline) {
121
+ outline.setRoundRect(0, 0, view.width, view.height, effectiveRadius)
122
+ }
123
+ }
116
124
  clipToOutline = true
117
125
  }
118
126
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lodev09/react-native-true-sheet",
3
- "version": "3.5.1-beta.4",
3
+ "version": "3.5.1",
4
4
  "description": "The true native bottom sheet experience for your React Native Apps.",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./lib/module/index.js",