react-native-nitro-modal 0.3.5-rc → 0.3.7-rc

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.
@@ -74,6 +74,9 @@ internal class BottomSheetPresenter(
74
74
  private var lastDetentIndex = -1
75
75
  private var reportedRestingTop = Int.MIN_VALUE
76
76
 
77
+ /** The detent a settle we started is heading for, until it arrives; -1 otherwise. */
78
+ private var settlingTo = -1
79
+
77
80
  /** The behavior is dragging the sheet (as opposed to a nested scroll moving it). */
78
81
  private var sheetDragging = false
79
82
 
@@ -96,6 +99,8 @@ internal class BottomSheetPresenter(
96
99
  return
97
100
  }
98
101
  if (newState == BottomSheetBehavior.STATE_DRAGGING) {
102
+ // The user took over; the behavior picks where it settles.
103
+ settlingTo = -1
99
104
  sheetDragging = true
100
105
  coordinator.notifyNativeGesture(started = true)
101
106
  // A refreshing sheet follows the finger from its lowest detent.
@@ -106,6 +111,7 @@ internal class BottomSheetPresenter(
106
111
  }
107
112
  val position = states().indexOf(newState)
108
113
  if (position < 0 || isDismissing) return
114
+ settlingTo = -1
109
115
  presented = true
110
116
  // Hideable while entering/exiting; at rest, swipe-to-dismiss follows the prop.
111
117
  behavior.isHideable = this@BottomSheetPresenter.config.dismissOnSwipe
@@ -195,11 +201,12 @@ internal class BottomSheetPresenter(
195
201
  // Settles with the behavior's own animation, from HIDDEN on show or from
196
202
  // wherever a reversed exit got to (back to the detent it left).
197
203
  val index = if (lastDetentIndex >= 0) lastDetentIndex else config.clampedInitialDetentIndex
198
- behavior.state = stateFor(index)
204
+ settleTo(index)
199
205
  }
200
206
  }
201
207
 
202
208
  override fun animateOut(fromBackGesture: Boolean, onEnd: () -> Unit) {
209
+ settlingTo = -1
203
210
  coordinator.cancelPull()
204
211
  if (behavior.state == BottomSheetBehavior.STATE_HIDDEN || !coordinator.isLaidOut) {
205
212
  onEnd()
@@ -261,11 +268,16 @@ internal class BottomSheetPresenter(
261
268
 
262
269
  override fun snapToDetent(index: Int) {
263
270
  if (!presented || isDismissing) return
264
- behavior.state = stateFor(index)
271
+ settleTo(index)
265
272
  }
266
273
 
267
274
  override fun onTeardown() = coordinator.release()
268
275
 
276
+ private fun settleTo(index: Int) {
277
+ settlingTo = index
278
+ behavior.state = stateFor(index)
279
+ }
280
+
269
281
  private fun applyAppearance() {
270
282
  val radius = activity.dpToPx(config.cornerRadius ?: DEFAULT_CORNER_RADIUS_DP)
271
283
  if (radius != cornerRadiusPx) {
@@ -291,6 +303,7 @@ internal class BottomSheetPresenter(
291
303
  val bottomInset = systemInsets.bottom
292
304
  maxContentHeight = (parentHeight - systemInsets.top - bottomInset).coerceAtLeast(1)
293
305
 
306
+ val previousHeights = sortedDetents.map { it.height }
294
307
  val requested = config.detents.ifEmpty { listOf(Detent.FitContent) }
295
308
  val detents = requested
296
309
  .mapIndexed { index, detent -> RestingHeight(index, contentHeightFor(detent) + bottomInset) }
@@ -330,6 +343,16 @@ internal class BottomSheetPresenter(
330
343
  }
331
344
  }
332
345
 
346
+ // A settle heads for where its detent was when it started, and the
347
+ // behavior only moves a sheet at rest when its detents change: content
348
+ // that grows while the sheet slides in would leave it stopped short.
349
+ // Send the settle to where the detent is now.
350
+ if (heights != previousHeights && settlingTo >= 0 && !isDismissing &&
351
+ behavior.state == BottomSheetBehavior.STATE_SETTLING
352
+ ) {
353
+ behavior.state = stateFor(settlingTo)
354
+ }
355
+
333
356
  val availableHeight =
334
357
  if (Detent.FitContent in requested) maxContentHeight else sheetHeight - bottomInset
335
358
  val areaHeight = availableHeight -
@@ -42,6 +42,7 @@ class NitroModalHostView(context: ThemedReactContext) : ViewGroup(context), Reac
42
42
 
43
43
  private val measureAndLayout = Runnable {
44
44
  layoutPending = false
45
+ forceLayout()
45
46
  measure(
46
47
  MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
47
48
  MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
@@ -78,8 +79,15 @@ class NitroModalHostView(context: ThemedReactContext) : ViewGroup(context), Reac
78
79
  override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
79
80
  // Laid out by Fabric. A modal's children live in the modal window; an
80
81
  // inline sheet's layout fills this view.
81
- val width = r - l
82
- val height = b - t
82
+ layoutChildren(r - l, b - t)
83
+ if (changed) onLayoutChange?.invoke()
84
+ if (forcePendingLayout()) {
85
+ layoutChildren(r - l, b - t)
86
+ if (forcePendingLayout()) scheduleLayout()
87
+ }
88
+ }
89
+
90
+ private fun layoutChildren(width: Int, height: Int) {
83
91
  for (i in 0 until childCount) {
84
92
  val child = getChildAt(i)
85
93
  child.measure(
@@ -88,7 +96,22 @@ class NitroModalHostView(context: ThemedReactContext) : ViewGroup(context), Reac
88
96
  )
89
97
  child.layout(0, 0, width, height)
90
98
  }
91
- if (changed) onLayoutChange?.invoke()
99
+ }
100
+
101
+ /**
102
+ * Whether a view in the sheet's layout waits for a layout pass. Marks the
103
+ * views above it so the next pass reaches it. The React content is laid out
104
+ * by Fabric, and gone views take no part in layout.
105
+ */
106
+ private fun forcePendingLayout(view: ViewGroup = this): Boolean {
107
+ var pending = false
108
+ for (i in 0 until view.childCount) {
109
+ val child = view.getChildAt(i)
110
+ if (child.visibility == GONE || child is ModalContentRoot) continue
111
+ if ((child is ViewGroup && forcePendingLayout(child)) || child.isLayoutRequested) pending = true
112
+ }
113
+ if (pending && view !== this) view.forceLayout()
114
+ return pending
92
115
  }
93
116
 
94
117
  override fun onAttachedToWindow() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-modal",
3
- "version": "0.3.5-rc",
3
+ "version": "0.3.7-rc",
4
4
  "description": "react native native modal",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",