11import type { PropsWithChildren } from 'react' ;
2- import React , { useCallback , useEffect , useMemo , useRef } from 'react' ;
2+ import React , { use , useCallback , useEffect , useMemo , useRef } from 'react' ;
33import type {
44 EmitterSubscription ,
55 KeyboardEvent ,
@@ -95,7 +95,7 @@ type ScrollViewResponderInterceptorProps = PropsWithChildren<{
9595 keyboardShouldPersistTaps ?: RNScrollViewProps [ 'keyboardShouldPersistTaps' ] ;
9696} > ;
9797
98- const ScrollViewResponderInterceptor = ( {
98+ export const ScrollViewResponderProvider = ( {
9999 children,
100100 keyboardShouldPersistTaps,
101101} : ScrollViewResponderInterceptorProps ) => {
@@ -110,44 +110,53 @@ const ScrollViewResponderInterceptor = ({
110110 return ( ) => unsubscribeFromKeyboardVisibility ( ) ;
111111 } , [ ] ) ;
112112
113+ return (
114+ < JSResponderContext value = { contextValue } > { children } </ JSResponderContext >
115+ ) ;
116+ } ;
117+
118+ const LogicalResponderChild = ( { children } : PropsWithChildren ) => {
119+ const jsResponderContext = use ( JSResponderContext ) ;
120+
113121 const resetRNGHResponderEvent = useCallback ( ( ) => {
114- isRNGHResponderEvent . current = false ;
122+ updateResponderEventValue ( jsResponderContext , false ) ;
115123 return false ;
116- } , [ ] ) ;
124+ } , [ jsResponderContext ] ) ;
117125
118126 const handleStartShouldSetResponder = useCallback ( ( ) => {
119127 const shouldHandleRNGHEvent =
120- keyboardShouldPersistTaps === 'handled' && isRNGHResponderEvent . current ;
128+ jsResponderContext ?. keyboardShouldPersistTaps === 'handled' &&
129+ jsResponderContext . isRNGHResponderEvent . current ;
121130
122- isRNGHResponderEvent . current = false ;
131+ updateResponderEventValue ( jsResponderContext , false ) ;
123132
124133 return shouldHandleRNGHEvent ;
125- } , [ keyboardShouldPersistTaps ] ) ;
126-
127- // RNGH tap responders need to let RN components higher in the tree handle
128- // the JS responder event first. If no RN component claims it, this logical
129- // ScrollView child consumes the marked event before ScrollView's own
130- // keyboardShouldPersistTaps='handled' responder logic handles it.
131- // For more information check this comment:
132- // https://github.com/software-mansion/react-native-gesture-handler/pull/4158#issuecomment-4431632964
134+ } , [ jsResponderContext ] ) ;
135+
133136 return (
134- < JSResponderContext value = { contextValue } >
135- < View
136- collapsable = { false }
137- onStartShouldSetResponderCapture = { resetRNGHResponderEvent }
138- onStartShouldSetResponder = { handleStartShouldSetResponder }
139- pointerEvents = "box-none"
140- style = { styles . logicalResponder } >
141- { children }
142- </ View >
143- </ JSResponderContext >
137+ < View
138+ collapsable = { false }
139+ onStartShouldSetResponderCapture = { resetRNGHResponderEvent }
140+ onStartShouldSetResponder = { handleStartShouldSetResponder }
141+ pointerEvents = "box-none"
142+ style = { styles . logicalResponder } >
143+ { children }
144+ </ View >
144145 ) ;
145146} ;
146147
148+ export function interceptScrollViewChildren ( children : React . ReactNode ) {
149+ return React . Children . map ( children , ( child ) =>
150+ child == null || typeof child === 'boolean' ? (
151+ child
152+ ) : (
153+ < LogicalResponderChild > { child } </ LogicalResponderChild >
154+ )
155+ ) ;
156+ }
157+
147158const styles = StyleSheet . create ( {
148159 logicalResponder : {
149160 display : 'contents' ,
150161 } ,
151162} ) ;
152-
153- export default ScrollViewResponderInterceptor ;
0 commit comments