@lodev09/react-native-true-sheet 4.0.0-beta.0 → 4.0.0-beta.2
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 +42 -31
- package/RNTrueSheet.podspec +10 -2
- package/android/build.gradle +2 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +174 -49
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerViewManager.kt +7 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +371 -18
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +14 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +156 -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/TrueSheetPackage.kt +5 -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 +45 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +526 -231
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +1224 -603
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +136 -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 +303 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +277 -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/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 +112 -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 +30 -0
- package/android/src/main/jni/CMakeLists.txt +63 -0
- package/android/src/main/jni/TrueSheetSpec.h +19 -0
- package/android/src/main/jni/TrueSheetStateUpdater.cpp +96 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +24 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +43 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +28 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +11 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +37 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +24 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +56 -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/TrueSheetViewComponentDescriptor.h +28 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +61 -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 +81 -6
- package/ios/TrueSheetContainerView.mm +275 -21
- package/ios/TrueSheetContentView.h +38 -1
- package/ios/TrueSheetContentView.mm +413 -43
- package/ios/TrueSheetFooterView.h +27 -2
- package/ios/TrueSheetFooterView.mm +141 -35
- package/ios/{events/OnDidDismissEvent.h → TrueSheetHeaderView.h} +10 -7
- package/ios/TrueSheetHeaderView.mm +64 -0
- package/ios/TrueSheetModule.mm +92 -5
- package/ios/TrueSheetPeekView.h +32 -0
- package/ios/TrueSheetPeekView.mm +99 -0
- package/ios/TrueSheetView.h +7 -15
- package/ios/TrueSheetView.mm +633 -215
- package/ios/TrueSheetViewController.h +84 -16
- package/ios/TrueSheetViewController.mm +1133 -333
- 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 +178 -0
- package/ios/core/TrueSheetKeyboardObserver.h +39 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +112 -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 +40 -0
- package/ios/events/TrueSheetLifecycleEvents.mm +71 -0
- package/ios/events/TrueSheetStateEvents.h +35 -0
- package/ios/events/TrueSheetStateEvents.mm +49 -0
- package/ios/tvos/TrueSheetStubs.mm +154 -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/{events/OnWillDismissEvent.h → utils/UIView+ScrollEdgeInteraction.h} +6 -7
- package/ios/utils/UIView+ScrollEdgeInteraction.mm +62 -0
- package/ios/utils/WindowUtil.mm +17 -1
- package/lib/module/TrueSheet.js +230 -64
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +1203 -0
- package/lib/module/TrueSheet.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/TrueSheetPeekViewNativeComponent.ts +8 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +105 -18
- package/lib/module/index.js +3 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks/index.js +93 -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/createTrueSheetRouter.js +166 -0
- package/lib/module/navigation/createTrueSheetRouter.js.map +1 -0
- package/lib/module/navigation/expo-router/index.js +48 -0
- package/lib/module/navigation/expo-router/index.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 +68 -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 +15 -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 +1309 -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 +51 -14
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +463 -54
- 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/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/TrueSheetPeekViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetPeekViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +67 -16
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/index.d.ts +43 -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/createTrueSheetRouter.d.ts +14 -0
- package/lib/typescript/src/navigation/createTrueSheetRouter.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/index.d.ts +46 -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 +33 -0
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -0
- package/lib/typescript/src/navigation/types.d.ts +177 -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 +13 -0
- package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/context.d.ts +53 -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 +228 -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 +95 -36
- package/react-native.config.js +9 -2
- package/src/TrueSheet.tsx +281 -62
- package/src/TrueSheet.types.ts +525 -71
- package/src/TrueSheet.web.tsx +1362 -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/TrueSheetPeekViewNativeComponent.ts +8 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +105 -18
- package/src/index.ts +2 -2
- package/src/mocks/index.ts +89 -0
- package/src/mocks/navigation.ts +79 -0
- package/src/mocks/navigationExpoRouter.ts +40 -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/createTrueSheetRouter.ts +222 -0
- package/src/navigation/expo-router/index.ts +89 -0
- package/src/navigation/index.ts +81 -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 +100 -0
- package/src/navigation/types.ts +251 -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 +20 -0
- package/src/web/vaul/context.ts +101 -0
- package/src/web/vaul/helpers.ts +131 -0
- package/src/web/vaul/index.tsx +1740 -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.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,41 @@
|
|
|
1
1
|
package com.lodev09.truesheet
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.text.Editable
|
|
5
|
+
import android.text.TextWatcher
|
|
6
|
+
import android.view.View
|
|
7
|
+
import android.view.ViewGroup
|
|
8
|
+
import android.widget.EditText
|
|
9
|
+
import android.widget.ScrollView
|
|
10
|
+
import androidx.core.widget.NestedScrollView
|
|
11
|
+
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|
12
|
+
import com.facebook.react.bridge.WritableNativeMap
|
|
13
|
+
import com.facebook.react.uimanager.PixelUtil.dpToPx
|
|
14
|
+
import com.facebook.react.uimanager.StateWrapper
|
|
4
15
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
5
16
|
import com.facebook.react.views.view.ReactViewGroup
|
|
17
|
+
import com.lodev09.truesheet.core.TrueSheetKeyboardObserver
|
|
18
|
+
import com.lodev09.truesheet.core.TrueSheetKeyboardObserverDelegate
|
|
19
|
+
import com.lodev09.truesheet.utils.isDescendantOf
|
|
20
|
+
import com.lodev09.truesheet.utils.smoothScrollBy
|
|
21
|
+
import com.lodev09.truesheet.utils.smoothScrollTo
|
|
22
|
+
|
|
23
|
+
data class ScrollableOptions(val keyboardScrollOffset: Float = 0f, val scrollingExpandsSheet: Boolean = true)
|
|
6
24
|
|
|
7
25
|
/**
|
|
8
26
|
* Delegate interface for content view size changes
|
|
9
27
|
*/
|
|
10
28
|
interface TrueSheetContentViewDelegate {
|
|
11
29
|
fun contentViewDidChangeSize(width: Int, height: Int)
|
|
30
|
+
fun contentViewDidScroll()
|
|
31
|
+
fun contentViewScrollViewDidChange()
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Keyboard occlusion adjustment below the content — positive for an absolute
|
|
35
|
+
* footer risen above the keyboard covering the content's bottom edge,
|
|
36
|
+
* negative for a relative footer sitting behind the keyboard shielding it.
|
|
37
|
+
*/
|
|
38
|
+
val footerKeyboardOcclusion: Int
|
|
12
39
|
}
|
|
13
40
|
|
|
14
41
|
/**
|
|
@@ -16,31 +43,357 @@ interface TrueSheetContentViewDelegate {
|
|
|
16
43
|
* This is the first child of TrueSheetContainerView
|
|
17
44
|
*/
|
|
18
45
|
@SuppressLint("ViewConstructor")
|
|
19
|
-
class TrueSheetContentView(
|
|
46
|
+
class TrueSheetContentView(private val reactContext: ThemedReactContext) : ReactViewGroup(reactContext) {
|
|
20
47
|
var delegate: TrueSheetContentViewDelegate? = null
|
|
48
|
+
var stateWrapper: StateWrapper? = null
|
|
21
49
|
|
|
22
50
|
private var lastWidth = 0
|
|
23
51
|
private var lastHeight = 0
|
|
24
52
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
53
|
+
private var pinnedScrollView: ViewGroup? = null
|
|
54
|
+
private var observedScrollChild: View? = null
|
|
55
|
+
private var originalScrollViewPaddingBottom: Int = 0
|
|
56
|
+
private var bottomInset: Int = 0
|
|
57
|
+
private var scrollableBounded = false
|
|
58
|
+
private var isReportPending = false
|
|
59
|
+
|
|
60
|
+
// Content growth is invisible to layout once the viewport is bounded, so track
|
|
61
|
+
// the scroll content size directly to keep the auto detent height in sync.
|
|
62
|
+
private val scrollChildLayoutListener =
|
|
63
|
+
View.OnLayoutChangeListener { _, _, top, _, bottom, _, oldTop, _, oldBottom ->
|
|
64
|
+
if (bottom - top != oldBottom - oldTop) {
|
|
65
|
+
reportSizeIfChanged()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Content height with the pinned ScrollView's viewport replaced by its content
|
|
71
|
+
* size — the height the content wants regardless of container bounds.
|
|
72
|
+
* Falls back to the view height when no ScrollView is pinned.
|
|
73
|
+
*/
|
|
74
|
+
val naturalHeight: Int
|
|
75
|
+
get() {
|
|
76
|
+
var naturalHeight = height
|
|
77
|
+
pinnedScrollView?.let { scrollView ->
|
|
78
|
+
scrollView.getChildAt(0)?.let { child ->
|
|
79
|
+
naturalHeight += child.height - scrollView.height
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return maxOf(0, naturalHeight)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private var keyboardScrollOffset: Float = 0f
|
|
86
|
+
private var keyboardObserver: TrueSheetKeyboardObserver? = null
|
|
87
|
+
|
|
88
|
+
private var watchedEditText: EditText? = null
|
|
89
|
+
private var caretTextWatcher: TextWatcher? = null
|
|
90
|
+
|
|
91
|
+
var scrollableOptions: ScrollableOptions? = null
|
|
92
|
+
set(value) {
|
|
93
|
+
field = value
|
|
94
|
+
keyboardScrollOffset = value?.keyboardScrollOffset?.dpToPx() ?: 0f
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Whether the sheet has an `auto` detent. Deriving the sheet height from the
|
|
99
|
+
* scroll content is circular with natural layout, so the pinned ScrollView's
|
|
100
|
+
* viewport is force-bounded to the container only in this case.
|
|
101
|
+
*/
|
|
102
|
+
var hasAutoDetent = false
|
|
103
|
+
set(value) {
|
|
104
|
+
if (field == value) return
|
|
105
|
+
field = value
|
|
106
|
+
if (pinnedScrollView != null) {
|
|
107
|
+
setScrollableBounded(value)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
override fun addView(child: View?, index: Int) {
|
|
112
|
+
super.addView(child, index)
|
|
113
|
+
checkScrollViewChanged()
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override fun removeViewAt(index: Int) {
|
|
117
|
+
super.removeViewAt(index)
|
|
118
|
+
checkScrollViewChanged()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private fun checkScrollViewChanged() {
|
|
122
|
+
if (pinnedScrollView == null || pinnedScrollView?.isDescendantOf(this) == false) {
|
|
123
|
+
delegate?.contentViewScrollViewDidChange()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
128
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
129
|
+
reportSizeIfChanged()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private fun reportSizeIfChanged() {
|
|
133
|
+
// naturalHeight mixes sizes from different views; mid-layout they're
|
|
134
|
+
// momentarily inconsistent (parent resizes before its children), which
|
|
135
|
+
// feeds back into the auto detent and oscillates. Coalesce to the next
|
|
136
|
+
// frame so sizes are settled before measuring.
|
|
137
|
+
if (pinnedScrollView != null) {
|
|
138
|
+
if (isReportPending) return
|
|
139
|
+
isReportPending = true
|
|
140
|
+
|
|
141
|
+
post {
|
|
142
|
+
isReportPending = false
|
|
143
|
+
reportSizeNow()
|
|
144
|
+
}
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
reportSizeNow()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private fun reportSizeNow() {
|
|
152
|
+
val newHeight = naturalHeight
|
|
153
|
+
if (width != lastWidth || newHeight != lastHeight) {
|
|
154
|
+
lastWidth = width
|
|
40
155
|
lastHeight = newHeight
|
|
156
|
+
delegate?.contentViewDidChangeSize(width, newHeight)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Tells the shadow node to fill the container (flexGrow/flexShrink) so the
|
|
162
|
+
* pinned ScrollView's viewport is bounded to the visible space. Only applied
|
|
163
|
+
* for auto detents — otherwise content lays out naturally like a regular view.
|
|
164
|
+
*/
|
|
165
|
+
private fun setScrollableBounded(bounded: Boolean) {
|
|
166
|
+
if (scrollableBounded == bounded) return
|
|
167
|
+
scrollableBounded = bounded
|
|
168
|
+
|
|
169
|
+
stateWrapper?.let {
|
|
170
|
+
val newState = WritableNativeMap()
|
|
171
|
+
newState.putBoolean("scrollableBounded", bounded)
|
|
172
|
+
it.updateState(newState)
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
fun setupScrollable(bottomInset: Int) {
|
|
177
|
+
// Check if pinned scroll view is still valid (still in view hierarchy)
|
|
178
|
+
if (pinnedScrollView != null && pinnedScrollView?.isDescendantOf(this) == false) {
|
|
179
|
+
clearScrollable()
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Already set up with same inset and valid scroll view
|
|
183
|
+
if (pinnedScrollView != null && this.bottomInset == bottomInset) {
|
|
184
|
+
return
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
val scrollView = findScrollView(this) ?: return
|
|
188
|
+
|
|
189
|
+
// Only capture originals on first pin
|
|
190
|
+
if (pinnedScrollView == null) {
|
|
191
|
+
originalScrollViewPaddingBottom = scrollView.paddingBottom
|
|
192
|
+
pinnedScrollView = scrollView
|
|
193
|
+
|
|
194
|
+
scrollView.isNestedScrollingEnabled = true
|
|
195
|
+
(scrollView.parent as? SwipeRefreshLayout)?.isNestedScrollingEnabled = false
|
|
196
|
+
|
|
197
|
+
scrollView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
|
198
|
+
if (scrollY != oldScrollY) {
|
|
199
|
+
delegate?.contentViewDidScroll()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
scrollView.getChildAt(0)?.let { child ->
|
|
204
|
+
observedScrollChild = child
|
|
205
|
+
child.addOnLayoutChangeListener(scrollChildLayoutListener)
|
|
206
|
+
}
|
|
207
|
+
setScrollableBounded(hasAutoDetent)
|
|
208
|
+
reportSizeIfChanged()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.bottomInset = bottomInset
|
|
212
|
+
|
|
213
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom + bottomInset)
|
|
41
214
|
|
|
42
|
-
|
|
43
|
-
|
|
215
|
+
// If keyboard is currently showing, re-apply the keyboard inset to the new ScrollView
|
|
216
|
+
val keyboardHeight = keyboardObserver?.currentHeight ?: 0
|
|
217
|
+
if (keyboardHeight > 0) {
|
|
218
|
+
updateScrollViewInsetForKeyboard(keyboardHeight)
|
|
44
219
|
}
|
|
45
220
|
}
|
|
221
|
+
|
|
222
|
+
private fun setScrollViewPaddingBottom(paddingBottom: Int) {
|
|
223
|
+
val scrollView = pinnedScrollView ?: return
|
|
224
|
+
scrollView.clipToPadding = false
|
|
225
|
+
scrollView.setPadding(
|
|
226
|
+
scrollView.paddingLeft,
|
|
227
|
+
scrollView.paddingTop,
|
|
228
|
+
scrollView.paddingRight,
|
|
229
|
+
paddingBottom
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
fun clearScrollable() {
|
|
234
|
+
pinnedScrollView?.setOnScrollChangeListener(null as View.OnScrollChangeListener?)
|
|
235
|
+
pinnedScrollView?.isNestedScrollingEnabled = false
|
|
236
|
+
(pinnedScrollView?.parent as? SwipeRefreshLayout)?.isNestedScrollingEnabled = true
|
|
237
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom)
|
|
238
|
+
observedScrollChild?.removeOnLayoutChangeListener(scrollChildLayoutListener)
|
|
239
|
+
observedScrollChild = null
|
|
240
|
+
setScrollableBounded(false)
|
|
241
|
+
pinnedScrollView = null
|
|
242
|
+
originalScrollViewPaddingBottom = 0
|
|
243
|
+
bottomInset = 0
|
|
244
|
+
reportSizeIfChanged()
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
fun findScrollView(): ViewGroup? {
|
|
248
|
+
if (pinnedScrollView != null) return pinnedScrollView
|
|
249
|
+
return findScrollView(this as View)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private fun findScrollView(view: View): ViewGroup? {
|
|
253
|
+
if (view is ScrollView || view is NestedScrollView) {
|
|
254
|
+
return view as ViewGroup
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (view is ViewGroup) {
|
|
258
|
+
for (i in 0 until view.childCount) {
|
|
259
|
+
val scrollView = findScrollView(view.getChildAt(i))
|
|
260
|
+
if (scrollView != null) {
|
|
261
|
+
return scrollView
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return null
|
|
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
|
+
override fun keyboardWillShow(height: Int) {
|
|
277
|
+
updateScrollViewInsetForKeyboard(height)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
override fun keyboardDidShow(height: Int) {
|
|
281
|
+
attachCaretListener()
|
|
282
|
+
scrollToFocusedInput()
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
override fun keyboardWillHide() {
|
|
286
|
+
detachCaretListener()
|
|
287
|
+
updateScrollViewInsetForKeyboard(0)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
override fun focusDidChange(newFocus: View) {
|
|
291
|
+
attachCaretListener()
|
|
292
|
+
scrollToFocusedInput()
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
start()
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
fun cleanupKeyboardHandler() {
|
|
300
|
+
detachCaretListener()
|
|
301
|
+
keyboardObserver?.stop()
|
|
302
|
+
keyboardObserver = null
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private fun attachCaretListener() {
|
|
306
|
+
val focused = findFocus() as? EditText
|
|
307
|
+
if (focused === watchedEditText) return
|
|
308
|
+
|
|
309
|
+
detachCaretListener()
|
|
310
|
+
if (focused == null) return
|
|
311
|
+
|
|
312
|
+
val watcher = object : TextWatcher {
|
|
313
|
+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
|
314
|
+
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
|
|
315
|
+
override fun afterTextChanged(s: Editable?) {
|
|
316
|
+
focused.post { scrollToFocusedInput() }
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
focused.addTextChangedListener(watcher)
|
|
321
|
+
watchedEditText = focused
|
|
322
|
+
caretTextWatcher = watcher
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private fun detachCaretListener() {
|
|
326
|
+
caretTextWatcher?.let { watchedEditText?.removeTextChangedListener(it) }
|
|
327
|
+
caretTextWatcher = null
|
|
328
|
+
watchedEditText = null
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private fun updateScrollViewInsetForKeyboard(keyboardHeight: Int) {
|
|
332
|
+
val scrollView = pinnedScrollView ?: return
|
|
333
|
+
|
|
334
|
+
// An absolute footer rises above the keyboard and covers the content's
|
|
335
|
+
// bottom edge — include it so the caret clears the footer, not just the
|
|
336
|
+
// keyboard. A relative footer stays behind the keyboard below the content,
|
|
337
|
+
// so its height shields that much of the keyboard's overlap.
|
|
338
|
+
val totalBottomInset = if (keyboardHeight > 0) {
|
|
339
|
+
maxOf(0, keyboardHeight + (delegate?.footerKeyboardOcclusion ?: 0))
|
|
340
|
+
} else {
|
|
341
|
+
bottomInset
|
|
342
|
+
}
|
|
343
|
+
setScrollViewPaddingBottom(originalScrollViewPaddingBottom + totalBottomInset)
|
|
344
|
+
|
|
345
|
+
scrollView.post { nudgeScrollView() }
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private fun nudgeScrollView() {
|
|
349
|
+
val scrollView = pinnedScrollView ?: return
|
|
350
|
+
scrollView.smoothScrollBy(0, 1)
|
|
351
|
+
scrollView.smoothScrollBy(0, -1)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
private fun scrollToFocusedInput() {
|
|
355
|
+
val scrollView = pinnedScrollView ?: findScrollView() ?: return
|
|
356
|
+
val focusedView = findFocus() ?: return
|
|
357
|
+
|
|
358
|
+
val focusedLocation = IntArray(2)
|
|
359
|
+
val scrollViewLocation = IntArray(2)
|
|
360
|
+
focusedView.getLocationOnScreen(focusedLocation)
|
|
361
|
+
scrollView.getLocationOnScreen(scrollViewLocation)
|
|
362
|
+
|
|
363
|
+
val viewTop = focusedLocation[1] - scrollViewLocation[1] + scrollView.scrollY
|
|
364
|
+
|
|
365
|
+
// Resolve the caret's line within the focused input so we follow the cursor
|
|
366
|
+
// rather than the input's full bounds (which over-scrolls tall inputs).
|
|
367
|
+
val editText = focusedView as? EditText
|
|
368
|
+
val layout = editText?.layout
|
|
369
|
+
|
|
370
|
+
val caretTop: Int
|
|
371
|
+
val caretBottom: Int
|
|
372
|
+
if (editText != null && layout != null) {
|
|
373
|
+
val line = layout.getLineForOffset(editText.selectionEnd.coerceAtLeast(0))
|
|
374
|
+
val textTop = viewTop + editText.totalPaddingTop - editText.scrollY
|
|
375
|
+
caretTop = textTop + layout.getLineTop(line)
|
|
376
|
+
caretBottom = textTop + layout.getLineBottom(line)
|
|
377
|
+
} else {
|
|
378
|
+
caretTop = viewTop
|
|
379
|
+
caretBottom = viewTop + focusedView.height
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
val offset = keyboardScrollOffset.toInt()
|
|
383
|
+
val visibleHeight = scrollView.height - scrollView.paddingBottom
|
|
384
|
+
val visibleTop = scrollView.scrollY
|
|
385
|
+
val visibleBottom = scrollView.scrollY + visibleHeight
|
|
386
|
+
|
|
387
|
+
when {
|
|
388
|
+
caretBottom + offset > visibleBottom ->
|
|
389
|
+
scrollView.smoothScrollTo(0, caretBottom + offset - visibleHeight)
|
|
390
|
+
|
|
391
|
+
caretTop - offset < visibleTop ->
|
|
392
|
+
scrollView.smoothScrollTo(0, (caretTop - offset).coerceAtLeast(0))
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
companion object {
|
|
397
|
+
const val TAG_NAME = "TrueSheet"
|
|
398
|
+
}
|
|
46
399
|
}
|
|
@@ -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,16 @@ 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
|
+
view.stateWrapper = stateWrapper
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@ReactProp(name = "pointerEvents")
|
|
28
|
+
fun setPointerEvents(view: TrueSheetContentView, pointerEventsStr: String?) {
|
|
29
|
+
view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
|
|
30
|
+
}
|
|
31
|
+
|
|
18
32
|
companion object {
|
|
19
33
|
const val REACT_CLASS = "TrueSheetContentView"
|
|
20
34
|
}
|
|
@@ -1,47 +1,182 @@
|
|
|
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
|
|
48
|
+
private var bottomInset = 0
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Skips the inset while the keyboard is open — an absolute footer rises
|
|
52
|
+
* above the keyboard, so the inset would leave a gap.
|
|
53
|
+
*/
|
|
54
|
+
var keyboardVisible = false
|
|
55
|
+
set(value) {
|
|
56
|
+
if (field == value) return
|
|
57
|
+
field = value
|
|
58
|
+
pushBottomInsetState()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Height the footer occupies above the keyboard — its layout height minus
|
|
63
|
+
* the safe-area inset it drops while the keyboard is open.
|
|
64
|
+
*/
|
|
65
|
+
val keyboardOcclusionHeight: Int
|
|
66
|
+
get() = maxOf(0, height - if (keyboardVisible) 0 else bottomInset)
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Tells the shadow node to pad the footer's bottom edge with the sheet's
|
|
70
|
+
* bottom safe-area inset — the footer owns the sheet's bottom edge, so it
|
|
71
|
+
* absorbs the inset and its background fills it.
|
|
72
|
+
*/
|
|
73
|
+
fun setBottomInset(inset: Int) {
|
|
74
|
+
if (bottomInset == inset) return
|
|
75
|
+
bottomInset = inset
|
|
76
|
+
pushBottomInsetState()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private fun pushBottomInsetState() {
|
|
80
|
+
val sw = stateWrapper ?: return
|
|
81
|
+
val insetDp = (if (keyboardVisible) 0 else bottomInset).toFloat().pxToDp()
|
|
82
|
+
|
|
83
|
+
// Synchronous update — the footer must be padded before detents are
|
|
84
|
+
// configured, otherwise the auto detent is set up an inset short
|
|
85
|
+
if (TrueSheetStateUpdater.updateFooterState(sw, insetDp)) return
|
|
86
|
+
|
|
87
|
+
// Fallback: async state update
|
|
88
|
+
val newState = WritableNativeMap()
|
|
89
|
+
newState.putDouble("bottomInset", insetDp.toDouble())
|
|
90
|
+
sw.updateState(newState)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private val jsTouchDispatcher = JSTouchDispatcher(this)
|
|
94
|
+
private var jsPointerDispatcher: JSPointerDispatcher? = null
|
|
95
|
+
private val touchDeduper = TouchEventDeduper()
|
|
96
|
+
|
|
97
|
+
init {
|
|
98
|
+
jsPointerDispatcher = JSPointerDispatcher(this)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
102
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
103
|
+
|
|
104
|
+
if (w != lastWidth || h != lastHeight) {
|
|
105
|
+
lastWidth = w
|
|
106
|
+
lastHeight = h
|
|
107
|
+
delegate?.footerViewDidChangeSize(w, h)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ==================== RootView Implementation ====================
|
|
112
|
+
|
|
113
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
114
|
+
eventDispatcher?.let { dispatcher ->
|
|
115
|
+
if (touchDeduper.shouldDispatch(event)) {
|
|
116
|
+
jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
117
|
+
}
|
|
118
|
+
jsPointerDispatcher?.handleMotionEvent(event, dispatcher, true)
|
|
119
|
+
}
|
|
120
|
+
return super.onInterceptTouchEvent(event)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
|
124
|
+
// Mirrors ReactSurfaceView: keep receiving onInterceptTouchEvent so
|
|
125
|
+
// jsTouchDispatcher sees the gesture end, but forward the request up the tree.
|
|
126
|
+
parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
|
|
127
|
+
}
|
|
25
128
|
|
|
26
|
-
override fun
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
top: Int,
|
|
30
|
-
right: Int,
|
|
31
|
-
bottom: Int
|
|
32
|
-
) {
|
|
33
|
-
super.onLayout(changed, left, top, right, bottom)
|
|
34
|
-
|
|
35
|
-
// Notify delegate when footer size changes
|
|
36
|
-
val newWidth = right - left
|
|
37
|
-
val newHeight = bottom - top
|
|
38
|
-
|
|
39
|
-
if (newWidth != lastWidth || newHeight != lastHeight) {
|
|
40
|
-
lastWidth = newWidth
|
|
41
|
-
lastHeight = newHeight
|
|
42
|
-
|
|
43
|
-
// Notify delegate of size change
|
|
44
|
-
delegate?.footerViewDidChangeSize(newWidth, newHeight)
|
|
129
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
130
|
+
if (pointerEvents == PointerEvents.NONE || pointerEvents == PointerEvents.BOX_NONE) {
|
|
131
|
+
return false
|
|
45
132
|
}
|
|
133
|
+
|
|
134
|
+
eventDispatcher?.let { dispatcher ->
|
|
135
|
+
if (touchDeduper.shouldDispatch(event)) {
|
|
136
|
+
jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
137
|
+
}
|
|
138
|
+
jsPointerDispatcher?.handleMotionEvent(event, dispatcher, false)
|
|
139
|
+
}
|
|
140
|
+
super.onTouchEvent(event)
|
|
141
|
+
return true
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
|
|
145
|
+
eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, true) }
|
|
146
|
+
return super.onHoverEvent(event)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
override fun onHoverEvent(event: MotionEvent): Boolean {
|
|
150
|
+
eventDispatcher?.let { jsPointerDispatcher?.handleMotionEvent(event, it, false) }
|
|
151
|
+
return super.onHoverEvent(event)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
|
|
155
|
+
findCoordinatorLayout()?.childDidClaimNativeGesture()
|
|
156
|
+
eventDispatcher?.let { dispatcher ->
|
|
157
|
+
jsTouchDispatcher.onChildStartedNativeGesture(ev, dispatcher)
|
|
158
|
+
jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, dispatcher)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private fun findCoordinatorLayout(): TrueSheetCoordinatorLayout? {
|
|
163
|
+
var current: ViewParent? = parent
|
|
164
|
+
while (current != null && current !is TrueSheetCoordinatorLayout) {
|
|
165
|
+
current = current.parent
|
|
166
|
+
}
|
|
167
|
+
return current as? TrueSheetCoordinatorLayout
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
|
|
171
|
+
eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
|
|
172
|
+
jsPointerDispatcher?.onChildEndedNativeGesture()
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
override fun handleException(t: Throwable) {
|
|
176
|
+
reactContext.reactApplicationContext.handleException(RuntimeException(t))
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
companion object {
|
|
180
|
+
const val TAG_NAME = "TrueSheet"
|
|
46
181
|
}
|
|
47
182
|
}
|
|
@@ -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 TrueSheetFooterView
|
|
@@ -15,6 +19,16 @@ class TrueSheetFooterViewManager : ViewGroupManager<TrueSheetFooterView>() {
|
|
|
15
19
|
|
|
16
20
|
override fun createViewInstance(reactContext: ThemedReactContext): TrueSheetFooterView = TrueSheetFooterView(reactContext)
|
|
17
21
|
|
|
22
|
+
override fun updateState(view: TrueSheetFooterView, props: ReactStylesDiffMap?, stateWrapper: StateWrapper?): Any? {
|
|
23
|
+
view.stateWrapper = stateWrapper
|
|
24
|
+
return null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@ReactProp(name = "pointerEvents")
|
|
28
|
+
fun setPointerEvents(view: TrueSheetFooterView, pointerEventsStr: String?) {
|
|
29
|
+
view.pointerEvents = PointerEvents.parsePointerEvents(pointerEventsStr)
|
|
30
|
+
}
|
|
31
|
+
|
|
18
32
|
companion object {
|
|
19
33
|
const val REACT_CLASS = "TrueSheetFooterView"
|
|
20
34
|
}
|