@niibase/bottom-sheet-manager 1.4.4 → 1.4.6

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 (41) hide show
  1. package/README.md +230 -14
  2. package/lib/commonjs/index.js +10 -2
  3. package/lib/commonjs/index.js.map +1 -1
  4. package/lib/commonjs/router/view.js +2 -2
  5. package/lib/commonjs/router/view.js.map +1 -1
  6. package/lib/commonjs/{sheet.js → sheets/gorhom.js} +29 -74
  7. package/lib/commonjs/sheets/gorhom.js.map +1 -0
  8. package/lib/commonjs/sheets/shared.js +69 -0
  9. package/lib/commonjs/sheets/shared.js.map +1 -0
  10. package/lib/commonjs/sheets/truesheet.js +237 -0
  11. package/lib/commonjs/sheets/truesheet.js.map +1 -0
  12. package/lib/module/index.js +2 -1
  13. package/lib/module/index.js.map +1 -1
  14. package/lib/module/router/view.js +1 -1
  15. package/lib/module/router/view.js.map +1 -1
  16. package/lib/module/{sheet.js → sheets/gorhom.js} +29 -74
  17. package/lib/module/sheets/gorhom.js.map +1 -0
  18. package/lib/module/sheets/shared.js +60 -0
  19. package/lib/module/sheets/shared.js.map +1 -0
  20. package/lib/module/sheets/truesheet.js +230 -0
  21. package/lib/module/sheets/truesheet.js.map +1 -0
  22. package/lib/typescript/index.d.ts +2 -1
  23. package/lib/typescript/index.d.ts.map +1 -1
  24. package/lib/typescript/{sheet.d.ts → sheets/gorhom.d.ts} +2 -2
  25. package/lib/typescript/sheets/gorhom.d.ts.map +1 -0
  26. package/lib/typescript/sheets/shared.d.ts +15 -0
  27. package/lib/typescript/sheets/shared.d.ts.map +1 -0
  28. package/lib/typescript/sheets/truesheet.d.ts +23 -0
  29. package/lib/typescript/sheets/truesheet.d.ts.map +1 -0
  30. package/lib/typescript/types.d.ts +5 -0
  31. package/lib/typescript/types.d.ts.map +1 -1
  32. package/package.json +13 -6
  33. package/src/index.ts +2 -1
  34. package/src/router/view.tsx +1 -1
  35. package/src/{sheet.tsx → sheets/gorhom.tsx} +31 -111
  36. package/src/sheets/shared.ts +108 -0
  37. package/src/sheets/truesheet.tsx +363 -0
  38. package/src/types.ts +6 -0
  39. package/lib/commonjs/sheet.js.map +0 -1
  40. package/lib/module/sheet.js.map +0 -1
  41. package/lib/typescript/sheet.d.ts.map +0 -1
@@ -11,6 +11,7 @@ import RNBottomSheet, {
11
11
  BottomSheetView,
12
12
  BottomSheetVirtualizedList,
13
13
  } from "@gorhom/bottom-sheet";
14
+ import React from "react";
14
15
  import {
15
16
  BackHandler,
16
17
  Platform,
@@ -19,23 +20,25 @@ import {
19
20
  type NativeEventSubscription,
20
21
  } from "react-native";
21
22
  import {
23
+ Easing,
22
24
  interpolate,
23
25
  useAnimatedReaction,
24
26
  useSharedValue,
27
+ type WithSpringConfig,
28
+ type WithTimingConfig,
25
29
  } from "react-native-reanimated";
26
30
  import { useSafeAreaInsets } from "react-native-safe-area-context";
27
- import React from "react";
28
31
 
32
+ import { PrivateManager } from "../manager";
29
33
  import {
30
34
  useProviderContext,
31
35
  useSheetIDContext,
32
36
  useSheetRef,
33
37
  useSheetSharedContext,
34
38
  useStackBehaviorContext,
35
- } from "./provider";
36
- import { BottomSheetInstance, BottomSheetProps, SheetIds, StackBehavior } from "./types";
37
- import { PrivateManager } from "./manager";
38
- import { eventManager } from "./events";
39
+ } from "../provider";
40
+ import { useSheetManager, useTeardownSheet } from "./shared";
41
+ import { BottomSheetInstance, BottomSheetProps, SheetIds, StackBehavior } from "../types";
39
42
 
40
43
  interface BottomSheetFC
41
44
  extends React.MemoExoticComponent<React.ForwardRefExoticComponent<BottomSheetProps>> {
@@ -59,50 +62,9 @@ interface BottomSheetFC
59
62
  const FULL_SCREEN_POINTS: (string | number)[] =
60
63
  Platform.OS === "ios" ? ["%90", "90%"] : ["%93", "93%"];
61
64
 
62
- const useSheetManager = ({
63
- id,
64
- onHide,
65
- onBeforeShow,
66
- onContextUpdate,
67
- }: {
68
- id?: string;
69
- onHide: (data?: unknown, dismiss?: boolean, behavior?: StackBehavior) => void;
70
- onBeforeShow?: (data?: unknown, behavior?: StackBehavior) => void;
71
- onContextUpdate: () => void;
72
- }) => {
73
- const currentContext = useProviderContext();
74
- const hasShownRef = React.useRef(false);
75
-
76
- React.useEffect(() => {
77
- if (!id) return undefined;
78
-
79
- const subscriptions = [
80
- eventManager.subscribe(
81
- `show_${id}`,
82
- (data: unknown, context?: string, behavior?: StackBehavior) => {
83
- if (currentContext !== context) return;
84
- if (!hasShownRef.current) {
85
- hasShownRef.current = true;
86
- onContextUpdate?.();
87
- onBeforeShow?.(data, behavior);
88
- }
89
- },
90
- ),
91
- eventManager.subscribe(
92
- `hide_${id}`,
93
- (data: unknown, context: string, dismiss?: boolean, behavior?: StackBehavior) => {
94
- if (currentContext !== context) return;
95
- hasShownRef.current = false;
96
- onHide?.(data, dismiss, behavior);
97
- },
98
- ),
99
- ];
100
-
101
- return () => {
102
- hasShownRef.current = false;
103
- subscriptions.forEach((s) => s?.unsubscribe?.());
104
- };
105
- }, [id, onHide, onBeforeShow, onContextUpdate, currentContext]);
65
+ const DEFAULT_SHEET_CLOSE_ANIMATION: WithTimingConfig = {
66
+ duration: 300,
67
+ easing: Easing.out(Easing.cubic),
106
68
  };
107
69
 
108
70
  const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetProps>(
@@ -121,6 +83,7 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
121
83
  style,
122
84
  passThrough,
123
85
  opacity,
86
+ closeAnimationConfigs,
124
87
  ...props
125
88
  },
126
89
  ref,
@@ -135,11 +98,12 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
135
98
  React.useState<StackBehavior>(stackBehavior);
136
99
  const isPushed = currentStackBehavior === "push";
137
100
 
138
- const { bottom, left, right } = useSafeAreaInsets();
101
+ const { bottom } = useSafeAreaInsets();
102
+ const defaultStyle = React.useMemo(() => ({ paddingBottom: bottom }), [bottom]);
139
103
 
140
- const defaultStyle = React.useMemo(
141
- () => ({ paddingBottom: bottom, paddingLeft: left, paddingRight: right }),
142
- [bottom, left, right],
104
+ const effectiveCloseAnimation = React.useMemo(
105
+ () => closeAnimationConfigs ?? DEFAULT_SHEET_CLOSE_ANIMATION,
106
+ [closeAnimationConfigs],
143
107
  );
144
108
 
145
109
  const { fullScreenValues } = useSheetSharedContext();
@@ -170,6 +134,7 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
170
134
  const teardownDataRef = React.useRef<{ dismiss?: boolean; behavior?: StackBehavior }>(
171
135
  {},
172
136
  );
137
+ const isClosingRef = React.useRef(false);
173
138
 
174
139
  const id = useSheetIDContext();
175
140
  const sheetId = props.id || id;
@@ -225,7 +190,7 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
225
190
  );
226
191
  const current = { ...fullScreenValues.value };
227
192
  current[sheetId] = val;
228
- fullScreenValues.value = current;
193
+ fullScreenValues.set(current);
229
194
  }
230
195
  },
231
196
  [iosModalSheetTypeOfAnimation, sheetId],
@@ -236,58 +201,12 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
236
201
  if (iosModalSheetTypeOfAnimation && sheetId) {
237
202
  const current = { ...fullScreenValues.value };
238
203
  delete current[sheetId];
239
- fullScreenValues.value = current;
204
+ fullScreenValues.set(current);
240
205
  }
241
206
  };
242
207
  }, [iosModalSheetTypeOfAnimation, sheetId, fullScreenValues]);
243
208
 
244
- const teardownSheet = React.useCallback(
245
- (value: unknown, dismiss: boolean | undefined, behavior: StackBehavior) => {
246
- if (!sheetId) return;
247
-
248
- const hasHistory = PrivateManager.history.length > 0;
249
- const shouldRestorePrevious = behavior !== "replace";
250
-
251
- eventManager.publish(
252
- `onclose_${sheetId}`,
253
- value,
254
- currentCtx,
255
- hasHistory || !!dismiss,
256
- behavior,
257
- );
258
-
259
- if (shouldRestorePrevious) {
260
- if (dismiss) {
261
- // it will surface naturally when the push sheet is closed.
262
- if (behavior !== "push") {
263
- PrivateManager.history.push({
264
- id: sheetId,
265
- context: currentCtx,
266
- behavior: behavior,
267
- });
268
- }
269
- } else if (hasHistory) {
270
- const otherSheetsStillOpen = PrivateManager.stack().some(
271
- (s) => !(s.id === sheetId && s.context === currentCtx),
272
- );
273
- if (!otherSheetsStillOpen) {
274
- const prev = PrivateManager.history.pop()!;
275
- eventManager.publish(
276
- `show_wrap_${prev.id}`,
277
- undefined,
278
- prev.context,
279
- true,
280
- prev.behavior,
281
- );
282
- }
283
- }
284
- }
285
-
286
- PrivateManager.remove(sheetId, currentCtx);
287
- },
288
- [sheetId, currentCtx],
289
- );
290
-
209
+ const teardownSheet = useTeardownSheet({ sheetId, currentCtx });
291
210
  const hideSheet = React.useCallback(
292
211
  (
293
212
  data?: unknown,
@@ -314,9 +233,11 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
314
233
  const shouldClose = activeBehavior !== "replace" || !dismiss;
315
234
 
316
235
  if (fromManager && shouldClose) {
236
+ if (isClosingRef.current) return;
237
+ isClosingRef.current = true;
317
238
  valueRef.current = value;
318
239
  teardownDataRef.current = { dismiss, behavior: activeBehavior };
319
- bottomSheetRef.current?.close();
240
+ bottomSheetRef.current?.close(effectiveCloseAnimation);
320
241
  return;
321
242
  }
322
243
 
@@ -330,15 +251,11 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
330
251
  const closeValue = onClose?.(value as never);
331
252
  if (closeValue !== undefined) value = closeValue;
332
253
 
333
- if (shouldClose) {
334
- bottomSheetRef.current?.close();
335
- }
336
-
337
254
  teardownSheet(value, finalDismiss, finalBehavior);
338
-
255
+ isClosingRef.current = false;
339
256
  if (fromManager) valueRef.current = data;
340
257
  },
341
- [currentStackBehavior, onClose, teardownSheet],
258
+ [currentStackBehavior, effectiveCloseAnimation, onClose, teardownSheet],
342
259
  );
343
260
 
344
261
  React.useEffect(() => {
@@ -349,7 +266,10 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
349
266
  (): BottomSheetInstance => ({
350
267
  close(options = {}): void {
351
268
  valueRef.current = (options as Record<string, unknown>).value;
352
- bottomSheetRef.current?.close(options?.animationConfigs);
269
+ const opts = options as {
270
+ animationConfigs?: WithSpringConfig | WithTimingConfig;
271
+ };
272
+ bottomSheetRef.current?.close(opts.animationConfigs ?? effectiveCloseAnimation);
353
273
  },
354
274
  expand(animationConfigs): void {
355
275
  bottomSheetRef.current?.expand(animationConfigs);
@@ -364,7 +284,7 @@ const BottomSheetComponent = React.forwardRef<BottomSheetInstance, BottomSheetPr
364
284
  bottomSheetRef.current?.snapToPosition(position, animationConfigs);
365
285
  },
366
286
  }),
367
- [],
287
+ [effectiveCloseAnimation],
368
288
  );
369
289
 
370
290
  React.useEffect(() => {
@@ -0,0 +1,108 @@
1
+ import React from "react";
2
+
3
+ import { eventManager } from "../events";
4
+ import { PrivateManager } from "../manager";
5
+ import { useProviderContext } from "../provider";
6
+ import { StackBehavior } from "../types";
7
+
8
+ type OnHide = (data?: unknown, dismiss?: boolean, behavior?: StackBehavior) => void;
9
+ type OnBeforeShow = (data?: unknown, behavior?: StackBehavior) => void;
10
+
11
+ export const useSheetManager = ({
12
+ id,
13
+ onHide,
14
+ onBeforeShow,
15
+ onContextUpdate,
16
+ }: {
17
+ id?: string;
18
+ onHide: OnHide;
19
+ onBeforeShow?: OnBeforeShow;
20
+ onContextUpdate: () => void;
21
+ }) => {
22
+ const currentContext = useProviderContext();
23
+ const hasShownRef = React.useRef(false);
24
+
25
+ React.useEffect(() => {
26
+ if (!id) return undefined;
27
+
28
+ const subscriptions = [
29
+ eventManager.subscribe(
30
+ `show_${id}`,
31
+ (data: unknown, context?: string, behavior?: StackBehavior) => {
32
+ if (currentContext !== context) return;
33
+ if (!hasShownRef.current) {
34
+ hasShownRef.current = true;
35
+ onContextUpdate?.();
36
+ onBeforeShow?.(data, behavior);
37
+ }
38
+ },
39
+ ),
40
+ eventManager.subscribe(
41
+ `hide_${id}`,
42
+ (data: unknown, context: string, dismiss?: boolean, behavior?: StackBehavior) => {
43
+ if (currentContext !== context) return;
44
+ hasShownRef.current = false;
45
+ onHide?.(data, dismiss, behavior);
46
+ },
47
+ ),
48
+ ];
49
+
50
+ return () => {
51
+ hasShownRef.current = false;
52
+ subscriptions.forEach((s) => s?.unsubscribe?.());
53
+ };
54
+ }, [id, onHide, onBeforeShow, onContextUpdate, currentContext]);
55
+ };
56
+
57
+ export const useTeardownSheet = ({
58
+ sheetId,
59
+ currentCtx,
60
+ }: {
61
+ sheetId?: string;
62
+ currentCtx: string;
63
+ }) =>
64
+ React.useCallback(
65
+ (value: unknown, dismiss: boolean | undefined, behavior: StackBehavior) => {
66
+ if (!sheetId) return;
67
+
68
+ const hasHistory = PrivateManager.history.length > 0;
69
+ const shouldRestorePrevious = behavior !== "replace";
70
+
71
+ eventManager.publish(
72
+ `onclose_${sheetId}`,
73
+ value,
74
+ currentCtx,
75
+ hasHistory || !!dismiss,
76
+ behavior,
77
+ );
78
+
79
+ if (shouldRestorePrevious) {
80
+ if (dismiss) {
81
+ if (behavior !== "push") {
82
+ PrivateManager.history.push({
83
+ id: sheetId,
84
+ context: currentCtx,
85
+ behavior,
86
+ });
87
+ }
88
+ } else if (hasHistory) {
89
+ const otherSheetsStillOpen = PrivateManager.stack().some(
90
+ (s) => !(s.id === sheetId && s.context === currentCtx),
91
+ );
92
+ if (!otherSheetsStillOpen) {
93
+ const prev = PrivateManager.history.pop()!;
94
+ eventManager.publish(
95
+ `show_wrap_${prev.id}`,
96
+ undefined,
97
+ prev.context,
98
+ true,
99
+ prev.behavior,
100
+ );
101
+ }
102
+ }
103
+ }
104
+
105
+ PrivateManager.remove(sheetId, currentCtx);
106
+ },
107
+ [sheetId, currentCtx],
108
+ );