@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.
Files changed (68) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +22 -2
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +29 -31
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +10 -9
  4. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +6 -12
  5. package/ios/TrueSheetContainerView.mm +7 -0
  6. package/ios/TrueSheetContentView.mm +7 -1
  7. package/ios/TrueSheetModule.mm +33 -9
  8. package/ios/TrueSheetView.h +3 -1
  9. package/ios/TrueSheetView.mm +47 -40
  10. package/ios/TrueSheetViewController.h +1 -0
  11. package/ios/TrueSheetViewController.mm +4 -8
  12. package/ios/core/RNScreensEventObserver.mm +23 -15
  13. package/lib/module/TrueSheet.js +45 -26
  14. package/lib/module/TrueSheet.js.map +1 -1
  15. package/lib/module/TrueSheet.web.js +26 -40
  16. package/lib/module/TrueSheet.web.js.map +1 -1
  17. package/lib/module/TrueSheetProvider.js +1 -0
  18. package/lib/module/TrueSheetProvider.js.map +1 -1
  19. package/lib/module/TrueSheetProvider.web.js +7 -32
  20. package/lib/module/TrueSheetProvider.web.js.map +1 -1
  21. package/lib/module/index.js +1 -1
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/mocks/index.js +3 -0
  24. package/lib/module/mocks/index.js.map +1 -1
  25. package/lib/module/mocks/reanimated.js +2 -0
  26. package/lib/module/mocks/reanimated.js.map +1 -1
  27. package/lib/module/navigation/TrueSheetRouter.js +42 -8
  28. package/lib/module/navigation/TrueSheetRouter.js.map +1 -1
  29. package/lib/module/navigation/screen/useSheetScreenState.js +8 -17
  30. package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
  31. package/lib/module/reanimated/ReanimatedTrueSheet.web.js +2 -2
  32. package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -1
  33. package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
  34. package/lib/typescript/src/TrueSheet.d.ts +29 -2
  35. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  36. package/lib/typescript/src/TrueSheet.types.d.ts +0 -48
  37. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  38. package/lib/typescript/src/TrueSheet.web.d.ts +4 -2
  39. package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
  40. package/lib/typescript/src/TrueSheetProvider.d.ts +3 -2
  41. package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -1
  42. package/lib/typescript/src/TrueSheetProvider.web.d.ts +6 -14
  43. package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
  44. package/lib/typescript/src/index.d.ts +1 -1
  45. package/lib/typescript/src/index.d.ts.map +1 -1
  46. package/lib/typescript/src/mocks/index.d.ts +6 -3
  47. package/lib/typescript/src/mocks/index.d.ts.map +1 -1
  48. package/lib/typescript/src/mocks/reanimated.d.ts +4 -2
  49. package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -1
  50. package/lib/typescript/src/navigation/TrueSheetRouter.d.ts.map +1 -1
  51. package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
  52. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +4 -3
  53. package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -1
  54. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +9 -1
  55. package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
  56. package/package.json +1 -1
  57. package/src/TrueSheet.tsx +45 -35
  58. package/src/TrueSheet.types.ts +0 -50
  59. package/src/TrueSheet.web.tsx +32 -50
  60. package/src/TrueSheetProvider.tsx +7 -2
  61. package/src/TrueSheetProvider.web.tsx +19 -38
  62. package/src/index.ts +1 -1
  63. package/src/mocks/index.ts +7 -6
  64. package/src/mocks/reanimated.ts +4 -5
  65. package/src/navigation/TrueSheetRouter.ts +51 -16
  66. package/src/navigation/screen/useSheetScreenState.ts +5 -11
  67. package/src/reanimated/ReanimatedTrueSheet.web.tsx +28 -30
  68. package/src/specs/NativeTrueSheetModule.ts +10 -1
@@ -1,4 +1,5 @@
1
- import type { TrueSheetProps, TrueSheetRef } from '../TrueSheet.types';
1
+ import { TrueSheet } from '../TrueSheet';
2
+ import type { TrueSheetProps } from '../TrueSheet.types';
2
3
  interface ReanimatedTrueSheetProps extends TrueSheetProps {
3
4
  /**
4
5
  * Callback for position changes.
@@ -18,7 +19,7 @@ interface ReanimatedTrueSheetProps extends TrueSheetProps {
18
19
  * import { ReanimatedTrueSheet, ReanimatedTrueSheetProvider } from '@lodev09/react-native-true-sheet/reanimated'
19
20
  *
20
21
  * function MyScreen() {
21
- * const sheetRef = useRef<TrueSheetRef>(null)
22
+ * const sheetRef = useRef<TrueSheet>(null)
22
23
  *
23
24
  * return (
24
25
  * <ReanimatedTrueSheetProvider>
@@ -36,6 +37,6 @@ interface ReanimatedTrueSheetProps extends TrueSheetProps {
36
37
  * }
37
38
  * ```
38
39
  */
39
- export declare const ReanimatedTrueSheet: import("react").ForwardRefExoticComponent<ReanimatedTrueSheetProps & import("react").RefAttributes<TrueSheetRef>>;
40
+ export declare const ReanimatedTrueSheet: import("react").ForwardRefExoticComponent<ReanimatedTrueSheetProps & import("react").RefAttributes<TrueSheet>>;
40
41
  export {};
41
42
  //# sourceMappingURL=ReanimatedTrueSheet.web.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReanimatedTrueSheet.web.d.ts","sourceRoot":"","sources":["../../../../src/reanimated/ReanimatedTrueSheet.web.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAuB,MAAM,oBAAoB,CAAC;AAG5F,UAAU,wBAAyB,SAAQ,cAAc;IACvD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC,kBAAkB,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,mHAgC/B,CAAC"}
1
+ {"version":3,"file":"ReanimatedTrueSheet.web.d.ts","sourceRoot":"","sources":["../../../../src/reanimated/ReanimatedTrueSheet.web.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,oBAAoB,CAAC;AAG9E,UAAU,wBAAyB,SAAQ,cAAc;IACvD;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,cAAc,CAAC,kBAAkB,CAAC,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,mBAAmB,gHA8B9B,CAAC"}
@@ -16,13 +16,21 @@ interface Spec extends TurboModule {
16
16
  */
17
17
  presentByRef(viewTag: number, index: number, animated: boolean): Promise<void>;
18
18
  /**
19
- * Dismiss a sheet by reference
19
+ * Dismiss a sheet and all sheets presented on top of it
20
20
  * @param viewTag - Native view tag of the sheet component
21
21
  * @param animated - Whether to animate the dismissal
22
22
  * @returns Promise that resolves when sheet is fully dismissed
23
23
  * @throws DISMISS_FAILED if dismissal fails
24
24
  */
25
25
  dismissByRef(viewTag: number, animated: boolean): Promise<void>;
26
+ /**
27
+ * Dismiss only the sheets presented on top of this sheet, keeping this sheet presented
28
+ * @param viewTag - Native view tag of the sheet component
29
+ * @param animated - Whether to animate the dismissal
30
+ * @returns Promise that resolves when all child sheets are fully dismissed
31
+ * @throws DISMISS_FAILED if dismissal fails
32
+ */
33
+ dismissStackByRef(viewTag: number, animated: boolean): Promise<void>;
26
34
  /**
27
35
  * Resize a sheet to a different index by reference
28
36
  * @param viewTag - Native view tag of the sheet component
@@ -1 +1 @@
1
- {"version":3,"file":"NativeTrueSheetModule.d.ts","sourceRoot":"","sources":["../../../../src/specs/NativeTrueSheetModule.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,UAAU,IAAK,SAAQ,WAAW;IAChC;;;;;;;OAOG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/E;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhE;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;;AAED,wBAAgE"}
1
+ {"version":3,"file":"NativeTrueSheetModule.d.ts","sourceRoot":"","sources":["../../../../src/specs/NativeTrueSheetModule.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,UAAU,IAAK,SAAQ,WAAW;IAChC;;;;;;;OAOG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE/E;;;;;;OAMG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhE;;;;;;OAMG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErE;;;;;OAKG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C;;AAED,wBAAgE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lodev09/react-native-true-sheet",
3
- "version": "3.8.0-beta.1",
3
+ "version": "3.8.0-beta.3",
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",
package/src/TrueSheet.tsx CHANGED
@@ -10,7 +10,6 @@ import {
10
10
 
11
11
  import type {
12
12
  TrueSheetProps,
13
- TrueSheetRef,
14
13
  DragBeginEvent,
15
14
  DragChangeEvent,
16
15
  DragEndEvent,
@@ -54,10 +53,7 @@ interface TrueSheetState {
54
53
  shouldRenderNativeView: boolean;
55
54
  }
56
55
 
57
- export class TrueSheet
58
- extends PureComponent<TrueSheetProps, TrueSheetState>
59
- implements TrueSheetRef
60
- {
56
+ export class TrueSheet extends PureComponent<TrueSheetProps, TrueSheetState> {
61
57
  displayName = 'TrueSheet';
62
58
 
63
59
  private readonly nativeRef: RefObject<NativeRef | null>;
@@ -199,6 +195,22 @@ export class TrueSheet
199
195
  return instance.dismiss(animated);
200
196
  }
201
197
 
198
+ /**
199
+ * Dismiss only the sheets presented on top of a sheet by given `name`
200
+ * @param name - Sheet name
201
+ * @param animated - Whether to animate the dismissal (default: true)
202
+ * @returns Promise that resolves when all child sheets are dismissed
203
+ * @throws Error if sheet not found
204
+ */
205
+ public static async dismissStack(name: string, animated: boolean = true): Promise<void> {
206
+ const instance = TrueSheet.getInstance(name);
207
+ if (!instance) {
208
+ throw new Error(`Sheet with name "${name}" not found`);
209
+ }
210
+
211
+ return instance.dismissStack(animated);
212
+ }
213
+
202
214
  /**
203
215
  * Resize the sheet by given `name` (Promise-based)
204
216
  * @param name - Sheet name
@@ -309,6 +321,11 @@ export class TrueSheet
309
321
  this.props.onBackPress?.(event);
310
322
  }
311
323
 
324
+ /**
325
+ * Present the sheet at a given detent index.
326
+ * @param index - The detent index to present at (default: 0)
327
+ * @param animated - Whether to animate the presentation (default: true)
328
+ */
312
329
  public async present(index: number = 0, animated: boolean = true): Promise<void> {
313
330
  const detentsLength = Math.min(this.props.detents?.length ?? 2, 3); // Max 3 detents
314
331
  if (index < 0 || index >= detentsLength) {
@@ -331,14 +348,31 @@ export class TrueSheet
331
348
  this.isPresenting = false;
332
349
  }
333
350
 
351
+ /**
352
+ * Resize the sheet to a given detent index.
353
+ * @param index - The detent index to resize to
354
+ */
334
355
  public async resize(index: number): Promise<void> {
335
356
  await TrueSheetModule?.resizeByRef(this.handle, index);
336
357
  }
337
358
 
359
+ /**
360
+ * Dismiss this sheet and all sheets presented on top of it in a single animation.
361
+ * @param animated - Whether to animate the dismissal (default: true)
362
+ */
338
363
  public async dismiss(animated: boolean = true): Promise<void> {
339
364
  return TrueSheetModule?.dismissByRef(this.handle, animated);
340
365
  }
341
366
 
367
+ /**
368
+ * Dismiss only the sheets presented on top of this sheet, keeping this sheet presented.
369
+ * If no sheets are presented on top, this method does nothing.
370
+ * @param animated - Whether to animate the dismissal (default: true)
371
+ */
372
+ public async dismissStack(animated: boolean = true): Promise<void> {
373
+ return TrueSheetModule?.dismissStackByRef(this.handle, animated);
374
+ }
375
+
342
376
  componentDidMount(): void {
343
377
  this.registerInstance();
344
378
  }
@@ -400,23 +434,11 @@ export class TrueSheet
400
434
  return Math.min(1, detent);
401
435
  });
402
436
 
403
- const containerStyle =
404
- this.props.scrollable &&
405
- Platform.select({
406
- android: styles.scrollableAndroidContainer,
407
- });
408
-
409
- const contentStyle =
410
- this.props.scrollable &&
411
- Platform.select({
412
- android: styles.scrollableAndroidContent,
413
- });
414
-
415
437
  return (
416
438
  <TrueSheetViewNativeComponent
417
439
  {...rest}
418
440
  ref={this.nativeRef}
419
- style={styles.sheetView}
441
+ style={[StyleSheet.absoluteFill, styles.sheetView]}
420
442
  detents={resolvedDetents}
421
443
  backgroundBlur={backgroundBlur}
422
444
  blurOptions={blurOptions}
@@ -455,13 +477,15 @@ export class TrueSheet
455
477
  onBackPress={this.onBackPress}
456
478
  >
457
479
  {this.state.shouldRenderNativeView && (
458
- <TrueSheetContainerViewNativeComponent style={containerStyle}>
480
+ <TrueSheetContainerViewNativeComponent style={scrollable && StyleSheet.absoluteFill}>
459
481
  {header && (
460
482
  <TrueSheetHeaderViewNativeComponent style={[styles.header, headerStyle]}>
461
483
  {isValidElement(header) ? header : createElement(header)}
462
484
  </TrueSheetHeaderViewNativeComponent>
463
485
  )}
464
- <TrueSheetContentViewNativeComponent style={[style, contentStyle]}>
486
+ <TrueSheetContentViewNativeComponent
487
+ style={[style, scrollable && styles.scrollableContent]}
488
+ >
465
489
  {children}
466
490
  </TrueSheetContentViewNativeComponent>
467
491
  {footer && (
@@ -480,22 +504,8 @@ const styles = StyleSheet.create({
480
504
  sheetView: {
481
505
  zIndex: -9999,
482
506
  pointerEvents: 'box-none',
483
- position: 'absolute',
484
- top: 0,
485
- left: 0,
486
- right: 0,
487
-
488
- // Android needs a fixed bottom to avoid jumping content
489
- bottom: Platform.select({ android: 0 }),
490
- },
491
- scrollableAndroidContainer: {
492
- position: 'absolute',
493
- top: 0,
494
- left: 0,
495
- right: 0,
496
- bottom: 0,
497
507
  },
498
- scrollableAndroidContent: {
508
+ scrollableContent: {
499
509
  flexGrow: 1,
500
510
  flexBasis: 0,
501
511
  },
@@ -46,56 +46,6 @@ export type WillFocusEvent = NativeSyntheticEvent<null>;
46
46
  export type WillBlurEvent = NativeSyntheticEvent<null>;
47
47
  export type BackPressEvent = NativeSyntheticEvent<null>;
48
48
 
49
- /**
50
- * Ref methods exposed by a TrueSheet instance.
51
- */
52
- export interface TrueSheetRef {
53
- /**
54
- * Present the sheet at a given detent index.
55
- * @param index - The detent index to present at (default: 0)
56
- * @param animated - Whether to animate the presentation (default: true)
57
- */
58
- present: (index?: number, animated?: boolean) => Promise<void>;
59
- /**
60
- * Dismiss the sheet. If other sheets are presented on top, dismisses them instead.
61
- * @param animated - Whether to animate the dismissal (default: true)
62
- */
63
- dismiss: (animated?: boolean) => Promise<void>;
64
- /**
65
- * Resize the sheet to a given detent index.
66
- * @param index - The detent index to resize to
67
- */
68
- resize: (index: number) => Promise<void>;
69
- }
70
-
71
- /**
72
- * Methods for controlling TrueSheet instances by name.
73
- * Returned by the `useTrueSheet` hook.
74
- */
75
- export interface TrueSheetContextMethods {
76
- /**
77
- * Present a sheet by name.
78
- * @param name - The name of the sheet to present
79
- * @param index - The detent index to present at (default: 0)
80
- */
81
- present: (name: string, index?: number) => Promise<void>;
82
- /**
83
- * Dismiss a sheet by name.
84
- * @param name - The name of the sheet to dismiss
85
- */
86
- dismiss: (name: string) => Promise<void>;
87
- /**
88
- * Resize a sheet by name.
89
- * @param name - The name of the sheet to resize
90
- * @param index - The detent index to resize to
91
- */
92
- resize: (name: string, index: number) => Promise<void>;
93
- /**
94
- * Dismiss all presented sheets.
95
- */
96
- dismissAll: () => Promise<void>;
97
- }
98
-
99
49
  /**
100
50
  * Options for customizing the grabber (drag handle) appearance.
101
51
  */
@@ -27,16 +27,9 @@ import BottomSheet, {
27
27
  } from '@gorhom/bottom-sheet';
28
28
  import { useDerivedValue, useSharedValue } from 'react-native-reanimated';
29
29
 
30
- import {
31
- BottomSheetContext,
32
- getPresent,
33
- getDismiss,
34
- getResize,
35
- getDismissAll,
36
- } from './TrueSheetProvider.web';
30
+ import { BottomSheetContext, type TrueSheetRefMethods } from './TrueSheetProvider.web';
37
31
  import type {
38
32
  TrueSheetProps,
39
- TrueSheetRef,
40
33
  DetentChangeEvent,
41
34
  DidBlurEvent,
42
35
  DidDismissEvent,
@@ -84,7 +77,7 @@ const renderSlot = (slot: TrueSheetProps['header'] | TrueSheetProps['footer']) =
84
77
  return createElement(slot);
85
78
  };
86
79
 
87
- const TrueSheetComponent = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref) => {
80
+ const TrueSheetComponent = forwardRef<TrueSheetRefMethods, TrueSheetProps>((props, ref) => {
88
81
  const {
89
82
  name,
90
83
  detents = [0.5, 1],
@@ -362,19 +355,7 @@ const TrueSheetComponent = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref)
362
355
  // For scrollable, we render the child directly
363
356
  const ContainerComponent = scrollable ? Fragment : BottomSheetView;
364
357
 
365
- const dismissInternal = useCallback(() => {
366
- return new Promise<void>((resolve) => {
367
- dismissResolver.current = resolve;
368
- isDismissing.current = true;
369
- if (isNonModal) {
370
- bottomSheetRef.current?.close();
371
- } else {
372
- bottomSheetModalRef.current?.dismiss();
373
- }
374
- });
375
- }, [isNonModal]);
376
-
377
- const sheetMethodsRef = useRef<TrueSheetRef & { dismissDirect?: () => Promise<void> }>({
358
+ const sheetMethodsRef = useRef<TrueSheetRefMethods>({
378
359
  present: (index = 0) => {
379
360
  return new Promise<void>((resolve) => {
380
361
  presentResolver.current = resolve;
@@ -390,20 +371,29 @@ const TrueSheetComponent = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref)
390
371
  },
391
372
  dismiss: () => {
392
373
  return new Promise<void>((resolve) => {
393
- // iOS-like behavior: dismiss sheets above, but not itself.
394
- // See: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621505-dismiss
374
+ dismissResolver.current = resolve;
375
+ isDismissing.current = true;
376
+ if (isNonModal) {
377
+ bottomSheetRef.current?.close();
378
+ } else {
379
+ bottomSheetModalRef.current?.dismiss();
380
+ }
381
+ });
382
+ },
383
+ dismissStack: () => {
384
+ return new Promise<void>((resolve) => {
385
+ // Dismiss only sheets above, keeping this sheet presented
395
386
  const sheetsAbove = bottomSheetContext?.getSheetsAbove(sheetName) ?? [];
396
387
  const immediateChild = sheetsAbove[sheetsAbove.length - 1];
397
388
  if (immediateChild) {
398
389
  // Dismiss the immediate child - gorhom will dismiss all sheets above it
399
- bottomSheetContext?.dismissDirect(immediateChild).then(resolve);
390
+ bottomSheetContext?.dismiss(immediateChild).then(resolve);
400
391
  return;
401
392
  }
402
393
 
403
- dismissInternal().then(resolve);
394
+ resolve();
404
395
  });
405
396
  },
406
- dismissDirect: () => dismissInternal(),
407
397
  resize: async (index: number) => {
408
398
  if (isNonModal) {
409
399
  bottomSheetRef.current?.snapToIndex(index);
@@ -494,45 +484,37 @@ const TrueSheetComponent = forwardRef<TrueSheetRef, TrueSheetProps>((props, ref)
494
484
  );
495
485
  });
496
486
 
487
+ const STATIC_METHOD_ERROR =
488
+ 'Static methods are not supported on web. Use the useTrueSheet() hook instead.';
489
+
497
490
  interface TrueSheetStatic {
498
491
  present: (name: string, index?: number) => Promise<void>;
499
492
  dismiss: (name: string) => Promise<void>;
493
+ dismissStack: (name: string) => Promise<void>;
500
494
  resize: (name: string, index: number) => Promise<void>;
501
495
  dismissAll: () => Promise<void>;
502
496
  }
503
497
 
504
498
  export const TrueSheet = TrueSheetComponent as typeof TrueSheetComponent & TrueSheetStatic;
505
499
 
506
- TrueSheet.present = async (name: string, index?: number) => {
507
- const present = getPresent();
508
- if (!present) {
509
- throw new Error('TrueSheet.present(): TrueSheetProvider is not mounted.');
510
- }
511
- return present(name, index);
500
+ TrueSheet.present = async () => {
501
+ throw new Error(STATIC_METHOD_ERROR);
512
502
  };
513
503
 
514
- TrueSheet.dismiss = async (name: string) => {
515
- const dismiss = getDismiss();
516
- if (!dismiss) {
517
- throw new Error('TrueSheet.dismiss(): TrueSheetProvider is not mounted.');
518
- }
519
- return dismiss(name);
504
+ TrueSheet.dismiss = async () => {
505
+ throw new Error(STATIC_METHOD_ERROR);
520
506
  };
521
507
 
522
- TrueSheet.resize = async (name: string, index: number) => {
523
- const resize = getResize();
524
- if (!resize) {
525
- throw new Error('TrueSheet.resize(): TrueSheetProvider is not mounted.');
526
- }
527
- return resize(name, index);
508
+ TrueSheet.dismissStack = async () => {
509
+ throw new Error(STATIC_METHOD_ERROR);
510
+ };
511
+
512
+ TrueSheet.resize = async () => {
513
+ throw new Error(STATIC_METHOD_ERROR);
528
514
  };
529
515
 
530
516
  TrueSheet.dismissAll = async () => {
531
- const dismissAll = getDismissAll();
532
- if (!dismissAll) {
533
- throw new Error('TrueSheet.dismissAll(): TrueSheetProvider is not mounted.');
534
- }
535
- return dismissAll();
517
+ throw new Error(STATIC_METHOD_ERROR);
536
518
  };
537
519
 
538
520
  const styles = StyleSheet.create({
@@ -1,7 +1,11 @@
1
1
  import type { ReactNode } from 'react';
2
2
 
3
3
  import { TrueSheet } from './TrueSheet';
4
- import type { TrueSheetContextMethods } from './TrueSheet.types';
4
+
5
+ export type TrueSheetStaticMethods = Pick<
6
+ typeof TrueSheet,
7
+ 'present' | 'dismiss' | 'dismissStack' | 'resize' | 'dismissAll'
8
+ >;
5
9
 
6
10
  export interface TrueSheetProviderProps {
7
11
  children: ReactNode;
@@ -20,10 +24,11 @@ export function TrueSheetProvider({ children }: TrueSheetProviderProps) {
20
24
  * Hook to control TrueSheet instances by name.
21
25
  * On native, this maps directly to TrueSheet static methods.
22
26
  */
23
- export function useTrueSheet(): TrueSheetContextMethods {
27
+ export function useTrueSheet(): TrueSheetStaticMethods {
24
28
  return {
25
29
  present: TrueSheet.present,
26
30
  dismiss: TrueSheet.dismiss,
31
+ dismissStack: TrueSheet.dismissStack,
27
32
  resize: TrueSheet.resize,
28
33
  dismissAll: TrueSheet.dismissAll,
29
34
  };
@@ -1,30 +1,24 @@
1
1
  import { createContext, useContext, useRef, type ReactNode, type RefObject } from 'react';
2
2
  import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
3
- import type { TrueSheetContextMethods, TrueSheetRef } from './TrueSheet.types';
4
3
 
5
- interface BottomSheetContextValue extends TrueSheetContextMethods {
6
- register: (name: string, methods: RefObject<TrueSheetRef>) => void;
4
+ import type { TrueSheetStaticMethods } from './TrueSheetProvider';
5
+ import type { TrueSheet } from './TrueSheet';
6
+
7
+ export type TrueSheetRefMethods = Pick<
8
+ TrueSheet,
9
+ 'present' | 'dismiss' | 'resize' | 'dismissStack'
10
+ >;
11
+
12
+ interface BottomSheetContextValue extends TrueSheetStaticMethods {
13
+ register: (name: string, methods: RefObject<TrueSheetRefMethods>) => void;
7
14
  unregister: (name: string) => void;
8
15
  pushToStack: (name: string) => void;
9
16
  removeFromStack: (name: string) => void;
10
17
  getSheetsAbove: (name: string) => string[];
11
- dismissDirect: (name: string) => Promise<void>;
12
- dismissAll: () => Promise<void>;
13
18
  }
14
19
 
15
20
  export const BottomSheetContext = createContext<BottomSheetContextValue | null>(null);
16
21
 
17
- // Module-level references for static methods
18
- let presentRef: ((name: string, index?: number) => Promise<void>) | null = null;
19
- let dismissRef: ((name: string) => Promise<void>) | null = null;
20
- let resizeRef: ((name: string, index: number) => Promise<void>) | null = null;
21
- let dismissAllRef: (() => Promise<void>) | null = null;
22
-
23
- export const getPresent = () => presentRef;
24
- export const getDismiss = () => dismissRef;
25
- export const getResize = () => resizeRef;
26
- export const getDismissAll = () => dismissAllRef;
27
-
28
22
  export interface TrueSheetProviderProps {
29
23
  children: ReactNode;
30
24
  }
@@ -34,10 +28,10 @@ export interface TrueSheetProviderProps {
34
28
  * Required to wrap your app for sheet management via useTrueSheet hook.
35
29
  */
36
30
  export function TrueSheetProvider({ children }: TrueSheetProviderProps) {
37
- const sheetsRef = useRef<Map<string, RefObject<TrueSheetRef>>>(new Map());
31
+ const sheetsRef = useRef<Map<string, RefObject<TrueSheetRefMethods>>>(new Map());
38
32
  const presentedStackRef = useRef<string[]>([]);
39
33
 
40
- const register = (name: string, methods: RefObject<TrueSheetRef>) => {
34
+ const register = (name: string, methods: RefObject<TrueSheetRefMethods>) => {
41
35
  sheetsRef.current.set(name, methods);
42
36
  };
43
37
 
@@ -88,17 +82,13 @@ export function TrueSheetProvider({ children }: TrueSheetProviderProps) {
88
82
  return sheet.current.dismiss();
89
83
  };
90
84
 
91
- /**
92
- * Dismisses a sheet directly without checking for sheets above.
93
- * Used internally when batch-dismissing stacked sheets.
94
- */
95
- const dismissDirect = async (name: string) => {
85
+ const dismissStack = async (name: string) => {
96
86
  const sheet = sheetsRef.current.get(name);
97
87
  if (!sheet?.current) {
98
88
  console.warn(`TrueSheet: Could not find sheet with name "${name}"`);
99
89
  return;
100
90
  }
101
- return (sheet.current as any).dismissDirect?.();
91
+ return sheet.current.dismissStack();
102
92
  };
103
93
 
104
94
  const resize = async (name: string, index: number) => {
@@ -113,15 +103,9 @@ export function TrueSheetProvider({ children }: TrueSheetProviderProps) {
113
103
  const dismissAll = async () => {
114
104
  const rootSheet = presentedStackRef.current[0];
115
105
  if (!rootSheet) return;
116
- return dismissDirect(rootSheet);
106
+ return dismiss(rootSheet);
117
107
  };
118
108
 
119
- // Set module-level refs for static access
120
- presentRef = present;
121
- dismissRef = dismiss;
122
- resizeRef = resize;
123
- dismissAllRef = dismissAll;
124
-
125
109
  return (
126
110
  <BottomSheetContext.Provider
127
111
  value={{
@@ -130,11 +114,11 @@ export function TrueSheetProvider({ children }: TrueSheetProviderProps) {
130
114
  pushToStack,
131
115
  removeFromStack,
132
116
  getSheetsAbove,
133
- dismissDirect,
134
- dismissAll,
135
117
  present,
136
118
  dismiss,
119
+ dismissStack,
137
120
  resize,
121
+ dismissAll,
138
122
  }}
139
123
  >
140
124
  <BottomSheetModalProvider>{children}</BottomSheetModalProvider>
@@ -142,11 +126,7 @@ export function TrueSheetProvider({ children }: TrueSheetProviderProps) {
142
126
  );
143
127
  }
144
128
 
145
- /**
146
- * Hook to control TrueSheet instances by name.
147
- * On web, this uses the TrueSheetContext from TrueSheetProvider.
148
- */
149
- export function useTrueSheet(): TrueSheetContextMethods {
129
+ export function useTrueSheet(): TrueSheetStaticMethods {
150
130
  const context = useContext(BottomSheetContext);
151
131
 
152
132
  if (!context) {
@@ -156,6 +136,7 @@ export function useTrueSheet(): TrueSheetContextMethods {
156
136
  return {
157
137
  present: context.present,
158
138
  dismiss: context.dismiss,
139
+ dismissStack: context.dismissStack,
159
140
  resize: context.resize,
160
141
  dismissAll: context.dismissAll,
161
142
  };
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export * from './TrueSheet';
2
2
  export * from './TrueSheet.types';
3
- export * from './TrueSheetProvider';
3
+ export { TrueSheetProvider, useTrueSheet } from './TrueSheetProvider';
@@ -1,7 +1,8 @@
1
1
  import React, { createElement, isValidElement, type ReactNode } from 'react';
2
2
  import { View } from 'react-native';
3
3
 
4
- import type { TrueSheetProps, TrueSheetRef, TrueSheetContextMethods } from '../TrueSheet.types';
4
+ import type { TrueSheetProps } from '../TrueSheet.types';
5
+ import type { TrueSheetStaticMethods } from '../TrueSheetProvider';
5
6
 
6
7
  interface TrueSheetState {
7
8
  shouldRenderNativeView: boolean;
@@ -11,13 +12,11 @@ interface TrueSheetState {
11
12
  * Mock TrueSheet component for testing.
12
13
  * Import from '@lodev09/react-native-true-sheet/mock' in your test setup.
13
14
  */
14
- export class TrueSheet
15
- extends React.Component<TrueSheetProps, TrueSheetState>
16
- implements TrueSheetRef
17
- {
15
+ export class TrueSheet extends React.Component<TrueSheetProps, TrueSheetState> {
18
16
  static instances: Record<string, TrueSheet> = {};
19
17
 
20
18
  static dismiss = jest.fn((_name: string, _animated?: boolean) => Promise.resolve());
19
+ static dismissStack = jest.fn((_name: string, _animated?: boolean) => Promise.resolve());
21
20
  static present = jest.fn((_name: string, _index?: number, _animated?: boolean) =>
22
21
  Promise.resolve()
23
22
  );
@@ -25,6 +24,7 @@ export class TrueSheet
25
24
  static dismissAll = jest.fn((_animated?: boolean) => Promise.resolve());
26
25
 
27
26
  dismiss = jest.fn((_animated?: boolean) => Promise.resolve());
27
+ dismissStack = jest.fn((_animated?: boolean) => Promise.resolve());
28
28
  present = jest.fn((_index?: number, _animated?: boolean) => Promise.resolve());
29
29
  resize = jest.fn((_index: number) => Promise.resolve());
30
30
 
@@ -70,10 +70,11 @@ export function TrueSheetProvider({ children }: { children: React.ReactNode }) {
70
70
  /**
71
71
  * Mock useTrueSheet hook for testing.
72
72
  */
73
- export function useTrueSheet(): TrueSheetContextMethods {
73
+ export function useTrueSheet(): TrueSheetStaticMethods {
74
74
  return {
75
75
  present: TrueSheet.present,
76
76
  dismiss: TrueSheet.dismiss,
77
+ dismissStack: TrueSheet.dismissStack,
77
78
  resize: TrueSheet.resize,
78
79
  dismissAll: TrueSheet.dismissAll,
79
80
  };
@@ -2,7 +2,7 @@ import React, { createElement, isValidElement, type ReactNode } from 'react';
2
2
  import { View } from 'react-native';
3
3
  import type { SharedValue } from 'react-native-reanimated';
4
4
 
5
- import type { TrueSheetProps, TrueSheetRef, PositionChangeEventPayload } from '../TrueSheet.types';
5
+ import type { TrueSheetProps, PositionChangeEventPayload } from '../TrueSheet.types';
6
6
 
7
7
  interface TrueSheetState {
8
8
  shouldRenderNativeView: boolean;
@@ -28,19 +28,18 @@ const createMockSharedValue = <T>(initialValue: T): SharedValue<T> =>
28
28
  * Mock ReanimatedTrueSheet component for testing.
29
29
  * Import from '@lodev09/react-native-true-sheet/reanimated/mock' in your test setup.
30
30
  */
31
- export class ReanimatedTrueSheet
32
- extends React.Component<TrueSheetProps, TrueSheetState>
33
- implements TrueSheetRef
34
- {
31
+ export class ReanimatedTrueSheet extends React.Component<TrueSheetProps, TrueSheetState> {
35
32
  static instances: Record<string, ReanimatedTrueSheet> = {};
36
33
 
37
34
  static dismiss = jest.fn((_name: string, _animated?: boolean) => Promise.resolve());
35
+ static dismissStack = jest.fn((_name: string, _animated?: boolean) => Promise.resolve());
38
36
  static present = jest.fn((_name: string, _index?: number, _animated?: boolean) =>
39
37
  Promise.resolve()
40
38
  );
41
39
  static resize = jest.fn((_name: string, _index: number) => Promise.resolve());
42
40
 
43
41
  dismiss = jest.fn((_animated?: boolean) => Promise.resolve());
42
+ dismissStack = jest.fn((_animated?: boolean) => Promise.resolve());
44
43
  present = jest.fn((_index?: number, _animated?: boolean) => Promise.resolve());
45
44
  resize = jest.fn((_index: number) => Promise.resolve());
46
45