import React, { useState, useEffect, useRef } from 'react'; import { arrayToClassName } from '../utils/utils'; export default function Tooltip( props ) { const baseClassName = 'e-app-tooltip', classes = [ baseClassName, props.className ], childRef = useRef( null ), isAborted = useRef( false ), isManualControl = Object.prototype.hasOwnProperty.call( props, 'show' ), [ isLibraryLoaded, setIsLibraryLoaded ] = useState( false ), [ showTooltip, setShowTooltip ] = useState( false ), directionsMap = { top: 's', right: 'w', down: 'n', left: 'e', }, tipsyConfig = { trigger: isManualControl ? 'manual' : 'hover', gravity: directionsMap[ props.direction ], offset: props.offset, title() { return props.title; }, }, setTipsy = () => { const $tooltipContainer = jQuery( childRef.current ); $tooltipContainer.tipsy( tipsyConfig ); if ( isManualControl ) { const displayMode = showTooltip ? 'show' : 'hide'; $tooltipContainer.tipsy( displayMode ); } }; useEffect( () => { // In case that the component is disabled the tipsy library will not be loaded by default. if ( ! props.disabled ) { isAborted.current = false; import( /* webpackIgnore: true */ `${ elementorCommon.config.urls.assets }lib/tipsy/tipsy.min.js?ver=1.0.0` ).then( () => { if ( ! isAborted.current ) { if ( isLibraryLoaded ) { setTipsy(); } else { setIsLibraryLoaded( true ); } } } ); } return () => { if ( ! props.disabled ) { // Aborting the current dynamic-import state update in case of re-render. isAborted.current = true; // Cleanup of existing tipsy element in case of re-render. const nodes = document.querySelectorAll( '.tipsy' ); nodes[ nodes.length - 1 ].remove(); } }; }, [ props.disabled ] ); useEffect( () => { if ( isLibraryLoaded ) { setTipsy(); } }, [ isLibraryLoaded, showTooltip ] ); useEffect( () => { // The "show" state should not be changed while the component is disabled. if ( ! props.disabled && props.show !== showTooltip ) { setShowTooltip( props.show ); } }, [ props.show ] ); return ( <props.tag className={ arrayToClassName( classes ) } ref={ childRef }> { props.children } </props.tag> ); } Tooltip.propTypes = { className: PropTypes.string, offset: PropTypes.number, show: PropTypes.bool, direction: PropTypes.oneOf( [ 'top', 'right', 'left', 'down' ] ), tag: PropTypes.string.isRequired, title: PropTypes.string.isRequired, disabled: PropTypes.bool, children: PropTypes.any, }; Tooltip.defaultProps = { className: '', offset: 10, direction: 'top', disabled: false, };