@lodev09/react-native-true-sheet 4.0.0-beta.2 → 4.0.0-beta.20
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 +302 -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 +119 -50
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +360 -163
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +54 -12
- 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 +212 -55
- 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 +173 -39
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +218 -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 +14 -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 +4 -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 +44 -6
- package/lib/module/web/vaul/index.js.map +1 -1
- package/lib/module/web/vaul/use-snap-points.js +6 -8
- 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 +135 -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 +11 -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 +1 -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 +7 -1
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -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 +206 -48
- package/src/TrueSheet.types.ts +142 -35
- package/src/TrueSheet.web.tsx +270 -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 +14 -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 +4 -0
- package/src/web/vaul/context.ts +1 -0
- package/src/web/vaul/helpers.ts +5 -0
- package/src/web/vaul/index.tsx +67 -5
- package/src/web/vaul/use-snap-points.ts +6 -14
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,6 +566,9 @@ 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,
|
|
461
574
|
grabber = true,
|
|
@@ -466,12 +579,11 @@ export class TrueSheet
|
|
|
466
579
|
initialDetentAnimated = true,
|
|
467
580
|
dimmedDetentIndex,
|
|
468
581
|
backgroundBlur,
|
|
469
|
-
blurOptions,
|
|
470
582
|
cornerRadius,
|
|
471
583
|
maxContentHeight,
|
|
472
584
|
maxContentWidth,
|
|
473
|
-
|
|
474
|
-
|
|
585
|
+
placement = 'automatic',
|
|
586
|
+
placementOffset,
|
|
475
587
|
scrollableOptions,
|
|
476
588
|
footerOptions,
|
|
477
589
|
presentation = 'page',
|
|
@@ -485,6 +597,7 @@ export class TrueSheet
|
|
|
485
597
|
insetAdjustment = 'automatic',
|
|
486
598
|
...rest
|
|
487
599
|
} = this.props;
|
|
600
|
+
delete rest.lazy;
|
|
488
601
|
|
|
489
602
|
// Trim to max 3 detents and clamp fractions
|
|
490
603
|
const resolvedDetents: number[] = detents.slice(0, 3).map((detent) => {
|
|
@@ -498,6 +611,12 @@ export class TrueSheet
|
|
|
498
611
|
return Math.min(1, detent);
|
|
499
612
|
});
|
|
500
613
|
|
|
614
|
+
// Hold initialDetentIndex back from native until the gate's effect flushes
|
|
615
|
+
// (see InitialPresentGate) — native presents when the prop lands.
|
|
616
|
+
const autoPresent = initialDetentIndex >= 0;
|
|
617
|
+
const gatedInitialDetentIndex =
|
|
618
|
+
autoPresent && !this.state.initialPresentReady ? -1 : initialDetentIndex;
|
|
619
|
+
|
|
501
620
|
// Cache grabberOptions to avoid creating a new object every render
|
|
502
621
|
if (grabberOptions !== this.cachedGrabberOptions) {
|
|
503
622
|
this.cachedGrabberOptions = grabberOptions;
|
|
@@ -507,6 +626,43 @@ export class TrueSheet
|
|
|
507
626
|
};
|
|
508
627
|
}
|
|
509
628
|
|
|
629
|
+
const sheetContent = (
|
|
630
|
+
<>
|
|
631
|
+
<TrueSheetBackground background={background} backgroundStyle={backgroundStyle} />
|
|
632
|
+
{header && (
|
|
633
|
+
<TrueSheetHeaderViewNativeComponent
|
|
634
|
+
style={[
|
|
635
|
+
styles.header,
|
|
636
|
+
headerOptions?.position === 'absolute' && styles.absoluteHeader,
|
|
637
|
+
headerStyle,
|
|
638
|
+
]}
|
|
639
|
+
>
|
|
640
|
+
{isValidElement(header) ? header : createElement(header)}
|
|
641
|
+
</TrueSheetHeaderViewNativeComponent>
|
|
642
|
+
)}
|
|
643
|
+
<TrueSheetContentViewNativeComponent style={style}>
|
|
644
|
+
{children}
|
|
645
|
+
</TrueSheetContentViewNativeComponent>
|
|
646
|
+
{footer && (
|
|
647
|
+
<TrueSheetFooterViewNativeComponent
|
|
648
|
+
autoBottomInset={insetAdjustment === 'automatic'}
|
|
649
|
+
style={[
|
|
650
|
+
styles.footer,
|
|
651
|
+
footerOptions?.position === 'absolute'
|
|
652
|
+
? styles.absoluteFooter
|
|
653
|
+
: styles.relativeFooter,
|
|
654
|
+
footerStyle,
|
|
655
|
+
]}
|
|
656
|
+
>
|
|
657
|
+
{isValidElement(footer) ? footer : createElement(footer)}
|
|
658
|
+
</TrueSheetFooterViewNativeComponent>
|
|
659
|
+
)}
|
|
660
|
+
{autoPresent && !this.state.initialPresentReady && (
|
|
661
|
+
<InitialPresentGate onReady={this.onInitialPresentReady} />
|
|
662
|
+
)}
|
|
663
|
+
</>
|
|
664
|
+
);
|
|
665
|
+
|
|
510
666
|
return (
|
|
511
667
|
<TrueSheetViewNativeComponent
|
|
512
668
|
{...rest}
|
|
@@ -514,27 +670,35 @@ export class TrueSheet
|
|
|
514
670
|
style={styles.sheetView}
|
|
515
671
|
detents={resolvedDetents}
|
|
516
672
|
backgroundBlur={backgroundBlur}
|
|
517
|
-
blurOptions={blurOptions}
|
|
518
673
|
backgroundColor={backgroundColor}
|
|
674
|
+
detentBackgrounds={
|
|
675
|
+
detentBackgrounds &&
|
|
676
|
+
Array.from(detentBackgrounds.slice(0, 3), (entry) => {
|
|
677
|
+
const normalized = normalizeDetentBackground(entry);
|
|
678
|
+
return normalized ? { ...normalized, color: processColor(normalized.color) } : {};
|
|
679
|
+
})
|
|
680
|
+
}
|
|
519
681
|
cornerRadius={cornerRadius}
|
|
520
682
|
grabber={grabber}
|
|
521
683
|
grabberOptions={this.resolvedGrabberOptions}
|
|
522
684
|
accessibilityOptions={accessibilityOptions}
|
|
523
685
|
dimmed={dimmed}
|
|
524
686
|
dimmedDetentIndex={dimmedDetentIndex}
|
|
525
|
-
initialDetentIndex={
|
|
687
|
+
initialDetentIndex={gatedInitialDetentIndex}
|
|
526
688
|
initialDetentAnimated={initialDetentAnimated}
|
|
527
689
|
dismissible={dismissible}
|
|
528
690
|
draggable={draggable}
|
|
529
691
|
maxContentHeight={maxContentHeight}
|
|
530
692
|
maxContentWidth={maxContentWidth}
|
|
531
|
-
|
|
532
|
-
|
|
693
|
+
placement={placement}
|
|
694
|
+
placementOffset={placementOffset}
|
|
695
|
+
scrollableHandle={this.state.scrollableHandle ?? -1}
|
|
533
696
|
scrollableOptions={scrollableOptions}
|
|
534
697
|
headerOptions={headerOptions}
|
|
535
698
|
footerOptions={{
|
|
536
699
|
footerPosition: footerOptions?.position,
|
|
537
700
|
keyboardOffset: footerOptions?.keyboardOffset,
|
|
701
|
+
avoidKeyboard: footerOptions?.avoidKeyboard,
|
|
538
702
|
}}
|
|
539
703
|
presentation={presentation}
|
|
540
704
|
insetAdjustment={insetAdjustment}
|
|
@@ -543,6 +707,7 @@ export class TrueSheet
|
|
|
543
707
|
onDidPresent={this.onDidPresent}
|
|
544
708
|
onWillDismiss={this.onWillDismiss}
|
|
545
709
|
onDidDismiss={this.onDidDismiss}
|
|
710
|
+
onDismissAttempt={this.onDismissAttempt}
|
|
546
711
|
onDetentChange={this.onDetentChange}
|
|
547
712
|
onDragBegin={this.onDragBegin}
|
|
548
713
|
onDragChange={this.onDragChange}
|
|
@@ -555,10 +720,11 @@ export class TrueSheet
|
|
|
555
720
|
onVisibilityChange={this.onVisibilityChange}
|
|
556
721
|
// These must stay on this host view, not on the container. The container is
|
|
557
722
|
// reparented into the native sheet, so this view is never a native ancestor of
|
|
558
|
-
// the sheet content
|
|
559
|
-
//
|
|
560
|
-
//
|
|
561
|
-
onStartShouldSetResponder={
|
|
723
|
+
// the sheet content — this is the React-tree boundary between the sheet and
|
|
724
|
+
// the presenting screen, where both the responder negotiation and raw touch
|
|
725
|
+
// bubbling must stop.
|
|
726
|
+
onStartShouldSetResponder={stopResponderNegotiation}
|
|
727
|
+
onMoveShouldSetResponder={stopResponderNegotiation}
|
|
562
728
|
onTouchStart={stopTouchPropagation}
|
|
563
729
|
onTouchMove={stopTouchPropagation}
|
|
564
730
|
onTouchEnd={stopTouchPropagation}
|
|
@@ -566,33 +732,22 @@ export class TrueSheet
|
|
|
566
732
|
>
|
|
567
733
|
{this.state.shouldRenderNativeView && (
|
|
568
734
|
<TrueSheetContainerViewNativeComponent style={styles.container}>
|
|
569
|
-
{
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
735
|
+
{AppContainer ? (
|
|
736
|
+
// Hosts the element inspector inside the sheet, like RN's Modal does —
|
|
737
|
+
// the app-level one sits behind the presented sheet.
|
|
738
|
+
// `display: contents` keeps AppContainer's wrapper views out of both
|
|
739
|
+
// Yoga layout and the native tree, so header/content/footer remain the
|
|
740
|
+
// container's direct native children, while the inspector overlay
|
|
741
|
+
// anchors to the container and lines up with measured frames.
|
|
742
|
+
<AppContainer
|
|
743
|
+
rootTag={this.context as RootTag}
|
|
744
|
+
rootViewStyle={styles.inspectorHost}
|
|
745
|
+
internal_excludeLogBox
|
|
576
746
|
>
|
|
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>
|
|
747
|
+
{sheetContent}
|
|
748
|
+
</AppContainer>
|
|
749
|
+
) : (
|
|
750
|
+
sheetContent
|
|
596
751
|
)}
|
|
597
752
|
</TrueSheetContainerViewNativeComponent>
|
|
598
753
|
)}
|
|
@@ -614,6 +769,9 @@ const styles = StyleSheet.create({
|
|
|
614
769
|
container: {
|
|
615
770
|
...StyleSheet.absoluteFill,
|
|
616
771
|
},
|
|
772
|
+
inspectorHost: {
|
|
773
|
+
display: 'contents',
|
|
774
|
+
},
|
|
617
775
|
header: {
|
|
618
776
|
pointerEvents: 'box-none',
|
|
619
777
|
},
|