import * as React from 'react'; import { I18nManager, Modal, TouchableOpacity } from 'react-native'; import { View } from '../../primitives'; import getTooltipCoordinate from './getTooltipCoordinate'; import { isIOS, ScreenHeight, ScreenWidth } from './helpers'; import Triangle from './Triangle'; type State = { isVisible: boolean; yOffset: number; xOffset: number; elementWidth: number; elementHeight: number; }; export type Props = { children?: JSX.Element | JSX.Element[]; withPointer?: boolean; popover?: JSX.Element; height?: number | string; width?: number | string; containerStyle?: any; pointerColor?: string; pointerStyle?: {}; onClose?: () => void; onOpen?: () => void; withOverlay?: boolean; overlayColor?: string; backgroundColor?: string; highlightColor?: string; toggleWrapperProps?: {}; closeOnPopoverPress?: boolean; closeOnBlur?: boolean; actionType?: 'press' | 'longPress' | 'none'; borderColor?: string; borderWidth?: number; }; class Tooltip extends React.PureComponent { state = { isVisible: false, yOffset: 0, xOffset: 0, elementWidth: 0, elementHeight: 0, }; renderedElement: any; timeout: any; static defaultProps: { toggleWrapperProps: {}; withOverlay: true; highlightColor: 'transparent'; withPointer: true; actionType: 'press'; height: 40; width: 150; containerStyle: {}; pointerStyle: {}; backgroundColor: '#617080'; onClose: () => void; onOpen: () => void; }; toggleTooltip = () => { const { onClose } = this.props; this.getElementPosition(); this.setState((prevState) => { if (prevState.isVisible && !isIOS) { onClose && onClose(); } return { isVisible: !prevState.isVisible }; }); }; wrapWithAction = (actionType: any, children: {} | null | undefined) => { if (actionType === 'press' || actionType === 'longPress') { return ( {children} ); } return children; }; getTooltipStyle = () => { const { yOffset, xOffset, elementHeight, elementWidth } = this.state; const { height, width, withPointer, containerStyle } = this.props; const { x, y } = getTooltipCoordinate( xOffset, yOffset, elementWidth, elementHeight, ScreenWidth, ScreenHeight, width, height, withPointer ); return { position: 'absolute', left: I18nManager.isRTL ? null : x, right: I18nManager.isRTL ? x : null, top: y, width, height, // default styles display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1, borderRadius: 10, paddingTop: 10, paddingBottom: 10, // borderWidth: 1, // borderColor: '#CBD5E0', ...containerStyle, }; }; renderPointer = (tooltipY: any) => { const { yOffset, xOffset, elementHeight, elementWidth } = this.state; const { backgroundColor, pointerStyle } = this.props; const pastMiddleLine = yOffset > tooltipY; const styling: any = { position: 'absolute', top: pastMiddleLine ? yOffset - 13 : yOffset + elementHeight - 2, left: I18nManager.isRTL ? null : xOffset + elementWidth / 2 - 7.5, right: I18nManager.isRTL ? xOffset + elementWidth / 2 - 7.5 : null, }; return ( ); }; renderContent = (withTooltip: any) => { const { popover, withPointer, highlightColor, actionType } = this.props; if (!withTooltip) return this.wrapWithAction(actionType, this.props.children); const { yOffset, xOffset, elementWidth, elementHeight } = this.state; const tooltipStyle = this.getTooltipStyle(); const styling: any = { position: 'absolute', top: yOffset, left: I18nManager.isRTL ? null : xOffset, right: I18nManager.isRTL ? xOffset : null, backgroundColor: highlightColor, overflow: 'visible', width: elementWidth, height: elementHeight, }; return ( {this.props.children} {withPointer && this.renderPointer(tooltipStyle.top)} {popover} ); }; componentDidMount() { // wait to compute onLayout values. this.timeout = setTimeout(this.getElementPosition, 500); } componentWillUnmount() { clearTimeout(this.timeout); } getElementPosition = () => { this.renderedElement && this.renderedElement.measureInWindow( (pageOffsetX: any, pageOffsetY: any, width: any, height: any) => { this.setState({ xOffset: pageOffsetX, yOffset: pageOffsetY, elementWidth: width, elementHeight: height, }); } ); }; render() { const { isVisible } = this.state; const { onClose, withOverlay, onOpen, overlayColor } = this.props; return ( (this.renderedElement = e)}> {this.renderContent(false)} {this.props.closeOnBlur ? ( ) : null} {this.props.closeOnPopoverPress ? ( {this.renderContent(true)} ) : ( this.renderContent(true) )} ); } } Tooltip.defaultProps = { toggleWrapperProps: {}, withOverlay: true, highlightColor: 'transparent', withPointer: true, actionType: 'press', height: 40, width: 150, containerStyle: {}, pointerStyle: {}, backgroundColor: '#617080', onClose: () => {}, onOpen: () => {}, }; const styles = { container: (withOverlay: any, overlayColor: any) => ({ backgroundColor: withOverlay ? overlayColor ? overlayColor : 'rgba(250, 250, 250, 0.70)' : 'transparent', flex: 1, zIndex: -1, }), }; export default Tooltip;