diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js index 037fb3afae73..efb64fbb5397 100644 --- a/src/components/PressableWithSecondaryInteraction/index.js +++ b/src/components/PressableWithSecondaryInteraction/index.js @@ -17,8 +17,12 @@ class PressableWithSecondaryInteraction extends Component { } componentDidMount() { - if (this.props.forwardedRef && _.isFunction(this.props.forwardedRef)) { - this.props.forwardedRef(this.pressableRef); + if (this.props.forwardedRef) { + if (_.isFunction(this.props.forwardedRef)) { + this.props.forwardedRef(this.pressableRef); + } else if (_.isObject(this.props.forwardedRef)) { + this.props.forwardedRef.current = this.pressableRef; + } } this.pressableRef.addEventListener('contextmenu', this.executeSecondaryInteractionOnContextMenu); } diff --git a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js index e54598cb1394..b036404e018d 100644 --- a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js +++ b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js @@ -1,4 +1,5 @@ import PropTypes from 'prop-types'; +import refPropTypes from '../refPropTypes'; import stylePropTypes from '../../styles/stylePropTypes'; const propTypes = { @@ -18,7 +19,7 @@ const propTypes = { children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired, /** The ref to the search input (may be null on small screen widths) */ - forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + forwardedRef: refPropTypes, /** Prevent the default ContextMenu on web/Desktop */ preventDefaultContextMenu: PropTypes.bool, diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index 9e8863fe9953..108cc5fc5339 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -27,6 +27,7 @@ import * as OptionsListUtils from '../../libs/OptionsListUtils'; import * as CurrencyUtils from '../../libs/CurrencyUtils'; import * as IOUUtils from '../../libs/IOUUtils'; import * as ReportUtils from '../../libs/ReportUtils'; +import refPropTypes from '../refPropTypes'; const propTypes = { /** The active IOUReport, used for Onyx subscription */ @@ -43,7 +44,7 @@ const propTypes = { action: PropTypes.shape(reportActionPropTypes), /** Popover context menu anchor, used for showing context menu */ - contextMenuAnchor: PropTypes.shape({current: PropTypes.elementType}), + contextMenuAnchor: refPropTypes, /** Callback for updating context menu active state, used for showing context menu */ checkIfContextMenuActive: PropTypes.func, diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js index 03a5f047275e..76cf17469496 100644 --- a/src/components/ReportActionItem/MoneyRequestAction.js +++ b/src/components/ReportActionItem/MoneyRequestAction.js @@ -20,6 +20,7 @@ import * as ReportUtils from '../../libs/ReportUtils'; import * as Report from '../../libs/actions/Report'; import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; +import refPropTypes from '../refPropTypes'; const propTypes = { /** All the data of the action */ @@ -35,7 +36,7 @@ const propTypes = { isMostRecentIOUReportAction: PropTypes.bool.isRequired, /** Popover context menu anchor, used for showing context menu */ - contextMenuAnchor: PropTypes.shape({current: PropTypes.elementType}), + contextMenuAnchor: refPropTypes, /** Callback for updating context menu active state, used for showing context menu */ checkIfContextMenuActive: PropTypes.func, diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js index 9758c6ab61d4..4c85be327bba 100644 --- a/src/components/ReportActionItem/ReportPreview.js +++ b/src/components/ReportActionItem/ReportPreview.js @@ -24,6 +24,7 @@ import SettlementButton from '../SettlementButton'; import themeColors from '../../styles/themes/default'; import getButtonState from '../../libs/getButtonState'; import * as IOU from '../../libs/actions/IOU'; +import refPropTypes from '../refPropTypes'; const propTypes = { /** All the data of the action */ @@ -71,7 +72,7 @@ const propTypes = { }), /** Popover context menu anchor, used for showing context menu */ - contextMenuAnchor: PropTypes.shape({current: PropTypes.elementType}), + contextMenuAnchor: refPropTypes, /** Callback for updating context menu active state, used for showing context menu */ checkIfContextMenuActive: PropTypes.func, diff --git a/src/components/refPropTypes.js b/src/components/refPropTypes.js new file mode 100644 index 000000000000..a67f6323d1d9 --- /dev/null +++ b/src/components/refPropTypes.js @@ -0,0 +1,3 @@ +import PropTypes from 'prop-types'; + +export default PropTypes.oneOfType([PropTypes.func, PropTypes.object]); diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js index e1acc7ecd736..1cc5a6e3b220 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js @@ -95,7 +95,7 @@ class PopoverReportActionContextMenu extends React.Component { getContextMenuMeasuredLocation() { return new Promise((resolve) => { if (this.contextMenuAnchor) { - this.contextMenuAnchor.measureInWindow((x, y) => resolve({x, y})); + this.contextMenuAnchor.current.measureInWindow((x, y) => resolve({x, y})); } else { resolve({x: 0, y: 0}); } diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index a0511469fa4a..a318d181e460 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; -import React, {Component} from 'react'; +import React, {useState, useRef, useEffect, memo, useCallback} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; @@ -66,9 +66,6 @@ const propTypes = { /** Is this the most recent IOU Action? */ isMostRecentIOUReportAction: PropTypes.bool.isRequired, - /** Whether there is an outstanding amount in IOU */ - hasOutstandingIOU: PropTypes.bool, - /** Should we display the new marker on top of the comment? */ shouldDisplayNewMarker: PropTypes.bool.isRequired, @@ -81,6 +78,10 @@ const propTypes = { /** Draft message - if this is set the comment is in 'edit' mode */ draftMessage: PropTypes.string, + /* Whether the option has an outstanding IOU */ + // eslint-disable-next-line react/no-unused-prop-types + hasOutstandingIOU: PropTypes.bool, + /** Stores user's preferred skin tone */ preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), @@ -95,105 +96,89 @@ const propTypes = { const defaultProps = { draftMessage: '', - hasOutstandingIOU: false, preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, personalDetails: {}, shouldShowSubscriptAvatar: false, + hasOutstandingIOU: false, betas: [], }; -class ReportActionItem extends Component { - constructor(props) { - super(props); - this.popoverAnchor = undefined; - this.state = { - isContextMenuActive: ReportActionContextMenu.isActiveReportAction(props.action.reportActionID), - }; - this.checkIfContextMenuActive = this.checkIfContextMenuActive.bind(this); - this.showPopover = this.showPopover.bind(this); - this.renderItemContent = this.renderItemContent.bind(this); - this.toggleReaction = this.toggleReaction.bind(this); - } - - shouldComponentUpdate(nextProps, nextState) { - return ( - this.props.displayAsGroup !== nextProps.displayAsGroup || - this.props.draftMessage !== nextProps.draftMessage || - this.props.isMostRecentIOUReportAction !== nextProps.isMostRecentIOUReportAction || - this.props.hasOutstandingIOU !== nextProps.hasOutstandingIOU || - this.props.shouldDisplayNewMarker !== nextProps.shouldDisplayNewMarker || - !_.isEqual(this.props.action, nextProps.action) || - this.state.isContextMenuActive !== nextState.isContextMenuActive || - lodashGet(this.props.report, 'statusNum') !== lodashGet(nextProps.report, 'statusNum') || - lodashGet(this.props.report, 'stateNum') !== lodashGet(nextProps.report, 'stateNum') || - this.props.translate !== nextProps.translate - ); - } +function ReportActionItem(props) { + const [isContextMenuActive, setIsContextMenuActive] = useState(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); + const textInputRef = useRef(); + const popoverAnchorRef = useRef(); - componentDidUpdate(prevProps) { - if (prevProps.draftMessage || !this.props.draftMessage) { + const isDraftEmpty = !props.draftMessage; + useEffect(() => { + if (isDraftEmpty) { return; } // Only focus the input when user edits a message, skip it for existing drafts being edited of the report. // There is an animation when the comment is hidden and the edit form is shown, and there can be bugs on different mobile platforms // if the input is given focus in the middle of that animation which can prevent the keyboard from opening. - focusTextInputAfterAnimation(this.textInput, 100); - } + focusTextInputAfterAnimation(textInputRef.current, 100); + }, [isDraftEmpty]); - checkIfContextMenuActive() { - this.setState({isContextMenuActive: ReportActionContextMenu.isActiveReportAction(this.props.action.reportActionID)}); - } + const toggleContextMenuFromActiveReportAction = useCallback(() => { + setIsContextMenuActive(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)); + }, [props.action.reportActionID]); /** * Show the ReportActionContextMenu modal popover. * * @param {Object} [event] - A press event. */ - showPopover(event) { - // Block menu on the message being Edited or if the report action item has errors - if (this.props.draftMessage || !_.isEmpty(this.props.action.errors)) { - return; - } - - this.setState({isContextMenuActive: true}); - - const selection = SelectionScraper.getCurrentSelection(); - ReportActionContextMenu.showContextMenu( - ContextMenuActions.CONTEXT_MENU_TYPES.REPORT_ACTION, - event, - selection, - this.popoverAnchor, - this.props.report.reportID, - this.props.action, - this.props.draftMessage, - undefined, - this.checkIfContextMenuActive, - ReportUtils.isArchivedRoom(this.props.report), - ReportUtils.chatIncludesChronos(this.props.report), - this.props.action.childReportID, - ); - } + const showPopover = useCallback( + (event) => { + // Block menu on the message being Edited or if the report action item has errors + if (props.draftMessage || !_.isEmpty(props.action.errors)) { + return; + } + + setIsContextMenuActive(true); + + const selection = SelectionScraper.getCurrentSelection(); + ReportActionContextMenu.showContextMenu( + ContextMenuActions.CONTEXT_MENU_TYPES.REPORT_ACTION, + event, + selection, + popoverAnchorRef, + props.report.reportID, + props.action, + props.draftMessage, + () => {}, + toggleContextMenuFromActiveReportAction, + ReportUtils.isArchivedRoom(props.report), + ReportUtils.chatIncludesChronos(props.report), + props.action.childReportID, + ); + }, + [props.draftMessage, props.action, props.report, toggleContextMenuFromActiveReportAction], + ); - toggleReaction(emoji) { - Report.toggleEmojiReaction(this.props.report.reportID, this.props.action, emoji); - } + const toggleReaction = useCallback( + (emoji) => { + Report.toggleEmojiReaction(props.report.reportID, props.action, emoji); + }, + [props.report, props.action], + ); /** * Get the content of ReportActionItem * @param {Boolean} hovered whether the ReportActionItem is hovered * @returns {Object} child component(s) */ - renderItemContent(hovered = false) { + const renderItemContent = (hovered = false) => { let children; - const originalMessage = lodashGet(this.props.action, 'originalMessage', {}); + const originalMessage = lodashGet(props.action, 'originalMessage', {}); // IOUDetails only exists when we are sending money const isSendingMoney = originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.PAY && _.has(originalMessage, 'IOUDetails'); // Show the IOUPreview for when request was created, bill was split or money was sent if ( - this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && + props.action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && originalMessage && // For the pay flow, we only want to show MoneyRequestAction when sending money. When paying, we display a regular system message (originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.CREATE || originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT || isSendingMoney) @@ -202,82 +187,79 @@ class ReportActionItem extends Component { const iouReportID = originalMessage.IOUReportID ? originalMessage.IOUReportID.toString() : '0'; children = ( ); - } else if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW) { + } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW) { children = ( ); } else if ( - this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED || - this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCANCELED || - this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED + props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED || + props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCANCELED || + props.action.actionName === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED ) { children = ( ); - } else if (ReportActionsUtils.isCreatedTaskReportAction(this.props.action)) { + } else if (ReportActionsUtils.isCreatedTaskReportAction(props.action)) { children = ( ); } else { - const message = _.last(lodashGet(this.props.action, 'message', [{}])); - const isAttachment = _.has(this.props.action, 'isAttachment') ? this.props.action.isAttachment : ReportUtils.isReportMessageAttachment(message); + const message = _.last(lodashGet(props.action, 'message', [{}])); + const isAttachment = _.has(props.action, 'isAttachment') ? props.action.isAttachment : ReportUtils.isReportMessageAttachment(message); children = ( - {!this.props.draftMessage ? ( + {!props.draftMessage ? ( ) : ( (this.textInput = el)} - report={this.props.report} + action={props.action} + draftMessage={props.draftMessage} + reportID={props.report.reportID} + index={props.index} + ref={textInputRef} + report={props.report} // Avoid defining within component due to an existing Onyx bug - preferredSkinTone={this.props.preferredSkinTone} + preferredSkinTone={props.preferredSkinTone} shouldDisableEmojiPicker={ - (ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge)) || - ReportUtils.isArchivedRoom(this.props.report) + (ReportUtils.chatIncludesConcierge(props.report) && User.isBlockedFromConcierge(props.blockedFromConcierge)) || ReportUtils.isArchivedRoom(props.report) } /> )} @@ -285,42 +267,39 @@ class ReportActionItem extends Component { ); } - const reactions = _.get(this.props, ['action', 'message', 0, 'reactions'], []); + const reactions = _.get(props, ['action', 'message', 0, 'reactions'], []); const hasReactions = reactions.length > 0; - const numberOfThreadReplies = _.get(this.props, ['action', 'childVisibleActionCount'], 0); + const numberOfThreadReplies = _.get(props, ['action', 'childVisibleActionCount'], 0); const hasReplies = numberOfThreadReplies > 0; const shouldDisplayThreadReplies = - hasReplies && - this.props.action.childCommenterCount && - Permissions.canUseThreads(this.props.betas) && - !ReportUtils.isThreadFirstChat(this.props.action, this.props.report.reportID); - const oldestFourEmails = lodashGet(this.props.action, 'childOldestFourEmails', '').split(','); + hasReplies && props.action.childCommenterCount && Permissions.canUseThreads(props.betas) && !ReportUtils.isThreadFirstChat(props.action, props.report.reportID); + const oldestFourEmails = lodashGet(props.action, 'childOldestFourEmails', '').split(','); return ( <> {children} {hasReactions && ( - + )} {shouldDisplayThreadReplies && ( )} ); - } + }; /** * Get ReportActionItem with a proper wrapper @@ -328,21 +307,21 @@ class ReportActionItem extends Component { * @param {Boolean} isWhisper whether the ReportActionItem is a whisper * @returns {Object} report action item */ - renderReportActionItem(hovered, isWhisper) { - const content = this.renderItemContent(hovered || this.state.isContextMenuActive); + const renderReportActionItem = (hovered, isWhisper) => { + const content = renderItemContent(hovered || isContextMenuActive); - if (this.props.draftMessage) { + if (props.draftMessage) { return {content}; } - if (!this.props.displayAsGroup) { + if (!props.displayAsGroup) { return ( {content} @@ -350,102 +329,101 @@ class ReportActionItem extends Component { } return {content}; - } + }; - render() { - if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { - return ; - } - if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { - return ; - } - if (this.props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CHRONOSOOOLIST) { - return ( - - ); - } - - const hasErrors = !_.isEmpty(this.props.action.errors); - const whisperedTo = lodashGet(this.props.action, 'whisperedTo', []); - const isWhisper = whisperedTo.length > 0; - const isMultipleParticipant = whisperedTo.length > 1; - const isWhisperOnlyVisibleByUser = isWhisper && ReportUtils.isCurrentUserTheOnlyParticipant(whisperedTo); - const whisperedToPersonalDetails = isWhisper ? _.filter(this.props.personalDetails, (details) => _.includes(whisperedTo, details.login)) : []; - const displayNamesWithTooltips = isWhisper ? ReportUtils.getDisplayNamesWithTooltips(whisperedToPersonalDetails, isMultipleParticipant) : []; + if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { + return ; + } + if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) { + return ; + } + if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.CHRONOSOOOLIST) { return ( - (this.popoverAnchor = el)} - onPressIn={() => this.props.isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} - onPressOut={() => ControlSelection.unblock()} - onSecondaryInteraction={this.showPopover} - preventDefaultContextMenu={!this.props.draftMessage && !hasErrors} - withoutFocusOnSecondaryInteraction - > - - {(hovered) => ( - - {this.props.shouldDisplayNewMarker && } - - + ); + } + + const hasErrors = !_.isEmpty(props.action.errors); + const whisperedTo = lodashGet(props.action, 'whisperedTo', []); + const isWhisper = whisperedTo.length > 0; + const isMultipleParticipant = whisperedTo.length > 1; + const isWhisperOnlyVisibleByUser = isWhisper && ReportUtils.isCurrentUserTheOnlyParticipant(whisperedTo); + const whisperedToPersonalDetails = isWhisper ? _.filter(props.personalDetails, (details) => _.includes(whisperedTo, details.login)) : []; + const displayNamesWithTooltips = isWhisper ? ReportUtils.getDisplayNamesWithTooltips(whisperedToPersonalDetails, isMultipleParticipant) : []; + return ( + props.isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} + onSecondaryInteraction={showPopover} + preventDefaultContextMenu={!props.draftMessage && !hasErrors} + withoutFocusOnSecondaryInteraction + > + + {(hovered) => ( + + {props.shouldDisplayNewMarker && } + + + ReportActions.clearReportActionErrors(props.report.reportID, props.action)} + pendingAction={props.draftMessage ? null : props.action.pendingAction} + errors={props.action.errors} + errorRowStyles={[styles.ml10, styles.mr2]} + needsOffscreenAlphaCompositing={ReportActionsUtils.isMoneyRequestAction(props.action)} > - ReportActions.clearReportActionErrors(this.props.report.reportID, this.props.action)} - pendingAction={this.props.draftMessage ? null : this.props.action.pendingAction} - errors={this.props.action.errors} - errorRowStyles={[styles.ml10, styles.mr2]} - needsOffscreenAlphaCompositing={ReportActionsUtils.isMoneyRequestAction(this.props.action)} - > - {isWhisper && ( - - - - - - {this.props.translate('reportActionContextMenu.onlyVisible')} -   - - + + - )} - {this.renderReportActionItem(hovered, isWhisper)} - - + + {props.translate('reportActionContextMenu.onlyVisible')} +   + + + + )} + {renderReportActionItem(hovered, isWhisper)} + - )} - - - - - - ); - } + + )} + + + + + + ); } + ReportActionItem.propTypes = propTypes; ReportActionItem.defaultProps = defaultProps; @@ -470,4 +448,18 @@ export default compose( key: ONYXKEYS.BETAS, }, }), -)(ReportActionItem); +)( + memo( + ReportActionItem, + (prevProps, nextProps) => + prevProps.displayAsGroup === nextProps.displayAsGroup && + prevProps.draftMessage === nextProps.draftMessage && + prevProps.isMostRecentIOUReportAction !== nextProps.isMostRecentIOUReportAction && + prevProps.hasOutstandingIOU === nextProps.hasOutstandingIOU && + prevProps.shouldDisplayNewMarker === nextProps.shouldDisplayNewMarker && + !_.isEqual(prevProps.action, nextProps.action) && + lodashGet(prevProps.report, 'statusNum') === lodashGet(nextProps.report, 'statusNum') && + lodashGet(prevProps.report, 'stateNum') === lodashGet(nextProps.report, 'stateNum') && + prevProps.translate === nextProps.translate, + ), +); diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 7b87b2aad31a..214eff33844e 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -30,6 +30,7 @@ import CONST from '../../../CONST'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; import withKeyboardState, {keyboardStatePropTypes} from '../../../components/withKeyboardState'; +import refPropTypes from '../../../components/refPropTypes'; import * as ComposerUtils from '../../../libs/ComposerUtils'; import * as ComposerActions from '../../../libs/actions/Composer'; import * as User from '../../../libs/actions/User'; @@ -48,7 +49,7 @@ const propTypes = { index: PropTypes.number.isRequired, /** A ref to forward to the text input */ - forwardedRef: PropTypes.func, + forwardedRef: refPropTypes, /** The report currently being looked at */ // eslint-disable-next-line react/no-unused-prop-types @@ -299,7 +300,7 @@ class ReportActionItemMessageEdit extends React.Component { multiline ref={(el) => { this.textInput = el; - this.props.forwardedRef(el); + this.props.forwardedRef.current = el; }} nativeID={this.messageEditInput} onChangeText={this.updateDraft} // Debounced saveDraftComment diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.js index 822b0318e39a..ab2b6b433224 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.js @@ -65,9 +65,10 @@ function isOverlappingAtTop(xOffset, yOffset, tooltip) { } const element = document.elementFromPoint(xOffset, yOffset); + const tooltipRef = (tooltip && tooltip.current) || tooltip; // Ensure it's not the already rendered element of this very tooltip, so the tooltip doesn't try to "avoid" itself - if (!element || (tooltip && tooltip.contains(element))) { + if (!element || (tooltipRef && tooltipRef.contains(element))) { return false; }