1- import React , { useCallback , useEffect , useMemo , useState } from 'react' ;
1+ import React , { useCallback , useMemo } from 'react' ;
22import { LayoutChangeEvent , StyleSheet , ViewStyle } from 'react-native' ;
3- import Animated , { useAnimatedKeyboard , useAnimatedStyle , useSharedValue , withTiming } from 'react-native-reanimated' ;
3+ import Animated from 'react-native-reanimated' ;
44import { Keyboard } from 'uilib-native' ;
55import { SafeAreaContextPackage } from '../../optionalDependencies' ;
66import View from '../view' ;
@@ -9,6 +9,7 @@ import Assets from '../../assets';
99import { Colors , Shadows , Spacings } from '../../style' ;
1010import { asBaseComponent , Constants } from '../../commons/new' ;
1111import { useKeyboardHeight } from '../../hooks' ;
12+ import useAnimatedFooterStyle from './useAnimatedFooterStyle' ;
1213import {
1314 ScreenFooterProps ,
1415 ScreenFooterLayouts ,
@@ -17,6 +18,7 @@ import {
1718 HorizontalItemsDistribution ,
1819 ItemsFit ,
1920 KeyboardBehavior ,
21+ ScreenFooterAnimationTypeProp ,
2022 ScreenFooterShadow
2123} from './types' ;
2224
@@ -28,9 +30,9 @@ export {
2830 HorizontalItemsDistribution ,
2931 ItemsFit ,
3032 KeyboardBehavior ,
33+ ScreenFooterAnimationTypeProp ,
3134 ScreenFooterShadow
3235} ;
33- const androidVersion = Constants . getAndroidVersion ( ) ;
3436const ScreenFooter = ( props : ScreenFooterProps ) => {
3537 const {
3638 testID,
@@ -44,41 +46,22 @@ const ScreenFooter = (props: ScreenFooterProps) => {
4446 itemWidth,
4547 horizontalItemsDistribution : distribution ,
4648 visible = true ,
47- animationDuration = 200 ,
49+ animationDuration,
50+ animationType,
4851 shadow = ScreenFooterShadow . SH20 ,
4952 hideDivider = false ,
50- isAndroidEdgeToEdge = ! ! androidVersion && androidVersion >= 35 ? true : undefined ,
53+ isAndroidEdgeToEdge,
5154 containerStyle : containerStyleOverride ,
5255 contentContainerStyle : contentContainerStyleOverride
5356 } = props ;
5457
55- const withoutAnimation = animationDuration === 0 ;
56-
57- const keyboard = useAnimatedKeyboard ( {
58- isNavigationBarTranslucentAndroid : isAndroidEdgeToEdge ,
59- isStatusBarTranslucentAndroid : isAndroidEdgeToEdge
60- } ) ;
61- const [ height , setHeight ] = useState ( 0 ) ;
62- const visibilityTranslateY = useSharedValue ( 0 ) ;
63-
64- // Update visibility translation when visible or height changes
65- useEffect ( ( ) => {
66- visibilityTranslateY . value = withTiming ( visible ? 0 : height , { duration : animationDuration } ) ;
67- } , [ visible , height , animationDuration , visibilityTranslateY ] ) ;
68-
69- // Animated style for STICKY behavior (counters Android system offset + visibility)
70- const stickyAnimatedStyle = useAnimatedStyle ( ( ) => {
71- const counterSystemOffset = Constants . isAndroid ? keyboard . height . value : 0 ;
72- return {
73- transform : [ { translateY : counterSystemOffset + visibilityTranslateY . value } ]
74- } ;
75- } ) ;
76-
77- // Animated style for HOISTED behavior (visibility only, keyboard handled by KeyboardAccessoryView)
78- const hoistedAnimatedStyle = useAnimatedStyle ( ( ) => {
79- return {
80- transform : [ { translateY : visibilityTranslateY . value } ]
81- } ;
58+ const { containerStyle, setHeight} = useAnimatedFooterStyle ( {
59+ animationDuration,
60+ animationType,
61+ keyboardBehavior,
62+ visible,
63+ isAndroidEdgeToEdge,
64+ containerStyle : containerStyleOverride
8265 } ) ;
8366
8467 const onLayout = useCallback ( ( event : LayoutChangeEvent ) => {
@@ -202,30 +185,28 @@ const ScreenFooter = (props: ScreenFooterProps) => {
202185 return null ;
203186 } , [ testID , isSolid , isFading , solidBackgroundStyle ] ) ;
204187
205- const renderChild = useCallback (
206- ( child : React . ReactNode , index : number ) => {
207- if ( itemsFit === ItemsFit . FIXED && itemWidth ) {
208- const fixedStyle : ViewStyle = isHorizontal
209- ? { width : itemWidth , flexShrink : 1 , overflow : 'hidden' , flexDirection : 'row' , justifyContent : 'center' }
210- : { width : itemWidth , maxWidth : '100%' } ;
211- return (
212- < View key = { index } style = { fixedStyle } >
213- { child }
214- </ View >
215- ) ;
216- }
188+ const renderChild = useCallback ( ( child : React . ReactNode , index : number ) => {
189+ if ( itemsFit === ItemsFit . FIXED && itemWidth ) {
190+ const fixedStyle : ViewStyle = isHorizontal
191+ ? { width : itemWidth , flexShrink : 1 , overflow : 'hidden' , flexDirection : 'row' , justifyContent : 'center' }
192+ : { width : itemWidth , maxWidth : '100%' } ;
193+ return (
194+ < View key = { index } style = { fixedStyle } >
195+ { child }
196+ </ View >
197+ ) ;
198+ }
217199
218- if ( isHorizontal && React . isValidElement ( child ) && itemsFit === ItemsFit . STRETCH ) {
219- return (
220- < View flex row centerH key = { index } >
221- { child }
222- </ View >
223- ) ;
224- }
225- return child ;
226- } ,
227- [ itemsFit , itemWidth , isHorizontal ]
228- ) ;
200+ if ( isHorizontal && React . isValidElement ( child ) && itemsFit === ItemsFit . STRETCH ) {
201+ return (
202+ < View flex row centerH key = { index } >
203+ { child }
204+ </ View >
205+ ) ;
206+ }
207+ return child ;
208+ } ,
209+ [ itemsFit , itemWidth , isHorizontal ] ) ;
229210
230211 const childrenArray = React . Children . toArray ( children ) . slice ( 0 , 3 ) . map ( renderChild ) ;
231212
@@ -240,20 +221,9 @@ const ScreenFooter = (props: ScreenFooterProps) => {
240221 ) ;
241222 } , [ renderBackground , testID , contentContainerStyle , childrenArray ] ) ;
242223
243- const Container = useMemo ( ( ) => {
244- return withoutAnimation ? View : Animated . View ;
245- } , [ withoutAnimation ] ) ;
246-
247- const containerStyle = useMemo ( ( ) => {
248- return withoutAnimation
249- ? [ styles . container , containerStyleOverride ]
250- : [ styles . container , hoistedAnimatedStyle , containerStyleOverride ] ;
251- // eslint-disable-next-line react-hooks/exhaustive-deps
252- } , [ withoutAnimation , containerStyleOverride ] ) ;
253-
254- if ( keyboardBehavior === KeyboardBehavior . HOISTED ) {
255- return (
256- < Container style = { containerStyle } pointerEvents = { visible ? 'box-none' : 'none' } >
224+ const renderKeyboardAwareFooter = useCallback ( ( ) => {
225+ if ( keyboardBehavior === 'hoisted' ) {
226+ return (
257227 < Keyboard . KeyboardAccessoryView
258228 renderContent = { renderFooterContent }
259229 kbInputRef = { undefined }
@@ -263,27 +233,27 @@ const ScreenFooter = (props: ScreenFooterProps) => {
263233 revealKeyboardInteractive
264234 onHeightChanged = { setHeight }
265235 />
266- </ Container >
267- ) ;
268- }
236+ ) ;
237+ } else {
238+ return renderFooterContent ( ) ;
239+ }
240+ } , [ keyboardBehavior , renderFooterContent ] ) ;
269241
270242 return (
271- < Animated . View testID = { testID } onLayout = { onLayout } style = { [ styles . container , stickyAnimatedStyle , containerStyleOverride ] } >
272- { renderFooterContent ( ) }
243+ < Animated . View
244+ testID = { testID }
245+ style = { containerStyle }
246+ onLayout = { keyboardBehavior === 'hoisted' ? undefined : onLayout }
247+ pointerEvents = { ! visible ? 'none' : keyboardBehavior === 'hoisted' ? 'box-none' : 'auto' }
248+ >
249+ { renderKeyboardAwareFooter ( ) }
273250 </ Animated . View >
274251 ) ;
275252} ;
276253
277254ScreenFooter . displayName = 'ScreenFooter' ;
278255
279256const styles = StyleSheet . create ( {
280- container : {
281- position : 'absolute' ,
282- bottom : 0 ,
283- left : 0 ,
284- right : 0 ,
285- zIndex : 50
286- } ,
287257 contentContainer : {
288258 paddingTop : Spacings . s4 ,
289259 paddingHorizontal : Spacings . s5 ,
0 commit comments