@@ -21,7 +21,7 @@ import { GestureDetectorType } from '../detectors';
2121import type { NativeGesture } from '../hooks/gestures/native/NativeTypes' ;
2222import { NativeWrapperProps } from '../hooks/utils' ;
2323import type { NativeWrapperProperties } from '../types/NativeWrapperType' ;
24- import {
24+ import ScrollViewResponderInterceptor , {
2525 interceptScrollViewChildren ,
2626 ScrollViewResponderProvider ,
2727} from './ScrollViewResponderInterceptor' ;
@@ -81,27 +81,56 @@ export const ScrollView = (
8181 } ) ;
8282 } ;
8383
84- return (
84+ // ScrollView resolves `stickyHeaderIndices` against its direct children, so
85+ // the single responder interceptor would collapse the
86+ // content into one child and pin all of it when index 0 is sticky.
87+ // ScrollViews using sticky headers move the responder context above the
88+ // ScrollView and leave the child count intact — with one logical responder
89+ // per child in 'handled' mode.
90+ const hasStickyHeaders =
91+ Array . isArray ( rest . stickyHeaderIndices ) &&
92+ rest . stickyHeaderIndices . length > 0 ;
93+
94+ const scrollView = (
95+ < GHScrollView
96+ { ...rest }
97+ ref = { props . ref }
98+ keyboardShouldPersistTaps = { keyboardShouldPersistTaps }
99+ onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER = { updateGesture }
100+ // @ts -ignore we don't pass `refreshing` prop as we only want to override the ref
101+ refreshControl = {
102+ refreshControl
103+ ? React . cloneElement (
104+ refreshControl ,
105+ // @ts -ignore block exists (on our RefreshControl)
106+ scrollGesture ? { block : scrollGesture } : { }
107+ )
108+ : undefined
109+ } >
110+ { ! hasStickyHeaders ? (
111+ < ScrollViewResponderInterceptor
112+ keyboardShouldPersistTaps = { keyboardShouldPersistTaps } >
113+ { children }
114+ </ ScrollViewResponderInterceptor >
115+ ) : keyboardShouldPersistTaps === 'handled' ? (
116+ interceptScrollViewChildren ( children )
117+ ) : (
118+ children
119+ ) }
120+ </ GHScrollView >
121+ ) ;
122+
123+ // The provider is required even when no logical responders are rendered —
124+ // Pressable and Touchable read its context (and its keyboard-visibility
125+ // tracking) to suppress presses on keyboard-dismissing taps in 'never'
126+ // mode. Only the responder wrappers are gated on 'handled'.
127+ return hasStickyHeaders ? (
85128 < ScrollViewResponderProvider
86129 keyboardShouldPersistTaps = { keyboardShouldPersistTaps } >
87- < GHScrollView
88- { ...rest }
89- ref = { props . ref }
90- keyboardShouldPersistTaps = { keyboardShouldPersistTaps }
91- onGestureUpdate_CAN_CAUSE_INFINITE_RERENDER = { updateGesture }
92- // @ts -ignore we don't pass `refreshing` prop as we only want to override the ref
93- refreshControl = {
94- refreshControl
95- ? React . cloneElement (
96- refreshControl ,
97- // @ts -ignore block exists (on our RefreshControl)
98- scrollGesture ? { block : scrollGesture } : { }
99- )
100- : undefined
101- } >
102- { interceptScrollViewChildren ( children ) }
103- </ GHScrollView >
130+ { scrollView }
104131 </ ScrollViewResponderProvider >
132+ ) : (
133+ scrollView
105134 ) ;
106135} ;
107136
0 commit comments