@lodev09/react-native-true-sheet 4.0.0-beta.3 → 4.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -5
- package/android/build.gradle +23 -1
- package/android/proguard-rules.pro +3 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContainerView.kt +50 -16
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentView.kt +303 -184
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetContentViewManager.kt +5 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetFooterView.kt +38 -109
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +13 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayView.kt +127 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetOverlayViewManager.kt +45 -0
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetPackage.kt +2 -1
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetStateUpdater.kt +29 -3
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +234 -66
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +491 -186
- package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +64 -10
- package/android/src/main/java/com/lodev09/truesheet/core/RNScreensEventObserver.kt +31 -14
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetBehavior.kt +135 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +23 -23
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +130 -6
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +104 -39
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +14 -17
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetGrabberView.kt +2 -4
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetOverlayRootView.kt +148 -0
- package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetStackManager.kt +33 -40
- package/android/src/main/java/com/lodev09/truesheet/events/TrueSheetLifecycleEvents.kt +15 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/ColorUtils.kt +19 -0
- package/android/src/main/java/com/lodev09/truesheet/utils/KeyboardUtils.kt +15 -2
- package/android/src/main/java/com/lodev09/truesheet/utils/ScreenUtils.kt +0 -12
- package/android/src/main/java/com/lodev09/truesheet/utils/ViewUtils.kt +19 -7
- package/android/src/main/jni/TrueSheetSpec.h +1 -0
- package/android/src/main/jni/TrueSheetStateUpdater.cpp +37 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h +1 -9
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.cpp +114 -30
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewShadowNode.h +30 -7
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.cpp +2 -2
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewState.h +9 -8
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.cpp +14 -3
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewShadowNode.h +5 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetFooterViewState.h +10 -6
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.cpp +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetInsets.h +1 -1
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetLayoutUtils.h +43 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h +21 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.cpp +17 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewShadowNode.h +33 -0
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.cpp +7 -40
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewShadowNode.h +3 -7
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.cpp +3 -5
- package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetViewState.h +4 -5
- package/ios/TrueSheetContainerView.h +23 -7
- package/ios/TrueSheetContainerView.mm +45 -25
- package/ios/TrueSheetContentView.h +44 -15
- package/ios/TrueSheetContentView.mm +221 -190
- package/ios/TrueSheetFooterView.mm +133 -28
- package/ios/TrueSheetModule.h +2 -7
- package/ios/TrueSheetModule.mm +18 -18
- package/ios/TrueSheetOverlayView.h +42 -0
- package/ios/TrueSheetOverlayView.mm +175 -0
- package/ios/TrueSheetView.h +2 -0
- package/ios/TrueSheetView.mm +268 -52
- package/ios/TrueSheetViewController.h +36 -3
- package/ios/TrueSheetViewController.mm +797 -102
- package/ios/core/RNScreensEventObserver.mm +31 -28
- package/ios/core/TrueSheetBlurView.h +0 -2
- package/ios/core/TrueSheetBlurView.mm +3 -36
- package/ios/core/TrueSheetDetentCalculator.h +18 -1
- package/ios/core/TrueSheetDetentCalculator.mm +44 -9
- package/ios/core/TrueSheetDimView.h +27 -0
- package/ios/core/TrueSheetDimView.mm +41 -0
- package/ios/core/TrueSheetGrabberView.mm +13 -3
- package/ios/core/TrueSheetKeyboardObserver.h +7 -0
- package/ios/core/TrueSheetKeyboardObserver.mm +107 -15
- package/ios/core/TrueSheetOverlayContainerView.h +31 -0
- package/ios/core/TrueSheetOverlayContainerView.mm +35 -0
- package/ios/events/TrueSheetLifecycleEvents.h +2 -0
- package/ios/events/TrueSheetLifecycleEvents.mm +8 -0
- package/ios/tvos/TrueSheetStubs.mm +12 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.h +1 -0
- package/ios/utils/UIView+ScrollEdgeInteraction.mm +24 -2
- package/lib/module/TrueSheet.js +222 -54
- package/lib/module/TrueSheet.js.map +1 -1
- package/lib/module/TrueSheet.web.js +364 -275
- package/lib/module/TrueSheet.web.js.map +1 -1
- package/lib/module/TrueSheetBackground.js +15 -0
- package/lib/module/TrueSheetBackground.js.map +1 -0
- package/lib/module/TrueSheetOverlay.js +30 -0
- package/lib/module/TrueSheetOverlay.js.map +1 -0
- package/lib/module/TrueSheetOverlay.web.js +35 -0
- package/lib/module/TrueSheetOverlay.web.js.map +1 -0
- package/lib/module/TrueSheetPeek.web.js +20 -15
- package/lib/module/TrueSheetPeek.web.js.map +1 -1
- package/lib/module/TrueSheetProvider.web.js +13 -9
- package/lib/module/TrueSheetProvider.web.js.map +1 -1
- package/lib/module/detentBackgrounds.js +21 -0
- package/lib/module/detentBackgrounds.js.map +1 -0
- package/lib/module/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/lib/module/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
- package/lib/module/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/lib/module/fabric/TrueSheetViewNativeComponent.ts +89 -73
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/mocks/index.js +18 -2
- package/lib/module/mocks/index.js.map +1 -1
- package/lib/module/mocks/navigationExpoRouter.js.map +1 -1
- package/lib/module/navigation/base-types.js +2 -0
- package/lib/module/navigation/base-types.js.map +1 -0
- package/lib/module/navigation/createTrueSheetRouter.js +158 -100
- package/lib/module/navigation/createTrueSheetRouter.js.map +1 -1
- package/lib/module/navigation/expo-router/base-types.js +2 -0
- package/lib/module/navigation/expo-router/base-types.js.map +1 -0
- package/lib/module/navigation/expo-router/extendTrueSheetRouter.js +71 -0
- package/lib/module/navigation/expo-router/extendTrueSheetRouter.js.map +1 -0
- package/lib/module/navigation/expo-router/index.js +18 -7
- package/lib/module/navigation/expo-router/index.js.map +1 -1
- package/lib/module/navigation/expo-router/types.js +4 -0
- package/lib/module/navigation/expo-router/types.js.map +1 -0
- package/lib/module/navigation/index.js.map +1 -1
- package/lib/module/navigation/screen/useSheetScreenState.js +1 -0
- package/lib/module/navigation/screen/useSheetScreenState.js.map +1 -1
- package/lib/module/scrollable.js +28 -0
- package/lib/module/scrollable.js.map +1 -0
- package/lib/module/web/constants.js +1 -1
- package/lib/module/web/constants.js.map +1 -1
- package/lib/module/web/keyboard.js +69 -0
- package/lib/module/web/keyboard.js.map +1 -0
- package/lib/module/web/layout.js +168 -0
- package/lib/module/web/layout.js.map +1 -0
- package/lib/module/web/vaul/constants.js +9 -0
- package/lib/module/web/vaul/constants.js.map +1 -1
- package/lib/module/web/vaul/context.js +4 -0
- package/lib/module/web/vaul/context.js.map +1 -1
- package/lib/module/web/vaul/helpers.js +1 -0
- package/lib/module/web/vaul/helpers.js.map +1 -1
- package/lib/module/web/vaul/index.js +83 -21
- package/lib/module/web/vaul/index.js.map +1 -1
- package/lib/module/web/vaul/use-snap-points.js +57 -28
- package/lib/module/web/vaul/use-snap-points.js.map +1 -1
- package/lib/typescript/src/TrueSheet.d.ts +18 -1
- package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.types.d.ts +209 -35
- package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheet.web.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheetBackground.d.ts +3 -0
- package/lib/typescript/src/TrueSheetBackground.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetOverlay.d.ts +8 -0
- package/lib/typescript/src/TrueSheetOverlay.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetOverlay.web.d.ts +8 -0
- package/lib/typescript/src/TrueSheetOverlay.web.d.ts.map +1 -0
- package/lib/typescript/src/TrueSheetPeek.web.d.ts +8 -4
- package/lib/typescript/src/TrueSheetPeek.web.d.ts.map +1 -1
- package/lib/typescript/src/TrueSheetProvider.web.d.ts +5 -1
- package/lib/typescript/src/TrueSheetProvider.web.d.ts.map +1 -1
- package/lib/typescript/src/detentBackgrounds.d.ts +10 -0
- package/lib/typescript/src/detentBackgrounds.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts +2 -3
- package/lib/typescript/src/fabric/TrueSheetFooterViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts +6 -0
- package/lib/typescript/src/fabric/TrueSheetOverlayViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +76 -65
- package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/index.d.ts +4 -0
- package/lib/typescript/src/mocks/index.d.ts.map +1 -1
- package/lib/typescript/src/mocks/navigationExpoRouter.d.ts +3 -3
- package/lib/typescript/src/mocks/navigationExpoRouter.d.ts.map +1 -1
- package/lib/typescript/src/navigation/base-types.d.ts +9 -0
- package/lib/typescript/src/navigation/base-types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts +36 -10
- package/lib/typescript/src/navigation/createTrueSheetRouter.d.ts.map +1 -1
- package/lib/typescript/src/navigation/expo-router/base-types.d.ts +8 -0
- package/lib/typescript/src/navigation/expo-router/base-types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts +33 -0
- package/lib/typescript/src/navigation/expo-router/extendTrueSheetRouter.d.ts.map +1 -0
- package/lib/typescript/src/navigation/expo-router/index.d.ts +9 -6
- package/lib/typescript/src/navigation/expo-router/index.d.ts.map +1 -1
- package/lib/typescript/src/navigation/expo-router/types.d.ts +44 -0
- package/lib/typescript/src/navigation/expo-router/types.d.ts.map +1 -0
- package/lib/typescript/src/navigation/index.d.ts +3 -4
- package/lib/typescript/src/navigation/index.d.ts.map +1 -1
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts +2 -1
- package/lib/typescript/src/navigation/screen/useSheetScreenState.d.ts.map +1 -1
- package/lib/typescript/src/navigation/types.d.ts +43 -6
- package/lib/typescript/src/navigation/types.d.ts.map +1 -1
- package/lib/typescript/src/scrollable.d.ts +2 -0
- package/lib/typescript/src/scrollable.d.ts.map +1 -0
- package/lib/typescript/src/web/constants.d.ts +1 -1
- package/lib/typescript/src/web/constants.d.ts.map +1 -1
- package/lib/typescript/src/web/keyboard.d.ts +15 -0
- package/lib/typescript/src/web/keyboard.d.ts.map +1 -0
- package/lib/typescript/src/web/layout.d.ts +20 -0
- package/lib/typescript/src/web/layout.d.ts.map +1 -0
- package/lib/typescript/src/web/vaul/constants.d.ts +3 -0
- package/lib/typescript/src/web/vaul/constants.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/context.d.ts +5 -1
- package/lib/typescript/src/web/vaul/context.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/helpers.d.ts +1 -0
- package/lib/typescript/src/web/vaul/helpers.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/index.d.ts +20 -1
- package/lib/typescript/src/web/vaul/index.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/types.d.ts +9 -0
- package/lib/typescript/src/web/vaul/types.d.ts.map +1 -1
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts +6 -4
- package/lib/typescript/src/web/vaul/use-snap-points.d.ts.map +1 -1
- package/package.json +18 -8
- package/react-native.config.js +1 -0
- package/src/TrueSheet.tsx +257 -62
- package/src/TrueSheet.types.ts +225 -35
- package/src/TrueSheet.web.tsx +445 -333
- package/src/TrueSheetBackground.tsx +17 -0
- package/src/TrueSheetOverlay.tsx +24 -0
- package/src/TrueSheetOverlay.web.tsx +33 -0
- package/src/TrueSheetPeek.web.tsx +25 -23
- package/src/TrueSheetProvider.web.tsx +22 -13
- package/src/detentBackgrounds.ts +24 -0
- package/src/fabric/TrueSheetContentViewNativeComponent.ts +1 -1
- package/src/fabric/TrueSheetFooterViewNativeComponent.ts +2 -3
- package/src/fabric/TrueSheetOverlayViewNativeComponent.ts +12 -0
- package/src/fabric/TrueSheetViewNativeComponent.ts +89 -73
- package/src/index.ts +1 -0
- package/src/mocks/index.ts +17 -2
- package/src/mocks/navigationExpoRouter.ts +6 -5
- package/src/navigation/base-types.ts +20 -0
- package/src/navigation/createTrueSheetRouter.ts +220 -144
- package/src/navigation/expo-router/base-types.ts +18 -0
- package/src/navigation/expo-router/extendTrueSheetRouter.ts +99 -0
- package/src/navigation/expo-router/index.ts +41 -30
- package/src/navigation/expo-router/types.ts +116 -0
- package/src/navigation/index.ts +6 -7
- package/src/navigation/screen/useSheetScreenState.ts +2 -0
- package/src/navigation/types.ts +81 -23
- package/src/scrollable.ts +25 -0
- package/src/web/constants.ts +1 -1
- package/src/web/keyboard.ts +79 -0
- package/src/web/layout.ts +196 -0
- package/src/web/vaul/constants.ts +9 -0
- package/src/web/vaul/context.ts +7 -1
- package/src/web/vaul/helpers.ts +5 -0
- package/src/web/vaul/index.tsx +113 -16
- package/src/web/vaul/types.ts +10 -0
- package/src/web/vaul/use-snap-points.ts +86 -33
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
package com.lodev09.truesheet.core
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.view.MotionEvent
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.widget.FrameLayout
|
|
7
|
+
import com.facebook.react.uimanager.JSPointerDispatcher
|
|
8
|
+
import com.facebook.react.uimanager.JSTouchDispatcher
|
|
9
|
+
import com.facebook.react.uimanager.RootView
|
|
10
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
11
|
+
import com.facebook.react.uimanager.TouchTargetHelper
|
|
12
|
+
import com.facebook.react.uimanager.events.EventDispatcher
|
|
13
|
+
import com.lodev09.truesheet.utils.TouchEventDeduper
|
|
14
|
+
|
|
15
|
+
interface TrueSheetOverlayRootViewDelegate {
|
|
16
|
+
val eventDispatcher: EventDispatcher?
|
|
17
|
+
fun overlayRootViewDidChangeSize(width: Int, height: Int)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Window-level view hosting an overlay's children, attached to the activity's
|
|
22
|
+
* content view above the sheet coordinators.
|
|
23
|
+
*
|
|
24
|
+
* Implements RootView to dispatch touches to JS. Touches that miss every child
|
|
25
|
+
* fall through to the views beneath.
|
|
26
|
+
*/
|
|
27
|
+
@SuppressLint("ViewConstructor")
|
|
28
|
+
class TrueSheetOverlayRootView(private val reactContext: ThemedReactContext) :
|
|
29
|
+
FrameLayout(reactContext),
|
|
30
|
+
RootView {
|
|
31
|
+
|
|
32
|
+
var delegate: TrueSheetOverlayRootViewDelegate? = null
|
|
33
|
+
|
|
34
|
+
private val eventDispatcher: EventDispatcher?
|
|
35
|
+
get() = delegate?.eventDispatcher
|
|
36
|
+
|
|
37
|
+
private val jsTouchDispatcher = JSTouchDispatcher(this)
|
|
38
|
+
private val jsPointerDispatcher = JSPointerDispatcher(this)
|
|
39
|
+
private val touchDeduper = TouchEventDeduper()
|
|
40
|
+
|
|
41
|
+
// Whether the current touch stream landed on a child
|
|
42
|
+
private var isHandlingStream = false
|
|
43
|
+
|
|
44
|
+
init {
|
|
45
|
+
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
46
|
+
|
|
47
|
+
// React children draw outside their bounds (shadows, overflow)
|
|
48
|
+
clipChildren = false
|
|
49
|
+
clipToPadding = false
|
|
50
|
+
|
|
51
|
+
// Draws and receives touches above the sheet coordinators regardless of add order
|
|
52
|
+
translationZ = OVERLAY_Z
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Children are measured and positioned by Fabric — a FrameLayout pass would stretch them to match_parent
|
|
56
|
+
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
57
|
+
setMeasuredDimension(
|
|
58
|
+
MeasureSpec.getSize(widthMeasureSpec),
|
|
59
|
+
MeasureSpec.getSize(heightMeasureSpec)
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override fun onLayout(
|
|
64
|
+
changed: Boolean,
|
|
65
|
+
left: Int,
|
|
66
|
+
top: Int,
|
|
67
|
+
right: Int,
|
|
68
|
+
bottom: Int
|
|
69
|
+
) {
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
73
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
74
|
+
delegate?.overlayRootViewDidChangeSize(w, h)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
|
|
78
|
+
if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
79
|
+
// The path ends with this root, so a touch that misses every child resolves to it
|
|
80
|
+
val target = TouchTargetHelper
|
|
81
|
+
.findTargetPathAndCoordinatesForTouch(ev.x, ev.y, this, FloatArray(2))
|
|
82
|
+
.firstNotNullOfOrNull { it.getView() }
|
|
83
|
+
isHandlingStream = target != null && target !== this
|
|
84
|
+
}
|
|
85
|
+
if (!isHandlingStream) return false
|
|
86
|
+
return super.dispatchTouchEvent(ev)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ==================== RootView Implementation ====================
|
|
90
|
+
|
|
91
|
+
override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
|
|
92
|
+
eventDispatcher?.let { dispatcher ->
|
|
93
|
+
if (touchDeduper.shouldDispatch(event)) {
|
|
94
|
+
jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
95
|
+
}
|
|
96
|
+
jsPointerDispatcher.handleMotionEvent(event, dispatcher, true)
|
|
97
|
+
}
|
|
98
|
+
return super.onInterceptTouchEvent(event)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
|
102
|
+
// Mirrors ReactSurfaceView: keep receiving onInterceptTouchEvent so
|
|
103
|
+
// jsTouchDispatcher sees the gesture end, but forward the request up the tree.
|
|
104
|
+
parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
108
|
+
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
109
|
+
eventDispatcher?.let { dispatcher ->
|
|
110
|
+
if (touchDeduper.shouldDispatch(event)) {
|
|
111
|
+
jsTouchDispatcher.handleTouchEvent(event, dispatcher, reactContext)
|
|
112
|
+
}
|
|
113
|
+
jsPointerDispatcher.handleMotionEvent(event, dispatcher, false)
|
|
114
|
+
}
|
|
115
|
+
super.onTouchEvent(event)
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
override fun onInterceptHoverEvent(event: MotionEvent): Boolean {
|
|
120
|
+
eventDispatcher?.let { jsPointerDispatcher.handleMotionEvent(event, it, true) }
|
|
121
|
+
return super.onHoverEvent(event)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override fun onHoverEvent(event: MotionEvent): Boolean {
|
|
125
|
+
eventDispatcher?.let { jsPointerDispatcher.handleMotionEvent(event, it, false) }
|
|
126
|
+
return super.onHoverEvent(event)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
|
|
130
|
+
eventDispatcher?.let { dispatcher ->
|
|
131
|
+
jsTouchDispatcher.onChildStartedNativeGesture(ev, dispatcher)
|
|
132
|
+
jsPointerDispatcher.onChildStartedNativeGesture(childView, ev, dispatcher)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
|
|
137
|
+
eventDispatcher?.let { jsTouchDispatcher.onChildEndedNativeGesture(ev, it) }
|
|
138
|
+
jsPointerDispatcher.onChildEndedNativeGesture()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
override fun handleException(t: Throwable) {
|
|
142
|
+
reactContext.reactApplicationContext.handleException(RuntimeException(t))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
companion object {
|
|
146
|
+
private const val OVERLAY_Z = 1000f
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -13,23 +13,31 @@ object TrueSheetStackManager {
|
|
|
13
13
|
private val presentedSheetStack = mutableListOf<TrueSheetView>()
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Returns the topmost presented and visible sheet, skipping sheets that are dismissing.
|
|
17
|
+
* A dismissing sheet can't parent a new one: its dim would suppress the child's own dim
|
|
18
|
+
* and then disappear with it, leaving the child undimmed.
|
|
18
19
|
* Must be called within synchronized block.
|
|
19
20
|
*/
|
|
20
|
-
private fun
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
private fun findTopmostSheet(): TrueSheetView? =
|
|
22
|
+
presentedSheetStack.lastOrNull {
|
|
23
|
+
it.viewController.run { isPresented && isSheetVisible && !isBeingDismissed }
|
|
24
|
+
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
* Returns the topmost presented
|
|
27
|
+
* Returns the topmost sheet hidden by screen navigation that was presented from the same
|
|
28
|
+
* screen as the given sheet. Sheets presented on the covering screen must not parent to it,
|
|
29
|
+
* or the hidden sheet would receive focus and blur events while it can't be seen.
|
|
27
30
|
* Must be called within synchronized block.
|
|
28
31
|
*/
|
|
29
|
-
private fun
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
private fun findScreenHiddenSheet(sheetView: TrueSheetView): TrueSheetView? {
|
|
33
|
+
val screenTag = RNScreensEventObserver.findPresenterScreenTag(sheetView)
|
|
34
|
+
if (screenTag == 0) return null
|
|
35
|
+
|
|
36
|
+
return presentedSheetStack.lastOrNull {
|
|
37
|
+
it.viewController.run { isPresented && wasHiddenByScreen && !isBeingDismissed } &&
|
|
38
|
+
it.screensEventObserver?.presenterScreenTag == screenTag
|
|
32
39
|
}
|
|
40
|
+
}
|
|
33
41
|
|
|
34
42
|
/**
|
|
35
43
|
* Registers a sheet in the stack and returns its parent sheet if any.
|
|
@@ -38,7 +46,8 @@ object TrueSheetStackManager {
|
|
|
38
46
|
@JvmStatic
|
|
39
47
|
fun registerSheet(sheetView: TrueSheetView): TrueSheetView? {
|
|
40
48
|
synchronized(presentedSheetStack) {
|
|
41
|
-
val parentSheet = findTopmostSheet()
|
|
49
|
+
val parentSheet = (findTopmostSheet() ?: findScreenHiddenSheet(sheetView))
|
|
50
|
+
?.takeIf { it.rootContainerView == sheetView.rootContainerView }
|
|
42
51
|
|
|
43
52
|
if (!presentedSheetStack.contains(sheetView)) {
|
|
44
53
|
presentedSheetStack.add(sheetView)
|
|
@@ -60,24 +69,20 @@ object TrueSheetStackManager {
|
|
|
60
69
|
|
|
61
70
|
/**
|
|
62
71
|
* Updates parent sheet translation based on the child sheet's position.
|
|
63
|
-
* Only affects parent sheets in the same container.
|
|
64
72
|
*/
|
|
65
73
|
@JvmStatic
|
|
66
74
|
fun updateParentTranslation(sheetView: TrueSheetView) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
sheetView.viewController.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
val childSheetTop = maxOf(childMinSheetTop, childCurrentSheetTop)
|
|
79
|
-
parentSheet.updateTranslationForChild(childSheetTop)
|
|
80
|
-
}
|
|
75
|
+
val parentSheet = sheetView.viewController.parentSheetView ?: return
|
|
76
|
+
|
|
77
|
+
// Post to ensure layout is complete before reading position
|
|
78
|
+
sheetView.viewController.post {
|
|
79
|
+
val childMinSheetTop = sheetView.viewController.detentCalculator.getSheetTopForDetentIndex(0)
|
|
80
|
+
val childCurrentSheetTop = sheetView.viewController.detentCalculator.getSheetTopForDetentIndex(
|
|
81
|
+
sheetView.viewController.currentDetentIndex
|
|
82
|
+
)
|
|
83
|
+
// Cap to minimum detent position
|
|
84
|
+
val childSheetTop = maxOf(childMinSheetTop, childCurrentSheetTop)
|
|
85
|
+
parentSheet.updateTranslationForChild(childSheetTop)
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
|
|
@@ -111,18 +116,6 @@ object TrueSheetStackManager {
|
|
|
111
116
|
}
|
|
112
117
|
}
|
|
113
118
|
|
|
114
|
-
/**
|
|
115
|
-
* Gets the parent sheet of the given sheet, if any.
|
|
116
|
-
* Only returns a parent if it's in the same container.
|
|
117
|
-
*/
|
|
118
|
-
@JvmStatic
|
|
119
|
-
fun getParentSheet(sheetView: TrueSheetView): TrueSheetView? {
|
|
120
|
-
synchronized(presentedSheetStack) {
|
|
121
|
-
val index = presentedSheetStack.indexOf(sheetView)
|
|
122
|
-
return getParentSheetAt(index, sheetView.rootContainerView)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
119
|
/**
|
|
127
120
|
* Returns true if the given sheet is the topmost presented sheet in its container.
|
|
128
121
|
*/
|
|
@@ -168,7 +161,7 @@ object TrueSheetStackManager {
|
|
|
168
161
|
return
|
|
169
162
|
}
|
|
170
163
|
|
|
171
|
-
// The dimmed sheet
|
|
164
|
+
// The dimmed sheet, any sheets above it, and overlays (rendered above every sheet) stay accessible
|
|
172
165
|
val accessibleCoordinators = presentedSheetStack
|
|
173
166
|
.subList(topDimmedIndex, presentedSheetStack.size)
|
|
174
167
|
.mapNotNull { it.viewController.coordinatorLayout }
|
|
@@ -176,7 +169,7 @@ object TrueSheetStackManager {
|
|
|
176
169
|
|
|
177
170
|
for (i in 0 until root.childCount) {
|
|
178
171
|
val child = root.getChildAt(i)
|
|
179
|
-
if (child in accessibleCoordinators) {
|
|
172
|
+
if (child in accessibleCoordinators || child is TrueSheetOverlayRootView) {
|
|
180
173
|
savedBackgroundImportance.remove(child)?.let { child.importantForAccessibility = it }
|
|
181
174
|
continue
|
|
182
175
|
}
|
|
@@ -93,6 +93,21 @@ class DidDismissEvent(surfaceId: Int, viewId: Int) : Event<DidDismissEvent>(surf
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Fired when the user tries to dismiss a non-dismissible sheet
|
|
98
|
+
*/
|
|
99
|
+
class DismissAttemptEvent(surfaceId: Int, viewId: Int) : Event<DismissAttemptEvent>(surfaceId, viewId) {
|
|
100
|
+
|
|
101
|
+
override fun getEventName(): String = EVENT_NAME
|
|
102
|
+
|
|
103
|
+
override fun getEventData(): WritableMap = Arguments.createMap()
|
|
104
|
+
|
|
105
|
+
companion object {
|
|
106
|
+
const val EVENT_NAME = "topDismissAttempt"
|
|
107
|
+
const val REGISTRATION_NAME = "onDismissAttempt"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
96
111
|
/**
|
|
97
112
|
* Fired when the sheet visibility changes due to screen transitions
|
|
98
113
|
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package com.lodev09.truesheet.utils
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.res.Configuration
|
|
5
|
+
import com.facebook.react.bridge.ColorPropConverter
|
|
6
|
+
import com.facebook.react.bridge.ReadableMap
|
|
7
|
+
import com.facebook.react.bridge.ReadableType
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a processed color (number or `PlatformColor` map) at [key], or null when missing.
|
|
11
|
+
*/
|
|
12
|
+
fun ReadableMap.getColorOrNull(key: String, context: Context): Int? {
|
|
13
|
+
if (!hasKey(key) || isNull(key)) return null
|
|
14
|
+
val value = if (getType(key) == ReadableType.Map) getMap(key) else getDouble(key)
|
|
15
|
+
return ColorPropConverter.getColor(value, context)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
val Context.isDarkMode: Boolean
|
|
19
|
+
get() = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
|
|
@@ -3,6 +3,7 @@ package com.lodev09.truesheet.utils
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.os.Build
|
|
5
5
|
import android.view.View
|
|
6
|
+
import android.view.WindowInsets
|
|
6
7
|
import android.view.inputmethod.InputMethodManager
|
|
7
8
|
import androidx.core.view.ViewCompat
|
|
8
9
|
import androidx.core.view.WindowInsetsAnimationCompat
|
|
@@ -19,7 +20,7 @@ object KeyboardUtils {
|
|
|
19
20
|
return isKeyboardVisible(rootView)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
fun isKeyboardVisible(view: View): Boolean {
|
|
23
24
|
val insets = ViewCompat.getRootWindowInsets(view) ?: return false
|
|
24
25
|
return insets.isVisible(WindowInsetsCompat.Type.ime())
|
|
25
26
|
}
|
|
@@ -36,10 +37,22 @@ object KeyboardUtils {
|
|
|
36
37
|
* Dismisses the soft keyboard with an optional callback when the animation completes.
|
|
37
38
|
*/
|
|
38
39
|
fun dismiss(view: View, onComplete: (() -> Unit)?) {
|
|
40
|
+
if (!isKeyboardVisible(view)) {
|
|
41
|
+
onComplete?.invoke()
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
39
45
|
val imm = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
|
|
40
46
|
val focusedView = view.rootView.findFocus()
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
// A keyboard can stay up with nothing focused, e.g. a blur that lands after focus was restored,
|
|
49
|
+
// so hide it through the window instead of treating it as already hidden.
|
|
50
|
+
if (focusedView == null) {
|
|
51
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
|
52
|
+
view.windowInsetsController?.hide(WindowInsets.Type.ime())
|
|
53
|
+
} else {
|
|
54
|
+
imm?.hideSoftInputFromWindow(view.windowToken, 0)
|
|
55
|
+
}
|
|
43
56
|
onComplete?.invoke()
|
|
44
57
|
return
|
|
45
58
|
}
|
|
@@ -104,18 +104,6 @@ object ScreenUtils {
|
|
|
104
104
|
*/
|
|
105
105
|
fun getScreenHeight(reactContext: ReactContext): Int = reactContext.resources.displayMetrics.heightPixels
|
|
106
106
|
|
|
107
|
-
/**
|
|
108
|
-
* Get the location of a view in screen coordinates
|
|
109
|
-
*
|
|
110
|
-
* @param view The view to get screen location for
|
|
111
|
-
* @return IntArray with [x, y] coordinates in screen space
|
|
112
|
-
*/
|
|
113
|
-
fun getScreenLocation(view: View): IntArray {
|
|
114
|
-
val location = IntArray(2)
|
|
115
|
-
view.getLocationOnScreen(location)
|
|
116
|
-
return location
|
|
117
|
-
}
|
|
118
|
-
|
|
119
107
|
/**
|
|
120
108
|
* Returns true if the device is a phone in portrait orientation.
|
|
121
109
|
*/
|
|
@@ -2,8 +2,10 @@ package com.lodev09.truesheet.utils
|
|
|
2
2
|
|
|
3
3
|
import android.view.View
|
|
4
4
|
import android.view.ViewGroup
|
|
5
|
+
import android.view.ViewParent
|
|
5
6
|
import android.widget.ScrollView
|
|
6
7
|
import androidx.core.widget.NestedScrollView
|
|
8
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
7
9
|
|
|
8
10
|
fun View.isDescendantOf(ancestor: View): Boolean {
|
|
9
11
|
if (!isAttachedToWindow) return false
|
|
@@ -15,16 +17,26 @@ fun View.isDescendantOf(ancestor: View): Boolean {
|
|
|
15
17
|
return false
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
fun ViewGroup.smoothScrollBy(dx: Int, dy: Int) {
|
|
19
|
-
when (this) {
|
|
20
|
-
is ScrollView -> smoothScrollBy(dx, dy)
|
|
21
|
-
is NestedScrollView -> smoothScrollBy(dx, dy)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
20
|
fun ViewGroup.smoothScrollTo(x: Int, y: Int) {
|
|
26
21
|
when (this) {
|
|
27
22
|
is ScrollView -> smoothScrollTo(x, y)
|
|
28
23
|
is NestedScrollView -> smoothScrollTo(x, y)
|
|
29
24
|
}
|
|
30
25
|
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The content view hosting this view — the activity's, or a Modal dialog's.
|
|
29
|
+
* Window-level views (sheet coordinators, overlays) attach here.
|
|
30
|
+
*/
|
|
31
|
+
fun View.findRootContainerView(reactContext: ThemedReactContext): ViewGroup? {
|
|
32
|
+
var current: ViewParent? = parent
|
|
33
|
+
|
|
34
|
+
while (current != null) {
|
|
35
|
+
if (current is ViewGroup && current.id == android.R.id.content) {
|
|
36
|
+
return current
|
|
37
|
+
}
|
|
38
|
+
current = current.parent
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return reactContext.currentActivity?.findViewById(android.R.id.content)
|
|
42
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include <jsi/jsi.h>
|
|
6
6
|
#include <react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h>
|
|
7
7
|
#include <react/renderer/components/TrueSheetSpec/TrueSheetFooterViewComponentDescriptor.h>
|
|
8
|
+
#include <react/renderer/components/TrueSheetSpec/TrueSheetOverlayViewComponentDescriptor.h>
|
|
8
9
|
#include <react/renderer/components/TrueSheetSpec/TrueSheetViewComponentDescriptor.h>
|
|
9
10
|
|
|
10
11
|
namespace facebook {
|
|
@@ -58,7 +58,8 @@ static jboolean updateStateImmediate(
|
|
|
58
58
|
static jboolean updateFooterStateImmediate(
|
|
59
59
|
jni::alias_ref<jclass> /*clazz*/,
|
|
60
60
|
jni::alias_ref<jobject> stateWrapper,
|
|
61
|
-
jfloat bottomInset
|
|
61
|
+
jfloat bottomInset,
|
|
62
|
+
jfloat translateY) {
|
|
62
63
|
auto state = getStateFromWrapper(stateWrapper);
|
|
63
64
|
if (!state) {
|
|
64
65
|
return JNI_FALSE;
|
|
@@ -67,15 +68,44 @@ static jboolean updateFooterStateImmediate(
|
|
|
67
68
|
auto concreteState =
|
|
68
69
|
std::static_pointer_cast<const ConcreteState<TrueSheetFooterViewState>>(state);
|
|
69
70
|
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
// Carries the translation too — RN's EventQueue drops a still-queued update
|
|
72
|
+
// for the same view (see updateFooterTranslation) when this one is enqueued
|
|
73
|
+
concreteState->updateState(
|
|
74
|
+
[bottomInset, translateY](const TrueSheetFooterViewState &oldData) -> StateData::Shared {
|
|
75
|
+
auto newData = oldData;
|
|
76
|
+
newData.bottomInset = bottomInset;
|
|
77
|
+
newData.translateY = translateY;
|
|
78
|
+
newData.initialized = true;
|
|
79
|
+
return std::make_shared<const TrueSheetFooterViewState>(newData);
|
|
80
|
+
},
|
|
81
|
+
EventQueue::UpdateMode::unstable_Immediate);
|
|
75
82
|
|
|
76
83
|
return JNI_TRUE;
|
|
77
84
|
}
|
|
78
85
|
|
|
86
|
+
// Mirrors the footer's resting translation into its state so measure()
|
|
87
|
+
// matches where it's drawn. Async — it only feeds measure().
|
|
88
|
+
static void updateFooterTranslation(
|
|
89
|
+
jni::alias_ref<jclass> /*clazz*/,
|
|
90
|
+
jni::alias_ref<jobject> stateWrapper,
|
|
91
|
+
jfloat translateY) {
|
|
92
|
+
auto state = getStateFromWrapper(stateWrapper);
|
|
93
|
+
if (!state) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
auto concreteState =
|
|
98
|
+
std::static_pointer_cast<const ConcreteState<TrueSheetFooterViewState>>(state);
|
|
99
|
+
|
|
100
|
+
concreteState->updateState(
|
|
101
|
+
[translateY](const TrueSheetFooterViewState &oldData) -> StateData::Shared {
|
|
102
|
+
auto newData = oldData;
|
|
103
|
+
newData.translateY = translateY;
|
|
104
|
+
return std::make_shared<const TrueSheetFooterViewState>(newData);
|
|
105
|
+
},
|
|
106
|
+
EventQueue::UpdateMode::Asynchronous);
|
|
107
|
+
}
|
|
108
|
+
|
|
79
109
|
// Publishes the precalculated bottom safe-area inset so a late-mounted
|
|
80
110
|
// footer's first layout is already padded (see TrueSheetFooterViewShadowNode).
|
|
81
111
|
static void setBottomSafeArea(jni::alias_ref<jclass> /*clazz*/, jfloat insetDp) {
|
|
@@ -90,6 +120,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/) {
|
|
|
90
120
|
->registerNatives({
|
|
91
121
|
makeNativeMethod("nativeUpdateState", facebook::react::updateStateImmediate),
|
|
92
122
|
makeNativeMethod("nativeUpdateFooterState", facebook::react::updateFooterStateImmediate),
|
|
123
|
+
makeNativeMethod("nativeUpdateFooterTranslation", facebook::react::updateFooterTranslation),
|
|
93
124
|
makeNativeMethod("nativeSetBottomSafeArea", facebook::react::setBottomSafeArea),
|
|
94
125
|
});
|
|
95
126
|
});
|
package/common/cpp/react/renderer/components/TrueSheetSpec/TrueSheetContentViewComponentDescriptor.h
CHANGED
|
@@ -11,14 +11,6 @@ namespace facebook::react {
|
|
|
11
11
|
class TrueSheetContentViewComponentDescriptor final
|
|
12
12
|
: public ConcreteComponentDescriptor<TrueSheetContentViewShadowNode> {
|
|
13
13
|
using ConcreteComponentDescriptor::ConcreteComponentDescriptor;
|
|
14
|
-
|
|
15
|
-
void adopt(ShadowNode &shadowNode) const override {
|
|
16
|
-
auto &concreteShadowNode =
|
|
17
|
-
static_cast<TrueSheetContentViewShadowNode &>(shadowNode);
|
|
18
|
-
concreteShadowNode.adjustLayoutWithState();
|
|
19
|
-
|
|
20
|
-
ConcreteComponentDescriptor::adopt(shadowNode);
|
|
21
|
-
}
|
|
22
14
|
};
|
|
23
15
|
|
|
24
|
-
}
|
|
16
|
+
} // namespace facebook::react
|