From 275b0aed673b59551185eb825d33aac35baa0387 Mon Sep 17 00:00:00 2001
From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com>
Date: Fri, 6 Jan 2023 00:34:11 +0100
Subject: [PATCH 1/3] Refactored Tooltips
---
.../Hoverable/hoverablePropTypes.js | 4 ---
src/components/Hoverable/index.js | 24 ++++++++++++----
src/components/Modal/BaseModal.js | 2 ++
src/components/Tooltip/index.js | 28 ++++++++++++++++---
src/libs/DomUtils/index.js | 7 +++++
src/libs/DomUtils/index.native.js | 5 ++++
src/libs/Navigation/NavigationRoot.js | 7 +++++
7 files changed, 63 insertions(+), 14 deletions(-)
create mode 100644 src/libs/DomUtils/index.js
create mode 100644 src/libs/DomUtils/index.native.js
diff --git a/src/components/Hoverable/hoverablePropTypes.js b/src/components/Hoverable/hoverablePropTypes.js
index 07b8a8741efb..c17fa804b601 100644
--- a/src/components/Hoverable/hoverablePropTypes.js
+++ b/src/components/Hoverable/hoverablePropTypes.js
@@ -19,9 +19,6 @@ const propTypes = {
/** Function that executes when the mouse leaves the children. */
onHoverOut: PropTypes.func,
-
- // If the mouse clicks outside, should we dismiss hover?
- resetsOnClickOutside: PropTypes.bool,
};
const defaultProps = {
@@ -29,7 +26,6 @@ const defaultProps = {
containerStyles: [],
onHoverIn: () => {},
onHoverOut: () => {},
- resetsOnClickOutside: false,
};
export {
diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js
index f06ed5602744..ef4bc2bf532d 100644
--- a/src/components/Hoverable/index.js
+++ b/src/components/Hoverable/index.js
@@ -72,10 +72,6 @@ class Hoverable extends Component {
if (!this.state.isHovered) {
return;
}
- if (this.props.resetsOnClickOutside) {
- this.setIsHovered(false);
- return;
- }
if (this.wrapperView && !this.wrapperView.contains(event.target)) {
this.setIsHovered(false);
}
@@ -93,8 +89,24 @@ class Hoverable extends Component {
ref(el);
}
},
- onMouseEnter: () => this.setIsHovered(true),
- onMouseLeave: () => this.setIsHovered(false),
+ onMouseEnter: (el) => {
+ this.setIsHovered(true);
+
+ // Call the original onMouseEnter, if any
+ const {onMouseEnter} = this.props.children;
+ if (_.isFunction(onMouseEnter)) {
+ onMouseEnter(el);
+ }
+ },
+ onMouseLeave: (el) => {
+ this.setIsHovered(false);
+
+ // Call the original onMouseLeave, if any
+ const {onMouseLeave} = this.props.children;
+ if (_.isFunction(onMouseLeave)) {
+ onMouseLeave(el);
+ }
+ },
});
}
return (
diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js
index 323df19c7720..580b8f9abc47 100644
--- a/src/components/Modal/BaseModal.js
+++ b/src/components/Modal/BaseModal.js
@@ -8,6 +8,7 @@ import * as StyleUtils from '../../styles/StyleUtils';
import themeColors from '../../styles/themes/default';
import {propTypes as modalPropTypes, defaultProps as modalDefaultProps} from './modalPropTypes';
import * as Modal from '../../libs/actions/Modal';
+import DomUtils from '../../libs/DomUtils';
import getModalStyles from '../../styles/getModalStyles';
import variables from '../../styles/variables';
@@ -90,6 +91,7 @@ class BaseModal extends PureComponent {
// Note: Escape key on web/desktop will trigger onBackButtonPress callback
// eslint-disable-next-line react/jsx-props-no-multi-spaces
onBackButtonPress={this.props.onClose}
+ onModalWillShow={DomUtils.blurActiveElement}
onModalShow={() => {
if (this.props.shouldSetModalVisibility) {
Modal.setModalVisibility(true);
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index 8d3a345492ac..dff351af2b01 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -63,7 +63,7 @@ class Tooltip extends PureComponent {
getWrapperPosition() {
return new Promise(((resolve) => {
// Make sure the wrapper is mounted before attempting to measure it.
- if (this.wrapperView) {
+ if (this.wrapperView && _.isFunction(this.wrapperView.measureInWindow)) {
this.wrapperView.measureInWindow((x, y, width, height) => resolve({
x, y, width, height,
}));
@@ -148,6 +148,9 @@ class Tooltip extends PureComponent {
this.wrapperView = el}
style={this.props.containerStyles}
+ onFocus={this.showTooltip}
+ onBlur={this.hideTooltip}
+ focusable
>
{this.props.children}
@@ -156,15 +159,33 @@ class Tooltip extends PureComponent {
if (this.props.absolute && React.isValidElement(this.props.children)) {
child = React.cloneElement(React.Children.only(this.props.children), {
ref: (el) => {
- // Keep your own reference
this.wrapperView = el;
// Call the original ref, if any
const {ref} = this.props.children;
- if (typeof ref === 'function') {
+ if (_.isFunction(ref)) {
ref(el);
}
},
+ onFocus: (el) => {
+ this.showTooltip();
+
+ // Call the original onFocus, if any
+ const {onFocus} = this.props.children;
+ if (_.isFunction(onFocus)) {
+ onFocus(el);
+ }
+ },
+ onBlur: (el) => {
+ this.hideTooltip();
+
+ // Call the original onBlur, if any
+ const {onBlur} = this.props.children;
+ if (_.isFunction(onBlur)) {
+ onBlur(el);
+ }
+ },
+ focusable: true,
});
}
return (
@@ -189,7 +210,6 @@ class Tooltip extends PureComponent {
containerStyles={this.props.containerStyles}
onHoverIn={this.showTooltip}
onHoverOut={this.hideTooltip}
- resetsOnClickOutside
>
{child}
diff --git a/src/libs/DomUtils/index.js b/src/libs/DomUtils/index.js
new file mode 100644
index 000000000000..4e58ea3a08fb
--- /dev/null
+++ b/src/libs/DomUtils/index.js
@@ -0,0 +1,7 @@
+function blurActiveElement() {
+ document.activeElement.blur();
+}
+
+export default {
+ blurActiveElement,
+};
diff --git a/src/libs/DomUtils/index.native.js b/src/libs/DomUtils/index.native.js
new file mode 100644
index 000000000000..0e796bc40b54
--- /dev/null
+++ b/src/libs/DomUtils/index.native.js
@@ -0,0 +1,5 @@
+function blurActiveElement() {}
+
+export default {
+ blurActiveElement,
+};
diff --git a/src/libs/Navigation/NavigationRoot.js b/src/libs/Navigation/NavigationRoot.js
index 7dea3a743bf3..0e0958e8a393 100644
--- a/src/libs/Navigation/NavigationRoot.js
+++ b/src/libs/Navigation/NavigationRoot.js
@@ -8,6 +8,7 @@ import AppNavigator from './AppNavigator';
import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
import themeColors from '../../styles/themes/default';
import styles from '../../styles/styles';
+import DomUtils from '../DomUtils';
import Log from '../Log';
// https://reactnavigation.org/docs/themes
@@ -45,6 +46,12 @@ function parseAndLogRoute(state) {
Log.info('Navigating to route', false, {path: currentPath});
}
+ // Clicking a button that does navigation will stay active even if it's out of view
+ // and it's tooltip will stay visible.
+ // We blur the element manually to fix that (especially for Safari).
+ // More info: https://github.com/Expensify/App/issues/13146
+ DomUtils.blurActiveElement();
+
Navigation.setIsNavigationReady();
}
From 2c6bd3e905cdefe08f461c864d5b1191d43c8a6c Mon Sep 17 00:00:00 2001
From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com>
Date: Fri, 6 Jan 2023 01:32:45 +0100
Subject: [PATCH 2/3] Do not show tooltips on mWeb
---
src/components/Tooltip/index.js | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index dff351af2b01..e737a7d75928 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -7,6 +7,7 @@ import withWindowDimensions from '../withWindowDimensions';
import {propTypes, defaultProps} from './tooltipPropTypes';
import TooltipSense from './TooltipSense';
import makeCancellablePromise from '../../libs/MakeCancellablePromise';
+import * as Browser from '../../libs/Browser';
class Tooltip extends PureComponent {
constructor(props) {
@@ -79,6 +80,12 @@ class Tooltip extends PureComponent {
* Display the tooltip in an animation.
*/
showTooltip() {
+ // On mWeb we do not show Tooltips as there are no way to hide them besides blurring.
+ // That's due to that fact that on mWeb there is no MouseLeave events.
+ if (Browser.isMobile()) {
+ return;
+ }
+
if (!this.state.isRendered) {
this.setState({isRendered: true});
}
From 6c910271555b9180814c68af2b7c44b8e488737a Mon Sep 17 00:00:00 2001
From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com>
Date: Fri, 6 Jan 2023 21:13:19 +0100
Subject: [PATCH 3/3] Removed onFocus functionality
---
src/components/Tooltip/index.js | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index e737a7d75928..890c249e075b 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -155,7 +155,6 @@ class Tooltip extends PureComponent {
this.wrapperView = el}
style={this.props.containerStyles}
- onFocus={this.showTooltip}
onBlur={this.hideTooltip}
focusable
>
@@ -174,15 +173,6 @@ class Tooltip extends PureComponent {
ref(el);
}
},
- onFocus: (el) => {
- this.showTooltip();
-
- // Call the original onFocus, if any
- const {onFocus} = this.props.children;
- if (_.isFunction(onFocus)) {
- onFocus(el);
- }
- },
onBlur: (el) => {
this.hideTooltip();