@lodev09/react-native-true-sheet 3.5.1-beta.2 → 3.5.1-beta.4

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.
Files changed (34) hide show
  1. package/android/src/main/java/com/lodev09/truesheet/TrueSheetModule.kt +2 -2
  2. package/android/src/main/java/com/lodev09/truesheet/TrueSheetView.kt +32 -28
  3. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewController.kt +378 -253
  4. package/android/src/main/java/com/lodev09/truesheet/TrueSheetViewManager.kt +0 -5
  5. package/android/src/main/java/com/lodev09/truesheet/core/RNScreensFragmentObserver.kt +36 -14
  6. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetBottomSheetView.kt +150 -0
  7. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetCoordinatorLayout.kt +55 -0
  8. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDetentCalculator.kt +18 -12
  9. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDimView.kt +91 -2
  10. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetKeyboardObserver.kt +21 -11
  11. package/android/src/main/java/com/lodev09/truesheet/core/{TrueSheetDialogObserver.kt → TrueSheetStackManager.kt} +7 -5
  12. package/ios/TrueSheetViewController.h +2 -3
  13. package/ios/TrueSheetViewController.mm +11 -4
  14. package/ios/core/TrueSheetDetentCalculator.h +2 -3
  15. package/ios/core/TrueSheetDetentCalculator.mm +7 -9
  16. package/lib/module/TrueSheet.js +1 -16
  17. package/lib/module/TrueSheet.js.map +1 -1
  18. package/lib/module/fabric/TrueSheetViewNativeComponent.ts +0 -1
  19. package/lib/typescript/src/TrueSheet.d.ts.map +1 -1
  20. package/lib/typescript/src/TrueSheet.types.d.ts +0 -8
  21. package/lib/typescript/src/TrueSheet.types.d.ts.map +1 -1
  22. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts +0 -1
  23. package/lib/typescript/src/fabric/TrueSheetViewNativeComponent.d.ts.map +1 -1
  24. package/lib/typescript/src/navigation/types.d.ts +1 -1
  25. package/lib/typescript/src/navigation/types.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/TrueSheet.tsx +1 -16
  28. package/src/TrueSheet.types.ts +0 -9
  29. package/src/fabric/TrueSheetViewNativeComponent.ts +0 -1
  30. package/src/navigation/types.ts +0 -1
  31. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetAnimator.kt +0 -145
  32. package/android/src/main/java/com/lodev09/truesheet/core/TrueSheetDialogFragment.kt +0 -320
  33. package/android/src/main/res/anim/fast_fade_out.xml +0 -6
  34. package/android/src/main/res/values/styles.xml +0 -21
@@ -1,320 +0,0 @@
1
- package com.lodev09.truesheet.core
2
-
3
- import android.app.Dialog
4
- import android.graphics.Color
5
- import android.graphics.drawable.ShapeDrawable
6
- import android.graphics.drawable.shapes.RoundRectShape
7
- import android.os.Bundle
8
- import android.util.TypedValue
9
- import android.view.LayoutInflater
10
- import android.view.View
11
- import android.view.ViewGroup
12
- import android.view.WindowManager
13
- import android.widget.FrameLayout
14
- import androidx.activity.OnBackPressedCallback
15
- import com.facebook.react.uimanager.PixelUtil.dpToPx
16
- import com.facebook.react.uimanager.ThemedReactContext
17
- import com.google.android.material.bottomsheet.BottomSheetBehavior
18
- import com.google.android.material.bottomsheet.BottomSheetDialog
19
- import com.google.android.material.bottomsheet.BottomSheetDialogFragment
20
- import com.lodev09.truesheet.BuildConfig
21
- import com.lodev09.truesheet.R
22
- import com.lodev09.truesheet.utils.ScreenUtils
23
-
24
- // =============================================================================
25
- // MARK: - Delegate Protocol
26
- // =============================================================================
27
-
28
- interface TrueSheetDialogFragmentDelegate {
29
- fun onDialogShow()
30
- fun onDialogDismiss()
31
- fun onDialogCancel()
32
- fun onStateChanged(sheetView: View, newState: Int)
33
- fun onSlide(sheetView: View, slideOffset: Float)
34
- fun onBackPressed()
35
- }
36
-
37
- // =============================================================================
38
- // MARK: - TrueSheetDialogFragment
39
- // =============================================================================
40
-
41
- /**
42
- * Custom BottomSheetDialogFragment for TrueSheet.
43
- * Provides a Material Design bottom sheet with proper lifecycle management.
44
- *
45
- * This fragment handles:
46
- * - Dialog creation with proper theming (edge-to-edge support)
47
- * - BottomSheetBehavior configuration and callbacks
48
- * - Background styling with corner radius
49
- * - Grabber view management
50
- * - Back press handling
51
- *
52
- * The parent TrueSheetViewController handles:
53
- * - React Native touch dispatching
54
- * - Detent calculations
55
- * - Animations
56
- * - Keyboard/modal observers
57
- * - Stacking and dimming
58
- */
59
- class TrueSheetDialogFragment : BottomSheetDialogFragment() {
60
-
61
- companion object {
62
- private const val GRABBER_TAG = "TrueSheetGrabber"
63
- private const val DEFAULT_MAX_WIDTH = 640 // dp
64
- private const val DEFAULT_CORNER_RADIUS = 16f // dp
65
-
66
- fun newInstance(): TrueSheetDialogFragment = TrueSheetDialogFragment()
67
- }
68
-
69
- // =============================================================================
70
- // MARK: - Properties
71
- // =============================================================================
72
-
73
- var delegate: TrueSheetDialogFragmentDelegate? = null
74
-
75
- // Content view provided by the controller
76
- var contentView: View? = null
77
-
78
- // React context for theme resolution and screen utils
79
- var reactContext: ThemedReactContext? = null
80
-
81
- // Configuration
82
- var sheetCornerRadius: Float = DEFAULT_CORNER_RADIUS.dpToPx()
83
- var sheetBackgroundColor: Int? = null
84
- var edgeToEdgeFullScreen: Boolean = false
85
- var grabberEnabled: Boolean = true
86
- var grabberOptions: GrabberOptions? = null
87
- var draggable: Boolean = true
88
-
89
- var dismissible: Boolean = true
90
- set(value) {
91
- field = value
92
- (dialog as? BottomSheetDialog)?.apply {
93
- setCanceledOnTouchOutside(value)
94
- setCancelable(value)
95
- behavior.isHideable = value
96
- }
97
- }
98
-
99
- // =============================================================================
100
- // MARK: - Computed Properties
101
- // =============================================================================
102
-
103
- val bottomSheetDialog: BottomSheetDialog?
104
- get() = dialog as? BottomSheetDialog
105
-
106
- val behavior: BottomSheetBehavior<FrameLayout>?
107
- get() = bottomSheetDialog?.behavior
108
-
109
- val bottomSheetView: FrameLayout?
110
- get() = dialog?.findViewById(com.google.android.material.R.id.design_bottom_sheet)
111
-
112
- private val edgeToEdgeEnabled: Boolean
113
- get() {
114
- val defaultEnabled = android.os.Build.VERSION.SDK_INT >= 36
115
- return BuildConfig.EDGE_TO_EDGE_ENABLED || bottomSheetDialog?.edgeToEdgeEnabled == true || defaultEnabled
116
- }
117
-
118
- val topInset: Int
119
- get() = reactContext?.let { if (edgeToEdgeEnabled) ScreenUtils.getInsets(it).top else 0 } ?: 0
120
-
121
- // =============================================================================
122
- // MARK: - Lifecycle
123
- // =============================================================================
124
-
125
- override fun onCreate(savedInstanceState: Bundle?) {
126
- super.onCreate(savedInstanceState)
127
- // Prevent dialog from being recreated on configuration change
128
- // The controller manages state separately
129
- retainInstance = true
130
- }
131
-
132
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
133
- val ctx = reactContext ?: requireContext()
134
-
135
- val style = if (edgeToEdgeEnabled) {
136
- R.style.TrueSheetEdgeToEdgeEnabledDialog
137
- } else {
138
- R.style.TrueSheetDialog
139
- }
140
-
141
- val dialog = BottomSheetDialog(ctx, style)
142
-
143
- dialog.window?.apply {
144
- setWindowAnimations(0)
145
- setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
146
- // Clear default dim - TrueSheet uses custom TrueSheetDimView for dimming
147
- clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
148
- }
149
-
150
- dialog.setOnShowListener {
151
- setupBottomSheetBehavior()
152
- setupBackground()
153
- setupGrabber()
154
- // Re-apply dismissible after show since behavior may reset it
155
- dialog.behavior.isHideable = dismissible
156
- delegate?.onDialogShow()
157
- }
158
-
159
- dialog.setCanceledOnTouchOutside(dismissible)
160
- dialog.setCancelable(dismissible)
161
- dialog.behavior.isHideable = dismissible
162
- dialog.behavior.isDraggable = draggable
163
- dialog.behavior.maxWidth = DEFAULT_MAX_WIDTH.dpToPx().toInt()
164
-
165
- // Handle back press
166
- dialog.onBackPressedDispatcher.addCallback(
167
- this,
168
- object : OnBackPressedCallback(true) {
169
- override fun handleOnBackPressed() {
170
- delegate?.onBackPressed()
171
- if (dismissible) {
172
- dismiss()
173
- }
174
- }
175
- }
176
- )
177
-
178
- return dialog
179
- }
180
-
181
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = contentView
182
-
183
- override fun onCancel(dialog: android.content.DialogInterface) {
184
- super.onCancel(dialog)
185
- delegate?.onDialogCancel()
186
- }
187
-
188
- override fun onDismiss(dialog: android.content.DialogInterface) {
189
- super.onDismiss(dialog)
190
- delegate?.onDialogDismiss()
191
- }
192
-
193
- override fun onDestroyView() {
194
- // Detach content view to prevent it from being destroyed with the fragment
195
- (contentView?.parent as? ViewGroup)?.removeView(contentView)
196
- super.onDestroyView()
197
- }
198
-
199
- // =============================================================================
200
- // MARK: - Setup
201
- // =============================================================================
202
-
203
- private fun setupBottomSheetBehavior() {
204
- val behavior = this.behavior ?: return
205
-
206
- behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
207
- override fun onSlide(sheetView: View, slideOffset: Float) {
208
- delegate?.onSlide(sheetView, slideOffset)
209
- }
210
-
211
- override fun onStateChanged(sheetView: View, newState: Int) {
212
- delegate?.onStateChanged(sheetView, newState)
213
- }
214
- })
215
- }
216
-
217
- fun setupBackground() {
218
- val bottomSheet = bottomSheetView ?: return
219
- val ctx = reactContext ?: return
220
-
221
- val radius = if (sheetCornerRadius < 0) DEFAULT_CORNER_RADIUS.dpToPx() else sheetCornerRadius
222
-
223
- // Rounded corners only on top
224
- val outerRadii = floatArrayOf(
225
- radius,
226
- radius,
227
- radius,
228
- radius,
229
- 0f,
230
- 0f,
231
- 0f,
232
- 0f
233
- )
234
- val backgroundColor = sheetBackgroundColor ?: getDefaultBackgroundColor(ctx)
235
-
236
- bottomSheet.background = ShapeDrawable(RoundRectShape(outerRadii, null, null)).apply {
237
- paint.color = backgroundColor
238
- }
239
- bottomSheet.clipToOutline = true
240
- }
241
-
242
- fun setupGrabber() {
243
- val bottomSheet = bottomSheetView ?: return
244
- val ctx = reactContext ?: return
245
-
246
- // Remove existing grabber
247
- bottomSheet.findViewWithTag<View>(GRABBER_TAG)?.let {
248
- bottomSheet.removeView(it)
249
- }
250
-
251
- if (!grabberEnabled || !draggable) return
252
-
253
- val grabberView = TrueSheetGrabberView(ctx, grabberOptions).apply {
254
- tag = GRABBER_TAG
255
- }
256
-
257
- bottomSheet.addView(grabberView)
258
- }
259
-
260
- // =============================================================================
261
- // MARK: - Configuration
262
- // =============================================================================
263
-
264
- /**
265
- * Configure detent-related behavior settings.
266
- * Called by the controller when detents change.
267
- */
268
- fun configureDetents(
269
- peekHeight: Int,
270
- halfExpandedRatio: Float,
271
- expandedOffset: Int,
272
- fitToContents: Boolean,
273
- skipCollapsed: Boolean = false,
274
- animate: Boolean = false
275
- ) {
276
- val behavior = this.behavior ?: return
277
-
278
- behavior.apply {
279
- isFitToContents = fitToContents
280
- this.skipCollapsed = skipCollapsed
281
- setPeekHeight(peekHeight, animate)
282
- this.halfExpandedRatio = halfExpandedRatio.coerceIn(0f, 0.999f)
283
- this.expandedOffset = expandedOffset
284
- }
285
- }
286
-
287
- /**
288
- * Set the behavior state.
289
- */
290
- fun setState(state: Int) {
291
- behavior?.state = state
292
- }
293
-
294
- /**
295
- * Update draggable state.
296
- */
297
- fun updateDraggable(enabled: Boolean) {
298
- draggable = enabled
299
- behavior?.isDraggable = enabled
300
- if (isAdded) setupGrabber()
301
- }
302
-
303
- // =============================================================================
304
- // MARK: - Helpers
305
- // =============================================================================
306
-
307
- private fun getDefaultBackgroundColor(context: ThemedReactContext): Int {
308
- val typedValue = TypedValue()
309
- return if (context.theme.resolveAttribute(
310
- com.google.android.material.R.attr.colorSurfaceContainerLow,
311
- typedValue,
312
- true
313
- )
314
- ) {
315
- typedValue.data
316
- } else {
317
- Color.WHITE
318
- }
319
- }
320
- }
@@ -1,6 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <alpha xmlns:android="http://schemas.android.com/apk/res/android"
3
- android:fromAlpha="1.0"
4
- android:toAlpha="0.0"
5
- android:duration="100"
6
- android:interpolator="@android:interpolator/accelerate_quad" />
@@ -1,21 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <!-- Fast fade out animation for hiding sheet when rn-screen is presented -->
4
- <style name="TrueSheetFastFadeOut" parent="Animation.AppCompat.Dialog">
5
- <item name="android:windowEnterAnimation">@null</item>
6
- <item name="android:windowExitAnimation">@anim/fast_fade_out</item>
7
- </style>
8
-
9
- <!-- Default BottomSheetDialog style with programmatic animations -->
10
- <style name="TrueSheetDialog" parent="Theme.Design.Light.BottomSheetDialog">
11
- <item name="android:windowAnimationStyle">@null</item>
12
- </style>
13
-
14
- <!-- BottomSheetDialog style with edge-to-edge and programmatic animations -->
15
- <style name="TrueSheetEdgeToEdgeEnabledDialog" parent="Theme.Design.Light.BottomSheetDialog">
16
- <item name="android:windowIsFloating">false</item>
17
- <item name="enableEdgeToEdge">true</item>
18
- <item name="android:navigationBarColor">@android:color/transparent</item>
19
- <item name="android:windowAnimationStyle">@null</item>
20
- </style>
21
- </resources>