react-native-buttered-toast
Version:
A customizable toast notification for React Native.
176 lines (169 loc) • 3.78 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import {
Animated,
StyleSheet,
PanResponder,
View,
Dimensions,
} from 'react-native';
const {
width: screenWidth,
} = Dimensions.get('window');
class Butter extends React.Component {
constructor(props) {
super(props);
this.state = {
panResponder: PanResponder
.create(
{
onStartShouldSetPanResponder: this.onStartShouldSetPanResponder,
onMoveShouldSetPanResponder: this.onMoveShouldSetPanResponder,
onPanResponderMove: this.onPanResponderMove,
onPanResponderRelease: this.onPanResponderRelease,
onPanResponderTerminate: this.onPanResponderTerminate,
},
),
animDrag: new Animated.ValueXY(
{
x: 0,
y: 0,
},
),
};
}
onStartShouldSetPanResponder = (e, gestureState) => false;
onMoveShouldSetPanResponder = (e, gestureState) => {
const { requestDrag } = this.props;
const { dx } = gestureState;
// XXX: Ensure the user has actually started dragging.
return (Math.abs(dx) >= 5) && requestDrag();
};
onPanResponderMove = (e, gestureState) => {
const { animDrag } = this.state;
const { dx } = gestureState;
return Animated.event(
[
null,
{
dx: animDrag.x,
dy: 0,
useNativeDriver: true,
}
],
)(
e,
gestureState,
);
};
onPanResponderRelease = (e, gestureState) => {
const { dx } = gestureState;
// TODO: Should be a prop.
const shouldConsume = Math.abs(dx) > (screenWidth * 0.25);
return this.handleFinishDrag(
e,
gestureState,
shouldConsume,
);
};
onPanResponderTerminate = (e, gestureState) => {
return this.handleFinishDrag(
e,
gestureState,
false,
);
};
handleFinishDrag = (e, gestureState, shouldConsume) => {
const { finishDrag } = this.props;
const { animDrag } = this.state;
if (shouldConsume) {
return Promise
.resolve()
.then(
() => finishDrag(
animDrag,
true,
),
);
}
return new Promise(
resolve => Animated
.timing(
animDrag,
{
toValue: {
x: 0,
y: 0,
},
useNativeDriver: true,
duration: 100, // TODO: must be a function of distance
},
)
.start(resolve),
)
.then(
() => finishDrag(
animDrag,
false,
),
);
};
render() {
const {
animValue,
containerStyle,
children,
...extraProps
} = this.props;
const {
animDrag,
panResponder,
...extraState
} = this.state;
return (
<Animated.View
{...panResponder.panHandlers}
{...extraProps}
style={[
containerStyle,
{
position: 'absolute',
},
{
transform: [
{
translateX: Animated.add(
animDrag.x,
animValue.x,
),
},
{
translateY: Animated.add(
animDrag.y,
animValue.y,
),
},
],
},
]}
>
{children}
</Animated.View>
);
}
}
const styles = StyleSheet
.create(
{
containerStyle: {
},
},
);
Butter.propTypes = {
animValue: PropTypes.shape({}).isRequired,
containerStyle: PropTypes.shape({}),
};
Butter.defaultProps = {
containerStyle: styles.containerStyle,
};
export default Butter;