@@ -22,6 +22,7 @@ import {
22
22
ViewProps ,
23
23
TouchableOpacityProps ,
24
24
ImageProps ,
25
+ useWindowDimensions ,
25
26
} from 'react-native' ;
26
27
import Queue from './Queue' ;
27
28
@@ -82,6 +83,11 @@ export const DropDownAlertTestID = {
82
83
CancelImage : 'cancelImage' ,
83
84
} ;
84
85
86
+ export enum DropdownAlertPosition {
87
+ Top = 'top' ,
88
+ Bottom = 'bottom' ,
89
+ }
90
+
85
91
// References
86
92
// Image source: https://reactnative.dev/docs/image#source
87
93
// Image style: https://reactnative.dev/docs/image#style
@@ -123,9 +129,6 @@ export type DropdownAlertProps = {
123
129
elevation ?: number ;
124
130
// It is used in the Animated.View style so alert is above other UI components
125
131
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 ;
129
132
// Distance on the Y-axis for the alert to be dismissed by pan gesture
130
133
// panResponderEnabled must be true as well
131
134
panResponderDismissDistance ?: number ;
@@ -174,6 +177,7 @@ export type DropdownAlertProps = {
174
177
dismiss ?: ( func : ( ) => void ) => void ;
175
178
springAnimationConfig ?: Animated . SpringAnimationConfig ;
176
179
children ?: ReactNode ;
180
+ alertPosition ?: 'top' | 'bottom' ;
177
181
} ;
178
182
179
183
const DropdownAlert : React . FunctionComponent < DropdownAlertProps > = ( {
@@ -237,7 +241,6 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
237
241
updateStatusBar = true ,
238
242
elevation = 1 ,
239
243
zIndex = 1 ,
240
- panResponderMoveDistance = 0 ,
241
244
renderImage = undefined ,
242
245
renderCancel = undefined ,
243
246
renderTitle = undefined ,
@@ -261,11 +264,13 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
261
264
} ,
262
265
panResponderDismissDistance = - 10 ,
263
266
children = undefined ,
267
+ alertPosition = DropdownAlertPosition . Top ,
264
268
} ) => {
269
+ const windowDimensions = useWindowDimensions ( ) ;
265
270
const isIOS = Platform . OS === 'ios' ;
266
271
const isAndroid = Platform . OS === 'android' ;
267
272
const isBelowIOS11 = isIOS && Number ( Platform . Version ) < 11 ;
268
- const [ top , setTop ] = useState ( 0 ) ;
273
+ const [ dimValue , setDimValue ] = useState ( 0 ) ;
269
274
const [ height , setHeight ] = useState ( 99 ) ;
270
275
const defaultAlertData : DropdownAlertData = {
271
276
type : '' ,
@@ -288,24 +293,40 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
288
293
_event : GestureResponderEvent ,
289
294
gestureState : PanResponderGestureState ,
290
295
) {
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
+ }
296
310
}
297
311
}
298
312
return PanResponder . create ( {
299
313
onStartShouldSetPanResponder : ( ) => panResponderEnabled ,
300
- onMoveShouldSetPanResponder : ( _event , gestureState ) => {
301
- if ( panResponderEnabled ) {
302
- return gestureState . dy <= panResponderMoveDistance ;
303
- }
304
- return panResponderEnabled ;
305
- } ,
314
+ onMoveShouldSetPanResponder : ( ) => panResponderEnabled ,
306
315
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
+ }
309
330
}
310
331
} ,
311
332
onPanResponderRelease : ( event , gestureState ) =>
@@ -318,7 +339,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
318
339
const panResponder = useMemo ( _getPanResponder , [
319
340
panResponderEnabled ,
320
341
panResponderDismissDistance ,
321
- panResponderMoveDistance ,
342
+ alertPosition ,
322
343
] ) ;
323
344
324
345
function _alertWithData ( data ?: DropdownAlertData ) {
@@ -378,7 +399,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
378
399
onDismissPress ( alertDataRef . current ) ;
379
400
break ;
380
401
}
381
- setTop ( 0 ) ;
402
+ setDimValue ( 0 ) ;
382
403
queue . current . dequeue ( ) ;
383
404
if ( ! queue . current . isEmpty ) {
384
405
_alert ( queue . current . first ) ;
@@ -389,7 +410,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
389
410
dismiss ( _dismiss ) ;
390
411
391
412
function _updateStatusBar ( active = false , type = '' ) {
392
- if ( updateStatusBar ) {
413
+ if ( updateStatusBar && alertPosition === DropdownAlertPosition . Top ) {
393
414
if ( isAndroid ) {
394
415
if ( active ) {
395
416
let backgroundColor = activeStatusBarBackgroundColor ;
@@ -545,23 +566,33 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
545
566
}
546
567
547
568
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
+ }
548
588
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 ,
558
590
{
559
591
transform : [
560
592
{
561
- translateY : animatedValue . current . interpolate ( {
562
- inputRange : [ 0 , 1 ] ,
563
- outputRange : [ 0 - height , 0 ] ,
564
- } ) ,
593
+ translateY : animatedValue . current . interpolate (
594
+ animatedInterpolateConfig ,
595
+ ) ,
565
596
} ,
566
597
] ,
567
598
} ,
0 commit comments