@lodev09/react-native-true-sheet 4.0.0-beta.3 → 4.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -5
- package/android/build.gradle +23 -1
- package/android/proguard-rules.pro +3 -0
- 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 +38 -109
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +13 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +127 -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 +29 -3
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +234 -66
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +491 -186
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +64 -10
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +31 -14
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +135 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +23 -23
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +130 -6
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +14 -17
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +2 -4
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +148 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +33 -40
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/ColorUtils.kt +19 -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/android/src/main/jni/TrueSheetStateUpdater.cpp +37 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +114 -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 +14 -3
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +5 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +10 -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 +23 -7
- package/ios/TrueSheetContainerView.mm +45 -25
- package/ios/TrueSheetContentView.h +44 -15
- package/ios/TrueSheetContentView.mm +221 -190
- package/ios/TrueSheetFooterView.mm +133 -28
- package/ios/TrueSheetModule.h +2 -7
- package/ios/TrueSheetModule.mm +18 -18
- package/ios/TrueSheetOverlayView.h +42 -0
- package/ios/TrueSheetOverlayView.mm +175 -0
- package/ios/TrueSheetView.h +2 -0
- package/ios/TrueSheetView.mm +268 -52
- package/ios/TrueSheetViewController.h +36 -3
- package/ios/TrueSheetViewController.mm +797 -102
- package/ios/core/RNScreensEventObserver.mm +31 -28
- package/ios/core/TrueSheetBlurView.h +0 -2
- package/ios/core/TrueSheetBlurView.mm +3 -36
- package/ios/core/TrueSheetDetentCalculator.h +18 -1
- package/ios/core/TrueSheetDetentCalculator.mm +44 -9
- package/ios/core/TrueSheetDimView.h +27 -0
- package/ios/core/TrueSheetDimView.mm +41 -0
- package/ios/core/TrueSheetGrabberView.mm +13 -3
- package/ios/core/TrueSheetKeyboardObserver.h +7 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +107 -15
- 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 +222 -54
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +364 -275
- 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/TrueSheetProvider.web.js +13 -9
- package/lib/module/TrueSheetProvider.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/TrueSheetFooterViewNativeComponent.ts +2 -3
- package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +89 -73
- 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 +158 -100
- 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/extendTrueSheetRouter.js +71 -0
- package/lib/module/navigation/expo-router/extendTrueSheetRouter.js.map +1 -0
- package/lib/module/navigation/expo-router/index.js +18 -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/scrollable.js +28 -0
- package/lib/module/scrollable.js.map +1 -0
- package/lib/module/web/constants.js +1 -1
- package/lib/module/web/constants.js.map +1 -1
- package/lib/module/web/keyboard.js +69 -0
- package/lib/module/web/keyboard.js.map +1 -0
- 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 +4 -0
- 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 +83 -21
- package/lib/module/web/vaul/index.js.map +1 -1
- package/lib/module/web/vaul/use-snap-points.js +57 -28
- package/lib/module/web/vaul/use-snap-points.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +18 -1
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +209 -35
- 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/TrueSheetProvider.web.d.ts +5 -1
- package/lib/typescript/src/TrueSheetProvider.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/TrueSheetFooterViewNativeComponent.d.ts +2 -3
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
- 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 +76 -65
- 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 +36 -10
- 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/extendTrueSheetRouter.d.ts +33 -0
- package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts.map +1 -0
- package/lib/typescript/src/navigation/expo-router/index.d.ts +9 -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 +43 -6
- package/lib/typescript/src/navigation/types.d.ts.map +1 -1
- package/lib/typescript/src/scrollable.d.ts +2 -0
- package/lib/typescript/src/scrollable.d.ts.map +1 -0
- 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/keyboard.d.ts +15 -0
- package/lib/typescript/src/web/keyboard.d.ts.map +1 -0
- package/lib/typescript/src/web/layout.d.ts +20 -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 +5 -1
- 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 +20 -1
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/types.d.ts +9 -0
- package/lib/typescript/src/web/vaul/types.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts +6 -4
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
- package/package.json +18 -8
- package/react-native.config.js +1 -0
- package/src/TrueSheet.tsx +257 -62
- package/src/TrueSheet.types.ts +225 -35
- package/src/TrueSheet.web.tsx +445 -333
- 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/TrueSheetProvider.web.tsx +22 -13
- package/src/detentBackgrounds.ts +24 -0
- package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/src/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
- package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +89 -73
- 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 +220 -144
- package/src/navigation/expo-router/base-types.ts +18 -0
- package/src/navigation/expo-router/extendTrueSheetRouter.ts +99 -0
- package/src/navigation/expo-router/index.ts +41 -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 +81 -23
- package/src/scrollable.ts +25 -0
- package/src/web/constants.ts +1 -1
- package/src/web/keyboard.ts +79 -0
- package/src/web/layout.ts +196 -0
- package/src/web/vaul/constants.ts +9 -0
- package/src/web/vaul/context.ts +7 -1
- package/src/web/vaul/helpers.ts +5 -0
- package/src/web/vaul/index.tsx +113 -16
- package/src/web/vaul/types.ts +10 -0
- package/src/web/vaul/use-snap-points.ts +86 -33
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo Router flavour of `../types`: same shapes, but bound to Expo Router's
|
|
3
|
+
* vendored React Navigation types so apps that only install `expo-router` still
|
|
4
|
+
* get real types instead of `any` — see `./base-types`.
|
|
5
|
+
*/
|
|
6
|
+
import type { TrueSheetActionType } from '../actions';
|
|
7
|
+
import type {
|
|
8
|
+
TrueSheetActionHelpersOf,
|
|
9
|
+
TrueSheetDispatch,
|
|
10
|
+
TrueSheetNavigationEventMap,
|
|
11
|
+
TrueSheetNavigationOptions,
|
|
12
|
+
TrueSheetStateOf,
|
|
13
|
+
} from '../types';
|
|
14
|
+
import type {
|
|
15
|
+
DefaultNavigatorOptions,
|
|
16
|
+
NavigationAction,
|
|
17
|
+
NavigationHelpers,
|
|
18
|
+
NavigationProp,
|
|
19
|
+
NavigationState,
|
|
20
|
+
ParamListBase,
|
|
21
|
+
RouteProp,
|
|
22
|
+
Router,
|
|
23
|
+
StackActionHelpers,
|
|
24
|
+
StackRouterOptions,
|
|
25
|
+
} from './base-types';
|
|
26
|
+
|
|
27
|
+
export type TrueSheetRouterOptions = StackRouterOptions;
|
|
28
|
+
|
|
29
|
+
export type TrueSheetNavigationState<ParamList extends ParamListBase> = TrueSheetStateOf<
|
|
30
|
+
NavigationState<ParamList>
|
|
31
|
+
>;
|
|
32
|
+
|
|
33
|
+
export type TrueSheetRouterState = TrueSheetNavigationState<ParamListBase>;
|
|
34
|
+
|
|
35
|
+
export type TrueSheetRouter = Router<TrueSheetRouterState, TrueSheetActionType>;
|
|
36
|
+
|
|
37
|
+
export type TrueSheetRouterFactory = (options: TrueSheetRouterOptions) => TrueSheetRouter;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The base `StackRouter` factory to wrap — see `../types` for the shared contract.
|
|
41
|
+
*/
|
|
42
|
+
export type StackRouterFactory = <
|
|
43
|
+
State extends NavigationState<ParamListBase>,
|
|
44
|
+
Action extends NavigationAction,
|
|
45
|
+
>(
|
|
46
|
+
options: TrueSheetRouterOptions
|
|
47
|
+
) => Router<State, Action>;
|
|
48
|
+
|
|
49
|
+
export type TrueSheetRoute = TrueSheetNavigationState<ParamListBase>['routes'][number];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Props injected into the navigator content by Expo Router's `createProps`.
|
|
53
|
+
* Raw routes carry the custom fields (`closing`, `dismissing`, `resizeIndex`, `resizeKey`)
|
|
54
|
+
* that the standard state strips out.
|
|
55
|
+
*/
|
|
56
|
+
export interface TrueSheetNavigatorContentExtraProps {
|
|
57
|
+
routes: TrueSheetRoute[];
|
|
58
|
+
dispatch: TrueSheetDispatch;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type TrueSheetActionHelpers<ParamList extends ParamListBase> = TrueSheetActionHelpersOf<
|
|
62
|
+
StackActionHelpers<ParamList>
|
|
63
|
+
>;
|
|
64
|
+
|
|
65
|
+
export type TrueSheetNavigationProp<
|
|
66
|
+
ParamList extends ParamListBase,
|
|
67
|
+
RouteName extends keyof ParamList = string,
|
|
68
|
+
NavigatorID extends string | undefined = undefined,
|
|
69
|
+
> = NavigationProp<
|
|
70
|
+
ParamList,
|
|
71
|
+
RouteName,
|
|
72
|
+
NavigatorID,
|
|
73
|
+
TrueSheetNavigationState<ParamList>,
|
|
74
|
+
TrueSheetNavigationOptions,
|
|
75
|
+
TrueSheetNavigationEventMap
|
|
76
|
+
> &
|
|
77
|
+
TrueSheetActionHelpers<ParamList>;
|
|
78
|
+
|
|
79
|
+
export type TrueSheetScreenProps<
|
|
80
|
+
ParamList extends ParamListBase,
|
|
81
|
+
RouteName extends keyof ParamList = string,
|
|
82
|
+
NavigatorID extends string | undefined = undefined,
|
|
83
|
+
> = {
|
|
84
|
+
navigation: TrueSheetNavigationProp<ParamList, RouteName, NavigatorID>;
|
|
85
|
+
route: RouteProp<ParamList, RouteName>;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export type TrueSheetNavigationHelpers = NavigationHelpers<
|
|
89
|
+
ParamListBase,
|
|
90
|
+
TrueSheetNavigationEventMap
|
|
91
|
+
>;
|
|
92
|
+
|
|
93
|
+
export type TrueSheetNavigatorProps = DefaultNavigatorOptions<
|
|
94
|
+
ParamListBase,
|
|
95
|
+
string | undefined,
|
|
96
|
+
TrueSheetNavigationState<ParamListBase>,
|
|
97
|
+
TrueSheetNavigationOptions,
|
|
98
|
+
TrueSheetNavigationEventMap,
|
|
99
|
+
unknown
|
|
100
|
+
> & {
|
|
101
|
+
/**
|
|
102
|
+
* The name of the route to use as the base screen.
|
|
103
|
+
* This screen will be rendered as a regular screen, while other screens are presented as sheets.
|
|
104
|
+
* Defaults to the first screen defined in the navigator.
|
|
105
|
+
*/
|
|
106
|
+
initialRouteName?: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export type {
|
|
110
|
+
PositionChangeHandler,
|
|
111
|
+
TrueSheetDispatch,
|
|
112
|
+
TrueSheetNavigationEventMap,
|
|
113
|
+
TrueSheetNavigationOptions,
|
|
114
|
+
TrueSheetNavigationSheetProps,
|
|
115
|
+
TrueSheetStandardEventMap,
|
|
116
|
+
} from '../types';
|
package/src/navigation/index.ts
CHANGED
|
@@ -4,16 +4,17 @@ import {
|
|
|
4
4
|
type StandardNavigationTypeBagBase,
|
|
5
5
|
} from '@react-navigation/native';
|
|
6
6
|
|
|
7
|
-
import { createTrueSheetRouter
|
|
7
|
+
import { createTrueSheetRouter } from './createTrueSheetRouter';
|
|
8
8
|
import { trueSheetNavigator } from './navigator';
|
|
9
9
|
import type {
|
|
10
|
+
StackRouterFactory,
|
|
10
11
|
TrueSheetActionHelpers,
|
|
11
12
|
TrueSheetNavigationOptions,
|
|
12
13
|
TrueSheetNavigationEventMap,
|
|
13
14
|
TrueSheetNavigationState,
|
|
14
15
|
TrueSheetNavigatorContentExtraProps,
|
|
16
|
+
TrueSheetRouterOptions,
|
|
15
17
|
} from './types';
|
|
16
|
-
import type { TrueSheetRouterOptions } from './createTrueSheetRouter';
|
|
17
18
|
|
|
18
19
|
export interface TrueSheetNavigationTypeBag extends StandardNavigationTypeBagBase {
|
|
19
20
|
State: TrueSheetNavigationState<this['ParamList']>;
|
|
@@ -62,20 +63,18 @@ export const createTrueSheetNavigator = createNavigator;
|
|
|
62
63
|
export const createTrueSheetScreen = createScreen;
|
|
63
64
|
|
|
64
65
|
export { TrueSheetActions, type TrueSheetActionType } from './actions';
|
|
65
|
-
export {
|
|
66
|
-
createTrueSheetRouter,
|
|
67
|
-
type StackRouterFactory,
|
|
68
|
-
type TrueSheetRouterOptions,
|
|
69
|
-
} from './createTrueSheetRouter';
|
|
66
|
+
export { createTrueSheetRouter } from './createTrueSheetRouter';
|
|
70
67
|
export { useTrueSheetNavigation } from './useTrueSheetNavigation';
|
|
71
68
|
|
|
72
69
|
export type { DetentInfoEventPayload, PositionChangeEventPayload } from '../TrueSheet.types';
|
|
73
70
|
|
|
74
71
|
export type {
|
|
72
|
+
StackRouterFactory,
|
|
75
73
|
TrueSheetNavigationEventMap,
|
|
76
74
|
TrueSheetNavigationHelpers,
|
|
77
75
|
TrueSheetNavigationOptions,
|
|
78
76
|
TrueSheetNavigationProp,
|
|
79
77
|
TrueSheetNavigationState,
|
|
78
|
+
TrueSheetRouterOptions,
|
|
80
79
|
TrueSheetScreenProps,
|
|
81
80
|
} from './types';
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
PositionChangeEventPayload,
|
|
15
15
|
WillBlurEvent,
|
|
16
16
|
WillDismissEvent,
|
|
17
|
+
DismissAttemptEvent,
|
|
17
18
|
WillFocusEvent,
|
|
18
19
|
WillPresentEvent,
|
|
19
20
|
} from '../../TrueSheet.types';
|
|
@@ -78,6 +79,7 @@ export const useSheetScreenState = (props: UseSheetScreenStateProps) => {
|
|
|
78
79
|
onDidPresent: (e: DidPresentEvent) => emitEvent('sheetDidPresent', e.nativeEvent),
|
|
79
80
|
onWillDismiss: (_e: WillDismissEvent) => emitEvent('sheetWillDismiss', undefined),
|
|
80
81
|
onDidDismiss,
|
|
82
|
+
onDismissAttempt: (_e: DismissAttemptEvent) => emitEvent('sheetDismissAttempt', undefined),
|
|
81
83
|
onDetentChange: (e: DetentChangeEvent) => emitEvent('sheetDetentChange', e.nativeEvent),
|
|
82
84
|
onDragBegin: (e: DragBeginEvent) => emitEvent('sheetDragBegin', e.nativeEvent),
|
|
83
85
|
onDragChange: (e: DragChangeEvent) => emitEvent('sheetDragChange', e.nativeEvent),
|
package/src/navigation/types.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
+
import type { NavigatorArgs } from 'standard-navigation';
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
DetentInfoEventPayload,
|
|
5
|
+
PositionChangeEventPayload,
|
|
6
|
+
TrueSheetProps,
|
|
7
|
+
} from '../TrueSheet.types';
|
|
8
|
+
import type { TrueSheetActionType } from './actions';
|
|
1
9
|
import type {
|
|
2
10
|
DefaultNavigatorOptions,
|
|
3
11
|
Descriptor,
|
|
12
|
+
NavigationAction,
|
|
4
13
|
NavigationHelpers,
|
|
5
14
|
NavigationProp,
|
|
6
15
|
NavigationState,
|
|
7
16
|
ParamListBase,
|
|
8
17
|
RouteProp,
|
|
18
|
+
Router,
|
|
9
19
|
StackActionHelpers,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import type {
|
|
14
|
-
DetentInfoEventPayload,
|
|
15
|
-
PositionChangeEventPayload,
|
|
16
|
-
TrueSheetProps,
|
|
17
|
-
} from '../TrueSheet.types';
|
|
18
|
-
import type { TrueSheetActionType } from './actions';
|
|
20
|
+
StackRouterOptions,
|
|
21
|
+
} from './base-types';
|
|
19
22
|
|
|
20
23
|
export type PositionChangeHandler = (payload: PositionChangeEventPayload) => void;
|
|
21
24
|
|
|
@@ -36,6 +39,10 @@ export type TrueSheetNavigationEventMap = {
|
|
|
36
39
|
* Event fired when the sheet has been dismissed.
|
|
37
40
|
*/
|
|
38
41
|
sheetDidDismiss: { data: undefined };
|
|
42
|
+
/**
|
|
43
|
+
* Event fired when the user tries to dismiss a non-dismissible sheet.
|
|
44
|
+
*/
|
|
45
|
+
sheetDismissAttempt: { data: undefined };
|
|
39
46
|
/**
|
|
40
47
|
* Event fired when the sheet's detent changes.
|
|
41
48
|
*/
|
|
@@ -74,18 +81,56 @@ export type TrueSheetNavigationEventMap = {
|
|
|
74
81
|
sheetDidBlur: { data: undefined };
|
|
75
82
|
};
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
/**
|
|
85
|
+
* A navigation state tagged as `true-sheet`, with the sheet fields the router
|
|
86
|
+
* adds to each route.
|
|
87
|
+
* Generic over the base state so each entry point can bind its own
|
|
88
|
+
* `NavigationState` — see `./base-types`.
|
|
89
|
+
*/
|
|
90
|
+
export type TrueSheetStateOf<State extends { routes: readonly unknown[] }> = Omit<
|
|
91
|
+
State,
|
|
79
92
|
'routes'
|
|
80
93
|
> & {
|
|
81
94
|
type: 'true-sheet';
|
|
82
|
-
routes: (
|
|
95
|
+
routes: (State['routes'][number] & {
|
|
83
96
|
resizeIndex?: number;
|
|
84
97
|
resizeKey?: number;
|
|
85
98
|
closing?: boolean;
|
|
99
|
+
// Stacked above a `closing` route and dismissed natively with it
|
|
100
|
+
dismissing?: boolean;
|
|
86
101
|
})[];
|
|
87
102
|
};
|
|
88
103
|
|
|
104
|
+
export type TrueSheetNavigationState<ParamList extends ParamListBase> = TrueSheetStateOf<
|
|
105
|
+
NavigationState<ParamList>
|
|
106
|
+
>;
|
|
107
|
+
|
|
108
|
+
export type TrueSheetRouterState = TrueSheetNavigationState<ParamListBase>;
|
|
109
|
+
|
|
110
|
+
export type TrueSheetRouterOptions = StackRouterOptions;
|
|
111
|
+
|
|
112
|
+
export type TrueSheetRouter = Router<TrueSheetRouterState, TrueSheetActionType>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The wrapped router factory — also the shape `createTrueSheetRouter` accepts,
|
|
116
|
+
* pre-instantiated so either entry point's `StackRouterFactory` fits it.
|
|
117
|
+
*/
|
|
118
|
+
export type TrueSheetRouterFactory = (options: TrueSheetRouterOptions) => TrueSheetRouter;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The base `StackRouter` factory to wrap, typed generically over the state and
|
|
122
|
+
* action types the wrapper threads through — `StackRouter` is structural and
|
|
123
|
+
* never touches the sheet-specific fields.
|
|
124
|
+
* Injected by each entry point so the shared router never imports
|
|
125
|
+
* `@react-navigation/*` at runtime (Expo Router apps don't install it).
|
|
126
|
+
*/
|
|
127
|
+
export type StackRouterFactory = <
|
|
128
|
+
State extends NavigationState<ParamListBase>,
|
|
129
|
+
Action extends NavigationAction,
|
|
130
|
+
>(
|
|
131
|
+
options: TrueSheetRouterOptions
|
|
132
|
+
) => Router<State, Action>;
|
|
133
|
+
|
|
89
134
|
/**
|
|
90
135
|
* `TrueSheetNavigationEventMap` in the `standard-navigation` event-map shape.
|
|
91
136
|
*/
|
|
@@ -108,7 +153,7 @@ export type TrueSheetEmitFn = NavigatorArgs<
|
|
|
108
153
|
/**
|
|
109
154
|
* Props injected into the navigator content by each adapter
|
|
110
155
|
* (React Navigation's `mapper` / Expo Router's `createProps`).
|
|
111
|
-
* Raw routes carry the custom fields (`closing`, `resizeIndex`, `resizeKey`)
|
|
156
|
+
* Raw routes carry the custom fields (`closing`, `dismissing`, `resizeIndex`, `resizeKey`)
|
|
112
157
|
* that the standard state strips out.
|
|
113
158
|
*/
|
|
114
159
|
export interface TrueSheetNavigatorContentExtraProps {
|
|
@@ -116,13 +161,20 @@ export interface TrueSheetNavigatorContentExtraProps {
|
|
|
116
161
|
dispatch: TrueSheetDispatch;
|
|
117
162
|
}
|
|
118
163
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Generic over the base helpers so each entry point can bind its own
|
|
166
|
+
* `StackActionHelpers` — see `./base-types`.
|
|
167
|
+
*/
|
|
168
|
+
export type TrueSheetActionHelpersOf<Helpers> = Helpers & {
|
|
169
|
+
/**
|
|
170
|
+
* Resize the sheet to a specific detent index.
|
|
171
|
+
*/
|
|
172
|
+
resize(index?: number): void;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export type TrueSheetActionHelpers<ParamList extends ParamListBase> = TrueSheetActionHelpersOf<
|
|
176
|
+
StackActionHelpers<ParamList>
|
|
177
|
+
>;
|
|
126
178
|
|
|
127
179
|
export type TrueSheetNavigationProp<
|
|
128
180
|
ParamList extends ParamListBase,
|
|
@@ -156,6 +208,9 @@ export type TrueSheetNavigationSheetProps = Pick<
|
|
|
156
208
|
TrueSheetProps,
|
|
157
209
|
| 'detents'
|
|
158
210
|
| 'backgroundColor'
|
|
211
|
+
| 'detentBackgrounds'
|
|
212
|
+
| 'background'
|
|
213
|
+
| 'backgroundStyle'
|
|
159
214
|
| 'cornerRadius'
|
|
160
215
|
| 'dismissible'
|
|
161
216
|
| 'draggable'
|
|
@@ -163,9 +218,10 @@ export type TrueSheetNavigationSheetProps = Pick<
|
|
|
163
218
|
| 'grabberOptions'
|
|
164
219
|
| 'accessibilityOptions'
|
|
165
220
|
| 'dimmed'
|
|
221
|
+
| 'dimColor'
|
|
222
|
+
| 'dimOpacity'
|
|
166
223
|
| 'dimmedDetentIndex'
|
|
167
224
|
| 'backgroundBlur'
|
|
168
|
-
| 'blurOptions'
|
|
169
225
|
| 'maxContentHeight'
|
|
170
226
|
| 'maxContentWidth'
|
|
171
227
|
| 'presentation'
|
|
@@ -176,10 +232,12 @@ export type TrueSheetNavigationSheetProps = Pick<
|
|
|
176
232
|
| 'footer'
|
|
177
233
|
| 'footerStyle'
|
|
178
234
|
| 'footerOptions'
|
|
235
|
+
| 'scrollableRef'
|
|
179
236
|
| 'scrollableOptions'
|
|
180
237
|
| 'insetAdjustment'
|
|
181
|
-
| '
|
|
182
|
-
| '
|
|
238
|
+
| 'placement'
|
|
239
|
+
| 'placementOffset'
|
|
240
|
+
| 'foldOptions'
|
|
183
241
|
| 'elevation'
|
|
184
242
|
| 'detached'
|
|
185
243
|
| 'detachedOffset'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const ACCESSORS = ['getScrollableNode', 'getNativeScrollRef'] as const;
|
|
2
|
+
|
|
3
|
+
// Resolves a `scrollableRef` value to its scroll node: a native tag on native,
|
|
4
|
+
// a DOM node on web. Imperative-handle lists (e.g. LegendList, FlashList) are
|
|
5
|
+
// not host components, so they go through the accessors ScrollView/FlatList
|
|
6
|
+
// also expose. A composite result is resolved again until it yields a tag or
|
|
7
|
+
// host node. `getScrollResponder` is skipped: it returns the ScrollView class
|
|
8
|
+
// instance, which findNodeHandle resolves to its first host child (the
|
|
9
|
+
// SwipeRefreshLayout on Android when a refreshControl is set).
|
|
10
|
+
export function resolveScrollable(scrollable: unknown): unknown {
|
|
11
|
+
if (!scrollable || typeof scrollable !== 'object') return scrollable;
|
|
12
|
+
for (const name of ACCESSORS) {
|
|
13
|
+
const accessor = (scrollable as Record<string, unknown>)[name];
|
|
14
|
+
if (typeof accessor !== 'function') continue;
|
|
15
|
+
let node: unknown;
|
|
16
|
+
try {
|
|
17
|
+
node = accessor.call(scrollable);
|
|
18
|
+
} catch {
|
|
19
|
+
// e.g. LegendList forwarding to a custom scroll component that lacks it
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (node != null && node !== scrollable) return resolveScrollable(node);
|
|
23
|
+
}
|
|
24
|
+
return scrollable;
|
|
25
|
+
}
|
package/src/web/constants.ts
CHANGED
|
@@ -4,7 +4,7 @@ export const DEFAULT_FORM_SHEET_WIDTH = 580;
|
|
|
4
4
|
export const DEFAULT_FORM_SHEET_HEIGHT_RATIO = 0.5;
|
|
5
5
|
export const COLOR_SURFACE_CONTAINER_LOW_LIGHT = '#F7F2FA';
|
|
6
6
|
export const COLOR_SURFACE_CONTAINER_LOW_DARK = '#1D1B20';
|
|
7
|
-
export const
|
|
7
|
+
export const DEFAULT_PLACEMENT_OFFSET = 16;
|
|
8
8
|
export const DEFAULT_DETACHED_OFFSET = 16;
|
|
9
9
|
export const DEFAULT_GRABBER_COLOR_LIGHT = 'rgba(0, 0, 0, 0.3)';
|
|
10
10
|
export const DEFAULT_GRABBER_COLOR_DARK = 'rgba(255, 255, 255, 0.3)';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { FOOTER_INSET } from './layout';
|
|
5
|
+
import { getScrollParent } from './vaul/use-prevent-scroll';
|
|
6
|
+
import type { KeyboardViewport } from './vaul/types';
|
|
7
|
+
|
|
8
|
+
// Subpixel tolerance between the visual and layout viewport heights
|
|
9
|
+
const VIEWPORT_EPSILON = 1;
|
|
10
|
+
|
|
11
|
+
const readKeyboardViewport = (): KeyboardViewport | undefined => {
|
|
12
|
+
const vv = window.visualViewport;
|
|
13
|
+
if (!vv) return undefined;
|
|
14
|
+
const layoutHeight = document.documentElement.clientHeight;
|
|
15
|
+
// Pinch-zoom shrinks the visual viewport too — scaling it back out leaves
|
|
16
|
+
// only what the keyboard covers.
|
|
17
|
+
if (vv.height * vv.scale >= layoutHeight - VIEWPORT_EPSILON) return undefined;
|
|
18
|
+
return { top: vv.offsetTop, height: vv.height, layoutHeight };
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const isSameViewport = (a: KeyboardViewport | undefined, b: KeyboardViewport | undefined) =>
|
|
22
|
+
a === b ||
|
|
23
|
+
(a !== undefined &&
|
|
24
|
+
b !== undefined &&
|
|
25
|
+
a.top === b.top &&
|
|
26
|
+
a.height === b.height &&
|
|
27
|
+
a.layoutHeight === b.layoutHeight);
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Tracks the visual viewport while a soft keyboard shrinks it. iOS Safari and
|
|
31
|
+
* Chrome (default `interactive-widget`) keep the layout viewport — and every
|
|
32
|
+
* fixed element — full height under the keyboard, so the sheet has to be laid
|
|
33
|
+
* out against the visual viewport instead.
|
|
34
|
+
*/
|
|
35
|
+
export function useKeyboardViewport(enabled: boolean): KeyboardViewport | undefined {
|
|
36
|
+
const [viewport, setViewport] = useState<KeyboardViewport | undefined>();
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const vv = window.visualViewport;
|
|
40
|
+
if (!enabled || !vv) {
|
|
41
|
+
setViewport(undefined);
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const update = () => {
|
|
46
|
+
const next = readKeyboardViewport();
|
|
47
|
+
setViewport((current) => (isSameViewport(current, next) ? current : next));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
update();
|
|
51
|
+
vv.addEventListener('resize', update);
|
|
52
|
+
vv.addEventListener('scroll', update);
|
|
53
|
+
window.addEventListener('resize', update);
|
|
54
|
+
return () => {
|
|
55
|
+
vv.removeEventListener('resize', update);
|
|
56
|
+
vv.removeEventListener('scroll', update);
|
|
57
|
+
window.removeEventListener('resize', update);
|
|
58
|
+
};
|
|
59
|
+
}, [enabled]);
|
|
60
|
+
|
|
61
|
+
return viewport;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Scrolls the focused field in `container` back above its scroll parent's
|
|
66
|
+
* bottom edge, clearing a floating footer. The browser only reveals it on
|
|
67
|
+
* focus — before the sheet fits above the keyboard.
|
|
68
|
+
*/
|
|
69
|
+
export function revealFocusedElement(container: HTMLElement) {
|
|
70
|
+
const focused = document.activeElement;
|
|
71
|
+
if (!(focused instanceof HTMLElement) || !container.contains(focused)) return;
|
|
72
|
+
const scroller = getScrollParent(focused);
|
|
73
|
+
if (!container.contains(scroller)) return;
|
|
74
|
+
const footerInset = parseFloat(getComputedStyle(scroller).getPropertyValue(FOOTER_INSET)) || 0;
|
|
75
|
+
const overflow =
|
|
76
|
+
focused.getBoundingClientRect().bottom -
|
|
77
|
+
(scroller.getBoundingClientRect().bottom - footerInset);
|
|
78
|
+
if (overflow > 0) scroller.scrollTop += overflow;
|
|
79
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
|
|
3
|
+
export const FOOTER_INSET = '--truesheet-footer-inset';
|
|
4
|
+
|
|
5
|
+
interface SheetLayoutOptions {
|
|
6
|
+
drawer: HTMLElement;
|
|
7
|
+
layout: HTMLElement;
|
|
8
|
+
getContent: () => HTMLElement | null;
|
|
9
|
+
getHeader: () => HTMLElement | null;
|
|
10
|
+
getFooter: () => HTMLElement | null;
|
|
11
|
+
getScrollable: () => HTMLElement | null;
|
|
12
|
+
absoluteHeader: boolean;
|
|
13
|
+
absoluteFooter: boolean;
|
|
14
|
+
footerInsetAdjustment: boolean;
|
|
15
|
+
measureContent: boolean;
|
|
16
|
+
onHeightChange: (height: number) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function observeSheetLayout({
|
|
20
|
+
drawer,
|
|
21
|
+
layout,
|
|
22
|
+
getContent,
|
|
23
|
+
getHeader,
|
|
24
|
+
getFooter,
|
|
25
|
+
getScrollable,
|
|
26
|
+
absoluteHeader,
|
|
27
|
+
absoluteFooter,
|
|
28
|
+
footerInsetAdjustment,
|
|
29
|
+
measureContent,
|
|
30
|
+
onHeightChange,
|
|
31
|
+
}: SheetLayoutOptions) {
|
|
32
|
+
let frame = 0;
|
|
33
|
+
let disposed = false;
|
|
34
|
+
let width = -1;
|
|
35
|
+
let height = -1;
|
|
36
|
+
let scroller: HTMLElement | null = null;
|
|
37
|
+
let originalPadding = '';
|
|
38
|
+
let insetPadding = '';
|
|
39
|
+
let appliedInset = 0;
|
|
40
|
+
const observed = new Set<Element>();
|
|
41
|
+
|
|
42
|
+
// This tree has no viewport constraint or injected footer inset. Its resize
|
|
43
|
+
// observer catches intrinsic changes without observing the live flex layout.
|
|
44
|
+
const measurement = measureContent ? document.createElement('div') : null;
|
|
45
|
+
if (measurement) {
|
|
46
|
+
Object.assign(measurement.style, {
|
|
47
|
+
position: 'absolute',
|
|
48
|
+
top: '0',
|
|
49
|
+
left: '0',
|
|
50
|
+
display: 'flex',
|
|
51
|
+
flexDirection: 'column',
|
|
52
|
+
visibility: 'hidden',
|
|
53
|
+
pointerEvents: 'none',
|
|
54
|
+
});
|
|
55
|
+
measurement.style.setProperty(FOOTER_INSET, '0px');
|
|
56
|
+
measurement.inert = true;
|
|
57
|
+
measurement.setAttribute('aria-hidden', 'true');
|
|
58
|
+
measurement.setAttribute('data-truesheet-measure', '');
|
|
59
|
+
drawer.appendChild(measurement);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const measure = () => {
|
|
63
|
+
if (!measurement?.isConnected) return;
|
|
64
|
+
const headerHeight = absoluteHeader ? 0 : (getHeader()?.offsetHeight ?? 0);
|
|
65
|
+
const footerHeight =
|
|
66
|
+
!absoluteFooter || (footerInsetAdjustment && scroller) ? (getFooter()?.offsetHeight ?? 0) : 0;
|
|
67
|
+
const next = measurement.offsetHeight + headerHeight + footerHeight;
|
|
68
|
+
if (height === next) return;
|
|
69
|
+
height = next;
|
|
70
|
+
onHeightChange(next);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const updateInset = () => {
|
|
74
|
+
let inset = 0;
|
|
75
|
+
const footer = getFooter();
|
|
76
|
+
if (footerInsetAdjustment && scroller && footer) {
|
|
77
|
+
let bottom = scroller.offsetTop + scroller.offsetHeight;
|
|
78
|
+
let parent = scroller.offsetParent;
|
|
79
|
+
while (parent instanceof HTMLElement && parent !== layout) {
|
|
80
|
+
bottom += parent.offsetTop;
|
|
81
|
+
parent = parent.offsetParent;
|
|
82
|
+
}
|
|
83
|
+
if (parent === layout) {
|
|
84
|
+
inset = Math.min(
|
|
85
|
+
footer.offsetHeight,
|
|
86
|
+
Math.max(0, bottom - (layout.clientHeight - footer.offsetHeight))
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (inset === appliedInset) return;
|
|
91
|
+
appliedInset = inset;
|
|
92
|
+
layout.style.setProperty(FOOTER_INSET, `${inset}px`);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
96
|
+
if (measurement && width !== layout.clientWidth) {
|
|
97
|
+
width = layout.clientWidth;
|
|
98
|
+
measurement.style.width = `${width}px`;
|
|
99
|
+
}
|
|
100
|
+
updateInset();
|
|
101
|
+
measure();
|
|
102
|
+
});
|
|
103
|
+
const measurementObserver = new ResizeObserver(measure);
|
|
104
|
+
if (measurement) measurementObserver.observe(measurement);
|
|
105
|
+
|
|
106
|
+
const restorePadding = () => {
|
|
107
|
+
if (scroller && scroller.style.paddingBottom === insetPadding) {
|
|
108
|
+
scroller.style.paddingBottom = originalPadding;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const sync = () => {
|
|
113
|
+
if (disposed) return;
|
|
114
|
+
const content = getContent();
|
|
115
|
+
const nextScroller = getScrollable();
|
|
116
|
+
if (nextScroller !== scroller) {
|
|
117
|
+
restorePadding();
|
|
118
|
+
scroller = nextScroller;
|
|
119
|
+
insetPadding = '';
|
|
120
|
+
}
|
|
121
|
+
if (
|
|
122
|
+
footerInsetAdjustment &&
|
|
123
|
+
scroller &&
|
|
124
|
+
(!insetPadding || scroller.style.paddingBottom !== insetPadding)
|
|
125
|
+
) {
|
|
126
|
+
originalPadding = scroller.style.paddingBottom;
|
|
127
|
+
const base = getComputedStyle(scroller).paddingBottom;
|
|
128
|
+
insetPadding = `calc(${base} + var(${FOOTER_INSET}, 0px))`;
|
|
129
|
+
scroller.style.paddingBottom = insetPadding;
|
|
130
|
+
insetPadding = scroller.style.paddingBottom;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const nodes = new Set<Element>([layout]);
|
|
134
|
+
for (const node of [getHeader(), getFooter(), scroller]) {
|
|
135
|
+
if (node) nodes.add(node);
|
|
136
|
+
}
|
|
137
|
+
for (const node of observed) {
|
|
138
|
+
if (!nodes.has(node)) {
|
|
139
|
+
resizeObserver.unobserve(node);
|
|
140
|
+
observed.delete(node);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const node of nodes) {
|
|
144
|
+
if (!observed.has(node)) {
|
|
145
|
+
resizeObserver.observe(node);
|
|
146
|
+
observed.add(node);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (measurement && content) {
|
|
151
|
+
width = layout.clientWidth;
|
|
152
|
+
measurement.style.width = `${width}px`;
|
|
153
|
+
measurement.replaceChildren(content.cloneNode(true));
|
|
154
|
+
}
|
|
155
|
+
updateInset();
|
|
156
|
+
measure();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const mutationObserver = new MutationObserver((mutations) => {
|
|
160
|
+
const changed = mutations.some(
|
|
161
|
+
(mutation) => mutation.target !== layout || mutation.type === 'childList'
|
|
162
|
+
);
|
|
163
|
+
if (!changed || frame) return;
|
|
164
|
+
frame = requestAnimationFrame(() => {
|
|
165
|
+
frame = 0;
|
|
166
|
+
sync();
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
sync();
|
|
171
|
+
mutationObserver.observe(layout, {
|
|
172
|
+
childList: true,
|
|
173
|
+
characterData: true,
|
|
174
|
+
attributes: true,
|
|
175
|
+
attributeFilter: ['style', 'class'],
|
|
176
|
+
subtree: true,
|
|
177
|
+
});
|
|
178
|
+
const footer = getFooter();
|
|
179
|
+
if (absoluteFooter && footer) {
|
|
180
|
+
mutationObserver.observe(footer, { childList: true, characterData: true, subtree: true });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
measure,
|
|
185
|
+
disconnect: () => {
|
|
186
|
+
disposed = true;
|
|
187
|
+
cancelAnimationFrame(frame);
|
|
188
|
+
mutationObserver.disconnect();
|
|
189
|
+
resizeObserver.disconnect();
|
|
190
|
+
measurementObserver.disconnect();
|
|
191
|
+
restorePadding();
|
|
192
|
+
layout.style.removeProperty(FOOTER_INSET);
|
|
193
|
+
measurement?.remove();
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
@@ -9,6 +9,15 @@ export const DEFAULT_PEEK_HEIGHT = 150;
|
|
|
9
9
|
|
|
10
10
|
export const CLOSE_THRESHOLD = 0.25;
|
|
11
11
|
|
|
12
|
+
// Compose Material3 SheetState's dismiss thresholds, used by the 'short'
|
|
13
|
+
// dismiss threshold: velocity in px/ms, distance in px.
|
|
14
|
+
export const SHORT_DISMISS_VELOCITY = 0.125;
|
|
15
|
+
export const SHORT_DISMISS_DISTANCE = 56;
|
|
16
|
+
|
|
17
|
+
// Minimum downward pull (px) on a non-dismissible drawer at its first snap
|
|
18
|
+
// point before the release counts as a dismiss attempt.
|
|
19
|
+
export const DISMISS_ATTEMPT_THRESHOLD = 24;
|
|
20
|
+
|
|
12
21
|
export const SCROLL_LOCK_TIMEOUT = 100;
|
|
13
22
|
|
|
14
23
|
export const BORDER_RADIUS = 8;
|