@lodev09/react-native-true-sheet 4.0.0-beta.2 → 4.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -4
- package/android/build.gradle +22 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -16
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +303 -184
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +21 -110
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +116 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +18 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +124 -50
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +369 -163
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +59 -12
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +126 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +22 -9
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +84 -5
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +3 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
- package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
- package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
- package/android/src/main/jni/TrueSheetSpec.h +1 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +110 -30
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +9 -3
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +3 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +4 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
- package/ios/TrueSheetContainerView.h +27 -7
- package/ios/TrueSheetContainerView.mm +31 -11
- package/ios/TrueSheetContentView.h +43 -15
- package/ios/TrueSheetContentView.mm +211 -189
- package/ios/TrueSheetFooterView.h +6 -0
- package/ios/TrueSheetFooterView.mm +93 -17
- package/ios/TrueSheetModule.h +2 -7
- package/ios/TrueSheetModule.mm +7 -16
- package/ios/TrueSheetOverlayView.h +32 -0
- package/ios/TrueSheetOverlayView.mm +161 -0
- package/ios/TrueSheetView.mm +275 -56
- package/ios/TrueSheetViewController.h +31 -3
- package/ios/TrueSheetViewController.mm +393 -94
- package/ios/core/TrueSheetBlurView.h +0 -2
- package/ios/core/TrueSheetBlurView.mm +3 -36
- package/ios/core/TrueSheetDetentCalculator.h +7 -1
- package/ios/core/TrueSheetDetentCalculator.mm +27 -4
- package/ios/core/TrueSheetGrabberView.mm +13 -3
- package/ios/core/TrueSheetKeyboardObserver.mm +2 -0
- package/ios/core/TrueSheetOverlayContainerView.h +31 -0
- package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
- package/ios/events/TrueSheetLifecycleEvents.h +2 -0
- package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
- package/ios/tvos/TrueSheetStubs.mm +12 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
- package/lib/module/TrueSheet.js +175 -39
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +220 -243
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/TrueSheetBackground.js +15 -0
- package/lib/module/TrueSheetBackground.js.map +1 -0
- package/lib/module/TrueSheetOverlay.js +30 -0
- package/lib/module/TrueSheetOverlay.js.map +1 -0
- package/lib/module/TrueSheetOverlay.web.js +35 -0
- package/lib/module/TrueSheetOverlay.web.js.map +1 -0
- package/lib/module/TrueSheetPeek.web.js +20 -15
- package/lib/module/TrueSheetPeek.web.js.map +1 -1
- package/lib/module/detentBackgrounds.js +21 -0
- package/lib/module/detentBackgrounds.js.map +1 -0
- package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +15 -10
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks/index.js +18 -2
- package/lib/module/mocks/index.js.map +1 -1
- package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
- package/lib/module/navigation/base-types.js +2 -0
- package/lib/module/navigation/base-types.js.map +1 -0
- package/lib/module/navigation/createTrueSheetRouter.js +0 -9
- package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
- package/lib/module/navigation/expo-router/base-types.js +2 -0
- package/lib/module/navigation/expo-router/base-types.js.map +1 -0
- package/lib/module/navigation/expo-router/index.js +10 -7
- package/lib/module/navigation/expo-router/index.js.map +1 -1
- package/lib/module/navigation/expo-router/types.js +4 -0
- package/lib/module/navigation/expo-router/types.js.map +1 -0
- package/lib/module/navigation/index.js.map +1 -1
- package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
- package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
- package/lib/module/web/constants.js +1 -1
- package/lib/module/web/constants.js.map +1 -1
- package/lib/module/web/layout.js +168 -0
- package/lib/module/web/layout.js.map +1 -0
- package/lib/module/web/vaul/constants.js +9 -0
- package/lib/module/web/vaul/constants.js.map +1 -1
- package/lib/module/web/vaul/context.js.map +1 -1
- package/lib/module/web/vaul/helpers.js +1 -0
- package/lib/module/web/vaul/helpers.js.map +1 -1
- package/lib/module/web/vaul/index.js +47 -7
- package/lib/module/web/vaul/index.js.map +1 -1
- package/lib/module/web/vaul/use-snap-points.js +21 -10
- package/lib/module/web/vaul/use-snap-points.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +6 -0
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +157 -34
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
- package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
- package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
- package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
- package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
- package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
- package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +12 -7
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/index.d.ts +4 -0
- package/lib/typescript/src/mocks/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
- package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
- package/lib/typescript/src/navigation/base-types.d.ts +9 -0
- package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +2 -13
- package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
- package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
- package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/expo-router/index.d.ts +8 -6
- package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
- package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
- package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/index.d.ts +3 -4
- package/lib/typescript/src/navigation/index.d.ts.map +1 -1
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
- package/lib/typescript/src/navigation/types.d.ts +41 -5
- package/lib/typescript/src/navigation/types.d.ts.map +1 -1
- package/lib/typescript/src/web/constants.d.ts +1 -1
- package/lib/typescript/src/web/constants.d.ts.map +1 -1
- package/lib/typescript/src/web/layout.d.ts +19 -0
- package/lib/typescript/src/web/layout.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/constants.d.ts +3 -0
- package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/context.d.ts +1 -0
- package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
- package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/index.d.ts +13 -1
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts +2 -1
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
- package/package.json +17 -8
- package/react-native.config.js +1 -0
- package/src/TrueSheet.tsx +208 -48
- package/src/TrueSheet.types.ts +166 -35
- package/src/TrueSheet.web.tsx +272 -290
- package/src/TrueSheetBackground.tsx +17 -0
- package/src/TrueSheetOverlay.tsx +24 -0
- package/src/TrueSheetOverlay.web.tsx +33 -0
- package/src/TrueSheetPeek.web.tsx +25 -23
- package/src/detentBackgrounds.ts +24 -0
- package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +15 -10
- package/src/index.ts +1 -0
- package/src/mocks/index.ts +17 -2
- package/src/mocks/navigationExpoRouter.ts +6 -5
- package/src/navigation/base-types.ts +20 -0
- package/src/navigation/createTrueSheetRouter.ts +5 -33
- package/src/navigation/expo-router/base-types.ts +18 -0
- package/src/navigation/expo-router/index.ts +28 -30
- package/src/navigation/expo-router/types.ts +116 -0
- package/src/navigation/index.ts +6 -7
- package/src/navigation/screen/useSheetScreenState.ts +2 -0
- package/src/navigation/types.ts +75 -22
- package/src/web/constants.ts +1 -1
- package/src/web/layout.ts +196 -0
- package/src/web/vaul/constants.ts +9 -0
- package/src/web/vaul/context.ts +1 -0
- package/src/web/vaul/helpers.ts +5 -0
- package/src/web/vaul/index.tsx +75 -5
- package/src/web/vaul/use-snap-points.ts +32 -15
package/src/TrueSheet.tsx
CHANGED
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
createRef,
|
|
5
5
|
type ReactNode,
|
|
6
6
|
type ComponentRef,
|
|
7
|
+
type ComponentType,
|
|
7
8
|
isValidElement,
|
|
8
9
|
createElement,
|
|
10
|
+
useEffect,
|
|
9
11
|
} from 'react';
|
|
10
12
|
|
|
11
13
|
import type {
|
|
@@ -21,6 +23,7 @@ import type {
|
|
|
21
23
|
PositionChangeEvent,
|
|
22
24
|
DidDismissEvent,
|
|
23
25
|
WillDismissEvent,
|
|
26
|
+
DismissAttemptEvent,
|
|
24
27
|
MountEvent,
|
|
25
28
|
WillFocusEvent,
|
|
26
29
|
DidFocusEvent,
|
|
@@ -34,17 +37,38 @@ import TrueSheetHeaderViewNativeComponent from './fabric/TrueSheetHeaderViewNati
|
|
|
34
37
|
import TrueSheetFooterViewNativeComponent from './fabric/TrueSheetFooterViewNativeComponent';
|
|
35
38
|
|
|
36
39
|
import TrueSheetModule from './specs/NativeTrueSheetModule';
|
|
40
|
+
import { TrueSheetBackground } from './TrueSheetBackground';
|
|
41
|
+
import { normalizeDetentBackground } from './detentBackgrounds';
|
|
37
42
|
|
|
38
43
|
import {
|
|
39
44
|
Platform,
|
|
40
45
|
StyleSheet,
|
|
41
46
|
BackHandler,
|
|
47
|
+
RootTagContext,
|
|
42
48
|
findNodeHandle,
|
|
43
49
|
processColor,
|
|
44
50
|
type NativeEventSubscription,
|
|
45
51
|
type GestureResponderEvent,
|
|
52
|
+
type RootTag,
|
|
53
|
+
type StyleProp,
|
|
54
|
+
type ViewStyle,
|
|
46
55
|
} from 'react-native';
|
|
47
56
|
|
|
57
|
+
interface AppContainerProps {
|
|
58
|
+
rootTag: RootTag;
|
|
59
|
+
rootViewStyle?: StyleProp<ViewStyle>;
|
|
60
|
+
internal_excludeLogBox?: boolean;
|
|
61
|
+
children?: ReactNode;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// RN has no public API for hosting the element inspector inside a presented view;
|
|
65
|
+
// this is the internal RN's Modal uses. Dev-only so prod bundles never resolve it.
|
|
66
|
+
// The template literal keeps the RN babel preset's deep-import warning off while
|
|
67
|
+
// Metro still resolves the module statically.
|
|
68
|
+
const AppContainer: ComponentType<AppContainerProps> | null = __DEV__
|
|
69
|
+
? require(`react-native/Libraries/ReactNative/AppContainer`).default
|
|
70
|
+
: null;
|
|
71
|
+
|
|
48
72
|
const LINKING_ERROR =
|
|
49
73
|
`The package '@lodev09/react-native-true-sheet' doesn't seem to be linked. Make sure: \n\n` +
|
|
50
74
|
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
|
|
@@ -58,23 +82,49 @@ if (!TrueSheetModule) {
|
|
|
58
82
|
|
|
59
83
|
type NativeRef = ComponentRef<typeof TrueSheetViewNativeComponent>;
|
|
60
84
|
|
|
61
|
-
// Claim touches that no descendant claimed so the responder negotiation
|
|
62
|
-
// doesn't bubble up to touchables outside the sheet
|
|
63
|
-
const absorbUnclaimedTouches = () => true;
|
|
64
|
-
|
|
65
85
|
// Stop raw touch events from bubbling past the sheet to outside ancestors
|
|
66
86
|
const stopTouchPropagation = (event: GestureResponderEvent) => event.stopPropagation();
|
|
67
87
|
|
|
88
|
+
// Stop the responder negotiation at the sheet boundary without claiming the
|
|
89
|
+
// responder. Views inside the sheet are asked before this one, so in-sheet
|
|
90
|
+
// touchables work normally; views outside are asked after, so stopping here
|
|
91
|
+
// keeps unclaimed touches from leaking to touchables behind the sheet.
|
|
92
|
+
// Claiming instead (returning true) would steal the responder from a pressed
|
|
93
|
+
// touchable whenever the negotiation re-runs mid-gesture — e.g. a second
|
|
94
|
+
// finger, or the duplicate touch stream from a nested react-native-screens
|
|
95
|
+
// screen that attaches its own touch handler inside the sheet.
|
|
96
|
+
const stopResponderNegotiation = (event: GestureResponderEvent) => {
|
|
97
|
+
event.stopPropagation();
|
|
98
|
+
return false;
|
|
99
|
+
};
|
|
100
|
+
|
|
68
101
|
interface TrueSheetState {
|
|
69
102
|
shouldRenderNativeView: boolean;
|
|
103
|
+
initialPresentReady: boolean;
|
|
104
|
+
scrollableHandle: number | null;
|
|
70
105
|
}
|
|
71
106
|
|
|
107
|
+
// Gates auto-present (initialDetentIndex) by one commit. Rendered last in the
|
|
108
|
+
// sheet subtree so its mount effect runs after the content's mount effects —
|
|
109
|
+
// updates they schedule (e.g. a navigation footer via setOptions) batch with
|
|
110
|
+
// onReady's, so native receives initialDetentIndex together with the settled
|
|
111
|
+
// tree and presents at the final height instead of resizing mid-flight.
|
|
112
|
+
const InitialPresentGate = ({ onReady }: { onReady: () => void }) => {
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
onReady();
|
|
115
|
+
}, [onReady]);
|
|
116
|
+
|
|
117
|
+
return null;
|
|
118
|
+
};
|
|
119
|
+
|
|
72
120
|
export class TrueSheet
|
|
73
121
|
extends PureComponent<TrueSheetProps, TrueSheetState>
|
|
74
122
|
implements TrueSheetMethods
|
|
75
123
|
{
|
|
76
124
|
displayName = 'TrueSheet';
|
|
77
125
|
|
|
126
|
+
static contextType = RootTagContext;
|
|
127
|
+
|
|
78
128
|
private readonly nativeRef: RefObject<NativeRef | null>;
|
|
79
129
|
|
|
80
130
|
private cachedGrabberOptions: TrueSheetProps['grabberOptions'] | undefined;
|
|
@@ -105,17 +155,21 @@ export class TrueSheet
|
|
|
105
155
|
|
|
106
156
|
this.validateDetents();
|
|
107
157
|
|
|
108
|
-
// Lazy load by default, except when
|
|
158
|
+
// Lazy load by default, except when auto-presenting or when lazy is disabled
|
|
109
159
|
const shouldRenderImmediately =
|
|
110
|
-
props.initialDetentIndex !== undefined && props.initialDetentIndex >= 0
|
|
160
|
+
(props.initialDetentIndex !== undefined && props.initialDetentIndex >= 0) ||
|
|
161
|
+
props.lazy === false;
|
|
111
162
|
|
|
112
163
|
this.state = {
|
|
113
164
|
shouldRenderNativeView: shouldRenderImmediately,
|
|
165
|
+
initialPresentReady: false,
|
|
166
|
+
scrollableHandle: null,
|
|
114
167
|
};
|
|
115
168
|
|
|
116
169
|
this.onMount = this.onMount.bind(this);
|
|
117
170
|
this.onWillDismiss = this.onWillDismiss.bind(this);
|
|
118
171
|
this.onDidDismiss = this.onDidDismiss.bind(this);
|
|
172
|
+
this.onDismissAttempt = this.onDismissAttempt.bind(this);
|
|
119
173
|
this.onWillPresent = this.onWillPresent.bind(this);
|
|
120
174
|
this.onDidPresent = this.onDidPresent.bind(this);
|
|
121
175
|
this.onDetentChange = this.onDetentChange.bind(this);
|
|
@@ -129,6 +183,33 @@ export class TrueSheet
|
|
|
129
183
|
this.onDidBlur = this.onDidBlur.bind(this);
|
|
130
184
|
this.handleBackPress = this.handleBackPress.bind(this);
|
|
131
185
|
this.onVisibilityChange = this.onVisibilityChange.bind(this);
|
|
186
|
+
this.onInitialPresentReady = this.onInitialPresentReady.bind(this);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private onInitialPresentReady(): void {
|
|
190
|
+
this.setState({ initialPresentReady: true });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Resolves after commit (didMount/didUpdate) — the scrollable mounts with the
|
|
194
|
+
// sheet content, so its ref is only populated once the native tree renders.
|
|
195
|
+
private updateScrollableHandle(): void {
|
|
196
|
+
const { scrollableRef } = this.props;
|
|
197
|
+
let scrollableHandle: number | null = null;
|
|
198
|
+
if (scrollableRef?.current) {
|
|
199
|
+
try {
|
|
200
|
+
scrollableHandle = findNodeHandle(scrollableRef.current);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
// A stale ref (e.g. a wrapper that never clears it on unmount) makes
|
|
203
|
+
// findNodeHandle throw. Treat it as no scrollable instead of crashing.
|
|
204
|
+
if (__DEV__) {
|
|
205
|
+
console.warn('TrueSheet: scrollableRef points to an unmounted component.', error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (scrollableHandle !== this.state.scrollableHandle) {
|
|
211
|
+
this.setState({ scrollableHandle });
|
|
212
|
+
}
|
|
132
213
|
}
|
|
133
214
|
|
|
134
215
|
private validateDetents(): void {
|
|
@@ -301,15 +382,18 @@ export class TrueSheet
|
|
|
301
382
|
this.props.onWillDismiss?.(event);
|
|
302
383
|
}
|
|
303
384
|
|
|
385
|
+
private onDismissAttempt(event: DismissAttemptEvent): void {
|
|
386
|
+
this.props.onDismissAttempt?.(event);
|
|
387
|
+
}
|
|
388
|
+
|
|
304
389
|
private onDidDismiss(event: DidDismissEvent): void {
|
|
305
390
|
this.isPresented = false;
|
|
306
391
|
this.isSheetVisible = true;
|
|
307
392
|
this.backHandlerSubscription?.remove();
|
|
308
393
|
this.backHandlerSubscription = null;
|
|
309
394
|
|
|
310
|
-
//
|
|
311
|
-
|
|
312
|
-
if (!this.isPresenting) {
|
|
395
|
+
// Non-lazy content stays mounted; otherwise clean it up unless another presentation is active.
|
|
396
|
+
if (!this.isPresenting && this.props.lazy !== false) {
|
|
313
397
|
this.setState({ shouldRenderNativeView: false });
|
|
314
398
|
}
|
|
315
399
|
|
|
@@ -371,9 +455,12 @@ export class TrueSheet
|
|
|
371
455
|
const nodeHandle = findNodeHandle(this.nativeRef.current);
|
|
372
456
|
if (nodeHandle == null || nodeHandle === -1) return false;
|
|
373
457
|
|
|
374
|
-
// When not dismissible,
|
|
458
|
+
// When not dismissible, report the attempt. An attempt handler consumes the back
|
|
459
|
+
// press; otherwise let it propagate (e.g. navigation goes back to the previous screen)
|
|
375
460
|
if (this.props.dismissible === false) {
|
|
376
|
-
|
|
461
|
+
const { onDismissAttempt, onBackPress } = this.props;
|
|
462
|
+
onDismissAttempt?.({ nativeEvent: null } as DismissAttemptEvent);
|
|
463
|
+
return onBackPress?.() ?? onDismissAttempt != null;
|
|
377
464
|
}
|
|
378
465
|
|
|
379
466
|
TrueSheetModule?.handleBackPress(nodeHandle);
|
|
@@ -434,15 +521,38 @@ export class TrueSheet
|
|
|
434
521
|
|
|
435
522
|
componentDidMount(): void {
|
|
436
523
|
this.registerInstance();
|
|
524
|
+
this.updateScrollableHandle();
|
|
437
525
|
}
|
|
438
526
|
|
|
439
527
|
componentDidUpdate(prevProps: TrueSheetProps): void {
|
|
440
528
|
this.registerInstance();
|
|
529
|
+
this.updateScrollableHandle();
|
|
530
|
+
|
|
531
|
+
if (
|
|
532
|
+
prevProps.lazy !== false &&
|
|
533
|
+
this.props.lazy === false &&
|
|
534
|
+
!this.state.shouldRenderNativeView
|
|
535
|
+
) {
|
|
536
|
+
this.setState({ shouldRenderNativeView: true });
|
|
537
|
+
}
|
|
441
538
|
|
|
442
539
|
// Validate when detents prop changes
|
|
443
540
|
if (prevProps.detents !== this.props.detents) {
|
|
444
541
|
this.validateDetents();
|
|
445
542
|
}
|
|
543
|
+
|
|
544
|
+
// initialDetentIndex set at runtime on a lazily-mounted sheet: render the
|
|
545
|
+
// native tree so InitialPresentGate can deliver the index (constructor
|
|
546
|
+
// only computes this for the initial prop).
|
|
547
|
+
const prevInitialDetentIndex = prevProps.initialDetentIndex ?? -1;
|
|
548
|
+
const initialDetentIndex = this.props.initialDetentIndex ?? -1;
|
|
549
|
+
if (
|
|
550
|
+
prevInitialDetentIndex < 0 &&
|
|
551
|
+
initialDetentIndex >= 0 &&
|
|
552
|
+
!this.state.shouldRenderNativeView
|
|
553
|
+
) {
|
|
554
|
+
this.setState({ shouldRenderNativeView: true });
|
|
555
|
+
}
|
|
446
556
|
}
|
|
447
557
|
|
|
448
558
|
componentWillUnmount(): void {
|
|
@@ -456,8 +566,12 @@ export class TrueSheet
|
|
|
456
566
|
const {
|
|
457
567
|
detents = [0.5, 1],
|
|
458
568
|
backgroundColor,
|
|
569
|
+
detentBackgrounds,
|
|
570
|
+
background,
|
|
571
|
+
backgroundStyle,
|
|
459
572
|
dismissible = true,
|
|
460
573
|
draggable = true,
|
|
574
|
+
dismissThreshold = 'half',
|
|
461
575
|
grabber = true,
|
|
462
576
|
grabberOptions,
|
|
463
577
|
accessibilityOptions,
|
|
@@ -466,12 +580,11 @@ export class TrueSheet
|
|
|
466
580
|
initialDetentAnimated = true,
|
|
467
581
|
dimmedDetentIndex,
|
|
468
582
|
backgroundBlur,
|
|
469
|
-
blurOptions,
|
|
470
583
|
cornerRadius,
|
|
471
584
|
maxContentHeight,
|
|
472
585
|
maxContentWidth,
|
|
473
|
-
|
|
474
|
-
|
|
586
|
+
placement = 'automatic',
|
|
587
|
+
placementOffset,
|
|
475
588
|
scrollableOptions,
|
|
476
589
|
footerOptions,
|
|
477
590
|
presentation = 'page',
|
|
@@ -485,6 +598,7 @@ export class TrueSheet
|
|
|
485
598
|
insetAdjustment = 'automatic',
|
|
486
599
|
...rest
|
|
487
600
|
} = this.props;
|
|
601
|
+
delete rest.lazy;
|
|
488
602
|
|
|
489
603
|
// Trim to max 3 detents and clamp fractions
|
|
490
604
|
const resolvedDetents: number[] = detents.slice(0, 3).map((detent) => {
|
|
@@ -498,6 +612,12 @@ export class TrueSheet
|
|
|
498
612
|
return Math.min(1, detent);
|
|
499
613
|
});
|
|
500
614
|
|
|
615
|
+
// Hold initialDetentIndex back from native until the gate's effect flushes
|
|
616
|
+
// (see InitialPresentGate) — native presents when the prop lands.
|
|
617
|
+
const autoPresent = initialDetentIndex >= 0;
|
|
618
|
+
const gatedInitialDetentIndex =
|
|
619
|
+
autoPresent && !this.state.initialPresentReady ? -1 : initialDetentIndex;
|
|
620
|
+
|
|
501
621
|
// Cache grabberOptions to avoid creating a new object every render
|
|
502
622
|
if (grabberOptions !== this.cachedGrabberOptions) {
|
|
503
623
|
this.cachedGrabberOptions = grabberOptions;
|
|
@@ -507,6 +627,43 @@ export class TrueSheet
|
|
|
507
627
|
};
|
|
508
628
|
}
|
|
509
629
|
|
|
630
|
+
const sheetContent = (
|
|
631
|
+
<>
|
|
632
|
+
<TrueSheetBackground background={background} backgroundStyle={backgroundStyle} />
|
|
633
|
+
{header && (
|
|
634
|
+
<TrueSheetHeaderViewNativeComponent
|
|
635
|
+
style={[
|
|
636
|
+
styles.header,
|
|
637
|
+
headerOptions?.position === 'absolute' && styles.absoluteHeader,
|
|
638
|
+
headerStyle,
|
|
639
|
+
]}
|
|
640
|
+
>
|
|
641
|
+
{isValidElement(header) ? header : createElement(header)}
|
|
642
|
+
</TrueSheetHeaderViewNativeComponent>
|
|
643
|
+
)}
|
|
644
|
+
<TrueSheetContentViewNativeComponent style={style}>
|
|
645
|
+
{children}
|
|
646
|
+
</TrueSheetContentViewNativeComponent>
|
|
647
|
+
{footer && (
|
|
648
|
+
<TrueSheetFooterViewNativeComponent
|
|
649
|
+
autoBottomInset={insetAdjustment === 'automatic'}
|
|
650
|
+
style={[
|
|
651
|
+
styles.footer,
|
|
652
|
+
footerOptions?.position === 'absolute'
|
|
653
|
+
? styles.absoluteFooter
|
|
654
|
+
: styles.relativeFooter,
|
|
655
|
+
footerStyle,
|
|
656
|
+
]}
|
|
657
|
+
>
|
|
658
|
+
{isValidElement(footer) ? footer : createElement(footer)}
|
|
659
|
+
</TrueSheetFooterViewNativeComponent>
|
|
660
|
+
)}
|
|
661
|
+
{autoPresent && !this.state.initialPresentReady && (
|
|
662
|
+
<InitialPresentGate onReady={this.onInitialPresentReady} />
|
|
663
|
+
)}
|
|
664
|
+
</>
|
|
665
|
+
);
|
|
666
|
+
|
|
510
667
|
return (
|
|
511
668
|
<TrueSheetViewNativeComponent
|
|
512
669
|
{...rest}
|
|
@@ -514,27 +671,36 @@ export class TrueSheet
|
|
|
514
671
|
style={styles.sheetView}
|
|
515
672
|
detents={resolvedDetents}
|
|
516
673
|
backgroundBlur={backgroundBlur}
|
|
517
|
-
blurOptions={blurOptions}
|
|
518
674
|
backgroundColor={backgroundColor}
|
|
675
|
+
detentBackgrounds={
|
|
676
|
+
detentBackgrounds &&
|
|
677
|
+
Array.from(detentBackgrounds.slice(0, 3), (entry) => {
|
|
678
|
+
const normalized = normalizeDetentBackground(entry);
|
|
679
|
+
return normalized ? { ...normalized, color: processColor(normalized.color) } : {};
|
|
680
|
+
})
|
|
681
|
+
}
|
|
519
682
|
cornerRadius={cornerRadius}
|
|
520
683
|
grabber={grabber}
|
|
521
684
|
grabberOptions={this.resolvedGrabberOptions}
|
|
522
685
|
accessibilityOptions={accessibilityOptions}
|
|
523
686
|
dimmed={dimmed}
|
|
524
687
|
dimmedDetentIndex={dimmedDetentIndex}
|
|
525
|
-
initialDetentIndex={
|
|
688
|
+
initialDetentIndex={gatedInitialDetentIndex}
|
|
526
689
|
initialDetentAnimated={initialDetentAnimated}
|
|
527
690
|
dismissible={dismissible}
|
|
528
691
|
draggable={draggable}
|
|
692
|
+
dismissThreshold={dismissThreshold}
|
|
529
693
|
maxContentHeight={maxContentHeight}
|
|
530
694
|
maxContentWidth={maxContentWidth}
|
|
531
|
-
|
|
532
|
-
|
|
695
|
+
placement={placement}
|
|
696
|
+
placementOffset={placementOffset}
|
|
697
|
+
scrollableHandle={this.state.scrollableHandle ?? -1}
|
|
533
698
|
scrollableOptions={scrollableOptions}
|
|
534
699
|
headerOptions={headerOptions}
|
|
535
700
|
footerOptions={{
|
|
536
701
|
footerPosition: footerOptions?.position,
|
|
537
702
|
keyboardOffset: footerOptions?.keyboardOffset,
|
|
703
|
+
avoidKeyboard: footerOptions?.avoidKeyboard,
|
|
538
704
|
}}
|
|
539
705
|
presentation={presentation}
|
|
540
706
|
insetAdjustment={insetAdjustment}
|
|
@@ -543,6 +709,7 @@ export class TrueSheet
|
|
|
543
709
|
onDidPresent={this.onDidPresent}
|
|
544
710
|
onWillDismiss={this.onWillDismiss}
|
|
545
711
|
onDidDismiss={this.onDidDismiss}
|
|
712
|
+
onDismissAttempt={this.onDismissAttempt}
|
|
546
713
|
onDetentChange={this.onDetentChange}
|
|
547
714
|
onDragBegin={this.onDragBegin}
|
|
548
715
|
onDragChange={this.onDragChange}
|
|
@@ -555,10 +722,11 @@ export class TrueSheet
|
|
|
555
722
|
onVisibilityChange={this.onVisibilityChange}
|
|
556
723
|
// These must stay on this host view, not on the container. The container is
|
|
557
724
|
// reparented into the native sheet, so this view is never a native ancestor of
|
|
558
|
-
// the sheet content
|
|
559
|
-
//
|
|
560
|
-
//
|
|
561
|
-
onStartShouldSetResponder={
|
|
725
|
+
// the sheet content — this is the React-tree boundary between the sheet and
|
|
726
|
+
// the presenting screen, where both the responder negotiation and raw touch
|
|
727
|
+
// bubbling must stop.
|
|
728
|
+
onStartShouldSetResponder={stopResponderNegotiation}
|
|
729
|
+
onMoveShouldSetResponder={stopResponderNegotiation}
|
|
562
730
|
onTouchStart={stopTouchPropagation}
|
|
563
731
|
onTouchMove={stopTouchPropagation}
|
|
564
732
|
onTouchEnd={stopTouchPropagation}
|
|
@@ -566,33 +734,22 @@ export class TrueSheet
|
|
|
566
734
|
>
|
|
567
735
|
{this.state.shouldRenderNativeView && (
|
|
568
736
|
<TrueSheetContainerViewNativeComponent style={styles.container}>
|
|
569
|
-
{
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
737
|
+
{AppContainer ? (
|
|
738
|
+
// Hosts the element inspector inside the sheet, like RN's Modal does —
|
|
739
|
+
// the app-level one sits behind the presented sheet.
|
|
740
|
+
// `display: contents` keeps AppContainer's wrapper views out of both
|
|
741
|
+
// Yoga layout and the native tree, so header/content/footer remain the
|
|
742
|
+
// container's direct native children, while the inspector overlay
|
|
743
|
+
// anchors to the container and lines up with measured frames.
|
|
744
|
+
<AppContainer
|
|
745
|
+
rootTag={this.context as RootTag}
|
|
746
|
+
rootViewStyle={styles.inspectorHost}
|
|
747
|
+
internal_excludeLogBox
|
|
576
748
|
>
|
|
577
|
-
{
|
|
578
|
-
</
|
|
579
|
-
)
|
|
580
|
-
|
|
581
|
-
{children}
|
|
582
|
-
</TrueSheetContentViewNativeComponent>
|
|
583
|
-
{footer && (
|
|
584
|
-
<TrueSheetFooterViewNativeComponent
|
|
585
|
-
autoBottomInset={insetAdjustment === 'automatic'}
|
|
586
|
-
style={[
|
|
587
|
-
styles.footer,
|
|
588
|
-
footerOptions?.position === 'absolute'
|
|
589
|
-
? styles.absoluteFooter
|
|
590
|
-
: styles.relativeFooter,
|
|
591
|
-
footerStyle,
|
|
592
|
-
]}
|
|
593
|
-
>
|
|
594
|
-
{isValidElement(footer) ? footer : createElement(footer)}
|
|
595
|
-
</TrueSheetFooterViewNativeComponent>
|
|
749
|
+
{sheetContent}
|
|
750
|
+
</AppContainer>
|
|
751
|
+
) : (
|
|
752
|
+
sheetContent
|
|
596
753
|
)}
|
|
597
754
|
</TrueSheetContainerViewNativeComponent>
|
|
598
755
|
)}
|
|
@@ -614,6 +771,9 @@ const styles = StyleSheet.create({
|
|
|
614
771
|
container: {
|
|
615
772
|
...StyleSheet.absoluteFill,
|
|
616
773
|
},
|
|
774
|
+
inspectorHost: {
|
|
775
|
+
display: 'contents',
|
|
776
|
+
},
|
|
617
777
|
header: {
|
|
618
778
|
pointerEvents: 'box-none',
|
|
619
779
|
},
|