@lodev09/react-native-true-sheet 4.0.0-beta.29 → 4.0.0-beta.30

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 (28) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +18 -8
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +5 -2
  3. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +38 -6
  4. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +4 -0
  5. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +2 -2
  6. package/ios/TrueSheetContainerView.mm +12 -14
  7. package/ios/TrueSheetContentView.mm +6 -0
  8. package/ios/TrueSheetFooterView.mm +40 -2
  9. package/ios/TrueSheetOverlayView.h +10 -0
  10. package/ios/TrueSheetOverlayView.mm +14 -0
  11. package/ios/TrueSheetViewController.mm +20 -1
  12. package/ios/core/TrueSheetKeyboardObserver.h +7 -0
  13. package/ios/core/TrueSheetKeyboardObserver.mm +7 -0
  14. package/lib/module/navigation/createTrueSheetRouter.js +47 -3
  15. package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
  16. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js +31 -3
  17. package/lib/module/navigation/expo-router/extendTrueSheetRouter.js.map +1 -1
  18. package/lib/module/navigation/expo-router/index.js +9 -6
  19. package/lib/module/navigation/expo-router/index.js.map +1 -1
  20. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +10 -0
  21. package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
  22. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts +6 -2
  23. package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts.map +1 -1
  24. package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
  25. package/package.json +1 -1
  26. package/src/navigation/createTrueSheetRouter.ts +72 -4
  27. package/src/navigation/expo-router/extendTrueSheetRouter.ts +33 -5
  28. package/src/navigation/expo-router/index.ts +14 -9
@@ -448,6 +448,17 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
448
448
  viewController.createSheet()
449
449
  setupScrollable()
450
450
 
451
+ // Attach before any keyboard wait so the touches meanwhile don't reach the views below
452
+ rootContainerView = findRootContainerView()
453
+ rootContainerView?.let { container ->
454
+ viewController.coordinatorLayout?.let {
455
+ it.blocksTouches = true
456
+ container.addView(it)
457
+ // Touches skip a view without a frame — don't wait for the next layout pass
458
+ it.layout(0, 0, container.width, container.height)
459
+ }
460
+ }
461
+
451
462
  // Dismiss keyboard if focused view is within a sheet or if target detent will be dimmed
452
463
  val parentSheet = TrueSheetStackManager.getTopmostSheet()
453
464
  val isFocusedViewWithinSheet = parentSheet?.viewController?.isFocusedViewWithinSheet() == true
@@ -481,10 +492,6 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
481
492
  return
482
493
  }
483
494
 
484
- // Attach coordinator to the root container
485
- rootContainerView = findRootContainerView()
486
- viewController.coordinatorLayout?.let { rootContainerView?.addView(it) }
487
-
488
495
  // Register with observer to track sheet stack hierarchy
489
496
  viewController.parentSheetView = TrueSheetStackManager.registerSheet(this)
490
497
 
@@ -492,6 +499,11 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
492
499
  viewController.present(detentIndex, animated)
493
500
  }
494
501
 
502
+ private fun detachCoordinator() {
503
+ viewController.coordinatorLayout?.let { rootContainerView?.removeView(it) }
504
+ rootContainerView = null
505
+ }
506
+
495
507
  @UiThread
496
508
  fun handleBackPress() {
497
509
  viewController.handleBackPress()
@@ -505,6 +517,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
505
517
  val callback = pendingPresentCallback ?: return false
506
518
  pendingPresentCallback = null
507
519
  pendingPresentParent = null
520
+ detachCoordinator()
508
521
  if (restoreFocus) {
509
522
  viewController.restoreFocusedView()
510
523
  } else {
@@ -725,10 +738,7 @@ class TrueSheetView(private val reactContext: ThemedReactContext) :
725
738
  // A slide-back cut short by this sheet's own dismissal never emits; don't carry it over
726
739
  isDidFocusPending = false
727
740
 
728
- // Detach coordinator from the root container view
729
- viewController.coordinatorLayout?.let { rootContainerView?.removeView(it) }
730
- rootContainerView = null
731
-
741
+ detachCoordinator()
732
742
  cleanupScreenEventObserver()
733
743
 
734
744
  val surfaceId = UIManagerHelper.getSurfaceId(this)
@@ -1017,6 +1017,8 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
1017
1017
  }
1018
1018
 
1019
1019
  private fun finishPresent() {
1020
+ coordinatorLayout?.blocksTouches = false
1021
+
1020
1022
  // Restore isHideable to actual value after present animation
1021
1023
  behavior?.isHideable = dismissible
1022
1024
 
@@ -1550,8 +1552,9 @@ class TrueSheetViewController(private val reactContext: ThemedReactContext) :
1550
1552
  delegate?.viewControllerWillDismiss()
1551
1553
  parentSheetView?.viewControllerWillFocus()
1552
1554
 
1553
- // Dismissed mid-present: finishPresent() won't run. Settle the pending present well
1554
- // before didDismiss so JS clears isPresenting and unmounts the lazy native view
1555
+ // Dismissed mid-present: finishPresent() won't run. Stop blocking touches, and settle the
1556
+ // pending present well before didDismiss so JS clears isPresenting and unmounts the lazy native view
1557
+ coordinatorLayout?.blocksTouches = false
1555
1558
  presentPromise?.invoke()
1556
1559
  presentPromise = null
1557
1560
  }
@@ -80,19 +80,29 @@ class TrueSheetCoordinatorLayout(context: Context) :
80
80
  // Pull-down tracking. BottomSheetBehavior gives no callback when a downward drag
81
81
  // is clamped by `isHideable = false` — the sheet stays put (or the scrollable
82
82
  // overscrolls) and no state change fires. Accumulate the downward finger travel
83
- // neither the sheet nor its scrollable followed and report it on release so the
84
- // controller can surface a blocked dismiss attempt.
83
+ // neither the sheet nor a scroller under the finger followed and report it on
84
+ // release so the controller can surface a blocked dismiss attempt. Like iOS, a
85
+ // pull that began on a scroller that could scroll up stays a scroll, even past
86
+ // its top.
85
87
  private var pullTracking = false
86
88
  private var pullStartX = 0f
87
89
  private var pullStartY = 0f
88
90
  private var pullLastY = 0f
89
91
  private var pullOverdrag = 0f
90
92
  private var pullKeyboardVisible = false
93
+ private var pullScrollers: List<View> = emptyList()
94
+ private var pullBeganScrolled = false
91
95
 
92
96
  // A touch that began inside the sheet is still down
93
97
  val isTouchingSheet: Boolean
94
98
  get() = pullTracking
95
99
 
100
+ // Set while the sheet presents, from present() (keyboard wait included) until the
101
+ // present finishes or a dismiss starts. A stream that begins meanwhile is swallowed
102
+ // whole so nothing below takes it, like the iOS presentation transition.
103
+ var blocksTouches = false
104
+ private var streamBlocked = false
105
+
96
106
  init {
97
107
  layoutParams = LayoutParams(
98
108
  LayoutParams.MATCH_PARENT,
@@ -123,6 +133,14 @@ class TrueSheetCoordinatorLayout(context: Context) :
123
133
  get() = PointerEvents.BOX_NONE
124
134
 
125
135
  override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
136
+ if (ev.actionMasked == MotionEvent.ACTION_DOWN) streamBlocked = blocksTouches
137
+ if (streamBlocked) {
138
+ if (ev.actionMasked == MotionEvent.ACTION_UP || ev.actionMasked == MotionEvent.ACTION_CANCEL) {
139
+ streamBlocked = false
140
+ }
141
+ return true
142
+ }
143
+
126
144
  when (ev.actionMasked) {
127
145
  MotionEvent.ACTION_DOWN -> {
128
146
  val sheet = delegate?.findSheetView()
@@ -140,9 +158,14 @@ class TrueSheetCoordinatorLayout(context: Context) :
140
158
  val handled = super.dispatchTouchEvent(ev)
141
159
  val step = ev.rawY - pullLastY
142
160
  pullLastY = ev.rawY
143
- // Finger moved down but the sheet stayed put and the scrollable is at
144
- // its top — the pull was clamped
145
- if (step > 0 && sheet != null && sheet.top == topBefore && delegate?.findScrollView()?.canScrollVertically(-1) != true) {
161
+ // Finger moved down but the sheet stayed put and nothing under the finger
162
+ // scrolled — the pull was clamped
163
+ if (!pullBeganScrolled &&
164
+ step > 0 &&
165
+ sheet != null &&
166
+ sheet.top == topBefore &&
167
+ pullScrollers.none { it.canScrollVertically(-1) }
168
+ ) {
146
169
  pullOverdrag += step
147
170
  }
148
171
  return handled
@@ -205,18 +228,27 @@ class TrueSheetCoordinatorLayout(context: Context) :
205
228
  /**
206
229
  * Resolves the stream's touch target (respecting zIndex and pointerEvents) and
207
230
  * decides whether the sheet may drag from it — inside the sheet, outside the detected
208
- * scrollable, and nothing along the target's chain scrolls vertically.
231
+ * scrollable, and nothing along the target's chain scrolls vertically. Also collects
232
+ * the chain's vertical scrollers for pull-down tracking.
209
233
  */
210
234
  private fun updateStreamTargetFlags(ev: MotionEvent) {
211
235
  streamSheetDraggable = false
212
236
  streamDraggableEditText = false
213
237
  streamScrollsIndependently = false
238
+ pullScrollers = emptyList()
239
+ pullBeganScrolled = false
214
240
 
215
241
  val sheet = delegate?.findSheetView() ?: return
216
242
  val target = TouchTargetHelper.findTargetPathAndCoordinatesForTouch(ev.x, ev.y, this, FloatArray(2))
217
243
  .firstNotNullOfOrNull { it.getView() } ?: return
218
244
  if (target !== sheet && !target.isDescendantOf(sheet)) return
219
245
 
246
+ pullScrollers = generateSequence(target) { it.parent as? View }
247
+ .takeWhile { it !== this }
248
+ .filter { it.canScrollVertically(1) || it.canScrollVertically(-1) }
249
+ .toList()
250
+ pullBeganScrolled = pullScrollers.any { it.canScrollVertically(-1) }
251
+
220
252
  // A detected scrollable that can scroll (or hosts pull-to-refresh) owns its
221
253
  // touches — nested scrolling drags the sheet. When it can't scroll (e.g.
222
254
  // the sheet is fully expanded and the content fits) it eats the gesture
@@ -44,6 +44,10 @@ class TrueSheetOverlayRootView(private val reactContext: ThemedReactContext) :
44
44
  init {
45
45
  layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
46
46
 
47
+ // React children draw outside their bounds (shadows, overflow)
48
+ clipChildren = false
49
+ clipToPadding = false
50
+
47
51
  // Draws and receives touches above the sheet coordinators regardless of add order
48
52
  translationZ = OVERLAY_Z
49
53
  }
@@ -161,7 +161,7 @@ object TrueSheetStackManager {
161
161
  return
162
162
  }
163
163
 
164
- // The dimmed sheet and any sheets above it stay accessible
164
+ // The dimmed sheet, any sheets above it, and overlays (rendered above every sheet) stay accessible
165
165
  val accessibleCoordinators = presentedSheetStack
166
166
  .subList(topDimmedIndex, presentedSheetStack.size)
167
167
  .mapNotNull { it.viewController.coordinatorLayout }
@@ -169,7 +169,7 @@ object TrueSheetStackManager {
169
169
 
170
170
  for (i in 0 until root.childCount) {
171
171
  val child = root.getChildAt(i)
172
- if (child in accessibleCoordinators) {
172
+ if (child in accessibleCoordinators || child is TrueSheetOverlayRootView) {
173
173
  savedBackgroundImportance.remove(child)?.let { child.importantForAccessibility = it }
174
174
  continue
175
175
  }
@@ -248,22 +248,29 @@ using namespace facebook::react;
248
248
  _contentView.footerView = _footerView;
249
249
  [_footerView setBottomInset:_footerBottomInset];
250
250
  [self footerViewDidChangeSize:_footerView.frame.size];
251
+
252
+ // The observer is set up on present — a footer mounted after that (e.g. a
253
+ // conditional one) joins it here and rises above a keyboard that's already open
254
+ _footerView.keyboardObserver = _keyboardObserver;
255
+ [self updateFooterKeyboardOffset];
251
256
  }
252
257
  }
253
258
 
254
259
  - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childComponentView index:(NSInteger)index {
255
- if ([childComponentView isKindOfClass:[TrueSheetContentView class]]) {
260
+ if (childComponentView == _contentView) {
261
+ _contentView.keyboardObserver = nil;
256
262
  _contentView.delegate = nil;
257
263
  _contentView = nil;
258
264
  }
259
265
 
260
- if ([childComponentView isKindOfClass:[TrueSheetHeaderView class]]) {
266
+ if (childComponentView == _headerView) {
261
267
  _headerView.delegate = nil;
262
268
  _headerView = nil;
263
269
  [self headerViewDidChangeSize:CGSizeZero];
264
270
  }
265
271
 
266
- if ([childComponentView isKindOfClass:[TrueSheetFooterView class]]) {
272
+ if (childComponentView == _footerView) {
273
+ _footerView.keyboardObserver = nil;
267
274
  _footerView.delegate = nil;
268
275
  _footerView = nil;
269
276
  _contentView.footerView = nil;
@@ -364,17 +371,8 @@ using namespace facebook::react;
364
371
 
365
372
  _keyboardObserver = [[TrueSheetKeyboardObserver alloc] init];
366
373
  _keyboardObserver.viewController = (TrueSheetViewController *)viewController;
367
-
368
- if (_contentView) {
369
- _contentView.keyboardObserver = _keyboardObserver;
370
- [_keyboardObserver addDelegate:_contentView];
371
- }
372
-
373
- if (_footerView) {
374
- _footerView.keyboardObserver = _keyboardObserver;
375
- [_keyboardObserver addDelegate:_footerView];
376
- }
377
-
374
+ _contentView.keyboardObserver = _keyboardObserver;
375
+ _footerView.keyboardObserver = _keyboardObserver;
378
376
  [_keyboardObserver start];
379
377
  }
380
378
 
@@ -388,6 +388,12 @@ using namespace facebook::react;
388
388
 
389
389
  #pragma mark - TrueSheetKeyboardObserverDelegate
390
390
 
391
+ - (void)setKeyboardObserver:(TrueSheetKeyboardObserver *)keyboardObserver {
392
+ [_keyboardObserver removeDelegate:self];
393
+ _keyboardObserver = keyboardObserver;
394
+ [keyboardObserver addDelegate:self];
395
+ }
396
+
391
397
  - (void)keyboardWillShow:(CGFloat)height duration:(NSTimeInterval)duration curve:(UIViewAnimationOptions)curve {
392
398
  if (!_detectedScrollView) {
393
399
  return;
@@ -156,7 +156,19 @@ using namespace facebook::react;
156
156
 
157
157
  - (void)updateLayoutMetrics:(const facebook::react::LayoutMetrics &)layoutMetrics
158
158
  oldLayoutMetrics:(const facebook::react::LayoutMetrics &)oldLayoutMetrics {
159
- [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
159
+ // UIKit resizes the sheet for the keyboard inside its animation, and the new
160
+ // size usually relays out the footer in the same pass. When the keyboard
161
+ // changes during a React commit (e.g. its input unmounts), that layout can
162
+ // only mount after the commit, outside the animation — the footer, pinned to
163
+ // the container's bottom edge, would snap by the keyboard's height while the
164
+ // sheet is still animating. Carry it on the rest of the keyboard's curve.
165
+ if (layoutMetrics.frame.origin.y != oldLayoutMetrics.frame.origin.y) {
166
+ [self animateAlongKeyboard:^{
167
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
168
+ }];
169
+ } else {
170
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
171
+ }
160
172
 
161
173
  // State lands before layout metrics within the same mount transaction, so
162
174
  // this reflects the inset the shadow node baked into this frame — seeded
@@ -197,6 +209,28 @@ using namespace facebook::react;
197
209
 
198
210
  #pragma mark - TrueSheetKeyboardObserverDelegate
199
211
 
212
+ - (void)setKeyboardObserver:(TrueSheetKeyboardObserver *)keyboardObserver {
213
+ [_keyboardObserver removeDelegate:self];
214
+ _keyboardObserver = keyboardObserver;
215
+ [keyboardObserver addDelegate:self];
216
+ }
217
+
218
+ - (void)animateAlongKeyboard:(void (^)(void))changes {
219
+ NSTimeInterval remaining = self.keyboardObserver.remainingAnimationDuration;
220
+ if (remaining > 0 && [UIView inheritedAnimationDuration] == 0) {
221
+ [UIView animateWithDuration:remaining
222
+ delay:0
223
+ options:self.keyboardObserver.animationCurve | UIViewAnimationOptionBeginFromCurrentState
224
+ animations:^{
225
+ changes();
226
+ [self syncEdgeEffect];
227
+ }
228
+ completion:nil];
229
+ } else {
230
+ changes();
231
+ }
232
+ }
233
+
200
234
  // Only an absolute footer floats above the keyboard — a relative footer stays
201
235
  // in the layout flow behind it, and an absolute one opts out via
202
236
  // footerOptions.avoidKeyboard.
@@ -291,7 +325,11 @@ using namespace facebook::react;
291
325
 
292
326
  CGFloat slide = [self keyboardSlideForHeight:height];
293
327
  [self setKeyboardOffset:slide];
294
- self.transform = CGAffineTransformMakeTranslation(0, -slide);
328
+ // A footer mounted or relaid out mid-keyboard animation follows the keyboard
329
+ // instead of snapping ahead of it
330
+ [self animateAlongKeyboard:^{
331
+ self.transform = CGAffineTransformMakeTranslation(0, -slide);
332
+ }];
295
333
  }
296
334
 
297
335
  @end
@@ -13,6 +13,11 @@
13
13
 
14
14
  NS_ASSUME_NONNULL_BEGIN
15
15
 
16
+ /**
17
+ * Posted when an overlay container joins or leaves a window.
18
+ */
19
+ extern NSNotificationName const TrueSheetOverlayWindowDidChangeNotification;
20
+
16
21
  /**
17
22
  * Hidden host that renders its children in a container attached directly to
18
23
  * the window, above every presented sheet.
@@ -25,6 +30,11 @@ NS_ASSUME_NONNULL_BEGIN
25
30
  */
26
31
  + (void)bringOverlaysToFrontInWindow:(nullable UIWindow *)window;
27
32
 
33
+ /**
34
+ * The overlay containers attached to the window, front to back.
35
+ */
36
+ + (NSArray<UIView *> *)overlayContainersInWindow:(nullable UIWindow *)window;
37
+
28
38
  @end
29
39
 
30
40
  NS_ASSUME_NONNULL_END
@@ -21,6 +21,8 @@
21
21
 
22
22
  using namespace facebook::react;
23
23
 
24
+ NSNotificationName const TrueSheetOverlayWindowDidChangeNotification = @"TrueSheetOverlayWindowDidChangeNotification";
25
+
24
26
  static NSHashTable<TrueSheetOverlayView *> *gOverlayViews;
25
27
 
26
28
  @interface TrueSheetOverlayView () <TrueSheetOverlayContainerViewDelegate>
@@ -53,6 +55,16 @@ static NSHashTable<TrueSheetOverlayView *> *gOverlayViews;
53
55
  }
54
56
  }
55
57
 
58
+ + (NSArray<UIView *> *)overlayContainersInWindow:(nullable UIWindow *)window {
59
+ NSMutableArray<UIView *> *containers = [NSMutableArray array];
60
+ for (UIView *subview in window.subviews.reverseObjectEnumerator) {
61
+ if ([subview isKindOfClass:[TrueSheetOverlayContainerView class]]) {
62
+ [containers addObject:subview];
63
+ }
64
+ }
65
+ return containers;
66
+ }
67
+
56
68
  - (instancetype)initWithFrame:(CGRect)frame {
57
69
  if (self = [super initWithFrame:frame]) {
58
70
  static const auto defaultProps = std::make_shared<const TrueSheetOverlayViewProps>();
@@ -100,6 +112,8 @@ static NSHashTable<TrueSheetOverlayView *> *gOverlayViews;
100
112
  [_containerView removeFromSuperview];
101
113
  [_containerController removeFromParentViewController];
102
114
  }
115
+
116
+ [[NSNotificationCenter defaultCenter] postNotificationName:TrueSheetOverlayWindowDidChangeNotification object:nil];
103
117
  }
104
118
 
105
119
  #pragma mark - State
@@ -9,6 +9,7 @@
9
9
  #import "TrueSheetViewController.h"
10
10
  #import "TrueSheetContainerView.h"
11
11
  #import "TrueSheetContentView.h"
12
+ #import "TrueSheetOverlayView.h"
12
13
  #import "core/TrueSheetBlurView.h"
13
14
  #import "core/TrueSheetDetentCalculator.h"
14
15
  #import "core/TrueSheetDimView.h"
@@ -172,6 +173,11 @@ static char TrueSheetAccessibilityWindowPreviousElementsKey;
172
173
  _hingeOffsets = [NSMutableDictionary dictionary];
173
174
  _detentCalculator = [[TrueSheetDetentCalculator alloc] init];
174
175
  _detentCalculator.delegate = self;
176
+
177
+ [[NSNotificationCenter defaultCenter] addObserver:self
178
+ selector:@selector(overlayWindowDidChange)
179
+ name:TrueSheetOverlayWindowDidChangeNotification
180
+ object:nil];
175
181
  }
176
182
  return self;
177
183
  }
@@ -686,6 +692,15 @@ static BOOL TrueSheetIsPhoneIdiom(void) {
686
692
  UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
687
693
  }
688
694
 
695
+ - (void)overlayWindowDidChange {
696
+ if (!self.canRefreshAccessibilityContainer) {
697
+ return;
698
+ }
699
+
700
+ [self setupAccessibilityContainer];
701
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
702
+ }
703
+
689
704
  - (UIViewController *)accessibilityPresentingViewController {
690
705
  UIViewController *presentingViewController = self.presentingViewController;
691
706
  while ([presentingViewController isKindOfClass:[TrueSheetViewController class]] &&
@@ -807,8 +822,12 @@ static BOOL TrueSheetIsPhoneIdiom(void) {
807
822
  }
808
823
  objc_setAssociatedObject(window, &TrueSheetAccessibilityWindowOwnerKey, [NSValue valueWithNonretainedObject:self],
809
824
  OBJC_ASSOCIATION_RETAIN_NONATOMIC);
810
- window.accessibilityElements =
825
+ NSArray *sheetElements =
811
826
  isAccessibilityModal ? @[ presentedView ] : @[ presentingViewController.view, presentedView ];
827
+ // Overlays render above every sheet. Listed first, since accessibility
828
+ // hit testing takes the first element containing the point.
829
+ window.accessibilityElements =
830
+ [[TrueSheetOverlayView overlayContainersInWindow:window] arrayByAddingObjectsFromArray:sheetElements];
812
831
  return;
813
832
  }
814
833
  }
@@ -26,6 +26,13 @@ NS_ASSUME_NONNULL_BEGIN
26
26
  @property (nonatomic, weak, nullable) TrueSheetViewController *viewController;
27
27
  @property (nonatomic, readonly) CGFloat currentHeight;
28
28
 
29
+ /**
30
+ * What's left of the keyboard's last show/hide animation, so a change landing
31
+ * outside it (e.g. after a React commit) can finish on the same curve.
32
+ */
33
+ @property (nonatomic, readonly) NSTimeInterval remainingAnimationDuration;
34
+ @property (nonatomic, readonly) UIViewAnimationOptions animationCurve;
35
+
29
36
  - (void)addDelegate:(id<TrueSheetKeyboardObserverDelegate>)delegate;
30
37
  - (void)removeDelegate:(id<TrueSheetKeyboardObserverDelegate>)delegate;
31
38
 
@@ -22,12 +22,17 @@ static const NSTimeInterval kUnanimatedKeyboardDuration = 0.25;
22
22
  NSHashTable<id<TrueSheetKeyboardObserverDelegate>> *_delegates;
23
23
  CGFloat _currentHeight;
24
24
  CGFloat _pendingMinimizedKeyboardOverlap;
25
+ CFTimeInterval _animationEndTime;
25
26
  }
26
27
 
27
28
  - (CGFloat)currentHeight {
28
29
  return _currentHeight;
29
30
  }
30
31
 
32
+ - (NSTimeInterval)remainingAnimationDuration {
33
+ return MAX(0, _animationEndTime - CACurrentMediaTime());
34
+ }
35
+
31
36
  - (instancetype)init {
32
37
  if (self = [super init]) {
33
38
  _delegates = [NSHashTable weakObjectsHashTable];
@@ -145,6 +150,8 @@ static const NSTimeInterval kUnanimatedKeyboardDuration = 0.25;
145
150
  }
146
151
 
147
152
  _currentHeight = keyboardHeight;
153
+ _animationEndTime = CACurrentMediaTime() + duration;
154
+ _animationCurve = curve;
148
155
 
149
156
  // UIKit also moves the sheet as the minimized keyboard comes and goes, by
150
157
  // whatever the detents couldn't absorb — settle again once it's done.
@@ -72,10 +72,11 @@ export const getTrueSheetStateForAction = (state, action) => {
72
72
  const closingIndex = targetIndex + 1;
73
73
 
74
74
  // Mark only the bottom-most route to pop as closing
75
- // The sheet's dismiss() will handle dismissing sheets above it first
75
+ // The sheet's dismiss() will handle dismissing sheets above it first.
76
+ // The index stays on the top sheet until REMOVE: Expo Router 58 treats the routes
77
+ // after `index` as preloaded.
76
78
  return {
77
79
  ...state,
78
- index: closingIndex,
79
80
  routes: state.routes.map((route, i) => {
80
81
  if (i === closingIndex) return {
81
82
  ...route,
@@ -133,6 +134,47 @@ export const getTrueSheetStateForAction = (state, action) => {
133
134
  return undefined;
134
135
  }
135
136
  };
137
+ const BASE_ROUTE_ACTIONS = new Set(['NAVIGATE', 'NAVIGATE_DEPRECATED', 'PUSH', 'REPLACE', 'POP_TO']);
138
+
139
+ /**
140
+ * Reduces an action that targets the base route by name. React Navigation 7 adds another base
141
+ * route for a `PUSH`, a `REPLACE` or a `NAVIGATE` without `pop`, which presents the base screen
142
+ * as a sheet, and this router's `POP_TO` drops the params and nested state. This goes back to it
143
+ * instead: `getPoppedState` reduces the action as a `NAVIGATE` with `pop` (a `PUSH` ignores
144
+ * `pop`) to update the base route (params, nested state), then the sheets above it are dismissed.
145
+ * Returns `undefined` for other actions, a `REPLACE` with no sheet (it swaps the base route), or
146
+ * when the base router doesn't land on the base route.
147
+ */
148
+ export const getStateForNavigateToBase = (state, action, getPoppedState) => {
149
+ const {
150
+ type,
151
+ payload
152
+ } = action;
153
+ const baseRoute = state.routes[0];
154
+ const hasSheets = state.routes.length > 1;
155
+ if (!BASE_ROUTE_ACTIONS.has(type) || payload?.name !== baseRoute.name || type === 'REPLACE' && !hasSheets) {
156
+ return undefined;
157
+ }
158
+ const popped = getPoppedState({
159
+ ...action,
160
+ type: 'NAVIGATE',
161
+ payload: {
162
+ ...payload,
163
+ pop: true
164
+ }
165
+ });
166
+ const base = popped?.routes[popped.index];
167
+ if (base?.key !== baseRoute.key) {
168
+ return undefined;
169
+ }
170
+ if (!hasSheets) {
171
+ return popped;
172
+ }
173
+ return getTrueSheetStateForAction({
174
+ ...state,
175
+ routes: [base, ...state.routes.slice(1)]
176
+ }, TrueSheetActions.pop(state.routes.length - 1));
177
+ };
136
178
  export const createTrueSheetRouter = stackRouter => routerOptions => {
137
179
  const baseRouter = stackRouter(routerOptions);
138
180
  return {
@@ -150,7 +192,9 @@ export const createTrueSheetRouter = stackRouter => routerOptions => {
150
192
  };
151
193
  },
152
194
  getStateForAction(state, action, options) {
153
- const result = getTrueSheetStateForAction(state, action);
195
+ const result = getStateForNavigateToBase(state, action,
196
+ // NAVIGATE never returns a partial state
197
+ popAction => baseRouter.getStateForAction(state, popAction, options)) ?? getTrueSheetStateForAction(state, action);
154
198
  return result === undefined ? baseRouter.getStateForAction(state, action, options) : result;
155
199
  },
156
200
  getRehydratedState(partialState, {
@@ -1 +1 @@
1
- {"version":3,"names":["TrueSheetActions","uid","Math","random","toString","slice","ensureBaseRoute","state","baseRouteName","routeParamList","hasBaseRoute","routes","some","r","name","baseRoute","key","params","index","length","getResizeRouteIndex","action","target","source","findIndex","getTrueSheetStateForAction","type","routeIndex","map","route","i","resizeIndex","resizeKey","pop","count","payload","maxPopCount","actualCount","min","targetIndex","closingIndex","closing","dismissing","popCount","targetName","routeKey","removed","isPopped","filter","undefined","createTrueSheetRouter","stackRouter","routerOptions","baseRouter","getInitialState","options","initialRouteName","routeNames","stateWithBaseRoute","stale","getStateForAction","result","getRehydratedState","partialState","routeGetIdList","actionCreators"],"sourceRoot":"../../../src","sources":["navigation/createTrueSheetRouter.ts"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["TrueSheetActions","uid","Math","random","toString","slice","ensureBaseRoute","state","baseRouteName","routeParamList","hasBaseRoute","routes","some","r","name","baseRoute","key","params","index","length","getResizeRouteIndex","action","target","source","findIndex","getTrueSheetStateForAction","type","routeIndex","map","route","i","resizeIndex","resizeKey","pop","count","payload","maxPopCount","actualCount","min","targetIndex","closingIndex","closing","dismissing","popCount","targetName","routeKey","removed","isPopped","filter","undefined","BASE_ROUTE_ACTIONS","Set","getStateForNavigateToBase","getPoppedState","hasSheets","has","popped","base","createTrueSheetRouter","stackRouter","routerOptions","baseRouter","getInitialState","options","initialRouteName","routeNames","stateWithBaseRoute","stale","getStateForAction","result","popAction","getRehydratedState","partialState","routeGetIdList","actionCreators"],"sourceRoot":"../../../src","sources":["navigation/createTrueSheetRouter.ts"],"mappings":"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","ignoreList":[]}
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
 
3
3
  import { TrueSheetActions } from "../actions.js";
4
- import { getResizeRouteIndex, getTrueSheetStateForAction } from "../createTrueSheetRouter.js";
4
+ import { getResizeRouteIndex, getStateForNavigateToBase, getTrueSheetStateForAction } from "../createTrueSheetRouter.js";
5
+
6
+ /**
7
+ * `RouterActionHandling.Unhandled` from Expo Router 58+, which deprecates `null`.
8
+ */
5
9
 
6
10
  /**
7
11
  * `extendRouter` from Expo Router 58+. Declared locally because the
@@ -13,7 +17,7 @@ import { getResizeRouteIndex, getTrueSheetStateForAction } from "../createTrueSh
13
17
  * (no `getInitialState`/`getRehydratedState`) and `getStateForAction` returns
14
18
  * `{ state, affectedRouteKey }`.
15
19
  */
16
- export const extendTrueSheetRouter = (extendRouter, stackRouter) => extendRouter(stackRouter, ({
20
+ export const extendTrueSheetRouter = (extendRouter, stackRouter, unhandled) => extendRouter(stackRouter, ({
17
21
  baseRouter,
18
22
  options
19
23
  }) => {
@@ -22,12 +26,36 @@ export const extendTrueSheetRouter = (extendRouter, stackRouter) => extendRouter
22
26
  }
23
27
  return {
24
28
  getStateForAction(state, action, config) {
29
+ const {
30
+ type,
31
+ payload
32
+ } = action;
33
+
34
+ // Expo Router keeps preloaded routes in `routes`, and the navigator presents every
35
+ // route there as a sheet. A parent navigator's route bubbles up to it, as in a `Stack`.
36
+ if (type === 'PRELOAD') {
37
+ return payload?.name && state.routeNames.includes(payload.name) ? {
38
+ state
39
+ } : unhandled;
40
+ }
41
+ const navigated = getStateForNavigateToBase(state, action, popAction => {
42
+ const popped = baseRouter.getStateForAction(state, popAction, config);
43
+ return popped === unhandled ? undefined : popped.state;
44
+ });
45
+
46
+ // Expo Router resolves the destination's nested state in the affected route
47
+ if (navigated) {
48
+ return {
49
+ state: navigated,
50
+ affectedRouteKey: navigated.routes[0]?.key
51
+ };
52
+ }
25
53
  const result = getTrueSheetStateForAction(state, action);
26
54
  if (result === undefined) {
27
55
  return baseRouter.getStateForAction(state, action, config);
28
56
  }
29
57
  if (result === null) {
30
- return null;
58
+ return unhandled;
31
59
  }
32
60
  const affectedIndex = action.type === 'RESIZE' ? getResizeRouteIndex(state, action) : result.index;
33
61
  return {
@@ -1 +1 @@
1
- {"version":3,"names":["TrueSheetActions","getResizeRouteIndex","getTrueSheetStateForAction","extendTrueSheetRouter","extendRouter","stackRouter","baseRouter","options","__DEV__","initialRouteName","undefined","console","warn","getStateForAction","state","action","config","result","affectedIndex","type","index","affectedRouteKey","routes","key","actionCreators"],"sourceRoot":"../../../../src","sources":["navigation/expo-router/extendTrueSheetRouter.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAkC,eAAY;AACvE,SAASC,mBAAmB,EAAEC,0BAA0B,QAAQ,6BAA0B;;AAgB1F;AACA;AACA;AACA;;AAOA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,qBAAqB,GAAGA,CACnCC,YAA0B,EAC1BC,WAA+B,KAE/BD,YAAY,CACVC,WAAW,EACX,CAAC;EAAEC,UAAU;EAAEC;AAAQ,CAAC,KAAK;EAC3B,IAAIC,OAAO,IAAID,OAAO,CAACE,gBAAgB,KAAKC,SAAS,EAAE;IACrDC,OAAO,CAACC,IAAI,CACV,wQACF,CAAC;EACH;EAEA,OAAO;IACLC,iBAAiBA,CACfC,KAA2B,EAC3BC,MAA2B,EAC3BC,MAAc,EACO;MACrB,MAAMC,MAAM,GAAGf,0BAA0B,CAACY,KAAK,EAAEC,MAAM,CAAC;MAExD,IAAIE,MAAM,KAAKP,SAAS,EAAE;QACxB,OAAOJ,UAAU,CAACO,iBAAiB,CAACC,KAAK,EAAEC,MAAM,EAAEC,MAAM,CAAC;MAC5D;MAEA,IAAIC,MAAM,KAAK,IAAI,EAAE;QACnB,OAAO,IAAI;MACb;MAEA,MAAMC,aAAa,GACjBH,MAAM,CAACI,IAAI,KAAK,QAAQ,GAAGlB,mBAAmB,CAACa,KAAK,EAAEC,MAAM,CAAC,GAAGE,MAAM,CAACG,KAAK;MAE9E,OAAO;QAAEN,KAAK,EAAEG,MAAM;QAAEI,gBAAgB,EAAEJ,MAAM,CAACK,MAAM,CAACJ,aAAa,CAAC,EAAEK;MAAI,CAAC;IAC/E,CAAC;IACDC,cAAc,EAAExB;EAClB,CAAC;AACH,CAAC,EACD;EAAEmB,IAAI,EAAE;AAAa,CACvB,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TrueSheetActions","getResizeRouteIndex","getStateForNavigateToBase","getTrueSheetStateForAction","extendTrueSheetRouter","extendRouter","stackRouter","unhandled","baseRouter","options","__DEV__","initialRouteName","undefined","console","warn","getStateForAction","state","action","config","type","payload","name","routeNames","includes","navigated","popAction","popped","affectedRouteKey","routes","key","result","affectedIndex","index","actionCreators"],"sourceRoot":"../../../../src","sources":["navigation/expo-router/extendTrueSheetRouter.ts"],"mappings":";;AAAA,SAASA,gBAAgB,QAAkC,eAAY;AACvE,SACEC,mBAAmB,EACnBC,yBAAyB,EACzBC,0BAA0B,QACrB,6BAA0B;;AAKjC;AACA;AACA;;AAcA;AACA;AACA;AACA;;AAOA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,qBAAqB,GAAGA,CACnCC,YAA0B,EAC1BC,WAA+B,EAC/BC,SAAoB,KAEpBF,YAAY,CACVC,WAAW,EACX,CAAC;EAAEE,UAAU;EAAEC;AAAQ,CAAC,KAAK;EAC3B,IAAIC,OAAO,IAAID,OAAO,CAACE,gBAAgB,KAAKC,SAAS,EAAE;IACrDC,OAAO,CAACC,IAAI,CACV,wQACF,CAAC;EACH;EAEA,OAAO;IACLC,iBAAiBA,CACfC,KAA2B,EAC3BC,MAA2B,EAC3BC,MAAc,EACY;MAC1B,MAAM;QAAEC,IAAI;QAAEC;MAAQ,CAAC,GAAGH,MAAuD;;MAEjF;MACA;MACA,IAAIE,IAAI,KAAK,SAAS,EAAE;QACtB,OAAOC,OAAO,EAAEC,IAAI,IAAIL,KAAK,CAACM,UAAU,CAACC,QAAQ,CAACH,OAAO,CAACC,IAAI,CAAC,GAAG;UAAEL;QAAM,CAAC,GAAGT,SAAS;MACzF;MAEA,MAAMiB,SAAS,GAAGtB,yBAAyB,CAACc,KAAK,EAAEC,MAAM,EAAGQ,SAAS,IAAK;QACxE,MAAMC,MAAM,GAAGlB,UAAU,CAACO,iBAAiB,CAACC,KAAK,EAAES,SAAS,EAAEP,MAAM,CAAC;QACrE,OAAOQ,MAAM,KAAKnB,SAAS,GAAGK,SAAS,GAAGc,MAAM,CAACV,KAAK;MACxD,CAAC,CAAC;;MAEF;MACA,IAAIQ,SAAS,EAAE;QACb,OAAO;UAAER,KAAK,EAAEQ,SAAS;UAAEG,gBAAgB,EAAEH,SAAS,CAACI,MAAM,CAAC,CAAC,CAAC,EAAEC;QAAI,CAAC;MACzE;MAEA,MAAMC,MAAM,GAAG3B,0BAA0B,CAACa,KAAK,EAAEC,MAAM,CAAC;MAExD,IAAIa,MAAM,KAAKlB,SAAS,EAAE;QACxB,OAAOJ,UAAU,CAACO,iBAAiB,CAACC,KAAK,EAAEC,MAAM,EAAEC,MAAM,CAAC;MAC5D;MAEA,IAAIY,MAAM,KAAK,IAAI,EAAE;QACnB,OAAOvB,SAAS;MAClB;MAEA,MAAMwB,aAAa,GACjBd,MAAM,CAACE,IAAI,KAAK,QAAQ,GAAGlB,mBAAmB,CAACe,KAAK,EAAEC,MAAM,CAAC,GAAGa,MAAM,CAACE,KAAK;MAE9E,OAAO;QAAEhB,KAAK,EAAEc,MAAM;QAAEH,gBAAgB,EAAEG,MAAM,CAACF,MAAM,CAACG,aAAa,CAAC,EAAEF;MAAI,CAAC;IAC/E,CAAC;IACDI,cAAc,EAAEjC;EAClB,CAAC;AACH,CAAC,EACD;EAAEmB,IAAI,EAAE;AAAa,CACvB,CAAC","ignoreList":[]}
@@ -6,12 +6,15 @@ import { createTrueSheetRouter } from "../createTrueSheetRouter.js";
6
6
  import { trueSheetNavigator } from "../navigator.js";
7
7
  import { extendTrueSheetRouter } from "./extendTrueSheetRouter.js";
8
8
  // Expo Router 58+ replaced the React Navigation router contract and ships `extendRouter`
9
- // for it. Before that, the vendored StackRouter is structurally identical to
10
- // @react-navigation's. Pinned to this entry's own router types: `createTrueSheetRouter` is
11
- // shared and typed against React Navigation, which resolves to `any` in apps that only
12
- // install expo-router.
13
- const extendRouter = ExpoRouter.extendRouter;
14
- const sheetRouter = extendRouter ? extendTrueSheetRouter(extendRouter, StackRouter) : createTrueSheetRouter(StackRouter);
9
+ // and `RouterActionHandling` for it. Before that, the vendored StackRouter is structurally
10
+ // identical to @react-navigation's. Pinned to this entry's own router types:
11
+ // `createTrueSheetRouter` is shared and typed against React Navigation, which resolves to
12
+ // `any` in apps that only install expo-router.
13
+ const {
14
+ extendRouter,
15
+ RouterActionHandling
16
+ } = ExpoRouter;
17
+ const sheetRouter = extendRouter ? extendTrueSheetRouter(extendRouter, StackRouter, RouterActionHandling.Unhandled) : createTrueSheetRouter(StackRouter);
15
18
 
16
19
  // `routes`/`dispatch` are injected by `createProps`, so they are declared as
17
20
  // CreateProps (last generic) and excluded from the public navigator props
@@ -1 +1 @@
1
- {"version":3,"names":["ExpoRouter","StackRouter","unstable_integrateWithRouter","useNavigation","createTrueSheetRouter","trueSheetNavigator","extendTrueSheetRouter","extendRouter","sheetRouter","SheetNavigator","createProps","state","dispatch","routes","Sheet","useTrueSheetNavigation","TrueSheetActions"],"sourceRoot":"../../../../src","sources":["navigation/expo-router/index.ts"],"mappings":";;AAAA,OAAO,KAAKA,UAAU,MAAM,aAAa;AACzC,SAASC,WAAW,EAAEC,4BAA4B,EAAEC,aAAa,QAAQ,aAAa;AAEtF,SAASC,qBAAqB,QAAQ,6BAA0B;AAChE,SAASC,kBAAkB,QAAQ,iBAAc;AAEjD,SAASC,qBAAqB,QAA2B,4BAAyB;AAalF;AACA;AACA;AACA;AACA;AACA,MAAMC,YAAY,GAAIP,UAAU,CAA6BO,YAEhD;AAEb,MAAMC,WAAmC,GAAGD,YAAY,GACpDD,qBAAqB,CAACC,YAAY,EAAEN,WAAiC,CAAC,GACtEG,qBAAqB,CAACH,WAAiC,CAAC;;AAE5D;AACA;AACA,MAAMQ,cAAc,GAAGP,4BAA4B,CAOjDG,kBAAkB,EAAEG,WAAW,EAAE;EACjCE,WAAW,EAAEA,CAAC;IAAEC,KAAK;IAAEC;EAAS,CAAC,MAAM;IACrCC,MAAM,EAAEF,KAAK,CAACE,MAAM;IACpBD;EACF,CAAC;AACH,CAAC,CAAC;;AAEF;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,KAAK,GAAGL,cAGpB;;AAED;AACA;AACA;AACA;AACA,OAAO,MAAMM,sBAAsB,GAAGA,CAAA,KAEHZ,aAAa,CAA6B,CAAC;AAE9E,SAASa,gBAAgB,QAAkC,eAAY","ignoreList":[]}
1
+ {"version":3,"names":["ExpoRouter","StackRouter","unstable_integrateWithRouter","useNavigation","createTrueSheetRouter","trueSheetNavigator","extendTrueSheetRouter","extendRouter","RouterActionHandling","sheetRouter","Unhandled","SheetNavigator","createProps","state","dispatch","routes","Sheet","useTrueSheetNavigation","TrueSheetActions"],"sourceRoot":"../../../../src","sources":["navigation/expo-router/index.ts"],"mappings":";;AAAA,OAAO,KAAKA,UAAU,MAAM,aAAa;AACzC,SAASC,WAAW,EAAEC,4BAA4B,EAAEC,aAAa,QAAQ,aAAa;AAEtF,SAASC,qBAAqB,QAAQ,6BAA0B;AAChE,SAASC,kBAAkB,QAAQ,iBAAc;AAEjD,SAASC,qBAAqB,QAA2C,4BAAyB;AAalG;AACA;AACA;AACA;AACA;AACA,MAAM;EAAEC,YAAY;EAAEC;AAAqB,CAAC,GAAGR,UAG9C;AAED,MAAMS,WAAmC,GAAGF,YAAY,GACpDD,qBAAqB,CACnBC,YAAY,EACZN,WAAW,EACXO,oBAAoB,CAAEE,SACxB,CAAC,GACDN,qBAAqB,CAACH,WAAiC,CAAC;;AAE5D;AACA;AACA,MAAMU,cAAc,GAAGT,4BAA4B,CAOjDG,kBAAkB,EAAEI,WAAW,EAAE;EACjCG,WAAW,EAAEA,CAAC;IAAEC,KAAK;IAAEC;EAAS,CAAC,MAAM;IACrCC,MAAM,EAAEF,KAAK,CAACE,MAAM;IACpBD;EACF,CAAC;AACH,CAAC,CAAC;;AAEF;AACA;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,KAAK,GAAGL,cAGpB;;AAED;AACA;AACA;AACA;AACA,OAAO,MAAMM,sBAAsB,GAAGA,CAAA,KAEHd,aAAa,CAA6B,CAAC;AAE9E,SAASe,gBAAgB,QAAkC,eAAY","ignoreList":[]}
@@ -25,6 +25,16 @@ export declare const getResizeRouteIndex: (state: SheetState, action: {
25
25
  * Returns `undefined` for actions the base `StackRouter` should handle.
26
26
  */
27
27
  export declare const getTrueSheetStateForAction: <State extends SheetState>(state: State, action: TrueSheetActionType) => State | null | undefined;
28
+ /**
29
+ * Reduces an action that targets the base route by name. React Navigation 7 adds another base
30
+ * route for a `PUSH`, a `REPLACE` or a `NAVIGATE` without `pop`, which presents the base screen
31
+ * as a sheet, and this router's `POP_TO` drops the params and nested state. This goes back to it
32
+ * instead: `getPoppedState` reduces the action as a `NAVIGATE` with `pop` (a `PUSH` ignores
33
+ * `pop`) to update the base route (params, nested state), then the sheets above it are dismissed.
34
+ * Returns `undefined` for other actions, a `REPLACE` with no sheet (it swaps the base route), or
35
+ * when the base router doesn't land on the base route.
36
+ */
37
+ export declare const getStateForNavigateToBase: <State extends SheetState>(state: State, action: TrueSheetActionType, getPoppedState: (action: TrueSheetActionType) => State | null | undefined) => State | undefined;
28
38
  export declare const createTrueSheetRouter: (stackRouter: TrueSheetRouterFactory) => (routerOptions: TrueSheetRouterOptions) => TrueSheetRouter;
29
39
  export {};
30
40
  //# sourceMappingURL=createTrueSheetRouter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createTrueSheetRouter.d.ts","sourceRoot":"","sources":["../../../../src/navigation/createTrueSheetRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAgC/F,KAAK,UAAU,GAAG;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AACF,KAAK,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,UAAU,EACjB,QAAQ;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAC3C,MAGc,CAAC;AAElB;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,KAAK,SAAS,UAAU,EACjE,OAAO,KAAK,EACZ,QAAQ,mBAAmB,KAC1B,KAAK,GAAG,IAAI,GAAG,SAmHjB,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC/B,aAAa,sBAAsB,MACnC,eAAe,sBAAsB,KAAG,eAiDxC,CAAC"}
1
+ {"version":3,"file":"createTrueSheetRouter.d.ts","sourceRoot":"","sources":["../../../../src/navigation/createTrueSheetRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EACtB,sBAAsB,EAEvB,MAAM,SAAS,CAAC;AAgCjB,KAAK,UAAU,GAAG;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AACF,KAAK,UAAU,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,UAAU,EACjB,QAAQ;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,KAC3C,MAGc,CAAC;AAElB;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,KAAK,SAAS,UAAU,EACjE,OAAO,KAAK,EACZ,QAAQ,mBAAmB,KAC1B,KAAK,GAAG,IAAI,GAAG,SAoHjB,CAAC;AAUF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,GAAI,KAAK,SAAS,UAAU,EAChE,OAAO,KAAK,EACZ,QAAQ,mBAAmB,EAC3B,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,KAAK,KAAK,GAAG,IAAI,GAAG,SAAS,KACxE,KAAK,GAAG,SAgCV,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC/B,aAAa,sBAAsB,MACnC,eAAe,sBAAsB,KAAG,eAwDxC,CAAC"}
@@ -4,9 +4,13 @@ type ActionResult = {
4
4
  state: TrueSheetRouterState;
5
5
  affectedRouteKey?: string;
6
6
  };
7
+ /**
8
+ * `RouterActionHandling.Unhandled` from Expo Router 58+, which deprecates `null`.
9
+ */
10
+ export type Unhandled = 'UNHANDLED';
7
11
  type RouterExtension = (context: {
8
12
  baseRouter: {
9
- getStateForAction(state: TrueSheetRouterState, action: TrueSheetActionType, options: object): ActionResult | null;
13
+ getStateForAction(state: TrueSheetRouterState, action: TrueSheetActionType, options: object): ActionResult | Unhandled;
10
14
  };
11
15
  options: {
12
16
  initialRouteName?: string;
@@ -24,6 +28,6 @@ export type ExtendRouter = (base: StackRouterFactory, extension: RouterExtension
24
28
  * (no `getInitialState`/`getRehydratedState`) and `getStateForAction` returns
25
29
  * `{ state, affectedRouteKey }`.
26
30
  */
27
- export declare const extendTrueSheetRouter: (extendRouter: ExtendRouter, stackRouter: StackRouterFactory) => TrueSheetRouterFactory;
31
+ export declare const extendTrueSheetRouter: (extendRouter: ExtendRouter, stackRouter: StackRouterFactory, unhandled: Unhandled) => TrueSheetRouterFactory;
28
32
  export {};
29
33
  //# sourceMappingURL=extendTrueSheetRouter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extendTrueSheetRouter.d.ts","sourceRoot":"","sources":["../../../../../src/navigation/expo-router/extendTrueSheetRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEhG,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,KAAK,eAAe,GAAG,CAAC,OAAO,EAAE;IAC/B,UAAU,EAAE;QACV,iBAAiB,CACf,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,GAAG,IAAI,CAAC;KACxB,CAAC;IACF,OAAO,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC,KAAK,MAAM,CAAC;AAEb;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KACtB,sBAAsB,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,cAAc,YAAY,EAC1B,aAAa,kBAAkB,KAC9B,sBAmCA,CAAC"}
1
+ {"version":3,"file":"extendTrueSheetRouter.d.ts","sourceRoot":"","sources":["../../../../../src/navigation/expo-router/extendTrueSheetRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAMxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEhG,KAAK,YAAY,GAAG;IAAE,KAAK,EAAE,oBAAoB,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,WAAW,CAAC;AAEpC,KAAK,eAAe,GAAG,CAAC,OAAO,EAAE;IAC/B,UAAU,EAAE;QACV,iBAAiB,CACf,KAAK,EAAE,oBAAoB,EAC3B,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,MAAM,GACd,YAAY,GAAG,SAAS,CAAC;KAC7B,CAAC;IACF,OAAO,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxC,KAAK,MAAM,CAAC;AAEb;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,KACtB,sBAAsB,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAChC,cAAc,YAAY,EAC1B,aAAa,kBAAkB,EAC/B,WAAW,SAAS,KACnB,sBAqDA,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/navigation/expo-router/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAEV,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EAExB,uBAAuB,EAGvB,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAiBjB,QAAA,MAAM,cAAc;;;;;CAYlB,CAAC;AAIH,KAAK,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,EAAE,iBAAiB,CAAC,GACpF,IAAI,CAAC,uBAAuB,EAAE,iBAAiB,CAAC,CAAC;AAEnD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,KAAK,EAAqB,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG;IACvE,MAAM,EAAE,OAAO,cAAc,CAAC,MAAM,CAAC;IACrC,SAAS,EAAE,OAAO,cAAc,CAAC,SAAS,CAAC;CAC5C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GACjC,CAAC,SAAS,aAAa,GAAG,aAAa,OACpC,uBAAuB,CAAC,CAAC,CAAgD,CAAC;AAE/E,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,YAAY,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEhG,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/navigation/expo-router/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAEV,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EAExB,uBAAuB,EAGvB,yBAAyB,EAC1B,MAAM,SAAS,CAAC;AAsBjB,QAAA,MAAM,cAAc;;;;;CAYlB,CAAC;AAIH,KAAK,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,EAAE,iBAAiB,CAAC,GACpF,IAAI,CAAC,uBAAuB,EAAE,iBAAiB,CAAC,CAAC;AAEnD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,KAAK,EAAqB,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG;IACvE,MAAM,EAAE,OAAO,cAAc,CAAC,MAAM,CAAC;IACrC,SAAS,EAAE,OAAO,cAAc,CAAC,SAAS,CAAC;CAC5C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GACjC,CAAC,SAAS,aAAa,GAAG,aAAa,OACpC,uBAAuB,CAAC,CAAC,CAAgD,CAAC;AAE/E,OAAO,EAAE,gBAAgB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAExE,YAAY,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAEhG,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,GACrB,MAAM,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lodev09/react-native-true-sheet",
3
- "version": "4.0.0-beta.29",
3
+ "version": "4.0.0-beta.30",
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",
@@ -1,5 +1,10 @@
1
1
  import { TrueSheetActions, type TrueSheetActionType } from './actions';
2
- import type { TrueSheetRouter, TrueSheetRouterFactory, TrueSheetRouterOptions } from './types';
2
+ import type {
3
+ TrueSheetRouter,
4
+ TrueSheetRouterFactory,
5
+ TrueSheetRouterOptions,
6
+ TrueSheetRouterState,
7
+ } from './types';
3
8
 
4
9
  const uid = () => Math.random().toString(36).slice(2, 10);
5
10
 
@@ -107,10 +112,11 @@ export const getTrueSheetStateForAction = <State extends SheetState>(
107
112
  const closingIndex = targetIndex + 1;
108
113
 
109
114
  // Mark only the bottom-most route to pop as closing
110
- // The sheet's dismiss() will handle dismissing sheets above it first
115
+ // The sheet's dismiss() will handle dismissing sheets above it first.
116
+ // The index stays on the top sheet until REMOVE: Expo Router 58 treats the routes
117
+ // after `index` as preloaded.
111
118
  return {
112
119
  ...state,
113
- index: closingIndex,
114
120
  routes: state.routes.map((route, i) => {
115
121
  if (i === closingIndex) return { ...route, closing: true };
116
122
  if (i > closingIndex) return { ...route, dismissing: true };
@@ -176,6 +182,61 @@ export const getTrueSheetStateForAction = <State extends SheetState>(
176
182
  }
177
183
  };
178
184
 
185
+ const BASE_ROUTE_ACTIONS = new Set([
186
+ 'NAVIGATE',
187
+ 'NAVIGATE_DEPRECATED',
188
+ 'PUSH',
189
+ 'REPLACE',
190
+ 'POP_TO',
191
+ ]);
192
+
193
+ /**
194
+ * Reduces an action that targets the base route by name. React Navigation 7 adds another base
195
+ * route for a `PUSH`, a `REPLACE` or a `NAVIGATE` without `pop`, which presents the base screen
196
+ * as a sheet, and this router's `POP_TO` drops the params and nested state. This goes back to it
197
+ * instead: `getPoppedState` reduces the action as a `NAVIGATE` with `pop` (a `PUSH` ignores
198
+ * `pop`) to update the base route (params, nested state), then the sheets above it are dismissed.
199
+ * Returns `undefined` for other actions, a `REPLACE` with no sheet (it swaps the base route), or
200
+ * when the base router doesn't land on the base route.
201
+ */
202
+ export const getStateForNavigateToBase = <State extends SheetState>(
203
+ state: State,
204
+ action: TrueSheetActionType,
205
+ getPoppedState: (action: TrueSheetActionType) => State | null | undefined
206
+ ): State | undefined => {
207
+ const { type, payload } = action as { type: string; payload?: { name?: string } };
208
+ const baseRoute = state.routes[0]!;
209
+ const hasSheets = state.routes.length > 1;
210
+
211
+ if (
212
+ !BASE_ROUTE_ACTIONS.has(type) ||
213
+ payload?.name !== baseRoute.name ||
214
+ (type === 'REPLACE' && !hasSheets)
215
+ ) {
216
+ return undefined;
217
+ }
218
+
219
+ const popped = getPoppedState({
220
+ ...action,
221
+ type: 'NAVIGATE',
222
+ payload: { ...payload, pop: true },
223
+ } as unknown as TrueSheetActionType);
224
+ const base = popped?.routes[popped.index];
225
+
226
+ if (base?.key !== baseRoute.key) {
227
+ return undefined;
228
+ }
229
+
230
+ if (!hasSheets) {
231
+ return popped!;
232
+ }
233
+
234
+ return getTrueSheetStateForAction(
235
+ { ...state, routes: [base, ...state.routes.slice(1)] },
236
+ TrueSheetActions.pop(state.routes.length - 1)
237
+ )!;
238
+ };
239
+
179
240
  export const createTrueSheetRouter =
180
241
  (stackRouter: TrueSheetRouterFactory) =>
181
242
  (routerOptions: TrueSheetRouterOptions): TrueSheetRouter => {
@@ -199,7 +260,14 @@ export const createTrueSheetRouter =
199
260
  },
200
261
 
201
262
  getStateForAction(state, action, options) {
202
- const result = getTrueSheetStateForAction(state, action);
263
+ const result =
264
+ getStateForNavigateToBase(
265
+ state,
266
+ action,
267
+ // NAVIGATE never returns a partial state
268
+ (popAction) =>
269
+ baseRouter.getStateForAction(state, popAction, options) as TrueSheetRouterState | null
270
+ ) ?? getTrueSheetStateForAction(state, action);
203
271
 
204
272
  return result === undefined ? baseRouter.getStateForAction(state, action, options) : result;
205
273
  },
@@ -1,16 +1,25 @@
1
1
  import { TrueSheetActions, type TrueSheetActionType } from '../actions';
2
- import { getResizeRouteIndex, getTrueSheetStateForAction } from '../createTrueSheetRouter';
2
+ import {
3
+ getResizeRouteIndex,
4
+ getStateForNavigateToBase,
5
+ getTrueSheetStateForAction,
6
+ } from '../createTrueSheetRouter';
3
7
  import type { StackRouterFactory, TrueSheetRouterFactory, TrueSheetRouterState } from './types';
4
8
 
5
9
  type ActionResult = { state: TrueSheetRouterState; affectedRouteKey?: string };
6
10
 
11
+ /**
12
+ * `RouterActionHandling.Unhandled` from Expo Router 58+, which deprecates `null`.
13
+ */
14
+ export type Unhandled = 'UNHANDLED';
15
+
7
16
  type RouterExtension = (context: {
8
17
  baseRouter: {
9
18
  getStateForAction(
10
19
  state: TrueSheetRouterState,
11
20
  action: TrueSheetActionType,
12
21
  options: object
13
- ): ActionResult | null;
22
+ ): ActionResult | Unhandled;
14
23
  };
15
24
  options: { initialRouteName?: string };
16
25
  }) => object;
@@ -32,7 +41,8 @@ export type ExtendRouter = (
32
41
  */
33
42
  export const extendTrueSheetRouter = (
34
43
  extendRouter: ExtendRouter,
35
- stackRouter: StackRouterFactory
44
+ stackRouter: StackRouterFactory,
45
+ unhandled: Unhandled
36
46
  ): TrueSheetRouterFactory =>
37
47
  extendRouter(
38
48
  stackRouter,
@@ -48,7 +58,25 @@ export const extendTrueSheetRouter = (
48
58
  state: TrueSheetRouterState,
49
59
  action: TrueSheetActionType,
50
60
  config: object
51
- ): ActionResult | null {
61
+ ): ActionResult | Unhandled {
62
+ const { type, payload } = action as { type: string; payload?: { name?: string } };
63
+
64
+ // Expo Router keeps preloaded routes in `routes`, and the navigator presents every
65
+ // route there as a sheet. A parent navigator's route bubbles up to it, as in a `Stack`.
66
+ if (type === 'PRELOAD') {
67
+ return payload?.name && state.routeNames.includes(payload.name) ? { state } : unhandled;
68
+ }
69
+
70
+ const navigated = getStateForNavigateToBase(state, action, (popAction) => {
71
+ const popped = baseRouter.getStateForAction(state, popAction, config);
72
+ return popped === unhandled ? undefined : popped.state;
73
+ });
74
+
75
+ // Expo Router resolves the destination's nested state in the affected route
76
+ if (navigated) {
77
+ return { state: navigated, affectedRouteKey: navigated.routes[0]?.key };
78
+ }
79
+
52
80
  const result = getTrueSheetStateForAction(state, action);
53
81
 
54
82
  if (result === undefined) {
@@ -56,7 +84,7 @@ export const extendTrueSheetRouter = (
56
84
  }
57
85
 
58
86
  if (result === null) {
59
- return null;
87
+ return unhandled;
60
88
  }
61
89
 
62
90
  const affectedIndex =
@@ -4,7 +4,7 @@ import { StackRouter, unstable_integrateWithRouter, useNavigation } from 'expo-r
4
4
  import { createTrueSheetRouter } from '../createTrueSheetRouter';
5
5
  import { trueSheetNavigator } from '../navigator';
6
6
  import type { ParamListBase } from './base-types';
7
- import { extendTrueSheetRouter, type ExtendRouter } from './extendTrueSheetRouter';
7
+ import { extendTrueSheetRouter, type ExtendRouter, type Unhandled } from './extendTrueSheetRouter';
8
8
  import type {
9
9
  StackRouterFactory,
10
10
  TrueSheetNavigationOptions,
@@ -18,16 +18,21 @@ import type {
18
18
  } from './types';
19
19
 
20
20
  // Expo Router 58+ replaced the React Navigation router contract and ships `extendRouter`
21
- // for it. Before that, the vendored StackRouter is structurally identical to
22
- // @react-navigation's. Pinned to this entry's own router types: `createTrueSheetRouter` is
23
- // shared and typed against React Navigation, which resolves to `any` in apps that only
24
- // install expo-router.
25
- const extendRouter = (ExpoRouter as Record<string, unknown>).extendRouter as
26
- | ExtendRouter
27
- | undefined;
21
+ // and `RouterActionHandling` for it. Before that, the vendored StackRouter is structurally
22
+ // identical to @react-navigation's. Pinned to this entry's own router types:
23
+ // `createTrueSheetRouter` is shared and typed against React Navigation, which resolves to
24
+ // `any` in apps that only install expo-router.
25
+ const { extendRouter, RouterActionHandling } = ExpoRouter as {
26
+ extendRouter?: ExtendRouter;
27
+ RouterActionHandling?: { Unhandled: Unhandled };
28
+ };
28
29
 
29
30
  const sheetRouter: TrueSheetRouterFactory = extendRouter
30
- ? extendTrueSheetRouter(extendRouter, StackRouter as StackRouterFactory)
31
+ ? extendTrueSheetRouter(
32
+ extendRouter,
33
+ StackRouter as StackRouterFactory,
34
+ RouterActionHandling!.Unhandled
35
+ )
31
36
  : createTrueSheetRouter(StackRouter as StackRouterFactory);
32
37
 
33
38
  // `routes`/`dispatch` are injected by `createProps`, so they are declared as