@@ -27,35 +27,38 @@ import {
27
27
StyleSheet ,
28
28
useWindowDimensions ,
29
29
} from 'react-native' ;
30
- import {
31
- Provider as JotaiProvider ,
32
- useAtom ,
33
- useAtomValue ,
34
- useSetAtom ,
35
- } from 'jotai/react' ;
36
- import { selectAtom } from 'jotai/utils' ;
37
30
import { Platform } from 'react-native' ;
38
31
39
- import { elementsAtom , inputsAtom , wrapperOffsetAtom } from './state' ;
40
32
import { useKeyboard } from './useKeyboard' ;
41
33
import { useSafeAreaInsets } from 'react-native-safe-area-context' ;
42
34
35
+ export type RefType = TextInput | View | Animated . View | null ;
36
+
37
+ export type Elements = Record <
38
+ string ,
39
+ {
40
+ isFocus : boolean ;
41
+ position : number ;
42
+ height : number ;
43
+ name : string ;
44
+ }
45
+ > ;
46
+
47
+ export type InputType = Record < string , RefObject < TextInput > > ;
48
+
43
49
const isAndroid = Platform . OS === 'android' ;
44
50
45
51
function Wrapper ( props : PropsWithChildren < { } > ) {
46
- const setWrapperOffsetAtom = useSetAtom ( wrapperOffsetAtom ) ;
47
52
const windowDimensions = useWindowDimensions ( ) ;
48
- const { wrapperRef } = useSmartScrollContext ( ) ;
53
+ const { wrapperRef, setWrapperOffset } = useSmartScrollContext ( ) ;
49
54
50
55
return (
51
56
< View
52
57
style = { styles . wrapper }
53
58
ref = { wrapperRef }
54
59
onLayout = { ( { nativeEvent } ) => {
55
60
if ( nativeEvent . layout . height < windowDimensions . height ) {
56
- setWrapperOffsetAtom (
57
- windowDimensions . height - nativeEvent . layout . height
58
- ) ;
61
+ setWrapperOffset ( windowDimensions . height - nativeEvent . layout . height ) ;
59
62
}
60
63
} }
61
64
>
@@ -72,11 +75,9 @@ const styles = StyleSheet.create({
72
75
73
76
export default function SmartScrollView ( props : PropsWithChildren < { } > ) {
74
77
return (
75
- < JotaiProvider >
76
- < SmartScrollProvider >
77
- < Wrapper { ...props } />
78
- </ SmartScrollProvider >
79
- </ JotaiProvider >
78
+ < SmartScrollProvider >
79
+ < Wrapper { ...props } />
80
+ </ SmartScrollProvider >
80
81
) ;
81
82
}
82
83
@@ -85,14 +86,31 @@ const SmartScrollContext = React.createContext<{
85
86
scrollY : SharedValue < number > ;
86
87
isReady : boolean ;
87
88
wrapperRef : RefObject < View > ;
89
+ wrapperOffset : number ;
90
+ setWrapperOffset : React . Dispatch < React . SetStateAction < number > > ;
91
+ elements : Elements ;
92
+ setElements : React . Dispatch < React . SetStateAction < Elements > > ;
93
+ inputs : InputType ;
94
+ setInputs : React . Dispatch < React . SetStateAction < InputType > > ;
95
+ currentFocus ?: null | Elements [ 0 ] ;
88
96
} | null > ( null ) ;
89
97
90
98
const SmartScrollProvider = ( { children } : { children : React . ReactNode } ) => {
91
99
const scrollRef = useAnimatedRef < Animated . ScrollView > ( ) ;
92
100
const scrollY = useSharedValue ( 0 ) ;
93
101
const wrapperRef = React . useRef < View > ( null ) ;
94
- const [ isReady , setIsReady ] = useState ( false ) ;
95
- const currentFocus = useAtomValue ( currentFocusAtom ) ;
102
+ const [ isReady , setIsReady ] = useState ( true ) ;
103
+ const [ elements , setElements ] = useState < Elements > ( { } ) ;
104
+ const [ wrapperOffset , setWrapperOffset ] = useState ( 0 ) ;
105
+ const [ inputs , setInputs ] = useState < InputType > ( { } ) ;
106
+
107
+ const currentFocus = useMemo (
108
+ ( ) =>
109
+ Object . keys ( elements )
110
+ . map ( ( key ) => elements [ key ] )
111
+ . find ( ( el ) => el ?. isFocus ) ,
112
+ [ elements ]
113
+ ) ;
96
114
97
115
// we have a flick on first focus so we make the scrollview wait a bit before animate
98
116
useLayoutEffect ( ( ) => {
@@ -103,7 +121,19 @@ const SmartScrollProvider = ({ children }: { children: React.ReactNode }) => {
103
121
104
122
return (
105
123
< SmartScrollContext . Provider
106
- value = { { scrollRef, scrollY, isReady, wrapperRef } }
124
+ value = { {
125
+ scrollRef,
126
+ scrollY,
127
+ isReady,
128
+ wrapperRef,
129
+ wrapperOffset,
130
+ setWrapperOffset,
131
+ elements,
132
+ setElements,
133
+ currentFocus,
134
+ inputs,
135
+ setInputs,
136
+ } }
107
137
>
108
138
{ children }
109
139
</ SmartScrollContext . Provider >
@@ -114,7 +144,9 @@ export const useSmartScrollContext = () => {
114
144
const context = React . useContext ( SmartScrollContext ) ;
115
145
116
146
if ( ! context ) {
117
- throw new Error ( 'Plz wrap with SmartScrollProvider' ) ;
147
+ throw new Error (
148
+ 'Component must be wrapped in a SmartScrollProvider. Please ensure the provider is included.'
149
+ ) ;
118
150
}
119
151
120
152
return context ;
@@ -154,29 +186,25 @@ export const ScrollView = (
154
186
) ;
155
187
} ;
156
188
157
- const currentFocusAtom = selectAtom ( elementsAtom , ( val ) =>
158
- Object . keys ( val )
159
- . map ( ( key ) => val [ key ] )
160
- . find ( ( el ) => el ?. isFocus )
161
- ) ;
162
-
163
189
export function useFormSmartScroll ( {
164
190
padding = 0 ,
165
191
} : {
166
192
padding ?: number ;
167
193
} = { } ) {
168
194
const insets = useSafeAreaInsets ( ) ;
169
- const wrapperOffset = useAtomValue ( wrapperOffsetAtom ) ;
170
-
171
- const { isReady, scrollY, scrollRef } = useSmartScrollContext ( ) ;
195
+ const {
196
+ currentFocus,
197
+ setElements,
198
+ isReady,
199
+ scrollY,
200
+ scrollRef,
201
+ wrapperOffset,
202
+ inputs,
203
+ setInputs,
204
+ } = useSmartScrollContext ( ) ;
172
205
173
206
const _keyboard = useKeyboard ( ) ;
174
207
175
- const setState = useSetAtom ( elementsAtom ) ;
176
- const [ inputs , setInputs ] = useAtom ( inputsAtom ) ;
177
-
178
- const currentFocus = useAtomValue ( currentFocusAtom ) ;
179
-
180
208
const scrollHandler = useAnimatedScrollHandler ( ( event ) => {
181
209
scrollY . value = event . contentOffset . y ;
182
210
} ) ;
@@ -247,6 +275,8 @@ export function useFormSmartScroll({
247
275
}
248
276
) ;
249
277
278
+ console . log ( { isReady } ) ;
279
+
250
280
const translateStyle = useAnimatedStyle ( ( ) => {
251
281
return {
252
282
transform : [ { translateY : isReady ? translateY . value : 0 } ] ,
@@ -278,7 +308,7 @@ export function useFormSmartScroll({
278
308
279
309
const onFocus = useCallback (
280
310
( name : string ) => ( ) => {
281
- setState ( ( s ) => ( {
311
+ setElements ( ( s ) => ( {
282
312
...s ,
283
313
[ name ] : {
284
314
height : 0 ,
@@ -289,12 +319,12 @@ export function useFormSmartScroll({
289
319
} ,
290
320
} ) ) ;
291
321
} ,
292
- [ setState ]
322
+ [ setElements ]
293
323
) ;
294
324
295
325
const onBlur = useCallback (
296
326
( name : string ) => ( ) => {
297
- setState ( ( s ) => ( {
327
+ setElements ( ( s ) => ( {
298
328
...s ,
299
329
[ name ] : {
300
330
height : 0 ,
@@ -305,7 +335,7 @@ export function useFormSmartScroll({
305
335
} ,
306
336
} ) ) ;
307
337
} ,
308
- [ setState ]
338
+ [ setElements ]
309
339
) ;
310
340
311
341
/**
0 commit comments