react-native-ui-lib
Version:
[](https://stand-with-ukraine.pp.ua)
158 lines (156 loc) • 5.38 kB
JavaScript
import React, { PureComponent } from 'react';
import { StyleSheet, Animated } from 'react-native';
import { Constants, asBaseComponent } from "../../commons/new";
import { Colors, Shadows, Spacings } from "../../style";
import View from "../view";
import Image from "../image";
import Button from "../button";
export let FloatingButtonLayouts = /*#__PURE__*/function (FloatingButtonLayouts) {
FloatingButtonLayouts["VERTICAL"] = "Vertical";
FloatingButtonLayouts["HORIZONTAL"] = "Horizontal";
return FloatingButtonLayouts;
}({});
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 displayName = 'FloatingButton';
static floatingButtonLayouts = FloatingButtonLayouts;
static defaultProps = {
duration: 300,
buttonLayout: FloatingButtonLayouts.VERTICAL
};
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]
})
}]
};
};
get isSecondaryHorizontal() {
const {
secondaryButton,
buttonLayout
} = this.props;
return secondaryButton && buttonLayout === FloatingButtonLayouts.HORIZONTAL;
}
get isSecondaryVertical() {
const {
secondaryButton,
buttonLayout
} = this.props;
return secondaryButton && buttonLayout === FloatingButtonLayouts.VERTICAL;
}
renderButton() {
const {
bottomMargin,
button,
fullWidth,
testID
} = this.props;
const bottom = this.isSecondaryVertical ? Spacings.s4 : bottomMargin || Spacings.s8;
const left = this.isSecondaryHorizontal || fullWidth ? Spacings.s4 : undefined;
const right = this.isSecondaryHorizontal ? 20 : fullWidth ? Spacings.s4 : undefined;
const shadowStyle = !button?.outline && !button?.link && styles.shadow;
const marginStyle = {
marginTop: 16,
marginBottom: bottom,
marginLeft: left,
marginRight: right
};
return <Button size={Button.sizes.large} flex={!!this.isSecondaryHorizontal} style={[shadowStyle, marginStyle]} testID={`${testID}.button`} {...button} />;
}
renderOverlay = () => {
if (!this.props.hideBackgroundOverlay) {
return <View pointerEvents={'none'} style={styles.image}>
<Image style={styles.image} source={gradientImage()} resizeMode={'stretch'} tintColor={Colors.$backgroundDefault} />
</View>;
}
};
renderSecondaryButton() {
const {
secondaryButton,
bottomMargin,
testID,
buttonLayout
} = this.props;
const bgColor = secondaryButton?.backgroundColor || Colors.$backgroundDefault;
const isHorizontal = buttonLayout === FloatingButtonLayouts.HORIZONTAL;
const buttonStyle = isHorizontal ? [styles.shadow, styles.secondaryMargin, {
backgroundColor: bgColor
}] : {
marginBottom: bottomMargin || Spacings.s7
};
return <Button outline={isHorizontal} flex={isHorizontal} link={!isHorizontal} size={Button.sizes.large} testID={`${testID}.secondaryButton`} {...secondaryButton} style={buttonStyle} enableShadow={false} />;
}
render() {
const {
withoutAnimation,
visible,
fullWidth,
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 row={this.isSecondaryHorizontal} center={this.isSecondaryHorizontal || !fullWidth} pointerEvents="box-none" animated style={[styles.container, this.getAnimatedStyle()]} testID={testID}>
{this.renderOverlay()}
{this.isSecondaryHorizontal && this.renderSecondaryButton()}
{this.renderButton()}
{this.isSecondaryVertical && this.renderSecondaryButton()}
</View>;
}
}
const styles = StyleSheet.create({
container: {
top: undefined,
zIndex: Constants.isAndroid ? 99 : undefined
},
image: {
...StyleSheet.absoluteFillObject,
width: '100%',
height: '100%'
},
shadow: {
...Shadows.sh20.bottom
},
secondaryMargin: {
marginTop: Spacings.s4,
marginBottom: Spacings.s7,
marginLeft: 20
}
});
export default asBaseComponent(FloatingButton);