Skip to content

Instantly share code, notes, and snippets.

@erictraut
Last active September 4, 2017 17:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erictraut/fb83e7f39bea07158731c9b20f9d10cd to your computer and use it in GitHub Desktop.
Save erictraut/fb83e7f39bea07158731c9b20f9d10cd to your computer and use it in GitHub Desktop.
ReactXP component that implements a toast notification view that slides in from the top of the screen
/**
* ToastView.tsx
*
* A component that dsplays system toast measages.
*/
import RX = require('reactxp');
import ToastService, { ToastMessage, ToastMessageParams } from '../services/ToastService';
interface ToastViewProps extends RX.CommonProps { }
interface ToastViewState {
currentMessage?: ToastMessage;
}
const _defaultToastTimeout = 3000;
const _toastHeight = 30;
const _marginBottom = 10;
const _containerHeight = 100 + _toastHeight;
const _styles = {
containerRounded: RX.Styles.createViewStyle({
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
flexDirection: 'row',
height: _containerHeight,
justifyContent: 'center',
alignItems: 'flex-end'
}),
barButton: RX.Styles.createButtonStyle({
bottom: 0,
left: 0,
right: 0,
height: _toastHeight
}),
contentContainer: RX.Styles.createViewStyle({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingHorizontal: 25,
height: _toastHeight,
backgroundColor: 'blue',
borderRadius: _toastHeight / 2
})
};
abstract class ToastView extends RX.Component<ToastViewProps, ToastViewState> {
private _hideToastTimerId: number;
private _button: RX.Button;
private _verticalAnimatedValue = new RX.Animated.Value(_containerHeight);
private _verticalAnimatedStyle = RX.Styles.createAnimatedViewStyle({
transform: [{
translateY: this._verticalAnimatedValue
}]
});
private _recalcDisplay(message: ToastMessage): void {
let newState: ToastViewState = {
currentMessage: message
};
this.setState(newState, () => {
this._showToast(0);
});
}
protected _buildState(props: ToastViewProps, initialBuild: boolean): ToastViewState {
let newState: ToastViewState = {};
if (initialBuild) {
newState.currentMessage = null;
}
return newState;
}
componentWillMount() {
super.componentWillMount();
ToastService.showToastEvent.subscribe(this._onShowToast);
}
componentWillUnmount() {
super.componentWillUnmount();
ToastService.showToastEvent.unsubscribe(this._onShowToast);
}
render(): JSX.Element {
// Bail, if there is not a valid current message.
if (!this.state.currentMessage) {
return null;
}
const params = this.state.currentMessage.params;
return (
<RX.View
style={ _styles.containerRounded }
ignorePointerEvents={ true }
>
<RX.Animated.View style={ this._verticalAnimatedStyle }>
<RX.Button
ref={ this._onButtonRef }
style={ _styles.barButton }
onPress={ this._onTapDismiss }
>
<RX.View style={ _styles.contentContainer }>
<RX.Text>
{ this.state.currentMessage.params.textMessage }
</RX.Text>
</RX.View>
</RX.Button>
</RX.Animated.View>
</RX.View>
);
}
private _onShowToast = (message: ToastMessage) => {
if (this.isComponentMounted()) {
this._recalcDisplay(message);
}
};
private _onTapDismiss = () => {
const params: ToastMessageParams = this.state.currentMessage ? this.state.currentMessage.params : null;
if (params && params.onPress) {
params.onPress();
}
clearTimeout(this._hideToastTimerId);
this._hideToast(0);
};
private _showToast(delay: number) {
const message = this.state.currentMessage;
if (!message) {
return;
}
const toValue = -1 * (this.state.currentMessage.params.bottomMargin ?
this.state.currentMessage.params.bottomMargin : _marginBottom);
setTimeout(() => {
if (this.isComponentMounted()) {
RX.Animated.timing(this._verticalAnimatedValue, {
toValue: toValue,
easing: RX.Animated.Easing.Out(),
duration: 250,
isInteraction: false
}).start();
}
}, delay);
}
private _hideToast(delay: number) {
this._hideToastTimerId = setTimeout(() => {
if (this.isComponentMounted()) {
RX.Animated.timing(this._verticalAnimatedValue, {
toValue: _containerHeight,
easing: RX.Animated.Easing.Out(),
duration: 200,
isInteraction: false
}).start();
}
}, delay);
}
private _onButtonRef = (button: RX.Button) => {
this._button = button;
}
}
export = ToastView;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment