react-native-ui-lib
Version:
<p align="center"> <img src="https://user-images.githubusercontent.com/1780255/105469025-56759000-5ca0-11eb-993d-3568c1fd54f4.png" height="250px" style="display:block"/> </p> <p align="center">UI Toolset & Components Library for React Native</p> <p a
174 lines (152 loc) • 4.64 kB
JavaScript
import _pt from "prop-types";
import React, { PureComponent } from 'react';
import { StyleSheet, Animated } from 'react-native';
import { Constants, asBaseComponent } from "../../commons/new";
import { Colors, Spacings } from "../../style";
import View from "../view";
import Button from "../button";
import Image from "../image";
const gradientImage = () => require("./gradient.png");
/**
* @description: Hovering button with gradient background
* @modifiers: margin, background, color
* @example: https://github.com/wix/react-native-ui-lib/blob/master/demo/src/screens/componentScreens/FloatingButtonScreen.tsx
* @gif: https://github.com/wix/react-native-ui-lib/blob/master/demo/showcase/FloatingButton/FloatingButton.gif?raw=true
*/
class FloatingButton extends PureComponent {
static propTypes = {
/**
* Whether the button is visible
*/
visible: _pt.bool,
/**
* The bottom margin of the button, or secondary button if passed
*/
bottomMargin: _pt.number,
/**
* The duration of the button's animations (show/hide)
*/
duration: _pt.number,
/**
* Whether to show/hide the button without animation
*/
withoutAnimation: _pt.bool,
/**
* Whether to show background overlay
*/
hideBackgroundOverlay: _pt.bool,
/**
* Used as testing identifier
* <TestID> - the floatingButton container
* <TestID>.button - the floatingButton main button
* <TestID>.secondaryButton - the floatingButton secondaryButton
*/
testID: _pt.string
};
static displayName = 'FloatingButton';
static defaultProps = {
duration: 300
};
constructor(props) {
super(props);
this.initialVisibility = props.visible;
this.firstLoad = true;
this.visibleAnimated = new Animated.Value(Number(!!props.visible));
}
componentDidUpdate(prevProps) {
const {
visible,
duration
} = this.props;
if (prevProps.visible !== visible) {
Animated.timing(this.visibleAnimated, {
toValue: Number(!!visible),
duration,
useNativeDriver: true
}).start();
}
}
getAnimatedStyle = () => {
return {
opacity: this.visibleAnimated,
transform: [{
translateY: this.visibleAnimated.interpolate({
inputRange: [0, 1],
outputRange: [Constants.screenHeight / 2, 0]
})
}]
};
};
renderButton() {
const {
bottomMargin,
button,
secondaryButton,
testID
} = this.props;
const bottom = secondaryButton ? Spacings.s4 : bottomMargin || Spacings.s8;
return <Button size={Button.sizes.large} style={[styles.shadow, {
marginTop: 16,
marginBottom: bottom
}]} testID={`${testID}.button`} {...button} />;
}
renderOverlay = () => {
if (!this.props.hideBackgroundOverlay) {
return <View pointerEvents={'none'} style={styles.image}>
<Image style={styles.image} source={gradientImage()} resizeMode={'stretch'} />
</View>;
}
};
renderSecondaryButton() {
const {
secondaryButton,
bottomMargin,
testID
} = this.props;
return <Button link size={Button.sizes.large} testID={`${testID}.secondaryButton`} {...secondaryButton} style={{
marginBottom: bottomMargin || Spacings.s7
}} enableShadow={false} />;
}
render() {
const {
withoutAnimation,
secondaryButton,
visible,
testID
} = this.props; // NOTE: keep this.firstLoad as true as long as the visibility changed to true
this.firstLoad && !visible ? this.firstLoad = true : this.firstLoad = false; // NOTE: On first load, don't show if it should not be visible
if (this.firstLoad === true && !this.initialVisibility) {
return false;
}
if (!visible && withoutAnimation) {
return false;
}
return <View pointerEvents="box-none" animated style={[styles.container, this.getAnimatedStyle()]} testID={testID}>
{this.renderOverlay()}
{this.renderButton()}
{secondaryButton && this.renderSecondaryButton()}
</View>;
}
}
const styles = StyleSheet.create({
container: { ...StyleSheet.absoluteFillObject,
top: undefined,
alignItems: 'center',
zIndex: Constants.isAndroid ? 99 : undefined
},
image: { ...StyleSheet.absoluteFillObject,
width: '100%',
height: '100%'
},
shadow: {
shadowColor: Colors.grey40,
shadowOffset: {
height: 5,
width: 0
},
shadowOpacity: 0.35,
shadowRadius: 12,
elevation: 2
}
});
export default asBaseComponent(FloatingButton);