@@ -22,6 +22,7 @@ import {
2222 ViewProps ,
2323 TouchableOpacityProps ,
2424 ImageProps ,
25+ useWindowDimensions ,
2526} from 'react-native' ;
2627import Queue from './Queue' ;
2728
@@ -82,6 +83,11 @@ export const DropDownAlertTestID = {
8283 CancelImage : 'cancelImage' ,
8384} ;
8485
86+ export enum DropdownAlertPosition {
87+ Top = 'top' ,
88+ Bottom = 'bottom' ,
89+ }
90+
8591// References
8692// Image source: https://reactnative.dev/docs/image#source
8793// Image style: https://reactnative.dev/docs/image#style
@@ -123,9 +129,6 @@ export type DropdownAlertProps = {
123129 elevation ?: number ;
124130 // It is used in the Animated.View style so alert is above other UI components
125131 zIndex ?: number ;
126- // Distance on the Y-axis for alert to move by pan gesture
127- // panResponderEnabled must be true as well
128- panResponderMoveDistance ?: number ;
129132 // Distance on the Y-axis for the alert to be dismissed by pan gesture
130133 // panResponderEnabled must be true as well
131134 panResponderDismissDistance ?: number ;
@@ -174,6 +177,7 @@ export type DropdownAlertProps = {
174177 dismiss ?: ( func : ( ) => void ) => void ;
175178 springAnimationConfig ?: Animated . SpringAnimationConfig ;
176179 children ?: ReactNode ;
180+ alertPosition ?: 'top' | 'bottom' ;
177181} ;
178182
179183const DropdownAlert : React . FunctionComponent < DropdownAlertProps > = ( {
@@ -237,7 +241,6 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
237241 updateStatusBar = true ,
238242 elevation = 1 ,
239243 zIndex = 1 ,
240- panResponderMoveDistance = 0 ,
241244 renderImage = undefined ,
242245 renderCancel = undefined ,
243246 renderTitle = undefined ,
@@ -261,11 +264,13 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
261264 } ,
262265 panResponderDismissDistance = - 10 ,
263266 children = undefined ,
267+ alertPosition = DropdownAlertPosition . Top ,
264268} ) => {
269+ const windowDimensions = useWindowDimensions ( ) ;
265270 const isIOS = Platform . OS === 'ios' ;
266271 const isAndroid = Platform . OS === 'android' ;
267272 const isBelowIOS11 = isIOS && Number ( Platform . Version ) < 11 ;
268- const [ top , setTop ] = useState ( 0 ) ;
273+ const [ dimValue , setDimValue ] = useState ( 0 ) ;
269274 const [ height , setHeight ] = useState ( 99 ) ;
270275 const defaultAlertData : DropdownAlertData = {
271276 type : '' ,
@@ -288,24 +293,40 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
288293 _event : GestureResponderEvent ,
289294 gestureState : PanResponderGestureState ,
290295 ) {
291- if (
292- panResponderEnabled &&
293- gestureState . dy <= panResponderDismissDistance
294- ) {
295- _dismiss ( DropdownAlertDismissAction . Pan ) ;
296+ if ( panResponderEnabled ) {
297+ switch ( alertPosition ) {
298+ case DropdownAlertPosition . Bottom :
299+ if ( gestureState . dy >= Math . abs ( panResponderDismissDistance ) ) {
300+ _dismiss ( DropdownAlertDismissAction . Pan ) ;
301+ }
302+ break ;
303+
304+ default :
305+ if ( gestureState . dy <= panResponderDismissDistance ) {
306+ _dismiss ( DropdownAlertDismissAction . Pan ) ;
307+ }
308+ break ;
309+ }
296310 }
297311 }
298312 return PanResponder . create ( {
299313 onStartShouldSetPanResponder : ( ) => panResponderEnabled ,
300- onMoveShouldSetPanResponder : ( _event , gestureState ) => {
301- if ( panResponderEnabled ) {
302- return gestureState . dy <= panResponderMoveDistance ;
303- }
304- return panResponderEnabled ;
305- } ,
314+ onMoveShouldSetPanResponder : ( ) => panResponderEnabled ,
306315 onPanResponderMove : ( _event , gestureState ) => {
307- if ( panResponderEnabled && gestureState . dy < 0 ) {
308- setTop ( gestureState . dy ) ;
316+ if ( panResponderEnabled ) {
317+ switch ( alertPosition ) {
318+ case DropdownAlertPosition . Bottom :
319+ if ( gestureState . dy > 0 ) {
320+ setDimValue ( 0 - gestureState . dy ) ;
321+ }
322+ break ;
323+
324+ default :
325+ if ( gestureState . dy < 0 ) {
326+ setDimValue ( gestureState . dy ) ;
327+ }
328+ break ;
329+ }
309330 }
310331 } ,
311332 onPanResponderRelease : ( event , gestureState ) =>
@@ -318,7 +339,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
318339 const panResponder = useMemo ( _getPanResponder , [
319340 panResponderEnabled ,
320341 panResponderDismissDistance ,
321- panResponderMoveDistance ,
342+ alertPosition ,
322343 ] ) ;
323344
324345 function _alertWithData ( data ?: DropdownAlertData ) {
@@ -378,7 +399,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
378399 onDismissPress ( alertDataRef . current ) ;
379400 break ;
380401 }
381- setTop ( 0 ) ;
402+ setDimValue ( 0 ) ;
382403 queue . current . dequeue ( ) ;
383404 if ( ! queue . current . isEmpty ) {
384405 _alert ( queue . current . first ) ;
@@ -389,7 +410,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
389410 dismiss ( _dismiss ) ;
390411
391412 function _updateStatusBar ( active = false , type = '' ) {
392- if ( updateStatusBar ) {
413+ if ( updateStatusBar && alertPosition === DropdownAlertPosition . Top ) {
393414 if ( isAndroid ) {
394415 if ( active ) {
395416 let backgroundColor = activeStatusBarBackgroundColor ;
@@ -545,23 +566,33 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
545566 }
546567
547568 function _getViewAnimatedStyle ( ) {
569+ let viewStyle : ViewStyle = {
570+ // https://github.com/microsoft/TypeScript/issues/11465
571+ position : 'absolute' as 'absolute' ,
572+ top : dimValue ,
573+ left : 0 ,
574+ right : 0 ,
575+ elevation,
576+ zIndex,
577+ } ;
578+ let animatedInterpolateConfig = {
579+ inputRange : [ 0 , 1 ] ,
580+ outputRange : [ 0 - height , 0 ] ,
581+ } ;
582+ if ( alertPosition === DropdownAlertPosition . Bottom ) {
583+ viewStyle . top = undefined ;
584+ viewStyle . bottom = dimValue ;
585+ animatedInterpolateConfig . outputRange [ 0 ] =
586+ windowDimensions . height - height ;
587+ }
548588 return [
549- {
550- // https://github.com/microsoft/TypeScript/issues/11465
551- position : 'absolute' as 'absolute' ,
552- top,
553- left : 0 ,
554- right : 0 ,
555- elevation,
556- zIndex,
557- } ,
589+ viewStyle ,
558590 {
559591 transform : [
560592 {
561- translateY : animatedValue . current . interpolate ( {
562- inputRange : [ 0 , 1 ] ,
563- outputRange : [ 0 - height , 0 ] ,
564- } ) ,
593+ translateY : animatedValue . current . interpolate (
594+ animatedInterpolateConfig ,
595+ ) ,
565596 } ,
566597 ] ,
567598 } ,
0 commit comments