react-native-keyboard-controller 1.21.11 → 1.21.12
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/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt +1 -2
- package/android/src/main/java/com/reactnativekeyboardcontroller/listeners/KeyboardAnimationCallback.kt +37 -9
- package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt +7 -2
- package/android/src/main/java/com/reactnativekeyboardcontroller/views/ClippingScrollViewDecoratorView.kt +95 -0
- package/lib/commonjs/components/KeyboardChatScrollView/index.js +9 -1
- package/lib/commonjs/components/KeyboardChatScrollView/index.js.map +1 -1
- package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js +7 -1
- package/lib/commonjs/components/ScrollViewWithBottomPadding/index.js.map +1 -1
- package/lib/module/components/KeyboardChatScrollView/index.js +9 -1
- package/lib/module/components/KeyboardChatScrollView/index.js.map +1 -1
- package/lib/module/components/ScrollViewWithBottomPadding/index.js +7 -1
- package/lib/module/components/ScrollViewWithBottomPadding/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/KeyboardChatScrollView/index.tsx +11 -1
- package/src/components/ScrollViewWithBottomPadding/index.tsx +7 -1
package/android/src/main/java/com/reactnativekeyboardcontroller/events/KeyboardTransitionEvent.kt
CHANGED
|
@@ -16,8 +16,7 @@ class KeyboardTransitionEvent(
|
|
|
16
16
|
) : Event<KeyboardTransitionEvent>(surfaceId, viewId) {
|
|
17
17
|
override fun getEventName() = event.value
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
override fun getCoalescingKey(): Short = 0
|
|
19
|
+
override fun canCoalesce() = false
|
|
21
20
|
|
|
22
21
|
override fun getEventData(): WritableMap? =
|
|
23
22
|
Arguments.createMap().apply {
|
|
@@ -64,8 +64,8 @@ class KeyboardAnimationCallback(
|
|
|
64
64
|
private val surfaceId = UIManagerHelper.getSurfaceId(eventPropagationView)
|
|
65
65
|
|
|
66
66
|
// state variables
|
|
67
|
-
private var persistentKeyboardHeight =
|
|
68
|
-
private var prevKeyboardHeight =
|
|
67
|
+
private var persistentKeyboardHeight = getCurrentKeyboardHeight()
|
|
68
|
+
private var prevKeyboardHeight = getCurrentKeyboardHeight()
|
|
69
69
|
private var isKeyboardVisible = false
|
|
70
70
|
private var isTransitioning = false
|
|
71
71
|
private var duration = 0
|
|
@@ -170,11 +170,34 @@ class KeyboardAnimationCallback(
|
|
|
170
170
|
Logger.i(TAG, "onApplyWindowInsets: ${this.persistentKeyboardHeight} -> $keyboardHeight")
|
|
171
171
|
layoutObserver?.syncUpLayout()
|
|
172
172
|
this.onKeyboardResized(keyboardHeight)
|
|
173
|
+
|
|
174
|
+
return insets
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// always verify insets, because sometimes default lifecycle methods may not be invoked
|
|
178
|
+
// (when we press "Share" on Android 16, when Modal closes keyboard, when permission Alert presented etc.)
|
|
179
|
+
val newHeight = getCurrentKeyboardHeight(insets)
|
|
180
|
+
if (prevKeyboardHeight != newHeight && !isMoving && !isSuspended) {
|
|
181
|
+
Logger.w(
|
|
182
|
+
TAG,
|
|
183
|
+
"detected desynchronized state - force updating it: $newHeight",
|
|
184
|
+
)
|
|
185
|
+
this.syncKeyboardPosition(newHeight, newHeight > 0)
|
|
173
186
|
}
|
|
174
187
|
|
|
175
188
|
return insets
|
|
176
189
|
}
|
|
177
190
|
|
|
191
|
+
override fun onPrepare(animation: WindowInsetsAnimationCompat) {
|
|
192
|
+
super.onPrepare(animation)
|
|
193
|
+
|
|
194
|
+
if (!animation.isKeyboardAnimation || isSuspended) {
|
|
195
|
+
return
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
isTransitioning = true
|
|
199
|
+
}
|
|
200
|
+
|
|
178
201
|
@Suppress("detekt:ReturnCount")
|
|
179
202
|
override fun onStart(
|
|
180
203
|
animation: WindowInsetsAnimationCompat,
|
|
@@ -184,7 +207,6 @@ class KeyboardAnimationCallback(
|
|
|
184
207
|
return bounds
|
|
185
208
|
}
|
|
186
209
|
|
|
187
|
-
isTransitioning = true
|
|
188
210
|
pendingStartEvent = null
|
|
189
211
|
isKeyboardVisible = isKeyboardVisible()
|
|
190
212
|
duration = animation.durationMillis.toInt()
|
|
@@ -371,8 +393,13 @@ class KeyboardAnimationCallback(
|
|
|
371
393
|
"KeyboardController::" + if (!isKeyboardVisible) "keyboardDidHide" else "keyboardDidShow",
|
|
372
394
|
getEventParams(keyboardHeight),
|
|
373
395
|
)
|
|
374
|
-
// dispatch
|
|
375
|
-
|
|
396
|
+
// dispatch full lifecycle of onStart/onMove/onEnd events to update RN animated value and
|
|
397
|
+
// keep imperative hooks like `useKeyboardHandler` in sync
|
|
398
|
+
listOf(
|
|
399
|
+
KeyboardTransitionEvent.Start,
|
|
400
|
+
KeyboardTransitionEvent.Move,
|
|
401
|
+
KeyboardTransitionEvent.End,
|
|
402
|
+
).forEach { eventName ->
|
|
376
403
|
context.dispatchEvent(
|
|
377
404
|
eventPropagationView.id,
|
|
378
405
|
KeyboardTransitionEvent(
|
|
@@ -431,14 +458,15 @@ class KeyboardAnimationCallback(
|
|
|
431
458
|
return insets?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
|
|
432
459
|
}
|
|
433
460
|
|
|
434
|
-
private fun getCurrentKeyboardHeight(): Double {
|
|
435
|
-
val
|
|
436
|
-
val
|
|
461
|
+
private fun getCurrentKeyboardHeight(insets: WindowInsetsCompat? = null): Double {
|
|
462
|
+
val root = ViewCompat.getRootWindowInsets(view)
|
|
463
|
+
val final = insets ?: root
|
|
464
|
+
val keyboardHeight = final?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
|
|
437
465
|
val navigationBar =
|
|
438
466
|
if (config.hasTranslucentNavigationBar) {
|
|
439
467
|
0
|
|
440
468
|
} else {
|
|
441
|
-
|
|
469
|
+
root?.getInsets(WindowInsetsCompat.Type.navigationBars())?.bottom ?: 0
|
|
442
470
|
}
|
|
443
471
|
|
|
444
472
|
// on hide it will be negative value, so we are using max function
|
package/android/src/main/java/com/reactnativekeyboardcontroller/modal/ModalAttachedWatcher.kt
CHANGED
|
@@ -82,14 +82,19 @@ class ModalAttachedWatcher(
|
|
|
82
82
|
// position ourself, because callback can be attached after keyboard
|
|
83
83
|
// auto-dismissal and we may miss some events and keyboard position
|
|
84
84
|
// will be outdated
|
|
85
|
-
|
|
85
|
+
view.post {
|
|
86
|
+
callback.syncKeyboardPosition(0.0, false)
|
|
87
|
+
}
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
dialog?.setOnDismissListener {
|
|
89
91
|
callback.syncKeyboardPosition()
|
|
90
92
|
callback.destroy()
|
|
91
93
|
eventView.removeSelf()
|
|
92
|
-
|
|
94
|
+
// un-pause it in next frame because straight away `onApplyWindowInsets` will be called
|
|
95
|
+
view.post {
|
|
96
|
+
this.callback()?.suspend(false)
|
|
97
|
+
}
|
|
93
98
|
}
|
|
94
99
|
|
|
95
100
|
// imitating edge-to-edge mode behavior
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
package com.reactnativekeyboardcontroller.views
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
+
import android.view.MotionEvent
|
|
4
5
|
import android.view.View
|
|
5
6
|
import android.view.ViewGroup
|
|
6
7
|
import android.widget.ScrollView
|
|
7
8
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
8
9
|
import com.facebook.react.views.view.ReactViewGroup
|
|
9
10
|
import com.reactnativekeyboardcontroller.extensions.px
|
|
11
|
+
import kotlin.math.max
|
|
10
12
|
|
|
11
13
|
@SuppressLint("ViewConstructor")
|
|
12
14
|
class ClippingScrollViewDecoratorView(
|
|
@@ -15,6 +17,7 @@ class ClippingScrollViewDecoratorView(
|
|
|
15
17
|
private var insetBottom = 0.0
|
|
16
18
|
private var insetTop = 0.0
|
|
17
19
|
private var appliedTopInsetPx = 0
|
|
20
|
+
private var paddingScrollWorkaroundActive = false
|
|
18
21
|
|
|
19
22
|
override fun onAttachedToWindow() {
|
|
20
23
|
super.onAttachedToWindow()
|
|
@@ -22,6 +25,34 @@ class ClippingScrollViewDecoratorView(
|
|
|
22
25
|
decorateScrollView()
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
|
|
29
|
+
val scrollView = findScrollView(this)
|
|
30
|
+
|
|
31
|
+
if (scrollView == null) {
|
|
32
|
+
return super.dispatchTouchEvent(event)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
|
36
|
+
paddingScrollWorkaroundActive = shouldUsePaddingScrollWorkaround(scrollView, event)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
val handled =
|
|
40
|
+
if (paddingScrollWorkaroundActive) {
|
|
41
|
+
dispatchWithExpandedContentRange(scrollView, event)
|
|
42
|
+
} else {
|
|
43
|
+
super.dispatchTouchEvent(event)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
event.actionMasked == MotionEvent.ACTION_UP ||
|
|
48
|
+
event.actionMasked == MotionEvent.ACTION_CANCEL
|
|
49
|
+
) {
|
|
50
|
+
paddingScrollWorkaroundActive = false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return handled
|
|
54
|
+
}
|
|
55
|
+
|
|
25
56
|
fun setContentInsetBottom(value: Double) {
|
|
26
57
|
insetBottom = value
|
|
27
58
|
decorateScrollView()
|
|
@@ -68,6 +99,65 @@ class ClippingScrollViewDecoratorView(
|
|
|
68
99
|
appliedTopInsetPx = newTopInsetPx
|
|
69
100
|
}
|
|
70
101
|
|
|
102
|
+
private fun shouldUsePaddingScrollWorkaround(
|
|
103
|
+
scrollView: ScrollView,
|
|
104
|
+
event: MotionEvent,
|
|
105
|
+
): Boolean {
|
|
106
|
+
val contentView = scrollView.getChildAt(0) ?: return false
|
|
107
|
+
val viewportHeight =
|
|
108
|
+
scrollView.height - scrollView.paddingTop - scrollView.paddingBottom
|
|
109
|
+
val paddingCreatesScrollRange = contentView.height > viewportHeight
|
|
110
|
+
|
|
111
|
+
return scrollView.scrollY == 0 &&
|
|
112
|
+
paddingCreatesScrollRange &&
|
|
113
|
+
!scrollView.canScrollVertically(1) &&
|
|
114
|
+
isTouchInScrollContent(scrollView, event)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private fun dispatchWithExpandedContentRange(
|
|
118
|
+
scrollView: ScrollView,
|
|
119
|
+
event: MotionEvent,
|
|
120
|
+
): Boolean {
|
|
121
|
+
val contentView = scrollView.getChildAt(0)
|
|
122
|
+
val originalBottom = contentView?.bottom ?: 0
|
|
123
|
+
val expandedBottom =
|
|
124
|
+
max(originalBottom, scrollView.height + scrollView.scrollY + MIN_SCROLL_RANGE_PX)
|
|
125
|
+
|
|
126
|
+
if (contentView == null || expandedBottom == originalBottom) {
|
|
127
|
+
return super.dispatchTouchEvent(event)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return try {
|
|
131
|
+
contentView.bottom = expandedBottom
|
|
132
|
+
super.dispatchTouchEvent(event)
|
|
133
|
+
} finally {
|
|
134
|
+
contentView.bottom = originalBottom
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private fun isTouchInScrollContent(
|
|
139
|
+
scrollView: ScrollView,
|
|
140
|
+
event: MotionEvent,
|
|
141
|
+
): Boolean {
|
|
142
|
+
val contentView = scrollView.getChildAt(0) ?: return false
|
|
143
|
+
val thisLocation = IntArray(COORDINATES_SIZE)
|
|
144
|
+
val scrollViewLocation = IntArray(COORDINATES_SIZE)
|
|
145
|
+
|
|
146
|
+
getLocationOnScreen(thisLocation)
|
|
147
|
+
scrollView.getLocationOnScreen(scrollViewLocation)
|
|
148
|
+
|
|
149
|
+
val x = event.x + thisLocation[0] - scrollViewLocation[0]
|
|
150
|
+
val y = event.y + thisLocation[1] - scrollViewLocation[1]
|
|
151
|
+
val scrollY = scrollView.scrollY
|
|
152
|
+
|
|
153
|
+
return !(
|
|
154
|
+
y < contentView.top - scrollY ||
|
|
155
|
+
y >= contentView.bottom - scrollY ||
|
|
156
|
+
x < contentView.left ||
|
|
157
|
+
x >= contentView.right
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
71
161
|
private fun findScrollView(view: View?): ScrollView? {
|
|
72
162
|
var result: ScrollView? = null
|
|
73
163
|
|
|
@@ -83,4 +173,9 @@ class ClippingScrollViewDecoratorView(
|
|
|
83
173
|
|
|
84
174
|
return result
|
|
85
175
|
}
|
|
176
|
+
|
|
177
|
+
companion object {
|
|
178
|
+
private const val COORDINATES_SIZE = 2
|
|
179
|
+
private const val MIN_SCROLL_RANGE_PX = 2
|
|
180
|
+
}
|
|
86
181
|
}
|
|
@@ -72,7 +72,15 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
72
72
|
inverted,
|
|
73
73
|
onEndVisible
|
|
74
74
|
});
|
|
75
|
-
|
|
75
|
+
|
|
76
|
+
// intentionally clamp `blankSpace` at one ScrollView viewport. The Android
|
|
77
|
+
// `ClippingScrollView` workaround temporarily substitutes padding/range
|
|
78
|
+
// during touch handling, and oversized blank ranges can de-sync during fast
|
|
79
|
+
// momentum gestures. One viewport is enough for the short-content case;
|
|
80
|
+
// larger values only allow scrolling to a fully blank screen which is not
|
|
81
|
+
// the use case for this library. If you found this comment and it causes
|
|
82
|
+
// a bug for you, please open an issue.
|
|
83
|
+
const totalPadding = (0, _reactNativeReanimated.useDerivedValue)(() => Math.min(layout.value.height, Math.max(blankSpace.value, padding.value + extraContentPadding.value)));
|
|
76
84
|
|
|
77
85
|
// Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).
|
|
78
86
|
// Apps that render into the unsafe area can supply a negative
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_useCombinedRef","_interopRequireDefault","_ScrollViewWithBottomPadding","_useChatKeyboard","_useEndVisible","_useExtraContentPadding","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","ZERO_CONTENT_PADDING","makeMutable","ZERO_BLANK_SPACE","KeyboardChatScrollView","forwardRef","children","ScrollViewComponent","Reanimated","ScrollView","inverted","keyboardLiftBehavior","freeze","offset","extraContentPadding","blankSpace","applyWorkaroundForContentInsetHitTestBug","onLayout","onLayoutProp","onContentSizeChange","onContentSizeChangeProp","onEndVisible","rest","ref","scrollViewRef","useAnimatedRef","onRef","useCombinedRef","freezeSV","useDerivedValue","value","padding","currentHeight","contentOffsetY","scroll","layout","size","onLayoutInternal","onContentSizeChangeInternal","useChatKeyboard","useExtraContentPadding","keyboardPadding","useEndVisible","totalPadding","Math","max","indicatorPadding","useCallback","w","h","commitStyle","useAnimatedStyle","transform","translateY","commit","useMemo","styles","commitView","createElement","Fragment","bottomPadding","scrollIndicatorPadding","View","style","StyleSheet","create","display","position","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport {\n makeMutable,\n useAnimatedRef,\n useAnimatedStyle,\n useDerivedValue,\n} from \"react-native-reanimated\";\nimport Reanimated from \"react-native-reanimated\";\n\nimport useCombinedRef from \"../hooks/useCombinedRef\";\nimport ScrollViewWithBottomPadding from \"../ScrollViewWithBottomPadding\";\n\nimport { useChatKeyboard } from \"./useChatKeyboard\";\nimport { useEndVisible } from \"./useEndVisible\";\nimport { useExtraContentPadding } from \"./useExtraContentPadding\";\n\nimport type { KeyboardChatScrollViewProps } from \"./types\";\nimport type { LayoutChangeEvent } from \"react-native\";\n\nconst ZERO_CONTENT_PADDING = makeMutable(0);\nconst ZERO_BLANK_SPACE = makeMutable(0);\n\nconst KeyboardChatScrollView = forwardRef<\n Reanimated.ScrollView,\n React.PropsWithChildren<KeyboardChatScrollViewProps>\n>(\n (\n {\n children,\n ScrollViewComponent = Reanimated.ScrollView,\n inverted = false,\n keyboardLiftBehavior = \"always\",\n freeze = false,\n offset = 0,\n extraContentPadding = ZERO_CONTENT_PADDING,\n blankSpace = ZERO_BLANK_SPACE,\n applyWorkaroundForContentInsetHitTestBug = false,\n onLayout: onLayoutProp,\n onContentSizeChange: onContentSizeChangeProp,\n onEndVisible,\n ...rest\n },\n ref,\n ) => {\n const scrollViewRef = useAnimatedRef<Reanimated.ScrollView>();\n const onRef = useCombinedRef(ref, scrollViewRef);\n const freezeSV = useDerivedValue(() =>\n typeof freeze === \"boolean\" ? freeze : freeze.value,\n );\n const {\n padding,\n currentHeight,\n contentOffsetY,\n scroll,\n layout,\n size,\n onLayout: onLayoutInternal,\n onContentSizeChange: onContentSizeChangeInternal,\n } = useChatKeyboard(scrollViewRef, {\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n offset,\n blankSpace,\n extraContentPadding,\n });\n\n useExtraContentPadding({\n scrollViewRef,\n extraContentPadding,\n keyboardPadding: padding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n });\n\n useEndVisible({\n scroll,\n layout,\n size,\n inverted,\n onEndVisible,\n });\n\n const totalPadding = useDerivedValue(() =>\n Math.max(blankSpace.value, padding.value + extraContentPadding.value),\n );\n\n // Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).\n // Apps that render into the unsafe area can supply a negative\n // scrollIndicatorInsets adjustment at the application layer.\n const indicatorPadding = useDerivedValue(\n () => padding.value + extraContentPadding.value,\n );\n\n const onLayout = useCallback(\n (e: LayoutChangeEvent) => {\n onLayoutInternal(e);\n onLayoutProp?.(e);\n },\n [onLayoutInternal, onLayoutProp],\n );\n\n const onContentSizeChange = useCallback(\n (w: number, h: number) => {\n onContentSizeChangeInternal(w, h);\n onContentSizeChangeProp?.(w, h);\n },\n [onContentSizeChangeInternal, onContentSizeChangeProp],\n );\n\n // Invisible view whose animated style changes every frame during keyboard\n // animation. On Fabric, this forces Reanimated to schedule a commit,\n // which flushes the scrollTo call in the same frame (fixing de-synchronization).\n // see https://github.com/software-mansion/react-native-reanimated/issues/9000\n const commitStyle = useAnimatedStyle(\n () => ({\n transform: [{ translateY: -currentHeight.value }],\n }),\n [],\n );\n const commit = useMemo(\n () => [styles.commitView, commitStyle],\n [commitStyle],\n );\n\n return (\n <>\n <ScrollViewWithBottomPadding\n ref={onRef}\n {...rest}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n bottomPadding={totalPadding}\n contentOffsetY={contentOffsetY}\n inverted={inverted}\n scrollIndicatorPadding={indicatorPadding}\n ScrollViewComponent={ScrollViewComponent}\n onContentSizeChange={onContentSizeChange}\n onLayout={onLayout}\n >\n {children}\n </ScrollViewWithBottomPadding>\n <Reanimated.View style={commit} />\n </>\n );\n },\n);\n\nconst styles = StyleSheet.create({\n commitView: {\n display: \"none\",\n position: \"absolute\",\n },\n});\n\nexport default KeyboardChatScrollView;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_useCombinedRef","_interopRequireDefault","_ScrollViewWithBottomPadding","_useChatKeyboard","_useEndVisible","_useExtraContentPadding","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","ZERO_CONTENT_PADDING","makeMutable","ZERO_BLANK_SPACE","KeyboardChatScrollView","forwardRef","children","ScrollViewComponent","Reanimated","ScrollView","inverted","keyboardLiftBehavior","freeze","offset","extraContentPadding","blankSpace","applyWorkaroundForContentInsetHitTestBug","onLayout","onLayoutProp","onContentSizeChange","onContentSizeChangeProp","onEndVisible","rest","ref","scrollViewRef","useAnimatedRef","onRef","useCombinedRef","freezeSV","useDerivedValue","value","padding","currentHeight","contentOffsetY","scroll","layout","size","onLayoutInternal","onContentSizeChangeInternal","useChatKeyboard","useExtraContentPadding","keyboardPadding","useEndVisible","totalPadding","Math","min","height","max","indicatorPadding","useCallback","w","h","commitStyle","useAnimatedStyle","transform","translateY","commit","useMemo","styles","commitView","createElement","Fragment","bottomPadding","scrollIndicatorPadding","View","style","StyleSheet","create","display","position","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport {\n makeMutable,\n useAnimatedRef,\n useAnimatedStyle,\n useDerivedValue,\n} from \"react-native-reanimated\";\nimport Reanimated from \"react-native-reanimated\";\n\nimport useCombinedRef from \"../hooks/useCombinedRef\";\nimport ScrollViewWithBottomPadding from \"../ScrollViewWithBottomPadding\";\n\nimport { useChatKeyboard } from \"./useChatKeyboard\";\nimport { useEndVisible } from \"./useEndVisible\";\nimport { useExtraContentPadding } from \"./useExtraContentPadding\";\n\nimport type { KeyboardChatScrollViewProps } from \"./types\";\nimport type { LayoutChangeEvent } from \"react-native\";\n\nconst ZERO_CONTENT_PADDING = makeMutable(0);\nconst ZERO_BLANK_SPACE = makeMutable(0);\n\nconst KeyboardChatScrollView = forwardRef<\n Reanimated.ScrollView,\n React.PropsWithChildren<KeyboardChatScrollViewProps>\n>(\n (\n {\n children,\n ScrollViewComponent = Reanimated.ScrollView,\n inverted = false,\n keyboardLiftBehavior = \"always\",\n freeze = false,\n offset = 0,\n extraContentPadding = ZERO_CONTENT_PADDING,\n blankSpace = ZERO_BLANK_SPACE,\n applyWorkaroundForContentInsetHitTestBug = false,\n onLayout: onLayoutProp,\n onContentSizeChange: onContentSizeChangeProp,\n onEndVisible,\n ...rest\n },\n ref,\n ) => {\n const scrollViewRef = useAnimatedRef<Reanimated.ScrollView>();\n const onRef = useCombinedRef(ref, scrollViewRef);\n const freezeSV = useDerivedValue(() =>\n typeof freeze === \"boolean\" ? freeze : freeze.value,\n );\n const {\n padding,\n currentHeight,\n contentOffsetY,\n scroll,\n layout,\n size,\n onLayout: onLayoutInternal,\n onContentSizeChange: onContentSizeChangeInternal,\n } = useChatKeyboard(scrollViewRef, {\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n offset,\n blankSpace,\n extraContentPadding,\n });\n\n useExtraContentPadding({\n scrollViewRef,\n extraContentPadding,\n keyboardPadding: padding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n });\n\n useEndVisible({\n scroll,\n layout,\n size,\n inverted,\n onEndVisible,\n });\n\n // intentionally clamp `blankSpace` at one ScrollView viewport. The Android\n // `ClippingScrollView` workaround temporarily substitutes padding/range\n // during touch handling, and oversized blank ranges can de-sync during fast\n // momentum gestures. One viewport is enough for the short-content case;\n // larger values only allow scrolling to a fully blank screen which is not\n // the use case for this library. If you found this comment and it causes\n // a bug for you, please open an issue.\n const totalPadding = useDerivedValue(() =>\n Math.min(\n layout.value.height,\n Math.max(blankSpace.value, padding.value + extraContentPadding.value),\n ),\n );\n\n // Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).\n // Apps that render into the unsafe area can supply a negative\n // scrollIndicatorInsets adjustment at the application layer.\n const indicatorPadding = useDerivedValue(\n () => padding.value + extraContentPadding.value,\n );\n\n const onLayout = useCallback(\n (e: LayoutChangeEvent) => {\n onLayoutInternal(e);\n onLayoutProp?.(e);\n },\n [onLayoutInternal, onLayoutProp],\n );\n\n const onContentSizeChange = useCallback(\n (w: number, h: number) => {\n onContentSizeChangeInternal(w, h);\n onContentSizeChangeProp?.(w, h);\n },\n [onContentSizeChangeInternal, onContentSizeChangeProp],\n );\n\n // Invisible view whose animated style changes every frame during keyboard\n // animation. On Fabric, this forces Reanimated to schedule a commit,\n // which flushes the scrollTo call in the same frame (fixing de-synchronization).\n // see https://github.com/software-mansion/react-native-reanimated/issues/9000\n const commitStyle = useAnimatedStyle(\n () => ({\n transform: [{ translateY: -currentHeight.value }],\n }),\n [],\n );\n const commit = useMemo(\n () => [styles.commitView, commitStyle],\n [commitStyle],\n );\n\n return (\n <>\n <ScrollViewWithBottomPadding\n ref={onRef}\n {...rest}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n bottomPadding={totalPadding}\n contentOffsetY={contentOffsetY}\n inverted={inverted}\n scrollIndicatorPadding={indicatorPadding}\n ScrollViewComponent={ScrollViewComponent}\n onContentSizeChange={onContentSizeChange}\n onLayout={onLayout}\n >\n {children}\n </ScrollViewWithBottomPadding>\n <Reanimated.View style={commit} />\n </>\n );\n },\n);\n\nconst styles = StyleSheet.create({\n commitView: {\n display: \"none\",\n position: \"absolute\",\n },\n});\n\nexport default KeyboardChatScrollView;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -76,9 +76,15 @@ const ScrollViewWithBottomPadding = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
76
76
|
};
|
|
77
77
|
if (contentOffsetY) {
|
|
78
78
|
const curr = contentOffsetY.value;
|
|
79
|
-
if (
|
|
79
|
+
if (prevContentOffsetY.value === null) {
|
|
80
|
+
// Swallow the initial evaluation: emitting `contentOffset {x:0,y:0}`
|
|
81
|
+
// in the first animatedProps run overrides the wrapped ScrollView's
|
|
82
|
+
// own `contentOffset` prop on Fabric (e.g. a list's initial scroll
|
|
83
|
+
// offset), making the list mount scrolled to the top natively.
|
|
80
84
|
// eslint-disable-next-line react-compiler/react-compiler
|
|
81
85
|
prevContentOffsetY.value = curr;
|
|
86
|
+
} else if (curr !== prevContentOffsetY.value) {
|
|
87
|
+
prevContentOffsetY.value = curr;
|
|
82
88
|
result.contentOffset = {
|
|
83
89
|
x: 0,
|
|
84
90
|
y: curr
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_bindings","_styles","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","OS","Platform","ReanimatedClippingScrollView","Reanimated","createAnimatedComponent","ClippingScrollView","ScrollViewWithBottomPadding","forwardRef","ScrollViewComponent","bottomPadding","scrollIndicatorPadding","contentInset","scrollIndicatorInsets","inverted","contentOffsetY","applyWorkaroundForContentInsetHitTestBug","onContentInsetChange","children","rest","ref","prevContentOffsetY","useSharedValue","insets","useDerivedValue","dynamicTop","value","dynamicBottom","dynamic","top","bottom","effective","left","right","useAnimatedReaction","current","previous","runOnJS","animatedProps","useAnimatedProps","indicatorPadding","indicatorTop","indicatorBottom","result","contentInsetBottom","contentInsetTop","curr","contentOffset","x","y","createElement","style","styles","container","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef } from \"react\";\nimport { Platform } from \"react-native\";\nimport Reanimated, {\n runOnJS,\n useAnimatedProps,\n useAnimatedReaction,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { ClippingScrollView } from \"../../bindings\";\n\nimport styles from \"./styles\";\n\nimport type { ScrollViewProps } from \"react-native\";\nimport type { SharedValue } from \"react-native-reanimated\";\n\nconst OS = Platform.OS;\nconst ReanimatedClippingScrollView =\n OS === \"android\"\n ? Reanimated.createAnimatedComponent(ClippingScrollView)\n : ClippingScrollView;\n\ntype AnimatedScrollViewProps = React.ComponentProps<\n typeof Reanimated.ScrollView\n>;\n\nexport type AnimatedScrollViewComponent = React.ForwardRefExoticComponent<\n AnimatedScrollViewProps & React.RefAttributes<Reanimated.ScrollView>\n>;\n\nexport type ScrollViewContentInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\ntype ScrollViewWithBottomPaddingProps = {\n ScrollViewComponent: AnimatedScrollViewComponent;\n children?: React.ReactNode;\n inverted?: boolean;\n bottomPadding: SharedValue<number>;\n /** Padding for scroll indicator insets (excludes blankSpace). Falls back to bottomPadding when not provided. */\n scrollIndicatorPadding?: SharedValue<number>;\n /** Absolute Y content offset (iOS only, for KeyboardChatScrollView). */\n contentOffsetY?: SharedValue<number>;\n applyWorkaroundForContentInsetHitTestBug?: boolean;\n /**\n * Fires whenever the effective content inset changes (combines the static `contentInset`\n * prop with the dynamic keyboard-driven padding). Useful on Android where the synthetic\n * inset is not reflected in `onScroll` events.\n */\n onContentInsetChange?: (insets: ScrollViewContentInsets) => void;\n} & ScrollViewProps;\n\nconst ScrollViewWithBottomPadding = forwardRef<\n Reanimated.ScrollView,\n ScrollViewWithBottomPaddingProps\n>(\n (\n {\n ScrollViewComponent,\n bottomPadding,\n scrollIndicatorPadding,\n contentInset,\n scrollIndicatorInsets,\n inverted,\n contentOffsetY,\n applyWorkaroundForContentInsetHitTestBug,\n onContentInsetChange,\n children,\n ...rest\n },\n ref,\n ) => {\n const prevContentOffsetY = useSharedValue<number | null>(null);\n\n const insets = useDerivedValue(() => {\n const dynamicTop = inverted ? bottomPadding.value : 0;\n const dynamicBottom = !inverted ? bottomPadding.value : 0;\n\n return {\n dynamic: {\n top: dynamicTop,\n bottom: dynamicBottom,\n },\n effective: {\n top: dynamicTop + (contentInset?.top || 0),\n bottom: dynamicBottom + (contentInset?.bottom || 0),\n left: contentInset?.left || 0,\n right: contentInset?.right || 0,\n } as ScrollViewContentInsets,\n };\n }, [\n inverted,\n contentInset?.top,\n contentInset?.bottom,\n contentInset?.left,\n contentInset?.right,\n ]);\n\n useAnimatedReaction(\n () => insets.value.effective,\n (current, previous) => {\n if (!onContentInsetChange) {\n return;\n }\n if (\n previous &&\n current.top === previous.top &&\n current.bottom === previous.bottom &&\n current.left === previous.left &&\n current.right === previous.right\n ) {\n return;\n }\n runOnJS(onContentInsetChange)(current);\n },\n [onContentInsetChange],\n );\n\n const animatedProps = useAnimatedProps(() => {\n const { dynamic, effective } = insets.value;\n\n const indicatorPadding = scrollIndicatorPadding ?? bottomPadding;\n const indicatorTop =\n (inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.top || 0);\n const indicatorBottom =\n (!inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.bottom || 0);\n\n const result: Record<string, unknown> = {\n // iOS prop\n contentInset: effective,\n scrollIndicatorInsets: {\n bottom: indicatorBottom,\n top: indicatorTop,\n right: scrollIndicatorInsets?.right,\n left: scrollIndicatorInsets?.left,\n },\n // Android prop\n contentInsetBottom: dynamic.bottom,\n contentInsetTop: dynamic.top,\n };\n\n if (contentOffsetY) {\n const curr = contentOffsetY.value;\n\n if (curr !== prevContentOffsetY.value) {\n // eslint-disable-next-line react-compiler/react-compiler\n prevContentOffsetY.value = curr;\n result.contentOffset = { x: 0, y: curr };\n }\n }\n\n return result;\n }, [\n scrollIndicatorInsets?.bottom,\n scrollIndicatorInsets?.top,\n scrollIndicatorInsets?.right,\n scrollIndicatorInsets?.left,\n inverted,\n contentOffsetY,\n ]);\n\n return (\n <ReanimatedClippingScrollView\n animatedProps={animatedProps}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n style={styles.container}\n >\n <ScrollViewComponent ref={ref} animatedProps={animatedProps} {...rest}>\n {children}\n </ScrollViewComponent>\n </ReanimatedClippingScrollView>\n );\n },\n);\n\nexport default ScrollViewWithBottomPadding;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_bindings","_styles","_interopRequireDefault","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_extends","assign","bind","arguments","length","apply","OS","Platform","ReanimatedClippingScrollView","Reanimated","createAnimatedComponent","ClippingScrollView","ScrollViewWithBottomPadding","forwardRef","ScrollViewComponent","bottomPadding","scrollIndicatorPadding","contentInset","scrollIndicatorInsets","inverted","contentOffsetY","applyWorkaroundForContentInsetHitTestBug","onContentInsetChange","children","rest","ref","prevContentOffsetY","useSharedValue","insets","useDerivedValue","dynamicTop","value","dynamicBottom","dynamic","top","bottom","effective","left","right","useAnimatedReaction","current","previous","runOnJS","animatedProps","useAnimatedProps","indicatorPadding","indicatorTop","indicatorBottom","result","contentInsetBottom","contentInsetTop","curr","contentOffset","x","y","createElement","style","styles","container","_default","exports"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef } from \"react\";\nimport { Platform } from \"react-native\";\nimport Reanimated, {\n runOnJS,\n useAnimatedProps,\n useAnimatedReaction,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { ClippingScrollView } from \"../../bindings\";\n\nimport styles from \"./styles\";\n\nimport type { ScrollViewProps } from \"react-native\";\nimport type { SharedValue } from \"react-native-reanimated\";\n\nconst OS = Platform.OS;\nconst ReanimatedClippingScrollView =\n OS === \"android\"\n ? Reanimated.createAnimatedComponent(ClippingScrollView)\n : ClippingScrollView;\n\ntype AnimatedScrollViewProps = React.ComponentProps<\n typeof Reanimated.ScrollView\n>;\n\nexport type AnimatedScrollViewComponent = React.ForwardRefExoticComponent<\n AnimatedScrollViewProps & React.RefAttributes<Reanimated.ScrollView>\n>;\n\nexport type ScrollViewContentInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\ntype ScrollViewWithBottomPaddingProps = {\n ScrollViewComponent: AnimatedScrollViewComponent;\n children?: React.ReactNode;\n inverted?: boolean;\n bottomPadding: SharedValue<number>;\n /** Padding for scroll indicator insets (excludes blankSpace). Falls back to bottomPadding when not provided. */\n scrollIndicatorPadding?: SharedValue<number>;\n /** Absolute Y content offset (iOS only, for KeyboardChatScrollView). */\n contentOffsetY?: SharedValue<number>;\n applyWorkaroundForContentInsetHitTestBug?: boolean;\n /**\n * Fires whenever the effective content inset changes (combines the static `contentInset`\n * prop with the dynamic keyboard-driven padding). Useful on Android where the synthetic\n * inset is not reflected in `onScroll` events.\n */\n onContentInsetChange?: (insets: ScrollViewContentInsets) => void;\n} & ScrollViewProps;\n\nconst ScrollViewWithBottomPadding = forwardRef<\n Reanimated.ScrollView,\n ScrollViewWithBottomPaddingProps\n>(\n (\n {\n ScrollViewComponent,\n bottomPadding,\n scrollIndicatorPadding,\n contentInset,\n scrollIndicatorInsets,\n inverted,\n contentOffsetY,\n applyWorkaroundForContentInsetHitTestBug,\n onContentInsetChange,\n children,\n ...rest\n },\n ref,\n ) => {\n const prevContentOffsetY = useSharedValue<number | null>(null);\n\n const insets = useDerivedValue(() => {\n const dynamicTop = inverted ? bottomPadding.value : 0;\n const dynamicBottom = !inverted ? bottomPadding.value : 0;\n\n return {\n dynamic: {\n top: dynamicTop,\n bottom: dynamicBottom,\n },\n effective: {\n top: dynamicTop + (contentInset?.top || 0),\n bottom: dynamicBottom + (contentInset?.bottom || 0),\n left: contentInset?.left || 0,\n right: contentInset?.right || 0,\n } as ScrollViewContentInsets,\n };\n }, [\n inverted,\n contentInset?.top,\n contentInset?.bottom,\n contentInset?.left,\n contentInset?.right,\n ]);\n\n useAnimatedReaction(\n () => insets.value.effective,\n (current, previous) => {\n if (!onContentInsetChange) {\n return;\n }\n if (\n previous &&\n current.top === previous.top &&\n current.bottom === previous.bottom &&\n current.left === previous.left &&\n current.right === previous.right\n ) {\n return;\n }\n runOnJS(onContentInsetChange)(current);\n },\n [onContentInsetChange],\n );\n\n const animatedProps = useAnimatedProps(() => {\n const { dynamic, effective } = insets.value;\n\n const indicatorPadding = scrollIndicatorPadding ?? bottomPadding;\n const indicatorTop =\n (inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.top || 0);\n const indicatorBottom =\n (!inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.bottom || 0);\n\n const result: Record<string, unknown> = {\n // iOS prop\n contentInset: effective,\n scrollIndicatorInsets: {\n bottom: indicatorBottom,\n top: indicatorTop,\n right: scrollIndicatorInsets?.right,\n left: scrollIndicatorInsets?.left,\n },\n // Android prop\n contentInsetBottom: dynamic.bottom,\n contentInsetTop: dynamic.top,\n };\n\n if (contentOffsetY) {\n const curr = contentOffsetY.value;\n\n if (prevContentOffsetY.value === null) {\n // Swallow the initial evaluation: emitting `contentOffset {x:0,y:0}`\n // in the first animatedProps run overrides the wrapped ScrollView's\n // own `contentOffset` prop on Fabric (e.g. a list's initial scroll\n // offset), making the list mount scrolled to the top natively.\n // eslint-disable-next-line react-compiler/react-compiler\n prevContentOffsetY.value = curr;\n } else if (curr !== prevContentOffsetY.value) {\n prevContentOffsetY.value = curr;\n result.contentOffset = { x: 0, y: curr };\n }\n }\n\n return result;\n }, [\n scrollIndicatorInsets?.bottom,\n scrollIndicatorInsets?.top,\n scrollIndicatorInsets?.right,\n scrollIndicatorInsets?.left,\n inverted,\n contentOffsetY,\n ]);\n\n return (\n <ReanimatedClippingScrollView\n animatedProps={animatedProps}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n style={styles.container}\n >\n <ScrollViewComponent ref={ref} animatedProps={animatedProps} {...rest}>\n {children}\n </ScrollViewComponent>\n </ReanimatedClippingScrollView>\n );\n },\n);\n\nexport default ScrollViewWithBottomPadding;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -65,7 +65,15 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({
|
|
|
65
65
|
inverted,
|
|
66
66
|
onEndVisible
|
|
67
67
|
});
|
|
68
|
-
|
|
68
|
+
|
|
69
|
+
// intentionally clamp `blankSpace` at one ScrollView viewport. The Android
|
|
70
|
+
// `ClippingScrollView` workaround temporarily substitutes padding/range
|
|
71
|
+
// during touch handling, and oversized blank ranges can de-sync during fast
|
|
72
|
+
// momentum gestures. One viewport is enough for the short-content case;
|
|
73
|
+
// larger values only allow scrolling to a fully blank screen which is not
|
|
74
|
+
// the use case for this library. If you found this comment and it causes
|
|
75
|
+
// a bug for you, please open an issue.
|
|
76
|
+
const totalPadding = useDerivedValue(() => Math.min(layout.value.height, Math.max(blankSpace.value, padding.value + extraContentPadding.value)));
|
|
69
77
|
|
|
70
78
|
// Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).
|
|
71
79
|
// Apps that render into the unsafe area can supply a negative
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","forwardRef","useCallback","useMemo","StyleSheet","makeMutable","useAnimatedRef","useAnimatedStyle","useDerivedValue","Reanimated","useCombinedRef","ScrollViewWithBottomPadding","useChatKeyboard","useEndVisible","useExtraContentPadding","ZERO_CONTENT_PADDING","ZERO_BLANK_SPACE","KeyboardChatScrollView","children","ScrollViewComponent","ScrollView","inverted","keyboardLiftBehavior","freeze","offset","extraContentPadding","blankSpace","applyWorkaroundForContentInsetHitTestBug","onLayout","onLayoutProp","onContentSizeChange","onContentSizeChangeProp","onEndVisible","rest","ref","scrollViewRef","onRef","freezeSV","value","padding","currentHeight","contentOffsetY","scroll","layout","size","onLayoutInternal","onContentSizeChangeInternal","keyboardPadding","totalPadding","Math","max","indicatorPadding","e","w","h","commitStyle","transform","translateY","commit","styles","commitView","createElement","Fragment","_extends","bottomPadding","scrollIndicatorPadding","View","style","create","display","position"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport {\n makeMutable,\n useAnimatedRef,\n useAnimatedStyle,\n useDerivedValue,\n} from \"react-native-reanimated\";\nimport Reanimated from \"react-native-reanimated\";\n\nimport useCombinedRef from \"../hooks/useCombinedRef\";\nimport ScrollViewWithBottomPadding from \"../ScrollViewWithBottomPadding\";\n\nimport { useChatKeyboard } from \"./useChatKeyboard\";\nimport { useEndVisible } from \"./useEndVisible\";\nimport { useExtraContentPadding } from \"./useExtraContentPadding\";\n\nimport type { KeyboardChatScrollViewProps } from \"./types\";\nimport type { LayoutChangeEvent } from \"react-native\";\n\nconst ZERO_CONTENT_PADDING = makeMutable(0);\nconst ZERO_BLANK_SPACE = makeMutable(0);\n\nconst KeyboardChatScrollView = forwardRef<\n Reanimated.ScrollView,\n React.PropsWithChildren<KeyboardChatScrollViewProps>\n>(\n (\n {\n children,\n ScrollViewComponent = Reanimated.ScrollView,\n inverted = false,\n keyboardLiftBehavior = \"always\",\n freeze = false,\n offset = 0,\n extraContentPadding = ZERO_CONTENT_PADDING,\n blankSpace = ZERO_BLANK_SPACE,\n applyWorkaroundForContentInsetHitTestBug = false,\n onLayout: onLayoutProp,\n onContentSizeChange: onContentSizeChangeProp,\n onEndVisible,\n ...rest\n },\n ref,\n ) => {\n const scrollViewRef = useAnimatedRef<Reanimated.ScrollView>();\n const onRef = useCombinedRef(ref, scrollViewRef);\n const freezeSV = useDerivedValue(() =>\n typeof freeze === \"boolean\" ? freeze : freeze.value,\n );\n const {\n padding,\n currentHeight,\n contentOffsetY,\n scroll,\n layout,\n size,\n onLayout: onLayoutInternal,\n onContentSizeChange: onContentSizeChangeInternal,\n } = useChatKeyboard(scrollViewRef, {\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n offset,\n blankSpace,\n extraContentPadding,\n });\n\n useExtraContentPadding({\n scrollViewRef,\n extraContentPadding,\n keyboardPadding: padding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n });\n\n useEndVisible({\n scroll,\n layout,\n size,\n inverted,\n onEndVisible,\n });\n\n const totalPadding = useDerivedValue(() =>\n Math.max(blankSpace.value, padding.value + extraContentPadding.value),\n );\n\n // Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).\n // Apps that render into the unsafe area can supply a negative\n // scrollIndicatorInsets adjustment at the application layer.\n const indicatorPadding = useDerivedValue(\n () => padding.value + extraContentPadding.value,\n );\n\n const onLayout = useCallback(\n (e: LayoutChangeEvent) => {\n onLayoutInternal(e);\n onLayoutProp?.(e);\n },\n [onLayoutInternal, onLayoutProp],\n );\n\n const onContentSizeChange = useCallback(\n (w: number, h: number) => {\n onContentSizeChangeInternal(w, h);\n onContentSizeChangeProp?.(w, h);\n },\n [onContentSizeChangeInternal, onContentSizeChangeProp],\n );\n\n // Invisible view whose animated style changes every frame during keyboard\n // animation. On Fabric, this forces Reanimated to schedule a commit,\n // which flushes the scrollTo call in the same frame (fixing de-synchronization).\n // see https://github.com/software-mansion/react-native-reanimated/issues/9000\n const commitStyle = useAnimatedStyle(\n () => ({\n transform: [{ translateY: -currentHeight.value }],\n }),\n [],\n );\n const commit = useMemo(\n () => [styles.commitView, commitStyle],\n [commitStyle],\n );\n\n return (\n <>\n <ScrollViewWithBottomPadding\n ref={onRef}\n {...rest}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n bottomPadding={totalPadding}\n contentOffsetY={contentOffsetY}\n inverted={inverted}\n scrollIndicatorPadding={indicatorPadding}\n ScrollViewComponent={ScrollViewComponent}\n onContentSizeChange={onContentSizeChange}\n onLayout={onLayout}\n >\n {children}\n </ScrollViewWithBottomPadding>\n <Reanimated.View style={commit} />\n </>\n );\n },\n);\n\nconst styles = StyleSheet.create({\n commitView: {\n display: \"none\",\n position: \"absolute\",\n },\n});\n\nexport default KeyboardChatScrollView;\n"],"mappings":";AAAA,OAAOA,KAAK,IAAIC,UAAU,EAAEC,WAAW,EAAEC,OAAO,QAAQ,OAAO;AAC/D,SAASC,UAAU,QAAQ,cAAc;AACzC,SACEC,WAAW,EACXC,cAAc,EACdC,gBAAgB,EAChBC,eAAe,QACV,yBAAyB;AAChC,OAAOC,UAAU,MAAM,yBAAyB;AAEhD,OAAOC,cAAc,MAAM,yBAAyB;AACpD,OAAOC,2BAA2B,MAAM,gCAAgC;AAExE,SAASC,eAAe,QAAQ,mBAAmB;AACnD,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,SAASC,sBAAsB,QAAQ,0BAA0B;AAKjE,MAAMC,oBAAoB,GAAGV,WAAW,CAAC,CAAC,CAAC;AAC3C,MAAMW,gBAAgB,GAAGX,WAAW,CAAC,CAAC,CAAC;AAEvC,MAAMY,sBAAsB,gBAAGhB,UAAU,CAIvC,CACE;EACEiB,QAAQ;EACRC,mBAAmB,GAAGV,UAAU,CAACW,UAAU;EAC3CC,QAAQ,GAAG,KAAK;EAChBC,oBAAoB,GAAG,QAAQ;EAC/BC,MAAM,GAAG,KAAK;EACdC,MAAM,GAAG,CAAC;EACVC,mBAAmB,GAAGV,oBAAoB;EAC1CW,UAAU,GAAGV,gBAAgB;EAC7BW,wCAAwC,GAAG,KAAK;EAChDC,QAAQ,EAAEC,YAAY;EACtBC,mBAAmB,EAAEC,uBAAuB;EAC5CC,YAAY;EACZ,GAAGC;AACL,CAAC,EACDC,GAAG,KACA;EACH,MAAMC,aAAa,GAAG7B,cAAc,CAAwB,CAAC;EAC7D,MAAM8B,KAAK,GAAG1B,cAAc,CAACwB,GAAG,EAAEC,aAAa,CAAC;EAChD,MAAME,QAAQ,GAAG7B,eAAe,CAAC,MAC/B,OAAOe,MAAM,KAAK,SAAS,GAAGA,MAAM,GAAGA,MAAM,CAACe,KAChD,CAAC;EACD,MAAM;IACJC,OAAO;IACPC,aAAa;IACbC,cAAc;IACdC,MAAM;IACNC,MAAM;IACNC,IAAI;IACJhB,QAAQ,EAAEiB,gBAAgB;IAC1Bf,mBAAmB,EAAEgB;EACvB,CAAC,GAAGlC,eAAe,CAACuB,aAAa,EAAE;IACjCd,QAAQ;IACRC,oBAAoB;IACpBC,MAAM,EAAEc,QAAQ;IAChBb,MAAM;IACNE,UAAU;IACVD;EACF,CAAC,CAAC;EAEFX,sBAAsB,CAAC;IACrBqB,aAAa;IACbV,mBAAmB;IACnBsB,eAAe,EAAER,OAAO;IACxBb,UAAU;IACVgB,MAAM;IACNC,MAAM;IACNC,IAAI;IACJH,cAAc;IACdpB,QAAQ;IACRC,oBAAoB;IACpBC,MAAM,EAAEc;EACV,CAAC,CAAC;EAEFxB,aAAa,CAAC;IACZ6B,MAAM;IACNC,MAAM;IACNC,IAAI;IACJvB,QAAQ;IACRW;EACF,CAAC,CAAC;
|
|
1
|
+
{"version":3,"names":["React","forwardRef","useCallback","useMemo","StyleSheet","makeMutable","useAnimatedRef","useAnimatedStyle","useDerivedValue","Reanimated","useCombinedRef","ScrollViewWithBottomPadding","useChatKeyboard","useEndVisible","useExtraContentPadding","ZERO_CONTENT_PADDING","ZERO_BLANK_SPACE","KeyboardChatScrollView","children","ScrollViewComponent","ScrollView","inverted","keyboardLiftBehavior","freeze","offset","extraContentPadding","blankSpace","applyWorkaroundForContentInsetHitTestBug","onLayout","onLayoutProp","onContentSizeChange","onContentSizeChangeProp","onEndVisible","rest","ref","scrollViewRef","onRef","freezeSV","value","padding","currentHeight","contentOffsetY","scroll","layout","size","onLayoutInternal","onContentSizeChangeInternal","keyboardPadding","totalPadding","Math","min","height","max","indicatorPadding","e","w","h","commitStyle","transform","translateY","commit","styles","commitView","createElement","Fragment","_extends","bottomPadding","scrollIndicatorPadding","View","style","create","display","position"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef, useCallback, useMemo } from \"react\";\nimport { StyleSheet } from \"react-native\";\nimport {\n makeMutable,\n useAnimatedRef,\n useAnimatedStyle,\n useDerivedValue,\n} from \"react-native-reanimated\";\nimport Reanimated from \"react-native-reanimated\";\n\nimport useCombinedRef from \"../hooks/useCombinedRef\";\nimport ScrollViewWithBottomPadding from \"../ScrollViewWithBottomPadding\";\n\nimport { useChatKeyboard } from \"./useChatKeyboard\";\nimport { useEndVisible } from \"./useEndVisible\";\nimport { useExtraContentPadding } from \"./useExtraContentPadding\";\n\nimport type { KeyboardChatScrollViewProps } from \"./types\";\nimport type { LayoutChangeEvent } from \"react-native\";\n\nconst ZERO_CONTENT_PADDING = makeMutable(0);\nconst ZERO_BLANK_SPACE = makeMutable(0);\n\nconst KeyboardChatScrollView = forwardRef<\n Reanimated.ScrollView,\n React.PropsWithChildren<KeyboardChatScrollViewProps>\n>(\n (\n {\n children,\n ScrollViewComponent = Reanimated.ScrollView,\n inverted = false,\n keyboardLiftBehavior = \"always\",\n freeze = false,\n offset = 0,\n extraContentPadding = ZERO_CONTENT_PADDING,\n blankSpace = ZERO_BLANK_SPACE,\n applyWorkaroundForContentInsetHitTestBug = false,\n onLayout: onLayoutProp,\n onContentSizeChange: onContentSizeChangeProp,\n onEndVisible,\n ...rest\n },\n ref,\n ) => {\n const scrollViewRef = useAnimatedRef<Reanimated.ScrollView>();\n const onRef = useCombinedRef(ref, scrollViewRef);\n const freezeSV = useDerivedValue(() =>\n typeof freeze === \"boolean\" ? freeze : freeze.value,\n );\n const {\n padding,\n currentHeight,\n contentOffsetY,\n scroll,\n layout,\n size,\n onLayout: onLayoutInternal,\n onContentSizeChange: onContentSizeChangeInternal,\n } = useChatKeyboard(scrollViewRef, {\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n offset,\n blankSpace,\n extraContentPadding,\n });\n\n useExtraContentPadding({\n scrollViewRef,\n extraContentPadding,\n keyboardPadding: padding,\n blankSpace,\n scroll,\n layout,\n size,\n contentOffsetY,\n inverted,\n keyboardLiftBehavior,\n freeze: freezeSV,\n });\n\n useEndVisible({\n scroll,\n layout,\n size,\n inverted,\n onEndVisible,\n });\n\n // intentionally clamp `blankSpace` at one ScrollView viewport. The Android\n // `ClippingScrollView` workaround temporarily substitutes padding/range\n // during touch handling, and oversized blank ranges can de-sync during fast\n // momentum gestures. One viewport is enough for the short-content case;\n // larger values only allow scrolling to a fully blank screen which is not\n // the use case for this library. If you found this comment and it causes\n // a bug for you, please open an issue.\n const totalPadding = useDerivedValue(() =>\n Math.min(\n layout.value.height,\n Math.max(blankSpace.value, padding.value + extraContentPadding.value),\n ),\n );\n\n // Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).\n // Apps that render into the unsafe area can supply a negative\n // scrollIndicatorInsets adjustment at the application layer.\n const indicatorPadding = useDerivedValue(\n () => padding.value + extraContentPadding.value,\n );\n\n const onLayout = useCallback(\n (e: LayoutChangeEvent) => {\n onLayoutInternal(e);\n onLayoutProp?.(e);\n },\n [onLayoutInternal, onLayoutProp],\n );\n\n const onContentSizeChange = useCallback(\n (w: number, h: number) => {\n onContentSizeChangeInternal(w, h);\n onContentSizeChangeProp?.(w, h);\n },\n [onContentSizeChangeInternal, onContentSizeChangeProp],\n );\n\n // Invisible view whose animated style changes every frame during keyboard\n // animation. On Fabric, this forces Reanimated to schedule a commit,\n // which flushes the scrollTo call in the same frame (fixing de-synchronization).\n // see https://github.com/software-mansion/react-native-reanimated/issues/9000\n const commitStyle = useAnimatedStyle(\n () => ({\n transform: [{ translateY: -currentHeight.value }],\n }),\n [],\n );\n const commit = useMemo(\n () => [styles.commitView, commitStyle],\n [commitStyle],\n );\n\n return (\n <>\n <ScrollViewWithBottomPadding\n ref={onRef}\n {...rest}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n bottomPadding={totalPadding}\n contentOffsetY={contentOffsetY}\n inverted={inverted}\n scrollIndicatorPadding={indicatorPadding}\n ScrollViewComponent={ScrollViewComponent}\n onContentSizeChange={onContentSizeChange}\n onLayout={onLayout}\n >\n {children}\n </ScrollViewWithBottomPadding>\n <Reanimated.View style={commit} />\n </>\n );\n },\n);\n\nconst styles = StyleSheet.create({\n commitView: {\n display: \"none\",\n position: \"absolute\",\n },\n});\n\nexport default KeyboardChatScrollView;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -68,9 +68,15 @@ const ScrollViewWithBottomPadding = /*#__PURE__*/forwardRef(({
|
|
|
68
68
|
};
|
|
69
69
|
if (contentOffsetY) {
|
|
70
70
|
const curr = contentOffsetY.value;
|
|
71
|
-
if (
|
|
71
|
+
if (prevContentOffsetY.value === null) {
|
|
72
|
+
// Swallow the initial evaluation: emitting `contentOffset {x:0,y:0}`
|
|
73
|
+
// in the first animatedProps run overrides the wrapped ScrollView's
|
|
74
|
+
// own `contentOffset` prop on Fabric (e.g. a list's initial scroll
|
|
75
|
+
// offset), making the list mount scrolled to the top natively.
|
|
72
76
|
// eslint-disable-next-line react-compiler/react-compiler
|
|
73
77
|
prevContentOffsetY.value = curr;
|
|
78
|
+
} else if (curr !== prevContentOffsetY.value) {
|
|
79
|
+
prevContentOffsetY.value = curr;
|
|
74
80
|
result.contentOffset = {
|
|
75
81
|
x: 0,
|
|
76
82
|
y: curr
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","forwardRef","Platform","Reanimated","runOnJS","useAnimatedProps","useAnimatedReaction","useDerivedValue","useSharedValue","ClippingScrollView","styles","OS","ReanimatedClippingScrollView","createAnimatedComponent","ScrollViewWithBottomPadding","ScrollViewComponent","bottomPadding","scrollIndicatorPadding","contentInset","scrollIndicatorInsets","inverted","contentOffsetY","applyWorkaroundForContentInsetHitTestBug","onContentInsetChange","children","rest","ref","prevContentOffsetY","insets","dynamicTop","value","dynamicBottom","dynamic","top","bottom","effective","left","right","current","previous","animatedProps","indicatorPadding","indicatorTop","indicatorBottom","result","contentInsetBottom","contentInsetTop","curr","contentOffset","x","y","createElement","style","container","_extends"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef } from \"react\";\nimport { Platform } from \"react-native\";\nimport Reanimated, {\n runOnJS,\n useAnimatedProps,\n useAnimatedReaction,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { ClippingScrollView } from \"../../bindings\";\n\nimport styles from \"./styles\";\n\nimport type { ScrollViewProps } from \"react-native\";\nimport type { SharedValue } from \"react-native-reanimated\";\n\nconst OS = Platform.OS;\nconst ReanimatedClippingScrollView =\n OS === \"android\"\n ? Reanimated.createAnimatedComponent(ClippingScrollView)\n : ClippingScrollView;\n\ntype AnimatedScrollViewProps = React.ComponentProps<\n typeof Reanimated.ScrollView\n>;\n\nexport type AnimatedScrollViewComponent = React.ForwardRefExoticComponent<\n AnimatedScrollViewProps & React.RefAttributes<Reanimated.ScrollView>\n>;\n\nexport type ScrollViewContentInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\ntype ScrollViewWithBottomPaddingProps = {\n ScrollViewComponent: AnimatedScrollViewComponent;\n children?: React.ReactNode;\n inverted?: boolean;\n bottomPadding: SharedValue<number>;\n /** Padding for scroll indicator insets (excludes blankSpace). Falls back to bottomPadding when not provided. */\n scrollIndicatorPadding?: SharedValue<number>;\n /** Absolute Y content offset (iOS only, for KeyboardChatScrollView). */\n contentOffsetY?: SharedValue<number>;\n applyWorkaroundForContentInsetHitTestBug?: boolean;\n /**\n * Fires whenever the effective content inset changes (combines the static `contentInset`\n * prop with the dynamic keyboard-driven padding). Useful on Android where the synthetic\n * inset is not reflected in `onScroll` events.\n */\n onContentInsetChange?: (insets: ScrollViewContentInsets) => void;\n} & ScrollViewProps;\n\nconst ScrollViewWithBottomPadding = forwardRef<\n Reanimated.ScrollView,\n ScrollViewWithBottomPaddingProps\n>(\n (\n {\n ScrollViewComponent,\n bottomPadding,\n scrollIndicatorPadding,\n contentInset,\n scrollIndicatorInsets,\n inverted,\n contentOffsetY,\n applyWorkaroundForContentInsetHitTestBug,\n onContentInsetChange,\n children,\n ...rest\n },\n ref,\n ) => {\n const prevContentOffsetY = useSharedValue<number | null>(null);\n\n const insets = useDerivedValue(() => {\n const dynamicTop = inverted ? bottomPadding.value : 0;\n const dynamicBottom = !inverted ? bottomPadding.value : 0;\n\n return {\n dynamic: {\n top: dynamicTop,\n bottom: dynamicBottom,\n },\n effective: {\n top: dynamicTop + (contentInset?.top || 0),\n bottom: dynamicBottom + (contentInset?.bottom || 0),\n left: contentInset?.left || 0,\n right: contentInset?.right || 0,\n } as ScrollViewContentInsets,\n };\n }, [\n inverted,\n contentInset?.top,\n contentInset?.bottom,\n contentInset?.left,\n contentInset?.right,\n ]);\n\n useAnimatedReaction(\n () => insets.value.effective,\n (current, previous) => {\n if (!onContentInsetChange) {\n return;\n }\n if (\n previous &&\n current.top === previous.top &&\n current.bottom === previous.bottom &&\n current.left === previous.left &&\n current.right === previous.right\n ) {\n return;\n }\n runOnJS(onContentInsetChange)(current);\n },\n [onContentInsetChange],\n );\n\n const animatedProps = useAnimatedProps(() => {\n const { dynamic, effective } = insets.value;\n\n const indicatorPadding = scrollIndicatorPadding ?? bottomPadding;\n const indicatorTop =\n (inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.top || 0);\n const indicatorBottom =\n (!inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.bottom || 0);\n\n const result: Record<string, unknown> = {\n // iOS prop\n contentInset: effective,\n scrollIndicatorInsets: {\n bottom: indicatorBottom,\n top: indicatorTop,\n right: scrollIndicatorInsets?.right,\n left: scrollIndicatorInsets?.left,\n },\n // Android prop\n contentInsetBottom: dynamic.bottom,\n contentInsetTop: dynamic.top,\n };\n\n if (contentOffsetY) {\n const curr = contentOffsetY.value;\n\n if (curr !== prevContentOffsetY.value) {\n // eslint-disable-next-line react-compiler/react-compiler\n prevContentOffsetY.value = curr;\n result.contentOffset = { x: 0, y: curr };\n }\n }\n\n return result;\n }, [\n scrollIndicatorInsets?.bottom,\n scrollIndicatorInsets?.top,\n scrollIndicatorInsets?.right,\n scrollIndicatorInsets?.left,\n inverted,\n contentOffsetY,\n ]);\n\n return (\n <ReanimatedClippingScrollView\n animatedProps={animatedProps}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n style={styles.container}\n >\n <ScrollViewComponent ref={ref} animatedProps={animatedProps} {...rest}>\n {children}\n </ScrollViewComponent>\n </ReanimatedClippingScrollView>\n );\n },\n);\n\nexport default ScrollViewWithBottomPadding;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["React","forwardRef","Platform","Reanimated","runOnJS","useAnimatedProps","useAnimatedReaction","useDerivedValue","useSharedValue","ClippingScrollView","styles","OS","ReanimatedClippingScrollView","createAnimatedComponent","ScrollViewWithBottomPadding","ScrollViewComponent","bottomPadding","scrollIndicatorPadding","contentInset","scrollIndicatorInsets","inverted","contentOffsetY","applyWorkaroundForContentInsetHitTestBug","onContentInsetChange","children","rest","ref","prevContentOffsetY","insets","dynamicTop","value","dynamicBottom","dynamic","top","bottom","effective","left","right","current","previous","animatedProps","indicatorPadding","indicatorTop","indicatorBottom","result","contentInsetBottom","contentInsetTop","curr","contentOffset","x","y","createElement","style","container","_extends"],"sources":["index.tsx"],"sourcesContent":["import React, { forwardRef } from \"react\";\nimport { Platform } from \"react-native\";\nimport Reanimated, {\n runOnJS,\n useAnimatedProps,\n useAnimatedReaction,\n useDerivedValue,\n useSharedValue,\n} from \"react-native-reanimated\";\n\nimport { ClippingScrollView } from \"../../bindings\";\n\nimport styles from \"./styles\";\n\nimport type { ScrollViewProps } from \"react-native\";\nimport type { SharedValue } from \"react-native-reanimated\";\n\nconst OS = Platform.OS;\nconst ReanimatedClippingScrollView =\n OS === \"android\"\n ? Reanimated.createAnimatedComponent(ClippingScrollView)\n : ClippingScrollView;\n\ntype AnimatedScrollViewProps = React.ComponentProps<\n typeof Reanimated.ScrollView\n>;\n\nexport type AnimatedScrollViewComponent = React.ForwardRefExoticComponent<\n AnimatedScrollViewProps & React.RefAttributes<Reanimated.ScrollView>\n>;\n\nexport type ScrollViewContentInsets = {\n top: number;\n bottom: number;\n left: number;\n right: number;\n};\n\ntype ScrollViewWithBottomPaddingProps = {\n ScrollViewComponent: AnimatedScrollViewComponent;\n children?: React.ReactNode;\n inverted?: boolean;\n bottomPadding: SharedValue<number>;\n /** Padding for scroll indicator insets (excludes blankSpace). Falls back to bottomPadding when not provided. */\n scrollIndicatorPadding?: SharedValue<number>;\n /** Absolute Y content offset (iOS only, for KeyboardChatScrollView). */\n contentOffsetY?: SharedValue<number>;\n applyWorkaroundForContentInsetHitTestBug?: boolean;\n /**\n * Fires whenever the effective content inset changes (combines the static `contentInset`\n * prop with the dynamic keyboard-driven padding). Useful on Android where the synthetic\n * inset is not reflected in `onScroll` events.\n */\n onContentInsetChange?: (insets: ScrollViewContentInsets) => void;\n} & ScrollViewProps;\n\nconst ScrollViewWithBottomPadding = forwardRef<\n Reanimated.ScrollView,\n ScrollViewWithBottomPaddingProps\n>(\n (\n {\n ScrollViewComponent,\n bottomPadding,\n scrollIndicatorPadding,\n contentInset,\n scrollIndicatorInsets,\n inverted,\n contentOffsetY,\n applyWorkaroundForContentInsetHitTestBug,\n onContentInsetChange,\n children,\n ...rest\n },\n ref,\n ) => {\n const prevContentOffsetY = useSharedValue<number | null>(null);\n\n const insets = useDerivedValue(() => {\n const dynamicTop = inverted ? bottomPadding.value : 0;\n const dynamicBottom = !inverted ? bottomPadding.value : 0;\n\n return {\n dynamic: {\n top: dynamicTop,\n bottom: dynamicBottom,\n },\n effective: {\n top: dynamicTop + (contentInset?.top || 0),\n bottom: dynamicBottom + (contentInset?.bottom || 0),\n left: contentInset?.left || 0,\n right: contentInset?.right || 0,\n } as ScrollViewContentInsets,\n };\n }, [\n inverted,\n contentInset?.top,\n contentInset?.bottom,\n contentInset?.left,\n contentInset?.right,\n ]);\n\n useAnimatedReaction(\n () => insets.value.effective,\n (current, previous) => {\n if (!onContentInsetChange) {\n return;\n }\n if (\n previous &&\n current.top === previous.top &&\n current.bottom === previous.bottom &&\n current.left === previous.left &&\n current.right === previous.right\n ) {\n return;\n }\n runOnJS(onContentInsetChange)(current);\n },\n [onContentInsetChange],\n );\n\n const animatedProps = useAnimatedProps(() => {\n const { dynamic, effective } = insets.value;\n\n const indicatorPadding = scrollIndicatorPadding ?? bottomPadding;\n const indicatorTop =\n (inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.top || 0);\n const indicatorBottom =\n (!inverted ? indicatorPadding.value : 0) +\n (scrollIndicatorInsets?.bottom || 0);\n\n const result: Record<string, unknown> = {\n // iOS prop\n contentInset: effective,\n scrollIndicatorInsets: {\n bottom: indicatorBottom,\n top: indicatorTop,\n right: scrollIndicatorInsets?.right,\n left: scrollIndicatorInsets?.left,\n },\n // Android prop\n contentInsetBottom: dynamic.bottom,\n contentInsetTop: dynamic.top,\n };\n\n if (contentOffsetY) {\n const curr = contentOffsetY.value;\n\n if (prevContentOffsetY.value === null) {\n // Swallow the initial evaluation: emitting `contentOffset {x:0,y:0}`\n // in the first animatedProps run overrides the wrapped ScrollView's\n // own `contentOffset` prop on Fabric (e.g. a list's initial scroll\n // offset), making the list mount scrolled to the top natively.\n // eslint-disable-next-line react-compiler/react-compiler\n prevContentOffsetY.value = curr;\n } else if (curr !== prevContentOffsetY.value) {\n prevContentOffsetY.value = curr;\n result.contentOffset = { x: 0, y: curr };\n }\n }\n\n return result;\n }, [\n scrollIndicatorInsets?.bottom,\n scrollIndicatorInsets?.top,\n scrollIndicatorInsets?.right,\n scrollIndicatorInsets?.left,\n inverted,\n contentOffsetY,\n ]);\n\n return (\n <ReanimatedClippingScrollView\n animatedProps={animatedProps}\n applyWorkaroundForContentInsetHitTestBug={\n applyWorkaroundForContentInsetHitTestBug\n }\n style={styles.container}\n >\n <ScrollViewComponent ref={ref} animatedProps={animatedProps} {...rest}>\n {children}\n </ScrollViewComponent>\n </ReanimatedClippingScrollView>\n );\n },\n);\n\nexport default ScrollViewWithBottomPadding;\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -88,8 +88,18 @@ const KeyboardChatScrollView = forwardRef<
|
|
|
88
88
|
onEndVisible,
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
// intentionally clamp `blankSpace` at one ScrollView viewport. The Android
|
|
92
|
+
// `ClippingScrollView` workaround temporarily substitutes padding/range
|
|
93
|
+
// during touch handling, and oversized blank ranges can de-sync during fast
|
|
94
|
+
// momentum gestures. One viewport is enough for the short-content case;
|
|
95
|
+
// larger values only allow scrolling to a fully blank screen which is not
|
|
96
|
+
// the use case for this library. If you found this comment and it causes
|
|
97
|
+
// a bug for you, please open an issue.
|
|
91
98
|
const totalPadding = useDerivedValue(() =>
|
|
92
|
-
Math.
|
|
99
|
+
Math.min(
|
|
100
|
+
layout.value.height,
|
|
101
|
+
Math.max(blankSpace.value, padding.value + extraContentPadding.value),
|
|
102
|
+
),
|
|
93
103
|
);
|
|
94
104
|
|
|
95
105
|
// Scroll indicator inset = keyboard + extraContentPadding (excludes blankSpace).
|
|
@@ -148,9 +148,15 @@ const ScrollViewWithBottomPadding = forwardRef<
|
|
|
148
148
|
if (contentOffsetY) {
|
|
149
149
|
const curr = contentOffsetY.value;
|
|
150
150
|
|
|
151
|
-
if (
|
|
151
|
+
if (prevContentOffsetY.value === null) {
|
|
152
|
+
// Swallow the initial evaluation: emitting `contentOffset {x:0,y:0}`
|
|
153
|
+
// in the first animatedProps run overrides the wrapped ScrollView's
|
|
154
|
+
// own `contentOffset` prop on Fabric (e.g. a list's initial scroll
|
|
155
|
+
// offset), making the list mount scrolled to the top natively.
|
|
152
156
|
// eslint-disable-next-line react-compiler/react-compiler
|
|
153
157
|
prevContentOffsetY.value = curr;
|
|
158
|
+
} else if (curr !== prevContentOffsetY.value) {
|
|
159
|
+
prevContentOffsetY.value = curr;
|
|
154
160
|
result.contentOffset = { x: 0, y: curr };
|
|
155
161
|
}
|
|
156
162
|
}
|