@lodev09/react-native-true-sheet 3.8.0-beta.1 → 3.8.0-beta.3
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/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +22 -2
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +29 -31
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +10 -9
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +6 -12
- package/ios/TrueSheetContainerView.mm +7 -0
- package/ios/TrueSheetContentView.mm +7 -1
- package/ios/TrueSheetModule.mm +33 -9
- package/ios/TrueSheetView.h +3 -1
- package/ios/TrueSheetView.mm +47 -40
- package/ios/TrueSheetViewController.h +1 -0
- package/ios/TrueSheetViewController.mm +4 -8
- package/ios/core/RNScreensEventObserver.mm +23 -15
- package/lib/module/TrueSheet.js +45 -26
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +26 -40
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/TrueSheetProvider.js +1 -0
- package/lib/module/TrueSheetProvider.js.map +1 -1
- package/lib/module/TrueSheetProvider.web.js +7 -32
- package/lib/module/TrueSheetProvider.web.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks/index.js +3 -0
- package/lib/module/mocks/index.js.map +1 -1
- package/lib/module/mocks/reanimated.js +2 -0
- package/lib/module/mocks/reanimated.js.map +1 -1
- package/lib/module/navigation/TrueSheetRouter.js +42 -8
- package/lib/module/navigation/TrueSheetRouter.js.map +1 -1
- package/lib/module/navigation/screen/useSheetScreenState.js +8 -17
- package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
- package/lib/module/reanimated/ReanimatedTrueSheet.web.js +2 -2
- package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -1
- package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +29 -2
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +0 -48
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts +4 -2
- package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheetProvider.d.ts +3 -2
- package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheetProvider.web.d.ts +6 -14
- package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/index.d.ts +6 -3
- package/lib/typescript/src/mocks/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/reanimated.d.ts +4 -2
- package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -1
- package/lib/typescript/src/navigation/TrueSheetRouter.d.ts.map +1 -1
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +4 -3
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +9 -1
- package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/TrueSheet.tsx +45 -35
- package/src/TrueSheet.types.ts +0 -50
- package/src/TrueSheet.web.tsx +32 -50
- package/src/TrueSheetProvider.tsx +7 -2
- package/src/TrueSheetProvider.web.tsx +19 -38
- package/src/index.ts +1 -1
- package/src/mocks/index.ts +7 -6
- package/src/mocks/reanimated.ts +4 -5
- package/src/navigation/TrueSheetRouter.ts +51 -16
- package/src/navigation/screen/useSheetScreenState.ts +5 -11
- package/src/reanimated/ReanimatedTrueSheet.web.tsx +28 -30
- package/src/specs/NativeTrueSheetModule.ts +10 -1
|
@@ -54,7 +54,7 @@ class TrueSheetModule(reactContext: ReactApplicationContext) :
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Dismiss a sheet
|
|
57
|
+
* Dismiss a sheet and all sheets presented on top of it
|
|
58
58
|
*
|
|
59
59
|
* @param viewTag Native view tag of the sheet component
|
|
60
60
|
* @param promise Promise that resolves when sheet is fully dismissed
|
|
@@ -73,6 +73,26 @@ class TrueSheetModule(reactContext: ReactApplicationContext) :
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Dismiss only the sheets presented on top of this sheet, keeping this sheet presented
|
|
78
|
+
*
|
|
79
|
+
* @param viewTag Native view tag of the sheet component
|
|
80
|
+
* @param promise Promise that resolves when all child sheets are fully dismissed
|
|
81
|
+
* @throws VIEW_NOT_FOUND if the view with the given tag is not found
|
|
82
|
+
* @throws INVALID_VIEW_TYPE if the view is not a TrueSheetView
|
|
83
|
+
* @throws OPERATION_FAILED if the operation fails for any other reason
|
|
84
|
+
*/
|
|
85
|
+
@ReactMethod
|
|
86
|
+
fun dismissStackByRef(viewTag: Double, animated: Boolean, promise: Promise) {
|
|
87
|
+
val tag = viewTag.toInt()
|
|
88
|
+
|
|
89
|
+
withTrueSheetView(tag, promise) { view ->
|
|
90
|
+
view.dismissStack(animated) {
|
|
91
|
+
promise.resolve(null)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
76
96
|
/**
|
|
77
97
|
* Resize a sheet to a different index by reference
|
|
78
98
|
*
|
|
@@ -111,7 +131,7 @@ class TrueSheetModule(reactContext: ReactApplicationContext) :
|
|
|
111
131
|
return@post
|
|
112
132
|
}
|
|
113
133
|
|
|
114
|
-
rootSheet.
|
|
134
|
+
rootSheet.dismiss(animated) {
|
|
115
135
|
promise.resolve(null)
|
|
116
136
|
}
|
|
117
137
|
} catch (e: Exception) {
|
|
@@ -135,11 +135,13 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
135
135
|
val child = getChildAt(index)
|
|
136
136
|
if (child is TrueSheetContainerView) {
|
|
137
137
|
child.delegate = null
|
|
138
|
-
viewController.createSheetSnapshot()
|
|
139
138
|
|
|
140
|
-
//
|
|
141
|
-
if (viewController.
|
|
142
|
-
|
|
139
|
+
// Skip if already dismissing - snapshot preserves visuals during dismiss
|
|
140
|
+
if (!viewController.isBeingDismissed) {
|
|
141
|
+
viewController.createSheetSnapshot()
|
|
142
|
+
if (viewController.isPresented) {
|
|
143
|
+
dismiss(true) {}
|
|
144
|
+
}
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
viewController.removeView(child)
|
|
@@ -171,13 +173,10 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
171
173
|
cleanupScreenEventObserver()
|
|
172
174
|
didInitiallyPresent = false
|
|
173
175
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
viewController.dismiss()
|
|
179
|
-
} else {
|
|
180
|
-
viewController.delegate = null
|
|
176
|
+
viewController.dismissPromise = { viewController.delegate = null }
|
|
177
|
+
|
|
178
|
+
if (viewController.isPresented && !viewController.isBeingDismissed) {
|
|
179
|
+
viewController.dismiss(animated = false)
|
|
181
180
|
}
|
|
182
181
|
}
|
|
183
182
|
|
|
@@ -344,7 +343,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
344
343
|
viewController.coordinatorLayout?.let { rootContainerView?.addView(it) }
|
|
345
344
|
|
|
346
345
|
// Register with observer to track sheet stack hierarchy
|
|
347
|
-
viewController.parentSheetView = TrueSheetStackManager.
|
|
346
|
+
viewController.parentSheetView = TrueSheetStackManager.registerSheet(this)
|
|
348
347
|
}
|
|
349
348
|
viewController.presentPromise = promiseCallback
|
|
350
349
|
viewController.present(detentIndex, animated)
|
|
@@ -352,30 +351,26 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
352
351
|
|
|
353
352
|
@UiThread
|
|
354
353
|
fun dismiss(animated: Boolean = true, promiseCallback: () -> Unit) {
|
|
355
|
-
//
|
|
356
|
-
|
|
357
|
-
// See: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621505-dismiss
|
|
358
|
-
val sheetsAbove = TrueSheetStackManager.getSheetsAbove(this)
|
|
359
|
-
if (sheetsAbove.isNotEmpty()) {
|
|
360
|
-
for (sheet in sheetsAbove) {
|
|
361
|
-
sheet.viewController.dismiss(animated)
|
|
362
|
-
}
|
|
363
|
-
promiseCallback()
|
|
364
|
-
return
|
|
365
|
-
}
|
|
354
|
+
// Dismiss all sheets above first
|
|
355
|
+
dismissStack(animated) {}
|
|
366
356
|
|
|
357
|
+
// Then dismiss itself
|
|
367
358
|
viewController.dismissPromise = promiseCallback
|
|
368
359
|
viewController.dismiss(animated)
|
|
369
360
|
}
|
|
370
361
|
|
|
371
362
|
@UiThread
|
|
372
|
-
fun
|
|
373
|
-
|
|
374
|
-
|
|
363
|
+
fun dismissStack(animated: Boolean = true, promiseCallback: () -> Unit) {
|
|
364
|
+
val sheetsAbove = TrueSheetStackManager.getSheetsAbove(this)
|
|
365
|
+
if (sheetsAbove.isNotEmpty()) {
|
|
366
|
+
// Create snapshot only for topmost sheet (first in reversed list)
|
|
367
|
+
sheetsAbove.firstOrNull()?.viewController?.createSheetSnapshot()
|
|
375
368
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
369
|
+
for (sheet in sheetsAbove) {
|
|
370
|
+
sheet.viewController.dismiss(animated)
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
promiseCallback()
|
|
379
374
|
}
|
|
380
375
|
|
|
381
376
|
@UiThread
|
|
@@ -397,7 +392,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
397
392
|
if (viewController.containerView == null) return@post
|
|
398
393
|
|
|
399
394
|
viewController.setupSheetDetentsForSizeChange()
|
|
400
|
-
TrueSheetStackManager.
|
|
395
|
+
TrueSheetStackManager.updateParentTranslation(this)
|
|
401
396
|
}
|
|
402
397
|
}
|
|
403
398
|
|
|
@@ -451,6 +446,9 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
451
446
|
// ==================== TrueSheetViewControllerDelegate ====================
|
|
452
447
|
|
|
453
448
|
override fun viewControllerWillPresent(index: Int, position: Float, detent: Float) {
|
|
449
|
+
// Update parent sheet translation now that content is measured
|
|
450
|
+
TrueSheetStackManager.updateParentTranslation(this)
|
|
451
|
+
|
|
454
452
|
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
455
453
|
eventDispatcher?.dispatchEvent(WillPresentEvent(surfaceId, id, index, position, detent))
|
|
456
454
|
}
|
|
@@ -477,7 +475,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
|
|
|
477
475
|
val surfaceId = UIManagerHelper.getSurfaceId(this)
|
|
478
476
|
eventDispatcher?.dispatchEvent(DidDismissEvent(surfaceId, id))
|
|
479
477
|
|
|
480
|
-
TrueSheetStackManager.
|
|
478
|
+
TrueSheetStackManager.unregisterSheet(this, hadParent)
|
|
481
479
|
}
|
|
482
480
|
|
|
483
481
|
override fun viewControllerDidChangeDetent(index: Int, position: Float, detent: Float) {
|
|
@@ -131,7 +131,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
131
131
|
private set
|
|
132
132
|
|
|
133
133
|
private var interactionState: InteractionState = InteractionState.Idle
|
|
134
|
-
|
|
134
|
+
internal var isBeingDismissed = false
|
|
135
|
+
private set
|
|
135
136
|
var wasHiddenByScreen = false
|
|
136
137
|
private var shouldAnimatePresent = false
|
|
137
138
|
private var isPresentAnimating = false
|
|
@@ -340,7 +341,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
340
341
|
sheetView = null
|
|
341
342
|
|
|
342
343
|
interactionState = InteractionState.Idle
|
|
343
|
-
|
|
344
|
+
isBeingDismissed = false
|
|
344
345
|
isPresented = false
|
|
345
346
|
isSheetVisible = false
|
|
346
347
|
wasHiddenByScreen = false
|
|
@@ -479,8 +480,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
479
480
|
|
|
480
481
|
private fun handleStateChanged(sheetView: View, newState: Int) {
|
|
481
482
|
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
|
|
482
|
-
if (
|
|
483
|
-
|
|
483
|
+
if (isBeingDismissed) return
|
|
484
|
+
isBeingDismissed = true
|
|
484
485
|
dismissKeyboard()
|
|
485
486
|
emitWillDismissEvents()
|
|
486
487
|
finishDismiss()
|
|
@@ -502,7 +503,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
502
503
|
|
|
503
504
|
private fun handleSlide(sheetView: View, slideOffset: Float) {
|
|
504
505
|
// Skip during dismiss animation
|
|
505
|
-
if (
|
|
506
|
+
if (isBeingDismissed) return
|
|
506
507
|
|
|
507
508
|
val behavior = behavior ?: return
|
|
508
509
|
|
|
@@ -705,9 +706,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
705
706
|
}
|
|
706
707
|
|
|
707
708
|
fun dismiss(animated: Boolean = true) {
|
|
708
|
-
if (
|
|
709
|
+
if (isBeingDismissed) return
|
|
709
710
|
|
|
710
|
-
|
|
711
|
+
isBeingDismissed = true
|
|
711
712
|
dismissKeyboard()
|
|
712
713
|
emitWillDismissEvents()
|
|
713
714
|
|
|
@@ -894,7 +895,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
894
895
|
if (!dimmed) return
|
|
895
896
|
if (contentHeight == 0) return
|
|
896
897
|
|
|
897
|
-
val keyboardOffset = if (
|
|
898
|
+
val keyboardOffset = if (isBeingDismissed) 0 else currentKeyboardInset
|
|
898
899
|
val top = (sheetTop ?: sheetView?.top ?: return) + keyboardOffset
|
|
899
900
|
|
|
900
901
|
if (animated) {
|
|
@@ -981,7 +982,7 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
|
|
|
981
982
|
if (!shouldHandleKeyboard(checkFocus = false)) return
|
|
982
983
|
|
|
983
984
|
setupSheetDetents()
|
|
984
|
-
if (!
|
|
985
|
+
if (!isBeingDismissed && detentIndexBeforeKeyboard >= 0) {
|
|
985
986
|
setStateForDetentIndex(detentIndexBeforeKeyboard)
|
|
986
987
|
}
|
|
987
988
|
}
|
|
@@ -31,18 +31,14 @@ object TrueSheetStackManager {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
* Returns the visible parent sheet to stack on, or null if none.
|
|
34
|
+
* Registers a sheet in the stack and returns its parent sheet if any.
|
|
36
35
|
* Only returns a parent if it's in the same container (e.g., same Screen).
|
|
37
36
|
*/
|
|
38
37
|
@JvmStatic
|
|
39
|
-
fun
|
|
38
|
+
fun registerSheet(sheetView: TrueSheetView): TrueSheetView? {
|
|
40
39
|
synchronized(presentedSheetStack) {
|
|
41
40
|
val parentSheet = findTopmostSheet()?.takeIf { it.rootContainerView == sheetView.rootContainerView }
|
|
42
41
|
|
|
43
|
-
val childSheetTop = sheetView.viewController.detentCalculator.getSheetTopForDetentIndex(detentIndex)
|
|
44
|
-
parentSheet?.updateTranslationForChild(childSheetTop)
|
|
45
|
-
|
|
46
42
|
if (!presentedSheetStack.contains(sheetView)) {
|
|
47
43
|
presentedSheetStack.add(sheetView)
|
|
48
44
|
}
|
|
@@ -52,11 +48,10 @@ object TrueSheetStackManager {
|
|
|
52
48
|
}
|
|
53
49
|
|
|
54
50
|
/**
|
|
55
|
-
*
|
|
56
|
-
* Resets parent sheet translation if this sheet was stacked on it.
|
|
51
|
+
* Unregisters a sheet from the stack and resets parent translation if needed.
|
|
57
52
|
*/
|
|
58
53
|
@JvmStatic
|
|
59
|
-
fun
|
|
54
|
+
fun unregisterSheet(sheetView: TrueSheetView, hadParent: Boolean) {
|
|
60
55
|
synchronized(presentedSheetStack) {
|
|
61
56
|
presentedSheetStack.remove(sheetView)
|
|
62
57
|
if (hadParent) {
|
|
@@ -66,12 +61,11 @@ object TrueSheetStackManager {
|
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
/**
|
|
69
|
-
*
|
|
70
|
-
* Updates parent sheet translations to match the new sheet position.
|
|
64
|
+
* Updates parent sheet translation based on the child sheet's position.
|
|
71
65
|
* Only affects parent sheets in the same container.
|
|
72
66
|
*/
|
|
73
67
|
@JvmStatic
|
|
74
|
-
fun
|
|
68
|
+
fun updateParentTranslation(sheetView: TrueSheetView) {
|
|
75
69
|
synchronized(presentedSheetStack) {
|
|
76
70
|
val index = presentedSheetStack.indexOf(sheetView)
|
|
77
71
|
val parentSheet = getParentSheetAt(index, sheetView.rootContainerView) ?: return
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
#import <React/RCTConversions.h>
|
|
25
25
|
#import <React/RCTLog.h>
|
|
26
|
+
#import <react/renderer/core/LayoutMetrics.h>
|
|
26
27
|
|
|
27
28
|
using namespace facebook::react;
|
|
28
29
|
|
|
@@ -162,6 +163,12 @@ using namespace facebook::react;
|
|
|
162
163
|
[super updateProps:props oldProps:oldProps];
|
|
163
164
|
}
|
|
164
165
|
|
|
166
|
+
#pragma clang diagnostic ignored "-Wobjc-missing-super-calls"
|
|
167
|
+
- (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
|
|
168
|
+
oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics {
|
|
169
|
+
// Intentionally skip super - AutoLayout handles container's frame, not Yoga
|
|
170
|
+
}
|
|
171
|
+
|
|
165
172
|
#pragma mark - TrueSheetContentViewDelegate
|
|
166
173
|
|
|
167
174
|
- (void)contentViewDidChangeSize:(CGSize)newSize {
|
|
@@ -119,7 +119,7 @@ using namespace facebook::react;
|
|
|
119
119
|
scrollView.scrollView.contentInset = contentInset;
|
|
120
120
|
|
|
121
121
|
UIEdgeInsets indicatorInsets = scrollView.scrollView.verticalScrollIndicatorInsets;
|
|
122
|
-
indicatorInsets.bottom = _originalIndicatorBottomInset
|
|
122
|
+
indicatorInsets.bottom = _originalIndicatorBottomInset;
|
|
123
123
|
scrollView.scrollView.verticalScrollIndicatorInsets = indicatorInsets;
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -138,9 +138,15 @@ using namespace facebook::react;
|
|
|
138
138
|
CGFloat newHeight = containerView.bounds.size.height - scrollViewFrameInContainer.origin.y;
|
|
139
139
|
|
|
140
140
|
if (newHeight > 0) {
|
|
141
|
+
// Preserve contentOffset before changing frame to prevent scroll jump
|
|
142
|
+
CGPoint savedContentOffset = _pinnedScrollView.scrollView.contentOffset;
|
|
143
|
+
|
|
141
144
|
CGRect frame = _pinnedScrollView.frame;
|
|
142
145
|
frame.size.height = newHeight;
|
|
143
146
|
_pinnedScrollView.frame = frame;
|
|
147
|
+
|
|
148
|
+
// Restore contentOffset after frame change
|
|
149
|
+
_pinnedScrollView.scrollView.contentOffset = savedContentOffset;
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
|
package/ios/TrueSheetModule.mm
CHANGED
|
@@ -93,6 +93,30 @@ RCT_EXPORT_MODULE(TrueSheetModule)
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
- (void)dismissStackByRef:(double)viewTag
|
|
97
|
+
animated:(BOOL)animated
|
|
98
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
99
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
100
|
+
RCTExecuteOnMainQueue(^{
|
|
101
|
+
TrueSheetView *trueSheetView = [TrueSheetModule getTrueSheetViewByTag:@((NSInteger)viewTag)];
|
|
102
|
+
|
|
103
|
+
if (!trueSheetView) {
|
|
104
|
+
reject(@"SHEET_NOT_FOUND", [NSString stringWithFormat:@"No sheet found with tag %d", (int)viewTag], nil);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
[trueSheetView
|
|
109
|
+
dismissStackAnimated:animated
|
|
110
|
+
completion:^(BOOL success, NSError *_Nullable error) {
|
|
111
|
+
if (success) {
|
|
112
|
+
resolve(nil);
|
|
113
|
+
} else {
|
|
114
|
+
reject(@"DISMISS_FAILED", error.localizedDescription ?: @"Failed to dismiss stack", error);
|
|
115
|
+
}
|
|
116
|
+
}];
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
96
120
|
- (void)resizeByRef:(double)viewTag
|
|
97
121
|
index:(double)index
|
|
98
122
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
@@ -141,15 +165,15 @@ RCT_EXPORT_MODULE(TrueSheetModule)
|
|
|
141
165
|
return;
|
|
142
166
|
}
|
|
143
167
|
|
|
144
|
-
[rootSheet
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
168
|
+
[rootSheet emitDismissedPosition];
|
|
169
|
+
[rootSheet dismissAnimated:animated
|
|
170
|
+
completion:^(BOOL success, NSError *_Nullable error) {
|
|
171
|
+
if (success) {
|
|
172
|
+
resolve(nil);
|
|
173
|
+
} else {
|
|
174
|
+
reject(@"DISMISS_FAILED", error.localizedDescription ?: @"Failed to dismiss sheets", error);
|
|
175
|
+
}
|
|
176
|
+
}];
|
|
153
177
|
}
|
|
154
178
|
});
|
|
155
179
|
}
|
package/ios/TrueSheetView.h
CHANGED
|
@@ -32,9 +32,11 @@ typedef void (^TrueSheetCompletionBlock)(BOOL success, NSError *_Nullable error)
|
|
|
32
32
|
|
|
33
33
|
- (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion;
|
|
34
34
|
|
|
35
|
+
- (void)emitDismissedPosition;
|
|
36
|
+
|
|
35
37
|
- (void)resizeToIndex:(NSInteger)index completion:(nullable TrueSheetCompletionBlock)completion;
|
|
36
38
|
|
|
37
|
-
- (void)
|
|
39
|
+
- (void)dismissStackAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion;
|
|
38
40
|
|
|
39
41
|
@end
|
|
40
42
|
|
package/ios/TrueSheetView.mm
CHANGED
|
@@ -111,7 +111,7 @@ using namespace facebook::react;
|
|
|
111
111
|
UIViewController *vc = [self findPresentingViewController];
|
|
112
112
|
|
|
113
113
|
// Only present if the view controller is in the same window and not being dismissed
|
|
114
|
-
if (vc && vc.view.window == self.window && !
|
|
114
|
+
if (vc && vc.view.window == self.window && !_controller.isBeingDismissed) {
|
|
115
115
|
_didInitiallyPresent = YES;
|
|
116
116
|
[self presentAtIndex:_initialDetentIndex animated:_initialDetentAnimated completion:nil];
|
|
117
117
|
} else {
|
|
@@ -262,19 +262,17 @@ using namespace facebook::react;
|
|
|
262
262
|
|
|
263
263
|
- (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState {
|
|
264
264
|
_state = std::static_pointer_cast<TrueSheetViewShadowNode::ConcreteState const>(state);
|
|
265
|
-
|
|
266
|
-
if (_controller) {
|
|
267
|
-
[self updateStateWithSize:_controller.view.frame.size];
|
|
268
|
-
}
|
|
269
|
-
|
|
270
265
|
[_screensEventObserver startObservingWithState:_state.get()->getData()];
|
|
271
266
|
}
|
|
272
267
|
|
|
273
268
|
/**
|
|
274
|
-
* Updates Fabric state with container
|
|
269
|
+
* Updates Fabric state with container dimensions for Yoga layout.
|
|
275
270
|
*/
|
|
276
271
|
- (void)updateStateWithSize:(CGSize)size {
|
|
277
|
-
if (!_state
|
|
272
|
+
if (!_state)
|
|
273
|
+
return;
|
|
274
|
+
|
|
275
|
+
if (CGSizeEqualToSize(size, _lastStateSize))
|
|
278
276
|
return;
|
|
279
277
|
|
|
280
278
|
_lastStateSize = size;
|
|
@@ -282,6 +280,7 @@ using namespace facebook::react;
|
|
|
282
280
|
-> TrueSheetViewShadowNode::ConcreteState::SharedData {
|
|
283
281
|
auto newData = oldData;
|
|
284
282
|
newData.containerWidth = static_cast<float>(size.width);
|
|
283
|
+
newData.containerHeight = static_cast<float>(size.height);
|
|
285
284
|
return std::make_shared<TrueSheetViewShadowNode::ConcreteState::Data const>(newData);
|
|
286
285
|
});
|
|
287
286
|
}
|
|
@@ -408,12 +407,7 @@ using namespace facebook::react;
|
|
|
408
407
|
- (void)presentAtIndex:(NSInteger)index
|
|
409
408
|
animated:(BOOL)animated
|
|
410
409
|
completion:(nullable TrueSheetCompletionBlock)completion {
|
|
411
|
-
if (_controller.isBeingPresented) {
|
|
412
|
-
RCTLogWarn(@"TrueSheet: sheet is being presented. Wait for it to transition before presenting again.");
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (_controller.isPresented) {
|
|
410
|
+
if (_controller.isBeingPresented || _controller.isPresented) {
|
|
417
411
|
RCTLogWarn(@"TrueSheet: sheet is already presented. Use resize() to change detent.");
|
|
418
412
|
if (completion) {
|
|
419
413
|
completion(YES, nil);
|
|
@@ -421,6 +415,9 @@ using namespace facebook::react;
|
|
|
421
415
|
return;
|
|
422
416
|
}
|
|
423
417
|
|
|
418
|
+
// Reset navigation dismiss flag when presenting (handles view recycling edge cases)
|
|
419
|
+
_dismissedByNavigation = NO;
|
|
420
|
+
|
|
424
421
|
UIViewController *presentingViewController = [self findPresentingViewController];
|
|
425
422
|
if (!presentingViewController) {
|
|
426
423
|
NSError *error = [NSError errorWithDomain:@"com.lodev09.TrueSheet"
|
|
@@ -447,27 +444,6 @@ using namespace facebook::react;
|
|
|
447
444
|
}];
|
|
448
445
|
}
|
|
449
446
|
|
|
450
|
-
- (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
|
|
451
|
-
if (_controller.isBeingDismissed) {
|
|
452
|
-
RCTLogWarn(@"TrueSheet: sheet is being dismissed. No need to dismiss it again.");
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (!_controller.isPresented) {
|
|
457
|
-
if (completion) {
|
|
458
|
-
completion(YES, nil);
|
|
459
|
-
}
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
[_controller dismissViewControllerAnimated:animated
|
|
464
|
-
completion:^{
|
|
465
|
-
if (completion) {
|
|
466
|
-
completion(YES, nil);
|
|
467
|
-
}
|
|
468
|
-
}];
|
|
469
|
-
}
|
|
470
|
-
|
|
471
447
|
- (void)resizeToIndex:(NSInteger)index completion:(nullable TrueSheetCompletionBlock)completion {
|
|
472
448
|
if (!_controller.isPresented) {
|
|
473
449
|
RCTLogWarn(@"TrueSheet: Cannot resize. Sheet is not presented.");
|
|
@@ -490,16 +466,20 @@ using namespace facebook::react;
|
|
|
490
466
|
return _controller;
|
|
491
467
|
}
|
|
492
468
|
|
|
493
|
-
- (void)
|
|
494
|
-
|
|
469
|
+
- (void)emitDismissedPosition {
|
|
470
|
+
[self viewControllerDidChangePosition:-1 position:_controller.screenHeight detent:0 realtime:NO];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
- (void)dismissAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
|
|
474
|
+
if (_controller.isBeingDismissed || !_controller.isPresented) {
|
|
475
|
+
RCTLogWarn(@"TrueSheet: sheet is already dismissed. No need to dismiss it again.");
|
|
476
|
+
|
|
495
477
|
if (completion) {
|
|
496
478
|
completion(YES, nil);
|
|
497
479
|
}
|
|
498
480
|
return;
|
|
499
481
|
}
|
|
500
482
|
|
|
501
|
-
[self viewControllerDidChangePosition:-1 position:_controller.screenHeight detent:0 realtime:NO];
|
|
502
|
-
|
|
503
483
|
// Dismiss from the presenting view controller to dismiss this sheet and all its children
|
|
504
484
|
UIViewController *presenter = _controller.presentingViewController;
|
|
505
485
|
[presenter dismissViewControllerAnimated:animated
|
|
@@ -510,6 +490,33 @@ using namespace facebook::react;
|
|
|
510
490
|
}];
|
|
511
491
|
}
|
|
512
492
|
|
|
493
|
+
- (void)dismissStackAnimated:(BOOL)animated completion:(nullable TrueSheetCompletionBlock)completion {
|
|
494
|
+
if (_controller.isBeingDismissed || !_controller.isPresented) {
|
|
495
|
+
RCTLogWarn(@"TrueSheet: sheet is already dismissed. No need to dismiss it again.");
|
|
496
|
+
|
|
497
|
+
if (completion) {
|
|
498
|
+
completion(YES, nil);
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Only dismiss presented children, not this sheet itself
|
|
504
|
+
if (!_controller.presentedViewController) {
|
|
505
|
+
if (completion) {
|
|
506
|
+
completion(YES, nil);
|
|
507
|
+
}
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Calling dismiss on _controller dismisses all VCs presented on top of it, but keeps _controller presented
|
|
512
|
+
[_controller dismissViewControllerAnimated:animated
|
|
513
|
+
completion:^{
|
|
514
|
+
if (completion) {
|
|
515
|
+
completion(YES, nil);
|
|
516
|
+
}
|
|
517
|
+
}];
|
|
518
|
+
}
|
|
519
|
+
|
|
513
520
|
#pragma mark - TrueSheetContainerViewDelegate
|
|
514
521
|
|
|
515
522
|
/**
|
|
@@ -628,7 +635,7 @@ using namespace facebook::react;
|
|
|
628
635
|
- (void)presenterScreenWillDisappear {
|
|
629
636
|
if (_controller.isPresented && !_controller.isBeingDismissed) {
|
|
630
637
|
_dismissedByNavigation = YES;
|
|
631
|
-
[self
|
|
638
|
+
[self dismissAnimated:YES completion:nil];
|
|
632
639
|
}
|
|
633
640
|
}
|
|
634
641
|
|
|
@@ -69,6 +69,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
69
69
|
@property (nonatomic, assign) BOOL isPresented;
|
|
70
70
|
@property (nonatomic, assign) NSInteger activeDetentIndex;
|
|
71
71
|
@property (nonatomic, readonly) BOOL isTopmostPresentedController;
|
|
72
|
+
|
|
72
73
|
@property (nonatomic, readonly) CGFloat screenHeight;
|
|
73
74
|
|
|
74
75
|
- (void)applyActiveDetent;
|
|
@@ -222,12 +222,8 @@
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
- (BOOL)isDismissing {
|
|
226
|
-
return self.presentingViewController == nil || self.isBeingDismissed;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
225
|
- (void)emitWillDismissEvents {
|
|
230
|
-
if (self.
|
|
226
|
+
if (self.isBeingDismissed && !_isWillDismissEmitted) {
|
|
231
227
|
_isWillDismissEmitted = YES;
|
|
232
228
|
|
|
233
229
|
[self.delegate viewControllerWillBlur];
|
|
@@ -237,7 +233,7 @@
|
|
|
237
233
|
}
|
|
238
234
|
|
|
239
235
|
- (void)emitDidDismissEvents {
|
|
240
|
-
if (self.
|
|
236
|
+
if (self.isBeingDismissed) {
|
|
241
237
|
_isPresented = NO;
|
|
242
238
|
_isWillDismissEmitted = NO;
|
|
243
239
|
|
|
@@ -398,12 +394,12 @@
|
|
|
398
394
|
CGRect dismissedFrame = CGRectMake(0, self.screenHeight, 0, 0);
|
|
399
395
|
CGRect presentedFrame = CGRectMake(0, self.currentPosition, 0, 0);
|
|
400
396
|
|
|
401
|
-
_transitionFakeView.frame = self.
|
|
397
|
+
_transitionFakeView.frame = self.isBeingDismissed ? presentedFrame : dismissedFrame;
|
|
402
398
|
[self storeResolvedPositionForIndex:self.currentDetentIndex];
|
|
403
399
|
|
|
404
400
|
auto animation = ^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
|
|
405
401
|
[[context containerView] addSubview:self->_transitionFakeView];
|
|
406
|
-
self->_transitionFakeView.frame = self.
|
|
402
|
+
self->_transitionFakeView.frame = self.isBeingDismissed ? dismissedFrame : presentedFrame;
|
|
407
403
|
|
|
408
404
|
self->_transitioningTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleTransitionTracker)];
|
|
409
405
|
[self->_transitioningTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
|