import React, { Fragment } from 'react'; import { TouchableOpacity, Modal, View, StatusBar, I18nManager, StyleSheet, Platform, } from 'react-native'; import { withTheme } from '../config'; import { ScreenWidth, ScreenHeight, isIOS } from '../helpers'; import Triangle from './Triangle'; import getTooltipCoordinate, { getElementVisibleWidth, } from './getTooltipCoordinate'; const defaultProps = { withOverlay: true, overlayColor: 'rgba(250, 250, 250, 0.70)', highlightColor: 'transparent', withPointer: true, toggleOnPress: true, toggleAction: 'onPress', height: 40, width: 150, containerStyle: {}, backgroundColor: '#617080', onClose: () => { }, onOpen: () => { }, skipAndroidStatusBar: false, ModalComponent: Modal, closeOnlyOnBackdropPress: false, }; class Tooltip extends React.Component { constructor() { super(...arguments); this._isMounted = false; this.state = { isVisible: false, yOffset: 0, xOffset: 0, elementWidth: 0, elementHeight: 0, }; this.toggleTooltip = () => { const { onClose } = this.props; this.getElementPosition(); this._isMounted && this.setState((prevState) => { if (prevState.isVisible) { onClose && onClose(); } return { isVisible: !prevState.isVisible }; }); }; this.wrapWithPress = (toggleOnPress, toggleAction, children) => { if (toggleOnPress) { return ( {children} ); } return children; }; this.containerStyle = (withOverlay, overlayColor) => { return { backgroundColor: withOverlay ? overlayColor : 'transparent', flex: 1, }; }; this.getTooltipStyle = () => { const { yOffset, xOffset, elementHeight, elementWidth } = this.state; const { height, backgroundColor, width, withPointer, containerStyle, } = this.props; const { x, y } = getTooltipCoordinate(xOffset, yOffset, elementWidth, elementHeight, ScreenWidth, ScreenHeight, width, height, withPointer); return StyleSheet.flatten([ { position: 'absolute', [I18nManager.isRTL ? 'right' : 'left']: x, top: y, width, height, backgroundColor, // default styles display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1, borderRadius: 10, padding: 10, }, containerStyle, ]); }; this.renderPointer = (tooltipY) => { const { yOffset, xOffset, elementHeight, elementWidth } = this.state; const { backgroundColor, pointerColor } = this.props; const pastMiddleLine = yOffset > (tooltipY || 0); return ( ); }; this.getTooltipHighlightedButtonStyle = () => { const { highlightColor } = this.props; const { yOffset, xOffset, elementWidth, elementHeight } = this.state; return { position: 'absolute', top: yOffset, [I18nManager.isRTL ? 'right' : 'left']: xOffset, backgroundColor: highlightColor, overflow: 'visible', width: elementWidth, height: elementHeight, }; }; this.renderTouchableHighlightedButton = () => { const TooltipHighlightedButtonStyle = this.getTooltipHighlightedButtonStyle(); return ( this.toggleTooltip()} style={TooltipHighlightedButtonStyle}> {this.props.children} ); }; this.renderStaticHighlightedButton = () => { const TooltipHighlightedButtonStyle = this.getTooltipHighlightedButtonStyle(); return ({this.props.children}); }; this.renderHighlightedButton = () => { const { closeOnlyOnBackdropPress } = this.props; if (closeOnlyOnBackdropPress) { return this.renderTouchableHighlightedButton(); } else { return this.renderStaticHighlightedButton(); } }; this.renderContent = (withTooltip) => { const { popover, withPointer, toggleOnPress, toggleAction } = this.props; if (!withTooltip) { return this.wrapWithPress(toggleOnPress, toggleAction, this.props.children); } const tooltipStyle = this.getTooltipStyle(); return ( {this.renderHighlightedButton()} {withPointer && this.renderPointer(tooltipStyle.top)} {popover} ); }; this.getElementPosition = () => { const { skipAndroidStatusBar } = this.props; this.renderedElement && this.renderedElement.measure((_frameOffsetX, _frameOffsetY, width, height, pageOffsetX, pageOffsetY) => { this._isMounted && this.setState({ xOffset: pageOffsetX, yOffset: isIOS || skipAndroidStatusBar ? pageOffsetY : pageOffsetY - Platform.select({ android: StatusBar.currentHeight, ios: 20, default: 0, }), elementWidth: width, elementHeight: height, }); }); }; this.renderStaticModalContent = () => { const { withOverlay, overlayColor } = this.props; return ( {this.renderContent(true)} ); }; this.renderTogglingModalContent = () => { const { withOverlay, overlayColor } = this.props; return ( {this.renderContent(true)} ); }; this.renderModalContent = () => { const { closeOnlyOnBackdropPress } = this.props; if (closeOnlyOnBackdropPress) { return this.renderStaticModalContent(); } else { return this.renderTogglingModalContent(); } }; } componentDidMount() { this._isMounted = true; // wait to compute onLayout values. requestAnimationFrame(this.getElementPosition); } componentWillUnmount() { this._isMounted = false; } render() { const { isVisible } = this.state; const { onOpen, ModalComponent } = this.props; return ( { this.renderedElement = e; }}> {this.renderContent(false)} {this.renderModalContent()} ); } } Tooltip.defaultProps = defaultProps; export { Tooltip }; export default withTheme(Tooltip, 'Tooltip');