@lodev09/react-native-true-sheet 4.0.0-beta.0 → 4.0.0-beta.10
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/LICENSE +1 -1
- package/README.md +62 -30
- package/RNTrueSheet.podspec +10 -2
- package/android/build.gradle +24 -2
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +189 -47
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +401 -19
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +18 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +145 -21
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterViewManager.kt +14 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderView.kt +38 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetHeaderViewManager.kt +28 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +84 -24
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +106 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +6 -4
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekView.kt +72 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPeekViewManager.kt +33 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +63 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +564 -226
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +1399 -598
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +161 -29
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +63 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +36 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +255 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +375 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +299 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +162 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +180 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +207 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +137 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +220 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetDragEvents.kt +71 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetFocusEvents.kt +65 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +127 -0
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetStateEvents.kt +56 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +84 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +93 -67
- package/android/src/main/java/com/lodev09/truesheet/utils/TouchEventDeduper.kt +31 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +42 -0
- package/android/src/main/jni/CMakeLists.txt +63 -0
- package/android/src/main/jni/TrueSheetSpec.h +20 -0
- package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +16 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +68 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +33 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +39 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +63 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +28 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +11 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +41 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +18 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +16 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +46 -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 +36 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +28 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +30 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +45 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +23 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +52 -0
- package/ios/TrueSheetContainerView.h +88 -6
- package/ios/TrueSheetContainerView.mm +278 -21
- package/ios/TrueSheetContentView.h +54 -1
- package/ios/TrueSheetContentView.mm +371 -47
- package/ios/TrueSheetFooterView.h +33 -2
- package/ios/TrueSheetFooterView.mm +187 -35
- package/ios/{events/OnWillDismissEvent.h → TrueSheetHeaderView.h} +10 -7
- package/ios/TrueSheetHeaderView.mm +64 -0
- package/ios/TrueSheetModule.h +2 -7
- package/ios/TrueSheetModule.mm +98 -20
- package/ios/TrueSheetOverlayView.h +32 -0
- package/ios/TrueSheetOverlayView.mm +161 -0
- package/ios/TrueSheetPeekView.h +32 -0
- package/ios/TrueSheetPeekView.mm +99 -0
- package/ios/TrueSheetView.h +7 -15
- package/ios/TrueSheetView.mm +775 -215
- package/ios/TrueSheetViewController.h +94 -16
- package/ios/TrueSheetViewController.mm +1316 -331
- package/ios/core/RNScreensEventObserver.h +46 -0
- package/ios/core/RNScreensEventObserver.mm +280 -0
- package/ios/core/TrueSheetBlurView.h +27 -0
- package/ios/core/TrueSheetBlurView.mm +82 -0
- package/ios/core/TrueSheetDetentCalculator.h +107 -0
- package/ios/core/TrueSheetDetentCalculator.mm +197 -0
- package/ios/core/TrueSheetGrabberView.h +72 -0
- package/ios/core/TrueSheetGrabberView.mm +188 -0
- package/ios/core/TrueSheetKeyboardObserver.h +39 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +112 -0
- package/ios/core/TrueSheetOverlayContainerView.h +31 -0
- package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
- package/ios/events/TrueSheetDragEvents.h +39 -0
- package/ios/events/TrueSheetDragEvents.mm +62 -0
- package/ios/events/{OnPositionChangeEvent.h → TrueSheetFocusEvents.h} +8 -5
- package/ios/events/TrueSheetFocusEvents.mm +49 -0
- package/ios/events/TrueSheetLifecycleEvents.h +42 -0
- package/ios/events/TrueSheetLifecycleEvents.mm +79 -0
- package/ios/events/TrueSheetStateEvents.h +35 -0
- package/ios/events/TrueSheetStateEvents.mm +49 -0
- package/ios/tvos/TrueSheetStubs.mm +166 -0
- package/ios/{events/OnMountEvent.h → utils/BlurUtil.h} +5 -7
- package/ios/utils/BlurUtil.mm +69 -0
- package/ios/utils/GestureUtil.h +7 -0
- package/ios/utils/GestureUtil.mm +12 -0
- package/ios/utils/PlatformUtil.h +15 -0
- package/ios/utils/UIView+FirstResponder.h +15 -0
- package/ios/utils/UIView+FirstResponder.mm +26 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.h +26 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.mm +84 -0
- package/ios/utils/WindowUtil.mm +17 -1
- package/lib/module/TrueSheet.js +349 -74
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +1270 -0
- package/lib/module/TrueSheet.web.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.js +15 -0
- package/lib/module/TrueSheetPeek.js.map +1 -0
- package/lib/module/TrueSheetPeek.web.js +55 -0
- package/lib/module/TrueSheetPeek.web.js.map +1 -0
- package/lib/module/TrueSheetProvider.js +28 -0
- package/lib/module/TrueSheetProvider.js.map +1 -0
- package/lib/module/TrueSheetProvider.web.js +157 -0
- package/lib/module/TrueSheetProvider.web.js.map +1 -0
- package/lib/module/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
- package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
- package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
- package/lib/module/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/lib/module/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +110 -18
- package/lib/module/index.js +4 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks/index.js +103 -0
- package/lib/module/mocks/index.js.map +1 -0
- package/lib/module/mocks/navigation.js +95 -0
- package/lib/module/mocks/navigation.js.map +1 -0
- package/lib/module/mocks/navigationExpoRouter.js +21 -0
- package/lib/module/mocks/navigationExpoRouter.js.map +1 -0
- package/lib/module/mocks/reanimated.js +91 -0
- package/lib/module/mocks/reanimated.js.map +1 -0
- package/lib/module/navigation/TrueSheetNavigatorContent.js +73 -0
- package/lib/module/navigation/TrueSheetNavigatorContent.js.map +1 -0
- package/lib/module/navigation/actions.js +50 -0
- package/lib/module/navigation/actions.js.map +1 -0
- 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 +157 -0
- package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
- 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 +50 -0
- package/lib/module/navigation/expo-router/index.js.map +1 -0
- 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 +47 -0
- package/lib/module/navigation/index.js.map +1 -0
- package/lib/module/navigation/navigator.js +10 -0
- package/lib/module/navigation/navigator.js.map +1 -0
- package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js +56 -0
- package/lib/module/navigation/screen/ReanimatedTrueSheetScreen.js.map +1 -0
- package/lib/module/navigation/screen/TrueSheetScreen.js +49 -0
- package/lib/module/navigation/screen/TrueSheetScreen.js.map +1 -0
- package/lib/module/navigation/screen/index.js +5 -0
- package/lib/module/navigation/screen/index.js.map +1 -0
- package/lib/module/navigation/screen/types.js +4 -0
- package/lib/module/navigation/screen/types.js.map +1 -0
- package/lib/module/navigation/screen/useSheetScreenState.js +69 -0
- package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -0
- package/lib/module/navigation/types.js +4 -0
- package/lib/module/navigation/types.js.map +1 -0
- package/lib/module/navigation/useTrueSheetNavigation.js +24 -0
- package/lib/module/navigation/useTrueSheetNavigation.js.map +1 -0
- package/lib/module/reanimated/ReanimatedTrueSheet.js +15 -9
- package/lib/module/reanimated/ReanimatedTrueSheet.js.map +1 -1
- package/lib/module/reanimated/ReanimatedTrueSheet.web.js +81 -0
- package/lib/module/reanimated/ReanimatedTrueSheet.web.js.map +1 -0
- package/lib/module/reanimated/ReanimatedTrueSheetProvider.js +4 -2
- package/lib/module/reanimated/ReanimatedTrueSheetProvider.js.map +1 -1
- package/lib/module/reanimated/index.js +2 -2
- package/lib/module/reanimated/index.js.map +1 -1
- package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js +20 -0
- package/lib/module/reanimated/useReanimatedPositionChangeHandler.web.js.map +1 -0
- package/lib/module/specs/NativeTrueSheetModule.js.map +1 -1
- package/lib/module/web/constants.js +16 -0
- package/lib/module/web/constants.js.map +1 -0
- package/lib/module/web/dom.js +10 -0
- package/lib/module/web/dom.js.map +1 -0
- package/lib/module/web/vaul/README.md +9 -0
- package/lib/module/web/vaul/browser.js +30 -0
- package/lib/module/web/vaul/browser.js.map +1 -0
- package/lib/module/web/vaul/constants.js +19 -0
- package/lib/module/web/vaul/constants.js.map +1 -0
- package/lib/module/web/vaul/context.js +59 -0
- package/lib/module/web/vaul/context.js.map +1 -0
- package/lib/module/web/vaul/helpers.js +99 -0
- package/lib/module/web/vaul/helpers.js.map +1 -0
- package/lib/module/web/vaul/index.js +1342 -0
- package/lib/module/web/vaul/index.js.map +1 -0
- package/lib/module/web/vaul/style.css +287 -0
- package/lib/module/web/vaul/style.css.d.js +2 -0
- package/lib/module/web/vaul/style.css.d.js.map +1 -0
- package/lib/module/web/vaul/types.js +2 -0
- package/lib/module/web/vaul/types.js.map +1 -0
- package/lib/module/web/vaul/use-composed-refs.js +34 -0
- package/lib/module/web/vaul/use-composed-refs.js.map +1 -0
- package/lib/module/web/vaul/use-controllable-state.js +54 -0
- package/lib/module/web/vaul/use-controllable-state.js.map +1 -0
- package/lib/module/web/vaul/use-position-fixed.js +123 -0
- package/lib/module/web/vaul/use-position-fixed.js.map +1 -0
- package/lib/module/web/vaul/use-prevent-scroll.js +258 -0
- package/lib/module/web/vaul/use-prevent-scroll.js.map +1 -0
- package/lib/module/web/vaul/use-scale-background.js +57 -0
- package/lib/module/web/vaul/use-scale-background.js.map +1 -0
- package/lib/module/web/vaul/use-snap-points.js +305 -0
- package/lib/module/web/vaul/use-snap-points.js.map +1 -0
- package/lib/typescript/src/TrueSheet.d.ts +57 -14
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +535 -55
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts +5 -0
- package/lib/typescript/src/TrueSheet.web.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.d.ts +9 -0
- package/lib/typescript/src/TrueSheetPeek.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetPeek.web.d.ts +28 -0
- package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetProvider.d.ts +18 -0
- package/lib/typescript/src/TrueSheetProvider.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetProvider.web.d.ts +27 -0
- package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetContainerViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetContentViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -0
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetHeaderViewNativeComponent.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/TrueSheetPeekViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +71 -16
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/index.d.ts +47 -0
- package/lib/typescript/src/mocks/index.d.ts.map +1 -0
- package/lib/typescript/src/mocks/navigation.d.ts +70 -0
- package/lib/typescript/src/mocks/navigation.d.ts.map +1 -0
- package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +22 -0
- package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -0
- package/lib/typescript/src/mocks/reanimated.d.ts +48 -0
- package/lib/typescript/src/mocks/reanimated.d.ts.map +1 -0
- package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts +5 -0
- package/lib/typescript/src/navigation/TrueSheetNavigatorContent.d.ts.map +1 -0
- package/lib/typescript/src/navigation/actions.d.ts +71 -0
- package/lib/typescript/src/navigation/actions.d.ts.map +1 -0
- 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 +3 -0
- package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -0
- 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 +37 -0
- package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -0
- 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 +45 -0
- package/lib/typescript/src/navigation/index.d.ts.map +1 -0
- package/lib/typescript/src/navigation/navigator.d.ts +7 -0
- package/lib/typescript/src/navigation/navigator.d.ts.map +1 -0
- package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts +3 -0
- package/lib/typescript/src/navigation/screen/ReanimatedTrueSheetScreen.d.ts.map +1 -0
- package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts +3 -0
- package/lib/typescript/src/navigation/screen/TrueSheetScreen.d.ts.map +1 -0
- package/lib/typescript/src/navigation/screen/index.d.ts +4 -0
- package/lib/typescript/src/navigation/screen/index.d.ts.map +1 -0
- package/lib/typescript/src/navigation/screen/types.d.ts +14 -0
- package/lib/typescript/src/navigation/screen/types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +34 -0
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
- package/lib/typescript/src/navigation/types.d.ts +213 -0
- package/lib/typescript/src/navigation/types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts +23 -0
- package/lib/typescript/src/navigation/useTrueSheetNavigation.d.ts.map +1 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts +41 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheet.web.d.ts.map +1 -0
- package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts +8 -2
- package/lib/typescript/src/reanimated/ReanimatedTrueSheetProvider.d.ts.map +1 -1
- package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts +15 -0
- package/lib/typescript/src/reanimated/useReanimatedPositionChangeHandler.web.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts +25 -3
- package/lib/typescript/src/specs/NativeTrueSheetModule.d.ts.map +1 -1
- package/lib/typescript/src/web/constants.d.ts +14 -0
- package/lib/typescript/src/web/constants.d.ts.map +1 -0
- package/lib/typescript/src/web/dom.d.ts +7 -0
- package/lib/typescript/src/web/dom.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/browser.d.ts +8 -0
- package/lib/typescript/src/web/vaul/browser.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/constants.d.ts +14 -0
- package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/context.d.ts +54 -0
- package/lib/typescript/src/web/vaul/context.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/helpers.d.ts +17 -0
- package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/index.d.ts +234 -0
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/types.d.ts +7 -0
- package/lib/typescript/src/web/vaul/types.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/use-composed-refs.d.ts +14 -0
- package/lib/typescript/src/web/vaul/use-composed-refs.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/use-controllable-state.d.ts +9 -0
- package/lib/typescript/src/web/vaul/use-controllable-state.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/use-position-fixed.d.ts +19 -0
- package/lib/typescript/src/web/vaul/use-position-fixed.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts +18 -0
- package/lib/typescript/src/web/vaul/use-prevent-scroll.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/use-scale-background.d.ts +2 -0
- package/lib/typescript/src/web/vaul/use-scale-background.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts +38 -0
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -0
- package/package.json +104 -37
- package/react-native.config.js +10 -2
- package/src/TrueSheet.tsx +424 -70
- package/src/TrueSheet.types.ts +602 -72
- package/src/TrueSheet.web.tsx +1437 -0
- package/src/TrueSheetOverlay.tsx +24 -0
- package/src/TrueSheetOverlay.web.tsx +33 -0
- package/src/TrueSheetPeek.tsx +11 -0
- package/src/TrueSheetPeek.web.tsx +64 -0
- package/src/TrueSheetProvider.tsx +33 -0
- package/src/TrueSheetProvider.web.tsx +220 -0
- package/src/fabric/TrueSheetContainerViewNativeComponent.ts +1 -1
- package/src/fabric/TrueSheetContentViewNativeComponent.ts +5 -1
- package/src/fabric/TrueSheetFooterViewNativeComponent.ts +10 -2
- package/src/fabric/TrueSheetHeaderViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/src/fabric/TrueSheetPeekViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +110 -18
- package/src/index.ts +3 -2
- package/src/mocks/index.ts +96 -0
- package/src/mocks/navigation.ts +79 -0
- package/src/mocks/navigationExpoRouter.ts +41 -0
- package/src/mocks/reanimated.ts +100 -0
- package/src/navigation/TrueSheetNavigatorContent.tsx +106 -0
- package/src/navigation/actions.ts +78 -0
- package/src/navigation/base-types.ts +20 -0
- package/src/navigation/createTrueSheetRouter.ts +194 -0
- package/src/navigation/expo-router/base-types.ts +18 -0
- package/src/navigation/expo-router/index.ts +90 -0
- package/src/navigation/expo-router/types.ts +116 -0
- package/src/navigation/index.ts +80 -0
- package/src/navigation/navigator.ts +18 -0
- package/src/navigation/screen/ReanimatedTrueSheetScreen.tsx +61 -0
- package/src/navigation/screen/TrueSheetScreen.tsx +54 -0
- package/src/navigation/screen/index.ts +3 -0
- package/src/navigation/screen/types.ts +19 -0
- package/src/navigation/screen/useSheetScreenState.ts +102 -0
- package/src/navigation/types.ts +302 -0
- package/src/navigation/useTrueSheetNavigation.ts +26 -0
- package/src/reanimated/ReanimatedTrueSheet.tsx +12 -7
- package/src/reanimated/ReanimatedTrueSheet.web.tsx +75 -0
- package/src/reanimated/ReanimatedTrueSheetProvider.tsx +12 -8
- package/src/reanimated/useReanimatedPositionChangeHandler.web.ts +31 -0
- package/src/specs/NativeTrueSheetModule.ts +28 -3
- package/src/web/constants.ts +13 -0
- package/src/web/dom.ts +9 -0
- package/src/web/vaul/README.md +9 -0
- package/src/web/vaul/browser.ts +38 -0
- package/src/web/vaul/constants.ts +24 -0
- package/src/web/vaul/context.ts +102 -0
- package/src/web/vaul/helpers.ts +131 -0
- package/src/web/vaul/index.tsx +1785 -0
- package/src/web/vaul/style.css +287 -0
- package/src/web/vaul/style.css.d.ts +1 -0
- package/src/web/vaul/types.ts +7 -0
- package/src/web/vaul/use-composed-refs.ts +35 -0
- package/src/web/vaul/use-controllable-state.ts +66 -0
- package/src/web/vaul/use-position-fixed.ts +147 -0
- package/src/web/vaul/use-prevent-scroll.ts +309 -0
- package/src/web/vaul/use-scale-background.ts +64 -0
- package/src/web/vaul/use-snap-points.ts +455 -0
- package/android/src/main/java/com/lodev09/truesheet/events/DetentChangeEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DidDismissEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/DidPresentEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DragBeginEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DragChangeEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/DragEndEvent.kt +0 -26
- package/android/src/main/java/com/lodev09/truesheet/events/MountEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/PositionChangeEvent.kt +0 -32
- package/android/src/main/java/com/lodev09/truesheet/events/SizeChangeEvent.kt +0 -27
- package/android/src/main/java/com/lodev09/truesheet/events/WillDismissEvent.kt +0 -20
- package/android/src/main/java/com/lodev09/truesheet/events/WillPresentEvent.kt +0 -26
- package/android/src/main/res/values/styles.xml +0 -8
- package/ios/events/OnDetentChangeEvent.h +0 -28
- package/ios/events/OnDetentChangeEvent.mm +0 -30
- package/ios/events/OnDidDismissEvent.h +0 -26
- package/ios/events/OnDidDismissEvent.mm +0 -25
- package/ios/events/OnDidPresentEvent.h +0 -28
- package/ios/events/OnDidPresentEvent.mm +0 -30
- package/ios/events/OnDragBeginEvent.h +0 -28
- package/ios/events/OnDragBeginEvent.mm +0 -30
- package/ios/events/OnDragChangeEvent.h +0 -28
- package/ios/events/OnDragChangeEvent.mm +0 -30
- package/ios/events/OnDragEndEvent.h +0 -28
- package/ios/events/OnDragEndEvent.mm +0 -30
- package/ios/events/OnMountEvent.mm +0 -25
- package/ios/events/OnPositionChangeEvent.mm +0 -32
- package/ios/events/OnSizeChangeEvent.h +0 -28
- package/ios/events/OnSizeChangeEvent.mm +0 -30
- package/ios/events/OnWillDismissEvent.mm +0 -25
- package/ios/events/OnWillPresentEvent.h +0 -28
- package/ios/events/OnWillPresentEvent.mm +0 -30
- package/ios/utils/LayoutUtil.h +0 -44
- package/ios/utils/LayoutUtil.mm +0 -50
- package/lib/module/TrueSheetGrabber.js +0 -51
- package/lib/module/TrueSheetGrabber.js.map +0 -1
- package/lib/typescript/src/TrueSheetGrabber.d.ts +0 -39
- package/lib/typescript/src/TrueSheetGrabber.d.ts.map +0 -1
- package/src/TrueSheetGrabber.tsx +0 -82
- package/src/__mocks__/index.js +0 -67
|
@@ -1,14 +1,52 @@
|
|
|
1
1
|
package com.lodev09.truesheet
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.os.Build
|
|
5
|
+
import android.text.Editable
|
|
6
|
+
import android.text.TextWatcher
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import android.view.ViewTreeObserver
|
|
10
|
+
import android.widget.EditText
|
|
11
|
+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
12
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
4
13
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
14
|
import com.facebook.react.views.view.ReactViewGroup
|
|
15
|
+
import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
|
|
16
|
+
import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
|
|
17
|
+
import com.lodev09.truesheet.utils.isDescendantOf
|
|
18
|
+
import com.lodev09.truesheet.utils.smoothScrollTo
|
|
19
|
+
|
|
20
|
+
data class ScrollableOptions(
|
|
21
|
+
val keyboardScrollOffset: Float = 0f,
|
|
22
|
+
val keyboardOffset: Float = 0f,
|
|
23
|
+
val scrollingExpandsSheet: Boolean = true,
|
|
24
|
+
val contentInsetAdjustment: Boolean = true
|
|
25
|
+
)
|
|
6
26
|
|
|
7
27
|
/**
|
|
8
28
|
* Delegate interface for content view size changes
|
|
9
29
|
*/
|
|
10
30
|
interface TrueSheetContentViewDelegate {
|
|
11
31
|
fun contentViewDidChangeSize(width: Int, height: Int)
|
|
32
|
+
fun contentViewDidScroll()
|
|
33
|
+
fun contentViewScrollViewDidChange()
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Keyboard occlusion adjustment below the content — positive for an absolute
|
|
37
|
+
* footer floating over the viewport's bottom edge (extends the caret reveal),
|
|
38
|
+
* negative for a relative footer sitting behind the keyboard shielding that
|
|
39
|
+
* much of its overlap (reduces the keyboard padding).
|
|
40
|
+
*/
|
|
41
|
+
val footerKeyboardOcclusion: Int
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* A relative footer sits below the content and absorbs the bottom safe-area
|
|
45
|
+
* inset — the scrollable doesn't reach the sheet's bottom edge, so no
|
|
46
|
+
* content inset is applied (mirrors iOS, where UIKit resolves this
|
|
47
|
+
* geometrically via the scroll view's safe area).
|
|
48
|
+
*/
|
|
49
|
+
val hasRelativeFooter: Boolean
|
|
12
50
|
}
|
|
13
51
|
|
|
14
52
|
/**
|
|
@@ -16,31 +54,375 @@ interface TrueSheetContentViewDelegate {
|
|
|
16
54
|
* This is the first child of TrueSheetContainerView
|
|
17
55
|
*/
|
|
18
56
|
@SuppressLint("ViewConstructor")
|
|
19
|
-
class TrueSheetContentView(
|
|
57
|
+
class TrueSheetContentView(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
|
|
20
58
|
var delegate: TrueSheetContentViewDelegate? = null
|
|
21
59
|
|
|
22
|
-
private var
|
|
23
|
-
|
|
60
|
+
private var detectedScrollView: ViewGroup? = null
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Content height measured unconstrained by the shadow node — the height the
|
|
64
|
+
* content wants regardless of container bounds (see
|
|
65
|
+
* TrueSheetContentViewShadowNode). Falls back to the view height before the
|
|
66
|
+
* first state update.
|
|
67
|
+
*/
|
|
68
|
+
val naturalHeight: Int
|
|
69
|
+
get() = if (lastNaturalHeight > 0) lastNaturalHeight else height
|
|
70
|
+
|
|
71
|
+
private var lastNaturalHeight = 0
|
|
72
|
+
|
|
73
|
+
fun updateNaturalHeight(heightDp: Double) {
|
|
74
|
+
val heightPx = heightDp.toFloat().dpToPx().toInt()
|
|
75
|
+
if (heightPx == lastNaturalHeight) return
|
|
76
|
+
lastNaturalHeight = heightPx
|
|
77
|
+
delegate?.contentViewDidChangeSize(width, heightPx)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private var keyboardScrollOffset: Float = 0f
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Adjustment added to the keyboard bottom inset applied to the detected
|
|
84
|
+
* scrollable — negative values reduce the inset (e.g. to cancel out safe-area
|
|
85
|
+
* padding already baked into the content's paddingBottom).
|
|
86
|
+
*/
|
|
87
|
+
private var keyboardOffset: Float = 0f
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* How much of keyboardOffset actually landed in the applied inset — the
|
|
91
|
+
* caret reveal compensates by this so it still targets the real keyboard edge.
|
|
92
|
+
*/
|
|
93
|
+
private var appliedKeyboardOffset = 0
|
|
94
|
+
|
|
95
|
+
private var keyboardObserver: TrueSheetKeyboardObserver? = null
|
|
96
|
+
|
|
97
|
+
private var watchedEditText: EditText? = null
|
|
98
|
+
private var caretTextWatcher: TextWatcher? = null
|
|
99
|
+
|
|
100
|
+
var scrollableOptions: ScrollableOptions? = null
|
|
101
|
+
set(value) {
|
|
102
|
+
field = value
|
|
103
|
+
keyboardScrollOffset = value?.keyboardScrollOffset?.dpToPx() ?: 0f
|
|
104
|
+
keyboardOffset = value?.keyboardOffset?.dpToPx() ?: 0f
|
|
105
|
+
updateContentInset()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Bottom safe-area inset applied to the scrollable's content padding while
|
|
110
|
+
* the content can scroll — Android counterpart of iOS's
|
|
111
|
+
* `contentInsetAdjustmentBehavior="automatic"`. Already zero when the
|
|
112
|
+
* sheet's `insetAdjustment` is `'never'`.
|
|
113
|
+
*/
|
|
114
|
+
var bottomInset: Int = 0
|
|
115
|
+
set(value) {
|
|
116
|
+
if (field == value) return
|
|
117
|
+
field = value
|
|
118
|
+
updateContentInset()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private var baseBottomInset = 0
|
|
122
|
+
private var keyboardBottomInset = 0
|
|
123
|
+
|
|
124
|
+
private val scrollableLayoutListener = ViewTreeObserver.OnGlobalLayoutListener {
|
|
125
|
+
updateContentInset()
|
|
126
|
+
clampScrollPosition()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private val scrollContentLayoutListener = View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
|
130
|
+
updateContentInset()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override fun onAttachedToWindow() {
|
|
134
|
+
super.onAttachedToWindow()
|
|
135
|
+
viewTreeObserver.addOnGlobalLayoutListener(scrollableLayoutListener)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override fun onDetachedFromWindow() {
|
|
139
|
+
viewTreeObserver.removeOnGlobalLayoutListener(scrollableLayoutListener)
|
|
140
|
+
super.onDetachedFromWindow()
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* React tag of the user-provided scrollable (see the `scrollableRef` prop).
|
|
145
|
+
* Setting a new handle clears the currently resolved ScrollView.
|
|
146
|
+
*/
|
|
147
|
+
var scrollableHandle: Int = -1
|
|
148
|
+
set(value) {
|
|
149
|
+
if (field == value) return
|
|
150
|
+
field = value
|
|
151
|
+
clearScrollable()
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
override fun addView(child: View?, index: Int) {
|
|
155
|
+
super.addView(child, index)
|
|
156
|
+
checkScrollViewChanged()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override fun removeViewAt(index: Int) {
|
|
160
|
+
super.removeViewAt(index)
|
|
161
|
+
checkScrollViewChanged()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private fun checkScrollViewChanged() {
|
|
165
|
+
if (detectedScrollView == null || detectedScrollView?.isDescendantOf(this) == false) {
|
|
166
|
+
delegate?.contentViewScrollViewDidChange()
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
fun setupScrollable() {
|
|
171
|
+
// Check if the detected scroll view is still valid (still in view hierarchy)
|
|
172
|
+
if (detectedScrollView != null && detectedScrollView?.isDescendantOf(this) == false) {
|
|
173
|
+
clearScrollable()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (detectedScrollView != null) {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
val scrollView = findScrollView() ?: return
|
|
181
|
+
|
|
182
|
+
detectedScrollView = scrollView
|
|
183
|
+
|
|
184
|
+
scrollView.isNestedScrollingEnabled = true
|
|
185
|
+
(scrollView.parent as? SwipeRefreshLayout)?.isNestedScrollingEnabled = false
|
|
186
|
+
|
|
187
|
+
scrollView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
|
188
|
+
if (scrollY != oldScrollY) {
|
|
189
|
+
delegate?.contentViewDidScroll()
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Restore the inset before ReactScrollView's listener clamps the offset.
|
|
194
|
+
scrollView.getChildAt(0)?.let { child ->
|
|
195
|
+
if (scrollView is View.OnLayoutChangeListener) child.removeOnLayoutChangeListener(scrollView)
|
|
196
|
+
child.addOnLayoutChangeListener(scrollContentLayoutListener)
|
|
197
|
+
if (scrollView is View.OnLayoutChangeListener) child.addOnLayoutChangeListener(scrollView)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
updateContentInset()
|
|
201
|
+
|
|
202
|
+
// If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
|
|
203
|
+
val keyboardHeight = keyboardObserver?.currentHeight ?: 0
|
|
204
|
+
if (keyboardHeight > 0) {
|
|
205
|
+
updateScrollViewInsetForKeyboard(keyboardHeight)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Re-applies the base content inset — the bottom safe-area inset while the
|
|
211
|
+
* content can scroll, no relative footer absorbs it, and
|
|
212
|
+
* `contentInsetAdjustmentBehavior` isn't disabled.
|
|
213
|
+
*/
|
|
214
|
+
fun updateContentInset() {
|
|
215
|
+
val scrollView = detectedScrollView ?: return
|
|
24
216
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
217
|
+
val enabled = scrollableOptions?.contentInsetAdjustment ?: true
|
|
218
|
+
baseBottomInset = if (enabled && delegate?.hasRelativeFooter != true && canScrollContent(scrollView)) {
|
|
219
|
+
bottomInset
|
|
220
|
+
} else {
|
|
221
|
+
0
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
applyBottomInset()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Fabric's measured height excludes the native inset, avoiding feedback.
|
|
228
|
+
private fun canScrollContent(scrollView: ViewGroup): Boolean {
|
|
229
|
+
val child = scrollView.getChildAt(0) ?: return false
|
|
230
|
+
return child.measuredHeight > scrollView.height - scrollView.paddingTop - scrollView.paddingBottom
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// The keyboard covers the safe-area region, so the larger inset wins over a sum
|
|
234
|
+
private fun applyBottomInset() {
|
|
235
|
+
setScrollContentInset(maxOf(baseBottomInset, keyboardBottomInset))
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private fun setScrollContentInset(inset: Int) {
|
|
239
|
+
val scrollView = detectedScrollView ?: return
|
|
240
|
+
val child = scrollView.getChildAt(0) ?: return
|
|
241
|
+
scrollView.clipToPadding = false
|
|
242
|
+
// ScrollView's canScrollVertically ignores bottom padding. Extend the
|
|
243
|
+
// content bounds instead, keeping Fabric's measured height as the baseline.
|
|
244
|
+
child.bottom = child.top + child.measuredHeight + inset
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
fun clearScrollable() {
|
|
248
|
+
detectedScrollView?.setOnScrollChangeListener(null as View.OnScrollChangeListener?)
|
|
249
|
+
detectedScrollView?.getChildAt(0)?.removeOnLayoutChangeListener(scrollContentLayoutListener)
|
|
250
|
+
detectedScrollView?.isNestedScrollingEnabled = false
|
|
251
|
+
(detectedScrollView?.parent as? SwipeRefreshLayout)?.isNestedScrollingEnabled = true
|
|
252
|
+
setScrollContentInset(0)
|
|
253
|
+
detectedScrollView = null
|
|
254
|
+
baseBottomInset = 0
|
|
255
|
+
keyboardBottomInset = 0
|
|
256
|
+
appliedKeyboardOffset = 0
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Resolves the user-provided `scrollableHandle` within the content subtree —
|
|
261
|
+
* React tags are view ids on Android.
|
|
262
|
+
*/
|
|
263
|
+
fun findScrollView(): ViewGroup? {
|
|
264
|
+
if (detectedScrollView != null) return detectedScrollView
|
|
265
|
+
if (scrollableHandle <= 0) return null
|
|
266
|
+
return findViewById<View>(scrollableHandle) as? ViewGroup
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ==================== Keyboard Handling ====================
|
|
270
|
+
|
|
271
|
+
fun setupKeyboardHandler() {
|
|
272
|
+
if (keyboardObserver != null) return
|
|
273
|
+
|
|
274
|
+
keyboardObserver = TrueSheetKeyboardObserver(this, reactContext).apply {
|
|
275
|
+
delegate = object : TrueSheetKeyboardObserverDelegate {
|
|
276
|
+
// Drive the inset per keyboard animation frame so the content tracks
|
|
277
|
+
// the keyboard edge instead of jumping to the final inset up front.
|
|
278
|
+
// On hide, the shrinking inset gradually clamps the scroll position
|
|
279
|
+
// back in sync with the keyboard.
|
|
280
|
+
override fun keyboardDidChangeHeight(height: Int) {
|
|
281
|
+
updateScrollViewInsetForKeyboard(height)
|
|
282
|
+
|
|
283
|
+
// Follow the caret frame-by-frame — only API 30+ delivers
|
|
284
|
+
// incremental heights; legacy fires once after the keyboard is
|
|
285
|
+
// already up, where keyboardDidShow's smooth reveal takes over
|
|
286
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !isHiding) {
|
|
287
|
+
scrollToFocusedInput(smooth = false)
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
override fun keyboardDidShow(height: Int) {
|
|
292
|
+
attachCaretListener()
|
|
293
|
+
scrollToFocusedInput()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
override fun keyboardWillHide() {
|
|
297
|
+
detachCaretListener()
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
override fun focusDidChange(newFocus: View) {
|
|
301
|
+
attachCaretListener()
|
|
302
|
+
scrollToFocusedInput()
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
start()
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
fun cleanupKeyboardHandler() {
|
|
310
|
+
detachCaretListener()
|
|
311
|
+
keyboardObserver?.stop()
|
|
312
|
+
keyboardObserver = null
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private fun attachCaretListener() {
|
|
316
|
+
val focused = findFocus() as? EditText
|
|
317
|
+
if (focused === watchedEditText) return
|
|
33
318
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
val newHeight = bottom - top
|
|
319
|
+
detachCaretListener()
|
|
320
|
+
if (focused == null) return
|
|
37
321
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
322
|
+
val watcher = object : TextWatcher {
|
|
323
|
+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
|
324
|
+
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
|
325
|
+
override fun afterTextChanged(s: Editable?) {
|
|
326
|
+
focused.post { scrollToFocusedInput() }
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
focused.addTextChangedListener(watcher)
|
|
331
|
+
watchedEditText = focused
|
|
332
|
+
caretTextWatcher = watcher
|
|
333
|
+
}
|
|
41
334
|
|
|
42
|
-
|
|
43
|
-
|
|
335
|
+
private fun detachCaretListener() {
|
|
336
|
+
caretTextWatcher?.let { watchedEditText?.removeTextChangedListener(it) }
|
|
337
|
+
caretTextWatcher = null
|
|
338
|
+
watchedEditText = null
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
private fun updateScrollViewInsetForKeyboard(keyboardHeight: Int) {
|
|
342
|
+
// A relative footer stays behind the keyboard below the content, so its
|
|
343
|
+
// height shields that much of the keyboard's overlap. An absolute footer
|
|
344
|
+
// floats within the viewport — its clearance is the content padding's job
|
|
345
|
+
// (the caret reveal accounts for it, see scrollToFocusedInput).
|
|
346
|
+
keyboardBottomInset = if (keyboardHeight > 0) {
|
|
347
|
+
val baseInset = maxOf(0, keyboardHeight + minOf(0, delegate?.footerKeyboardOcclusion ?: 0))
|
|
348
|
+
val adjustedInset = maxOf(0, baseInset + keyboardOffset.toInt())
|
|
349
|
+
appliedKeyboardOffset = adjustedInset - baseInset
|
|
350
|
+
adjustedInset
|
|
351
|
+
} else {
|
|
352
|
+
appliedKeyboardOffset = 0
|
|
353
|
+
0
|
|
44
354
|
}
|
|
355
|
+
applyBottomInset()
|
|
356
|
+
clampScrollPosition()
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Content bounds changes don't re-clamp the scroll position until the next layout
|
|
360
|
+
// pass — clamp synchronously so the content follows the shrinking inset on
|
|
361
|
+
// every keyboard frame instead of snapping afterwards
|
|
362
|
+
private fun clampScrollPosition() {
|
|
363
|
+
val scrollView = detectedScrollView ?: return
|
|
364
|
+
val child = scrollView.getChildAt(0) ?: return
|
|
365
|
+
val maxScrollY = maxOf(0, child.height - (scrollView.height - scrollView.paddingTop - scrollView.paddingBottom))
|
|
366
|
+
if (scrollView.scrollY > maxScrollY) {
|
|
367
|
+
scrollView.scrollTo(scrollView.scrollX, maxScrollY)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
private fun scrollToFocusedInput(smooth: Boolean = true) {
|
|
372
|
+
val scrollView = detectedScrollView ?: findScrollView() ?: return
|
|
373
|
+
val focusedView = findFocus() ?: return
|
|
374
|
+
|
|
375
|
+
val focusedLocation = IntArray(2)
|
|
376
|
+
val scrollViewLocation = IntArray(2)
|
|
377
|
+
focusedView.getLocationOnScreen(focusedLocation)
|
|
378
|
+
scrollView.getLocationOnScreen(scrollViewLocation)
|
|
379
|
+
|
|
380
|
+
val viewTop = focusedLocation[1] - scrollViewLocation[1] + scrollView.scrollY
|
|
381
|
+
|
|
382
|
+
// Resolve the caret's line within the focused input so we follow the cursor
|
|
383
|
+
// rather than the input's full bounds (which over-scrolls tall inputs).
|
|
384
|
+
val editText = focusedView as? EditText
|
|
385
|
+
val layout = editText?.layout
|
|
386
|
+
|
|
387
|
+
val caretTop: Int
|
|
388
|
+
val caretBottom: Int
|
|
389
|
+
if (editText != null && layout != null) {
|
|
390
|
+
val line = layout.getLineForOffset(editText.selectionEnd.coerceAtLeast(0))
|
|
391
|
+
val textTop = viewTop + editText.totalPaddingTop - editText.scrollY
|
|
392
|
+
caretTop = textTop + layout.getLineTop(line)
|
|
393
|
+
caretBottom = textTop + layout.getLineBottom(line)
|
|
394
|
+
} else {
|
|
395
|
+
caretTop = viewTop
|
|
396
|
+
caretBottom = viewTop + focusedView.height
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// An absolute footer floats over the viewport's bottom edge — extend the
|
|
400
|
+
// caret target so it clears the footer, not just the keyboard.
|
|
401
|
+
val footerOcclusion = maxOf(0, delegate?.footerKeyboardOcclusion ?: 0)
|
|
402
|
+
|
|
403
|
+
val offset = keyboardScrollOffset.toInt()
|
|
404
|
+
val visibleHeight = scrollView.height - scrollView.paddingBottom - maxOf(baseBottomInset, keyboardBottomInset) + appliedKeyboardOffset
|
|
405
|
+
val visibleTop = scrollView.scrollY
|
|
406
|
+
val visibleBottom = scrollView.scrollY + visibleHeight
|
|
407
|
+
|
|
408
|
+
val targetY = when {
|
|
409
|
+
caretBottom + offset + footerOcclusion > visibleBottom ->
|
|
410
|
+
caretBottom + offset + footerOcclusion - visibleHeight
|
|
411
|
+
|
|
412
|
+
caretTop - offset < visibleTop ->
|
|
413
|
+
(caretTop - offset).coerceAtLeast(0)
|
|
414
|
+
|
|
415
|
+
else -> return
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (smooth) {
|
|
419
|
+
scrollView.smoothScrollTo(0, targetY)
|
|
420
|
+
} else {
|
|
421
|
+
scrollView.scrollTo(0, targetY)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
companion object {
|
|
426
|
+
const val TAG_NAME = "TrueSheet"
|
|
45
427
|
}
|
|
46
428
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
package com.lodev09.truesheet
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.module.annotations.ReactModule
|
|
4
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
5
|
+
import com.facebook.react.uimanager.ReactStylesDiffMap
|
|
6
|
+
import com.facebook.react.uimanager.StateWrapper
|
|
4
7
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
8
|
import com.facebook.react.uimanager.ViewGroupManager
|
|
9
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* ViewManager for TrueSheetContentView
|
|
@@ -15,6 +19,20 @@ class TrueSheetContentViewManager : ViewGroupManager<TrueSheetContentView>() {
|
|
|
15
19
|
|
|
16
20
|
override fun createViewInstance(reactContext: ThemedReactContext): TrueSheetContentView = TrueSheetContentView(reactContext)
|
|
17
21
|
|
|
22
|
+
override fun updateState(view: TrueSheetContentView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
|
|
23
|
+
stateWrapper?.stateData?.let { data ->
|
|
24
|
+
if (data.hasKey("naturalHeight")) {
|
|
25
|
+
view.updateNaturalHeight(data.getDouble("naturalHeight"))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@ReactProp(name = "pointerEvents")
|
|
32
|
+
fun setPointerEvents(view: TrueSheetContentView, pointerEventsStr: String?) {
|
|
33
|
+
view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
|
|
34
|
+
}
|
|
35
|
+
|
|
18
36
|
companion object {
|
|
19
37
|
const val REACT_CLASS = "TrueSheetContentView"
|
|
20
38
|
}
|
|
@@ -1,47 +1,171 @@
|
|
|
1
1
|
package com.lodev09.truesheet
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.view.MotionEvent
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewParent
|
|
7
|
+
import com.facebook.react.bridge.WritableNativeMap
|
|
8
|
+
import com.facebook.react.uimanager.JSPointerDispatcher
|
|
9
|
+
import com.facebook.react.uimanager.JSTouchDispatcher
|
|
10
|
+
import com.facebook.react.uimanager.PixelUtil.pxToDp
|
|
11
|
+
import com.facebook.react.uimanager.PointerEvents
|
|
12
|
+
import com.facebook.react.uimanager.RootView
|
|
13
|
+
import com.facebook.react.uimanager.StateWrapper
|
|
4
14
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
15
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
5
16
|
import com.facebook.react.views.view.ReactViewGroup
|
|
17
|
+
import com.lodev09.truesheet.core.TrueSheetCoordinatorLayout
|
|
18
|
+
import com.lodev09.truesheet.utils.TouchEventDeduper
|
|
6
19
|
|
|
7
20
|
/**
|
|
8
|
-
* Delegate interface for footer view size changes
|
|
21
|
+
* Delegate interface for footer view size changes and event dispatching
|
|
9
22
|
*/
|
|
10
23
|
interface TrueSheetFooterViewDelegate {
|
|
11
24
|
fun footerViewDidChangeSize(width: Int, height: Int)
|
|
25
|
+
val eventDispatcher: EventDispatcher?
|
|
12
26
|
}
|
|
13
27
|
|
|
14
28
|
/**
|
|
15
29
|
* Footer view that holds the footer content
|
|
16
30
|
* This is the second child of TrueSheetContainerView
|
|
17
31
|
* Positioned absolutely at the bottom of the sheet
|
|
32
|
+
*
|
|
33
|
+
* Implements RootView to handle touch events when positioned outside parent bounds.
|
|
18
34
|
*/
|
|
19
35
|
@SuppressLint("ViewConstructor")
|
|
20
|
-
class TrueSheetFooterView(
|
|
36
|
+
class TrueSheetFooterView(private val reactContext: ThemedReactContext) :
|
|
37
|
+
ReactViewGroup(reactContext),
|
|
38
|
+
RootView {
|
|
39
|
+
|
|
21
40
|
var delegate: TrueSheetFooterViewDelegate? = null
|
|
41
|
+
var stateWrapper: StateWrapper? = null
|
|
42
|
+
|
|
43
|
+
private val eventDispatcher: EventDispatcher?
|
|
44
|
+
get() = delegate?.eventDispatcher
|
|
22
45
|
|
|
23
46
|
private var lastWidth = 0
|
|
24
47
|
private var lastHeight = 0
|
|
25
48
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
var bottomInset = 0
|
|
50
|
+
private set
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Height the footer occupies above the keyboard — its layout height minus
|
|
54
|
+
* the safe-area inset, which rides below the keyboard's top edge while the
|
|
55
|
+
* keyboard is open (see positionFooter).
|
|
56
|
+
*/
|
|
57
|
+
val keyboardOcclusionHeight: Int
|
|
58
|
+
get() = maxOf(0, height - bottomInset)
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Tells the shadow node to pad the footer's bottom edge with the sheet's
|
|
62
|
+
* bottom safe-area inset — the footer owns the sheet's bottom edge, so it
|
|
63
|
+
* absorbs the inset and its background fills it.
|
|
64
|
+
*/
|
|
65
|
+
fun setBottomInset(inset: Int) {
|
|
66
|
+
if (bottomInset == inset) return
|
|
67
|
+
bottomInset = inset
|
|
68
|
+
|
|
69
|
+
val sw = stateWrapper ?: return
|
|
70
|
+
val insetDp = bottomInset.toFloat().pxToDp()
|
|
71
|
+
|
|
72
|
+
// Synchronous update — the footer must be padded before detents are
|
|
73
|
+
// configured, otherwise the auto detent is set up an inset short
|
|
74
|
+
if (TrueSheetStateUpdater.updateFooterState(sw, insetDp)) return
|
|
75
|
+
|
|
76
|
+
// Fallback: async state update
|
|
77
|
+
val newState = WritableNativeMap()
|
|
78
|
+
newState.putDouble("bottomInset", insetDp.toDouble())
|
|
79
|
+
sw.updateState(newState)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private val jsTouchDispatcher = JSTouchDispatcher(this)
|
|
83
|
+
private var jsPointerDispatcher: JSPointerDispatcher? = null
|
|
84
|
+
private val touchDeduper = TouchEventDeduper()
|
|
85
|
+
|
|
86
|
+
init {
|
|
87
|
+
jsPointerDispatcher = JSPointerDispatcher(this)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
91
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
92
|
+
|
|
93
|
+
if (w != lastWidth || h != lastHeight) {
|
|
94
|
+
lastWidth = w
|
|
95
|
+
lastHeight = h
|
|
96
|
+
delegate?.footerViewDidChangeSize(w, h)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ==================== RootView Implementation ====================
|
|
101
|
+
|
|
102
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
103
|
+
eventDispatcher?.let { dispatcher ->
|
|
104
|
+
if (touchDeduper.shouldDispatch(event)) {
|
|
105
|
+
jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
106
|
+
}
|
|
107
|
+
jsPointerDispatcher?.handleMotionEvent(event, dispatcher, true)
|
|
108
|
+
}
|
|
109
|
+
return super.onInterceptTouchEvent(event)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
|
113
|
+
// Mirrors ReactSurfaceView: keep receiving onInterceptTouchEvent so
|
|
114
|
+
// jsTouchDispatcher sees the gesture end, but forward the request up the tree.
|
|
115
|
+
parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
119
|
+
if (pointerEvents == PointerEvents.NONE || pointerEvents == PointerEvents.BOX_NONE) {
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
eventDispatcher?.let { dispatcher ->
|
|
124
|
+
if (touchDeduper.shouldDispatch(event)) {
|
|
125
|
+
jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
126
|
+
}
|
|
127
|
+
jsPointerDispatcher?.handleMotionEvent(event, dispatcher, false)
|
|
128
|
+
}
|
|
129
|
+
super.onTouchEvent(event)
|
|
130
|
+
return true
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
|
|
134
|
+
eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, true) }
|
|
135
|
+
return super.onHoverEvent(event)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
override fun onHoverEvent(event: MotionEvent): Boolean {
|
|
139
|
+
eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, false) }
|
|
140
|
+
return super.onHoverEvent(event)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
|
|
144
|
+
findCoordinatorLayout()?.childDidClaimNativeGesture()
|
|
145
|
+
eventDispatcher?.let { dispatcher ->
|
|
146
|
+
jsTouchDispatcher.onChildStartedNativeGesture(ev, dispatcher)
|
|
147
|
+
jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, dispatcher)
|
|
45
148
|
}
|
|
46
149
|
}
|
|
150
|
+
|
|
151
|
+
private fun findCoordinatorLayout(): TrueSheetCoordinatorLayout? {
|
|
152
|
+
var current: ViewParent? = parent
|
|
153
|
+
while (current != null && current !is TrueSheetCoordinatorLayout) {
|
|
154
|
+
current = current.parent
|
|
155
|
+
}
|
|
156
|
+
return current as? TrueSheetCoordinatorLayout
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
|
|
160
|
+
eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
|
|
161
|
+
jsPointerDispatcher?.onChildEndedNativeGesture()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
override fun handleException(t: Throwable) {
|
|
165
|
+
reactContext.reactApplicationContext.handleException(RuntimeException(t))
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
companion object {
|
|
169
|
+
const val TAG_NAME = "TrueSheet"
|
|
170
|
+
}
|
|
47
171
|
}
|