@lodev09/react-native-true-sheet 3.0.0-beta.13 → 3.0.0-beta.15

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 (74) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +20 -20
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +49 -14
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +10 -1
  4. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogObserver.kt +17 -43
  5. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
  6. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
  7. package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +94 -0
  8. package/android/src/main/java/com/lodev09/truesheet/events/{PositionChangeEvent.kt → TrueSheetStateEvents.kt} +25 -3
  9. package/ios/TrueSheetView.mm +39 -25
  10. package/ios/TrueSheetViewController.h +7 -1
  11. package/ios/TrueSheetViewController.mm +101 -51
  12. package/ios/core/TrueSheetBlurView.h +24 -0
  13. package/ios/{utils/ConversionUtil.mm → core/TrueSheetBlurView.mm} +65 -3
  14. package/ios/events/TrueSheetDragEvents.h +39 -0
  15. package/ios/events/TrueSheetDragEvents.mm +62 -0
  16. package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -6
  17. package/ios/events/TrueSheetFocusEvents.mm +49 -0
  18. package/ios/events/TrueSheetLifecycleEvents.h +40 -0
  19. package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
  20. package/ios/events/TrueSheetStateEvents.h +35 -0
  21. package/ios/events/TrueSheetStateEvents.mm +49 -0
  22. package/ios/utils/GestureUtil.h +7 -0
  23. package/ios/utils/GestureUtil.mm +12 -0
  24. package/lib/module/TrueSheet.js +12 -0
  25. package/lib/module/TrueSheet.js.map +1 -1
  26. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +8 -1
  27. package/lib/module/reanimated/ReanimatedTrueSheet.js +6 -6
  28. package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
  29. package/lib/typescript/src/TrueSheet.d.ts +2 -0
  30. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  31. package/lib/typescript/src/TrueSheet.types.d.ts +37 -3
  32. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  33. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +6 -1
  34. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  35. package/package.json +1 -1
  36. package/src/TrueSheet.tsx +16 -0
  37. package/src/TrueSheet.types.ts +42 -3
  38. package/src/fabric/TrueSheetViewNativeComponent.ts +8 -1
  39. package/src/reanimated/ReanimatedTrueSheet.tsx +6 -6
  40. package/android/src/main/java/com/lodev09/truesheet/events/BlurEvent.kt +0 -20
  41. package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -27
  42. package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
  43. package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -27
  44. package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -27
  45. package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -27
  46. package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -27
  47. package/android/src/main/java/com/lodev09/truesheet/events/FocusEvent.kt +0 -20
  48. package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
  49. package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
  50. package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -27
  51. package/ios/events/OnDetentChangeEvent.h +0 -29
  52. package/ios/events/OnDetentChangeEvent.mm +0 -32
  53. package/ios/events/OnDidBlurEvent.h +0 -26
  54. package/ios/events/OnDidBlurEvent.mm +0 -25
  55. package/ios/events/OnDidDismissEvent.h +0 -26
  56. package/ios/events/OnDidDismissEvent.mm +0 -25
  57. package/ios/events/OnDidFocusEvent.h +0 -26
  58. package/ios/events/OnDidFocusEvent.mm +0 -25
  59. package/ios/events/OnDidPresentEvent.h +0 -29
  60. package/ios/events/OnDidPresentEvent.mm +0 -32
  61. package/ios/events/OnDragBeginEvent.h +0 -29
  62. package/ios/events/OnDragBeginEvent.mm +0 -32
  63. package/ios/events/OnDragChangeEvent.h +0 -29
  64. package/ios/events/OnDragChangeEvent.mm +0 -32
  65. package/ios/events/OnDragEndEvent.h +0 -29
  66. package/ios/events/OnDragEndEvent.mm +0 -32
  67. package/ios/events/OnMountEvent.h +0 -26
  68. package/ios/events/OnMountEvent.mm +0 -25
  69. package/ios/events/OnPositionChangeEvent.mm +0 -34
  70. package/ios/events/OnWillDismissEvent.h +0 -26
  71. package/ios/events/OnWillDismissEvent.mm +0 -25
  72. package/ios/events/OnWillPresentEvent.h +0 -29
  73. package/ios/events/OnWillPresentEvent.mm +0 -32
  74. package/ios/utils/ConversionUtil.h +0 -24
@@ -14,18 +14,7 @@ import com.facebook.react.uimanager.UIManagerHelper
14
14
  import com.facebook.react.uimanager.events.EventDispatcher
15
15
  import com.facebook.react.views.view.ReactViewGroup
16
16
  import com.lodev09.truesheet.core.TrueSheetDialogObserver
17
- import com.lodev09.truesheet.events.BlurEvent
18
- import com.lodev09.truesheet.events.DetentChangeEvent
19
- import com.lodev09.truesheet.events.DidDismissEvent
20
- import com.lodev09.truesheet.events.DidPresentEvent
21
- import com.lodev09.truesheet.events.DragBeginEvent
22
- import com.lodev09.truesheet.events.DragChangeEvent
23
- import com.lodev09.truesheet.events.DragEndEvent
24
- import com.lodev09.truesheet.events.FocusEvent
25
- import com.lodev09.truesheet.events.MountEvent
26
- import com.lodev09.truesheet.events.PositionChangeEvent
27
- import com.lodev09.truesheet.events.WillDismissEvent
28
- import com.lodev09.truesheet.events.WillPresentEvent
17
+ import com.lodev09.truesheet.events.*
29
18
 
30
19
  /**
31
20
  * Main TrueSheet host view that manages the sheet dialog and dispatches events to JavaScript.
@@ -187,12 +176,11 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
187
176
  containerView?.footerView?.eventDispatcher = null
188
177
  }
189
178
 
190
- override fun viewControllerDidDismiss() {
179
+ override fun viewControllerDidDismiss(hadParent: Boolean) {
191
180
  val surfaceId = UIManagerHelper.getSurfaceId(this)
192
181
  eventDispatcher?.dispatchEvent(DidDismissEvent(surfaceId, id))
193
182
 
194
- // Notify observer that this sheet was dismissed (will show/focus parent sheet)
195
- TrueSheetDialogObserver.onSheetDidDismiss(this)
183
+ TrueSheetDialogObserver.onSheetDidDismiss(this, hadParent)
196
184
  }
197
185
 
198
186
  override fun viewControllerDidChangeDetent(index: Int, position: Float, detent: Float) {
@@ -215,20 +203,30 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
215
203
  eventDispatcher?.dispatchEvent(DragEndEvent(surfaceId, id, index, position, detent))
216
204
  }
217
205
 
218
- override fun viewControllerDidChangePosition(index: Float, position: Float, detent: Float, transitioning: Boolean) {
206
+ override fun viewControllerDidChangePosition(index: Float, position: Float, detent: Float, realtime: Boolean) {
219
207
  val surfaceId = UIManagerHelper.getSurfaceId(this)
220
- eventDispatcher?.dispatchEvent(PositionChangeEvent(surfaceId, id, index, position, detent, transitioning))
208
+ eventDispatcher?.dispatchEvent(PositionChangeEvent(surfaceId, id, index, position, detent, realtime))
221
209
  }
222
210
 
223
211
  override fun viewControllerDidChangeSize(width: Int, height: Int) {
224
212
  updateState(width, height)
225
213
  }
226
214
 
215
+ override fun viewControllerWillFocus() {
216
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
217
+ eventDispatcher?.dispatchEvent(WillFocusEvent(surfaceId, id))
218
+ }
219
+
227
220
  override fun viewControllerDidFocus() {
228
221
  val surfaceId = UIManagerHelper.getSurfaceId(this)
229
222
  eventDispatcher?.dispatchEvent(FocusEvent(surfaceId, id))
230
223
  }
231
224
 
225
+ override fun viewControllerWillBlur() {
226
+ val surfaceId = UIManagerHelper.getSurfaceId(this)
227
+ eventDispatcher?.dispatchEvent(WillBlurEvent(surfaceId, id))
228
+ }
229
+
232
230
  override fun viewControllerDidBlur() {
233
231
  val surfaceId = UIManagerHelper.getSurfaceId(this)
234
232
  eventDispatcher?.dispatchEvent(BlurEvent(surfaceId, id))
@@ -275,6 +273,10 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
275
273
  viewController.dismissible = dismissible
276
274
  }
277
275
 
276
+ fun setDraggable(draggable: Boolean) {
277
+ viewController.draggable = draggable
278
+ }
279
+
278
280
  fun setGrabber(grabber: Boolean) {
279
281
  viewController.grabber = grabber
280
282
  }
@@ -309,11 +311,9 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
309
311
 
310
312
  @UiThread
311
313
  fun present(detentIndex: Int, animated: Boolean = true, promiseCallback: () -> Unit) {
312
- // Notify observer that this sheet will present (will hide/blur topmost sheet)
313
314
  if (!viewController.isPresented) {
314
- TrueSheetDialogObserver.onSheetWillPresent(this, detentIndex)
315
+ viewController.parentSheetView = TrueSheetDialogObserver.onSheetWillPresent(this, detentIndex)
315
316
  }
316
-
317
317
  viewController.presentPromise = promiseCallback
318
318
  viewController.present(detentIndex, animated)
319
319
  }
@@ -34,14 +34,16 @@ interface TrueSheetViewControllerDelegate {
34
34
  fun viewControllerWillPresent(index: Int, position: Float, detent: Float)
35
35
  fun viewControllerDidPresent(index: Int, position: Float, detent: Float)
36
36
  fun viewControllerWillDismiss()
37
- fun viewControllerDidDismiss()
37
+ fun viewControllerDidDismiss(hadParent: Boolean)
38
38
  fun viewControllerDidChangeDetent(index: Int, position: Float, detent: Float)
39
39
  fun viewControllerDidDragBegin(index: Int, position: Float, detent: Float)
40
40
  fun viewControllerDidDragChange(index: Int, position: Float, detent: Float)
41
41
  fun viewControllerDidDragEnd(index: Int, position: Float, detent: Float)
42
- fun viewControllerDidChangePosition(index: Float, position: Float, detent: Float, transitioning: Boolean)
42
+ fun viewControllerDidChangePosition(index: Float, position: Float, detent: Float, realtime: Boolean)
43
43
  fun viewControllerDidChangeSize(width: Int, height: Int)
44
+ fun viewControllerWillFocus()
44
45
  fun viewControllerDidFocus()
46
+ fun viewControllerWillBlur()
45
47
  fun viewControllerDidBlur()
46
48
  }
47
49
 
@@ -109,6 +111,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
109
111
  var isPresented = false
110
112
  private set
111
113
 
114
+ var isDialogVisible = false
115
+ private set
116
+
112
117
  var currentDetentIndex: Int = -1
113
118
  private set
114
119
 
@@ -119,6 +124,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
119
124
  var presentPromise: (() -> Unit)? = null
120
125
  var dismissPromise: (() -> Unit)? = null
121
126
 
127
+ // Reference to parent TrueSheetView (if presented from another sheet)
128
+ var parentSheetView: TrueSheetView? = null
129
+
122
130
  // ====================================================================
123
131
  // MARK: - Configuration Properties
124
132
  // ====================================================================
@@ -145,6 +153,12 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
145
153
  }
146
154
  }
147
155
 
156
+ var draggable: Boolean = true
157
+ set(value) {
158
+ field = value
159
+ behavior?.isDraggable = value
160
+ }
161
+
148
162
  // ====================================================================
149
163
  // MARK: - Computed Properties
150
164
  // ====================================================================
@@ -226,6 +240,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
226
240
  setCanceledOnTouchOutside(dismissible)
227
241
  setCancelable(dismissible)
228
242
  behavior.isHideable = dismissible
243
+ behavior.isDraggable = draggable
229
244
  }
230
245
  }
231
246
 
@@ -242,12 +257,14 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
242
257
  dialog = null
243
258
  isDragging = false
244
259
  isPresented = false
260
+ isDialogVisible = false
245
261
  lastEmittedPositionPx = -1
246
262
  }
247
263
 
248
264
  private fun setupDialogListeners(dialog: BottomSheetDialog) {
249
265
  dialog.setOnShowListener {
250
266
  isPresented = true
267
+ isDialogVisible = true
251
268
  resetAnimation()
252
269
  setupBackground()
253
270
  setupGrabber()
@@ -257,7 +274,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
257
274
  val detent = getDetentValueForIndex(detentInfo.index)
258
275
  val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
259
276
  delegate?.viewControllerDidPresent(detentInfo.index, detentInfo.position, detent)
260
- emitChangePositionDelegate(detentInfo.index, positionPx, transitioning = true)
277
+ emitChangePositionDelegate(detentInfo.index, positionPx, realtime = false)
278
+
279
+ // Notify parent sheet that it has lost focus (after this sheet appeared)
280
+ parentSheetView?.viewControllerDidBlur()
261
281
 
262
282
  presentPromise?.invoke()
263
283
  presentPromise = null
@@ -267,13 +287,22 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
267
287
  }
268
288
 
269
289
  dialog.setOnCancelListener {
290
+ // Notify parent sheet that it is about to regain focus
291
+ parentSheetView?.viewControllerWillFocus()
292
+
270
293
  delegate?.viewControllerWillDismiss()
271
294
  }
272
295
 
273
296
  dialog.setOnDismissListener {
297
+ val hadParent = parentSheetView != null
298
+
299
+ // Notify parent sheet that it has regained focus
300
+ parentSheetView?.viewControllerDidFocus()
301
+ parentSheetView = null
302
+
274
303
  dismissPromise?.invoke()
275
304
  dismissPromise = null
276
- delegate?.viewControllerDidDismiss()
305
+ delegate?.viewControllerDidDismiss(hadParent)
277
306
  cleanupDialog()
278
307
  }
279
308
  }
@@ -286,7 +315,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
286
315
  val positionPx = getCurrentPositionPx(sheetView)
287
316
  val detentIndex = getDetentIndexForPosition(positionPx)
288
317
 
289
- emitChangePositionDelegate(detentIndex, positionPx, transitioning = false)
318
+ emitChangePositionDelegate(detentIndex, positionPx, realtime = true)
290
319
 
291
320
  when (behavior.state) {
292
321
  BottomSheetBehavior.STATE_DRAGGING,
@@ -374,13 +403,14 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
374
403
 
375
404
  /**
376
405
  * Hides the dialog without dismissing it.
377
- * Used when another TrueSheet presents on top.
406
+ * Used when another TrueSheet presents on top or when RN screen is presented.
378
407
  */
379
408
  fun hideDialog() {
409
+ isDialogVisible = false
380
410
  dialog?.window?.decorView?.visibility = View.INVISIBLE
381
411
 
382
412
  // Emit off-screen position (detent = 0 since sheet is fully hidden)
383
- emitChangePositionDelegate(currentDetentIndex, screenHeight, transitioning = true)
413
+ emitChangePositionDelegate(currentDetentIndex, screenHeight, realtime = false)
384
414
  }
385
415
 
386
416
  /**
@@ -388,11 +418,12 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
388
418
  * Used when the sheet on top dismisses.
389
419
  */
390
420
  fun showDialog() {
421
+ isDialogVisible = true
391
422
  dialog?.window?.decorView?.visibility = View.VISIBLE
392
423
 
393
424
  // Emit current position
394
425
  val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
395
- emitChangePositionDelegate(currentDetentIndex, positionPx, transitioning = true)
426
+ emitChangePositionDelegate(currentDetentIndex, positionPx, realtime = false)
396
427
  }
397
428
 
398
429
  // ====================================================================
@@ -420,6 +451,10 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
420
451
 
421
452
  val detentInfo = getDetentInfoForIndex(detentIndex)
422
453
  val detent = getDetentValueForIndex(detentInfo.index)
454
+
455
+ // Notify parent sheet that it is about to lose focus (before this sheet appears)
456
+ parentSheetView?.viewControllerWillBlur()
457
+
423
458
  delegate?.viewControllerWillPresent(detentInfo.index, detentInfo.position, detent)
424
459
 
425
460
  if (!animated) {
@@ -433,7 +468,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
433
468
  fun dismiss() {
434
469
  this.post {
435
470
  // Emit off-screen position (detent = 0 since sheet is fully hidden)
436
- emitChangePositionDelegate(currentDetentIndex, screenHeight, transitioning = true)
471
+ emitChangePositionDelegate(currentDetentIndex, screenHeight, realtime = false)
437
472
  }
438
473
  dialog?.dismiss()
439
474
  }
@@ -487,7 +522,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
487
522
  bottomSheet.removeView(it)
488
523
  }
489
524
 
490
- if (!grabber) return
525
+ if (!grabber || !draggable) return
491
526
 
492
527
  val grabberView = View(reactContext).apply {
493
528
  tag = GRABBER_TAG
@@ -607,16 +642,16 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
607
642
  * Emits position change to the delegate if the position has changed.
608
643
  * @param index The current detent index (discrete, used as fallback)
609
644
  * @param positionPx The current position in pixels (screen Y coordinate)
610
- * @param transitioning Whether the sheet is transitioning (programmatic) vs dragging
645
+ * @param realtime Whether the position is a real-time value (during drag or animation tracking)
611
646
  */
612
- private fun emitChangePositionDelegate(index: Int, positionPx: Int, transitioning: Boolean) {
647
+ private fun emitChangePositionDelegate(index: Int, positionPx: Int, realtime: Boolean) {
613
648
  if (positionPx == lastEmittedPositionPx) return
614
649
 
615
650
  lastEmittedPositionPx = positionPx
616
651
  val position = positionPx.pxToDp()
617
652
  val interpolatedIndex = getInterpolatedIndexForPosition(positionPx)
618
653
  val detent = getDetentValueForIndex(kotlin.math.round(interpolatedIndex).toInt())
619
- delegate?.viewControllerDidChangePosition(interpolatedIndex, position, detent, transitioning)
654
+ delegate?.viewControllerDidChangePosition(interpolatedIndex, position, detent, realtime)
620
655
  }
621
656
 
622
657
  /**
@@ -835,7 +870,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
835
870
  this.post {
836
871
  positionFooter()
837
872
  val positionPx = bottomSheetView?.let { ScreenUtils.getScreenY(it) } ?: screenHeight
838
- emitChangePositionDelegate(currentDetentIndex, positionPx, transitioning = true)
873
+ emitChangePositionDelegate(currentDetentIndex, positionPx, realtime = false)
839
874
  }
840
875
  }
841
876
  }
@@ -67,7 +67,11 @@ class TrueSheetViewManager :
67
67
  DragBeginEvent.EVENT_NAME to hashMapOf("registrationName" to DragBeginEvent.REGISTRATION_NAME),
68
68
  DragChangeEvent.EVENT_NAME to hashMapOf("registrationName" to DragChangeEvent.REGISTRATION_NAME),
69
69
  DragEndEvent.EVENT_NAME to hashMapOf("registrationName" to DragEndEvent.REGISTRATION_NAME),
70
- PositionChangeEvent.EVENT_NAME to hashMapOf("registrationName" to PositionChangeEvent.REGISTRATION_NAME)
70
+ PositionChangeEvent.EVENT_NAME to hashMapOf("registrationName" to PositionChangeEvent.REGISTRATION_NAME),
71
+ WillFocusEvent.EVENT_NAME to hashMapOf("registrationName" to WillFocusEvent.REGISTRATION_NAME),
72
+ FocusEvent.EVENT_NAME to hashMapOf("registrationName" to FocusEvent.REGISTRATION_NAME),
73
+ WillBlurEvent.EVENT_NAME to hashMapOf("registrationName" to WillBlurEvent.REGISTRATION_NAME),
74
+ BlurEvent.EVENT_NAME to hashMapOf("registrationName" to BlurEvent.REGISTRATION_NAME)
71
75
  )
72
76
 
73
77
  // ==================== Props ====================
@@ -110,6 +114,11 @@ class TrueSheetViewManager :
110
114
  view.setDismissible(dismissible)
111
115
  }
112
116
 
117
+ @ReactProp(name = "draggable", defaultBoolean = true)
118
+ override fun setDraggable(view: TrueSheetView, draggable: Boolean) {
119
+ view.setDraggable(draggable)
120
+ }
121
+
113
122
  @ReactProp(name = "dimmed", defaultBoolean = true)
114
123
  override fun setDimmed(view: TrueSheetView, dimmed: Boolean) {
115
124
  view.setDimmed(dimmed)
@@ -3,76 +3,54 @@ package com.lodev09.truesheet.core
3
3
  import com.lodev09.truesheet.TrueSheetView
4
4
 
5
5
  /**
6
- * Observes TrueSheet dialog lifecycle to manage sheet stacking.
7
- * Automatically hides/shows sheets and dispatches focus/blur events
8
- * when sheets are presented on top of each other.
6
+ * Manages TrueSheet stacking behavior.
7
+ * Tracks presented sheets and handles visibility when sheets stack on top of each other.
9
8
  */
10
9
  object TrueSheetDialogObserver {
11
10
 
12
- /**
13
- * Stack of currently presented sheet views (most recent on top)
14
- */
15
11
  private val presentedSheetStack = mutableListOf<TrueSheetView>()
16
12
 
17
13
  /**
18
14
  * Called when a sheet is about to be presented.
19
- * Hides and blurs the current topmost sheet if exists.
20
- *
21
- * @param sheetView The sheet that is about to be presented
22
- * @param detentIndex The detent index the sheet will be presented at
15
+ * Returns the visible parent sheet to stack on, or null if none.
23
16
  */
24
17
  @JvmStatic
25
- fun onSheetWillPresent(sheetView: TrueSheetView, detentIndex: Int) {
18
+ fun onSheetWillPresent(sheetView: TrueSheetView, detentIndex: Int): TrueSheetView? {
26
19
  synchronized(presentedSheetStack) {
27
- // Get the current topmost sheet
28
- val topSheet = presentedSheetStack.lastOrNull()
29
-
30
- // Hide and blur the topmost sheet if it exists
31
- topSheet?.let {
32
- // Don't hide if the top sheet is fully expanded (covers the screen)
33
- // or if the top sheet is smaller than the presenting sheet
34
- // A smaller topSheetTop value means the sheet is taller (closer to top of screen)
35
- val topSheetTop = it.viewController.currentSheetTop
36
- val presentingSheetTop = sheetView.viewController.getExpectedSheetTop(detentIndex)
20
+ val parentSheet = presentedSheetStack.lastOrNull()
21
+ ?.takeIf { it.viewController.isPresented && it.viewController.isDialogVisible }
37
22
 
38
- if (!it.viewController.isExpanded && topSheetTop <= presentingSheetTop) {
23
+ // Hide parent if the new sheet would cover it
24
+ parentSheet?.let {
25
+ val parentTop = it.viewController.currentSheetTop
26
+ val newSheetTop = sheetView.viewController.getExpectedSheetTop(detentIndex)
27
+ if (!it.viewController.isExpanded && parentTop <= newSheetTop) {
39
28
  it.viewController.hideDialog()
40
29
  }
41
- it.viewControllerDidBlur()
42
30
  }
43
31
 
44
- // Add new sheet to stack
45
32
  if (!presentedSheetStack.contains(sheetView)) {
46
33
  presentedSheetStack.add(sheetView)
47
34
  }
35
+
36
+ return parentSheet
48
37
  }
49
38
  }
50
39
 
51
40
  /**
52
41
  * Called when a sheet has been dismissed.
53
- * Shows and focuses the sheet below it (if any).
54
- *
55
- * @param sheetView The sheet that was dismissed
42
+ * Shows the parent sheet if this sheet was stacked on it.
56
43
  */
57
44
  @JvmStatic
58
- fun onSheetDidDismiss(sheetView: TrueSheetView) {
45
+ fun onSheetDidDismiss(sheetView: TrueSheetView, hadParent: Boolean) {
59
46
  synchronized(presentedSheetStack) {
60
47
  presentedSheetStack.remove(sheetView)
61
-
62
- // Show and focus the new topmost sheet
63
- presentedSheetStack.lastOrNull()?.let {
64
- it.viewController.showDialog()
65
- it.viewControllerDidFocus()
48
+ if (hadParent) {
49
+ presentedSheetStack.lastOrNull()?.viewController?.showDialog()
66
50
  }
67
51
  }
68
52
  }
69
53
 
70
- /**
71
- * Removes a sheet from the stack without triggering focus events.
72
- * Used when a sheet is being destroyed/cleaned up.
73
- *
74
- * @param sheetView The sheet to remove
75
- */
76
54
  @JvmStatic
77
55
  fun removeSheet(sheetView: TrueSheetView) {
78
56
  synchronized(presentedSheetStack) {
@@ -80,10 +58,6 @@ object TrueSheetDialogObserver {
80
58
  }
81
59
  }
82
60
 
83
- /**
84
- * Clears all tracked sheets.
85
- * Used when the module is invalidated.
86
- */
87
61
  @JvmStatic
88
62
  fun clear() {
89
63
  synchronized(presentedSheetStack) {
@@ -0,0 +1,71 @@
1
+ package com.lodev09.truesheet.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ /**
8
+ * Fired when dragging begins
9
+ * Payload: { index: number, position: number, detent: number }
10
+ */
11
+ class DragBeginEvent(surfaceId: Int, viewId: Int, private val index: Int, private val position: Float, private val detent: Float) :
12
+ Event<DragBeginEvent>(surfaceId, viewId) {
13
+
14
+ override fun getEventName(): String = EVENT_NAME
15
+
16
+ override fun getEventData(): WritableMap =
17
+ Arguments.createMap().apply {
18
+ putInt("index", index)
19
+ putDouble("position", position.toDouble())
20
+ putDouble("detent", detent.toDouble())
21
+ }
22
+
23
+ companion object {
24
+ const val EVENT_NAME = "topDragBegin"
25
+ const val REGISTRATION_NAME = "onDragBegin"
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Fired continuously during dragging
31
+ * Payload: { index: number, position: number, detent: number }
32
+ */
33
+ class DragChangeEvent(surfaceId: Int, viewId: Int, private val index: Int, private val position: Float, private val detent: Float) :
34
+ Event<DragChangeEvent>(surfaceId, viewId) {
35
+
36
+ override fun getEventName(): String = EVENT_NAME
37
+
38
+ override fun getEventData(): WritableMap =
39
+ Arguments.createMap().apply {
40
+ putInt("index", index)
41
+ putDouble("position", position.toDouble())
42
+ putDouble("detent", detent.toDouble())
43
+ }
44
+
45
+ companion object {
46
+ const val EVENT_NAME = "topDragChange"
47
+ const val REGISTRATION_NAME = "onDragChange"
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Fired when dragging ends
53
+ * Payload: { index: number, position: number, detent: number }
54
+ */
55
+ class DragEndEvent(surfaceId: Int, viewId: Int, private val index: Int, private val position: Float, private val detent: Float) :
56
+ Event<DragEndEvent>(surfaceId, viewId) {
57
+
58
+ override fun getEventName(): String = EVENT_NAME
59
+
60
+ override fun getEventData(): WritableMap =
61
+ Arguments.createMap().apply {
62
+ putInt("index", index)
63
+ putDouble("position", position.toDouble())
64
+ putDouble("detent", detent.toDouble())
65
+ }
66
+
67
+ companion object {
68
+ const val EVENT_NAME = "topDragEnd"
69
+ const val REGISTRATION_NAME = "onDragEnd"
70
+ }
71
+ }
@@ -0,0 +1,65 @@
1
+ package com.lodev09.truesheet.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ /**
8
+ * Fired when the sheet is about to regain focus because a sheet on top of it is being dismissed
9
+ */
10
+ class WillFocusEvent(surfaceId: Int, viewId: Int) : Event<WillFocusEvent>(surfaceId, viewId) {
11
+
12
+ override fun getEventName(): String = EVENT_NAME
13
+
14
+ override fun getEventData(): WritableMap = Arguments.createMap()
15
+
16
+ companion object {
17
+ const val EVENT_NAME = "topWillFocus"
18
+ const val REGISTRATION_NAME = "onWillFocus"
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Fired when the sheet regains focus after a sheet on top of it is dismissed
24
+ */
25
+ class FocusEvent(surfaceId: Int, viewId: Int) : Event<FocusEvent>(surfaceId, viewId) {
26
+
27
+ override fun getEventName(): String = EVENT_NAME
28
+
29
+ override fun getEventData(): WritableMap = Arguments.createMap()
30
+
31
+ companion object {
32
+ const val EVENT_NAME = "topDidFocus"
33
+ const val REGISTRATION_NAME = "onDidFocus"
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Fired when the sheet is about to lose focus because another sheet is being presented on top of it
39
+ */
40
+ class WillBlurEvent(surfaceId: Int, viewId: Int) : Event<WillBlurEvent>(surfaceId, viewId) {
41
+
42
+ override fun getEventName(): String = EVENT_NAME
43
+
44
+ override fun getEventData(): WritableMap = Arguments.createMap()
45
+
46
+ companion object {
47
+ const val EVENT_NAME = "topWillBlur"
48
+ const val REGISTRATION_NAME = "onWillBlur"
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Fired when the sheet loses focus because another sheet is presented on top of it
54
+ */
55
+ class BlurEvent(surfaceId: Int, viewId: Int) : Event<BlurEvent>(surfaceId, viewId) {
56
+
57
+ override fun getEventName(): String = EVENT_NAME
58
+
59
+ override fun getEventData(): WritableMap = Arguments.createMap()
60
+
61
+ companion object {
62
+ const val EVENT_NAME = "topDidBlur"
63
+ const val REGISTRATION_NAME = "onDidBlur"
64
+ }
65
+ }
@@ -0,0 +1,94 @@
1
+ package com.lodev09.truesheet.events
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.facebook.react.uimanager.events.Event
6
+
7
+ /**
8
+ * Fired when the sheet component is mounted and ready
9
+ */
10
+ class MountEvent(surfaceId: Int, viewId: Int) : Event<MountEvent>(surfaceId, viewId) {
11
+
12
+ override fun getEventName(): String = EVENT_NAME
13
+
14
+ override fun getEventData(): WritableMap = Arguments.createMap()
15
+
16
+ companion object {
17
+ const val EVENT_NAME = "topMount"
18
+ const val REGISTRATION_NAME = "onMount"
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Fired before the sheet is presented
24
+ * Payload: { index: number, position: number, detent: number }
25
+ */
26
+ class WillPresentEvent(surfaceId: Int, viewId: Int, private val index: Int, private val position: Float, private val detent: Float) :
27
+ Event<WillPresentEvent>(surfaceId, viewId) {
28
+
29
+ override fun getEventName(): String = EVENT_NAME
30
+
31
+ override fun getEventData(): WritableMap =
32
+ Arguments.createMap().apply {
33
+ putInt("index", index)
34
+ putDouble("position", position.toDouble())
35
+ putDouble("detent", detent.toDouble())
36
+ }
37
+
38
+ companion object {
39
+ const val EVENT_NAME = "topWillPresent"
40
+ const val REGISTRATION_NAME = "onWillPresent"
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Fired after the sheet is presented
46
+ * Payload: { index: number, position: number, detent: number }
47
+ */
48
+ class DidPresentEvent(surfaceId: Int, viewId: Int, private val index: Int, private val position: Float, private val detent: Float) :
49
+ Event<DidPresentEvent>(surfaceId, viewId) {
50
+
51
+ override fun getEventName(): String = EVENT_NAME
52
+
53
+ override fun getEventData(): WritableMap =
54
+ Arguments.createMap().apply {
55
+ putInt("index", index)
56
+ putDouble("position", position.toDouble())
57
+ putDouble("detent", detent.toDouble())
58
+ }
59
+
60
+ companion object {
61
+ const val EVENT_NAME = "topDidPresent"
62
+ const val REGISTRATION_NAME = "onDidPresent"
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Fired before the sheet is dismissed
68
+ */
69
+ class WillDismissEvent(surfaceId: Int, viewId: Int) : Event<WillDismissEvent>(surfaceId, viewId) {
70
+
71
+ override fun getEventName(): String = EVENT_NAME
72
+
73
+ override fun getEventData(): WritableMap = Arguments.createMap()
74
+
75
+ companion object {
76
+ const val EVENT_NAME = "topWillDismiss"
77
+ const val REGISTRATION_NAME = "onWillDismiss"
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Fired after the sheet is dismissed
83
+ */
84
+ class DidDismissEvent(surfaceId: Int, viewId: Int) : Event<DidDismissEvent>(surfaceId, viewId) {
85
+
86
+ override fun getEventName(): String = EVENT_NAME
87
+
88
+ override fun getEventData(): WritableMap = Arguments.createMap()
89
+
90
+ companion object {
91
+ const val EVENT_NAME = "topDidDismiss"
92
+ const val REGISTRATION_NAME = "onDidDismiss"
93
+ }
94
+ }