Skip to content

Commit

Permalink
implement alert position bottom (#302)
Browse files Browse the repository at this point in the history
* implement alert position bottom

In doing so, opportunity to correct onMoveShouldSetPanResponder to be based on panResponderEnabled hence eliminates need for panResponderMoveDistance prop. This was based on: "Called for every touch move on the View when it is not the responder: does this view want to "claim" touch responsiveness?"  for this case yes when enabled. https://reactnative.dev/docs/gesture-responder-system#responder-lifecycle

* update readme support

* update demo gif
  • Loading branch information
testshallpass authored Aug 8, 2023
1 parent 0cb8bf9 commit a340b77
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 41 deletions.
99 changes: 65 additions & 34 deletions DropdownAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
ViewProps,
TouchableOpacityProps,
ImageProps,
useWindowDimensions,
} from 'react-native';
import Queue from './Queue';

Expand Down Expand Up @@ -82,6 +83,11 @@ export const DropDownAlertTestID = {
CancelImage: 'cancelImage',
};

export enum DropdownAlertPosition {
Top = 'top',
Bottom = 'bottom',
}

// References
// Image source: https://reactnative.dev/docs/image#source
// Image style: https://reactnative.dev/docs/image#style
Expand Down Expand Up @@ -123,9 +129,6 @@ export type DropdownAlertProps = {
elevation?: number;
// It is used in the Animated.View style so alert is above other UI components
zIndex?: number;
// Distance on the Y-axis for alert to move by pan gesture
// panResponderEnabled must be true as well
panResponderMoveDistance?: number;
// Distance on the Y-axis for the alert to be dismissed by pan gesture
// panResponderEnabled must be true as well
panResponderDismissDistance?: number;
Expand Down Expand Up @@ -174,6 +177,7 @@ export type DropdownAlertProps = {
dismiss?: (func: () => void) => void;
springAnimationConfig?: Animated.SpringAnimationConfig;
children?: ReactNode;
alertPosition?: 'top' | 'bottom';
};

const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
Expand Down Expand Up @@ -237,7 +241,6 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
updateStatusBar = true,
elevation = 1,
zIndex = 1,
panResponderMoveDistance = 0,
renderImage = undefined,
renderCancel = undefined,
renderTitle = undefined,
Expand All @@ -261,11 +264,13 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
},
panResponderDismissDistance = -10,
children = undefined,
alertPosition = DropdownAlertPosition.Top,
}) => {
const windowDimensions = useWindowDimensions();
const isIOS = Platform.OS === 'ios';
const isAndroid = Platform.OS === 'android';
const isBelowIOS11 = isIOS && Number(Platform.Version) < 11;
const [top, setTop] = useState(0);
const [dimValue, setDimValue] = useState(0);
const [height, setHeight] = useState(99);
const defaultAlertData: DropdownAlertData = {
type: '',
Expand All @@ -288,24 +293,40 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
_event: GestureResponderEvent,
gestureState: PanResponderGestureState,
) {
if (
panResponderEnabled &&
gestureState.dy <= panResponderDismissDistance
) {
_dismiss(DropdownAlertDismissAction.Pan);
if (panResponderEnabled) {
switch (alertPosition) {
case DropdownAlertPosition.Bottom:
if (gestureState.dy >= Math.abs(panResponderDismissDistance)) {
_dismiss(DropdownAlertDismissAction.Pan);
}
break;

default:
if (gestureState.dy <= panResponderDismissDistance) {
_dismiss(DropdownAlertDismissAction.Pan);
}
break;
}
}
}
return PanResponder.create({
onStartShouldSetPanResponder: () => panResponderEnabled,
onMoveShouldSetPanResponder: (_event, gestureState) => {
if (panResponderEnabled) {
return gestureState.dy <= panResponderMoveDistance;
}
return panResponderEnabled;
},
onMoveShouldSetPanResponder: () => panResponderEnabled,
onPanResponderMove: (_event, gestureState) => {
if (panResponderEnabled && gestureState.dy < 0) {
setTop(gestureState.dy);
if (panResponderEnabled) {
switch (alertPosition) {
case DropdownAlertPosition.Bottom:
if (gestureState.dy > 0) {
setDimValue(0 - gestureState.dy);
}
break;

default:
if (gestureState.dy < 0) {
setDimValue(gestureState.dy);
}
break;
}
}
},
onPanResponderRelease: (event, gestureState) =>
Expand All @@ -318,7 +339,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
const panResponder = useMemo(_getPanResponder, [
panResponderEnabled,
panResponderDismissDistance,
panResponderMoveDistance,
alertPosition,
]);

function _alertWithData(data?: DropdownAlertData) {
Expand Down Expand Up @@ -378,7 +399,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
onDismissPress(alertDataRef.current);
break;
}
setTop(0);
setDimValue(0);
queue.current.dequeue();
if (!queue.current.isEmpty) {
_alert(queue.current.first);
Expand All @@ -389,7 +410,7 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
dismiss(_dismiss);

function _updateStatusBar(active = false, type = '') {
if (updateStatusBar) {
if (updateStatusBar && alertPosition === DropdownAlertPosition.Top) {
if (isAndroid) {
if (active) {
let backgroundColor = activeStatusBarBackgroundColor;
Expand Down Expand Up @@ -545,23 +566,33 @@ const DropdownAlert: React.FunctionComponent<DropdownAlertProps> = ({
}

function _getViewAnimatedStyle() {
let viewStyle: ViewStyle = {
// https://github.com/microsoft/TypeScript/issues/11465
position: 'absolute' as 'absolute',
top: dimValue,
left: 0,
right: 0,
elevation,
zIndex,
};
let animatedInterpolateConfig = {
inputRange: [0, 1],
outputRange: [0 - height, 0],
};
if (alertPosition === DropdownAlertPosition.Bottom) {
viewStyle.top = undefined;
viewStyle.bottom = dimValue;
animatedInterpolateConfig.outputRange[0] =
windowDimensions.height - height;
}
return [
{
// https://github.com/microsoft/TypeScript/issues/11465
position: 'absolute' as 'absolute',
top,
left: 0,
right: 0,
elevation,
zIndex,
},
viewStyle,
{
transform: [
{
translateY: animatedValue.current.interpolate({
inputRange: [0, 1],
outputRange: [0 - height, 0],
}),
translateY: animatedValue.current.interpolate(
animatedInterpolateConfig,
),
},
],
},
Expand Down
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ An alert to notify users about an error or something else. It can be dismissed b
import the library

```javascript
import DropdownAlert, {DropdownAlertData, DropdownAlertType} from 'react-native-dropdownalert';
import DropdownAlert, {
DropdownAlertData,
DropdownAlertType,
} from 'react-native-dropdownalert';
```

create an alert promise function variable
Expand All @@ -56,10 +59,11 @@ const alertData = await alert({

## Support

| react-native version | package version | reason |
| -------------------- | :-------------: | ------------------- |
| 0.50.0 | >=3.2.0 | use `SafeAreaView` |
| 0.44.0 | >=2.12.0 | use `ViewPropTypes` |
| react minium version | react-native minium version | package version | reason |
| :------------------: | :-------------------------: | :-------------: | ------------------- |
| v16.8.0 | v0.61.0 | v5.0.0 | use react hooks |
| v16.0.0 | v0.50.0 | v3.2.0 | use `SafeAreaView` |
| v16.0.0-alpha.6 | v0.44.0 | v2.12.0 | use `ViewPropTypes` |

## Using `children` prop

Expand All @@ -80,6 +84,6 @@ Either way `DropdownAlert` will render these instead of the pre-defined child co
## Caveats

- Modals can overlap `DropdownAlert`` if it is not inside the modal's document tree.
- It is important you place the `DropdownAlert` above the `StackNavigator`.
- It is important you place the `DropdownAlert` below the `StackNavigator`.

> Inspired by: [RKDropdownAlert](https://github.com/cwRichardKim/RKDropdownAlert)
15 changes: 14 additions & 1 deletion example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import DropdownAlert, {
DropdownAlertType,
DropdownAlertColor,
DropdownAlertProps,
} from 'react-native-dropdownalert';
} from './src/DropdownAlert';
import NotificationIOS from './NotificationIOS';
import NotificationAndroid from './NotificationAndroid';

Expand Down Expand Up @@ -132,6 +132,19 @@ function App(): JSX.Element {
},
color: 'teal',
},
{
name: 'Bottom',
alertData: {
type: DropdownAlertType.Info,
title: 'Info',
message: 'This demonstrates an info alert with bottom alert position.',
},
alertProps: {
alertPosition: 'bottom',
infoColor: 'green',
},
color: 'green',
},
];

function _renderItem(listItemIndex: ListItemIndex) {
Expand Down
Binary file modified screenshots/demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit a340b77

Please sign in to comment.