diff --git a/packages/material-ui/src/Tooltip/Tooltip.js b/packages/material-ui/src/Tooltip/Tooltip.js
index 92ca464604d828..e461a6a68a083f 100644
--- a/packages/material-ui/src/Tooltip/Tooltip.js
+++ b/packages/material-ui/src/Tooltip/Tooltip.js
@@ -78,13 +78,14 @@ export const styles = (theme) => ({
padding: '4px 8px',
fontSize: theme.typography.pxToRem(11),
maxWidth: 300,
+ margin: 2,
wordWrap: 'break-word',
fontWeight: theme.typography.fontWeightMedium,
},
/* Styles applied to the tooltip (label wrapper) element if `arrow={true}`. */
tooltipArrow: {
position: 'relative',
- margin: '0',
+ margin: 0,
},
/* Styles applied to the arrow element. */
arrow: {
@@ -240,14 +241,23 @@ const Tooltip = React.forwardRef(function Tooltip(props, ref) {
const id = useId(idProp);
+ const prevUserSelect = React.useRef();
+ const stopTouchInteraction = React.useCallback(() => {
+ if (prevUserSelect.current !== undefined) {
+ document.body.style.WebkitUserSelect = prevUserSelect.current;
+ prevUserSelect.current = undefined;
+ }
+ clearTimeout(touchTimer.current);
+ }, []);
+
React.useEffect(() => {
return () => {
clearTimeout(closeTimer.current);
clearTimeout(enterTimer.current);
clearTimeout(leaveTimer.current);
- clearTimeout(touchTimer.current);
+ stopTouchInteraction();
};
- }, []);
+ }, [stopTouchInteraction]);
const handleOpen = (event) => {
clearTimeout(hystersisTimer);
@@ -369,9 +379,15 @@ const Tooltip = React.forwardRef(function Tooltip(props, ref) {
detectTouchStart(event);
clearTimeout(leaveTimer.current);
clearTimeout(closeTimer.current);
- clearTimeout(touchTimer.current);
+ stopTouchInteraction();
event.persist();
+
+ prevUserSelect.current = document.body.style.WebkitUserSelect;
+ // Prevent iOS text selection on long-tap.
+ document.body.style.WebkitUserSelect = 'none';
+
touchTimer.current = setTimeout(() => {
+ document.body.style.WebkitUserSelect = prevUserSelect.current;
handleEnter(event);
}, enterTouchDelay);
};
diff --git a/packages/material-ui/src/Tooltip/Tooltip.test.js b/packages/material-ui/src/Tooltip/Tooltip.test.js
index b757cefab1d17b..83a6c9431c89cd 100644
--- a/packages/material-ui/src/Tooltip/Tooltip.test.js
+++ b/packages/material-ui/src/Tooltip/Tooltip.test.js
@@ -410,9 +410,7 @@ describe('', () => {
title="Hello World"
TransitionProps={{ timeout: transitionTimeout }}
>
-
+
,
);
act(() => {
@@ -1083,4 +1081,70 @@ describe('', () => {
}
});
});
+
+ describe('user-select state', () => {
+ let prevWebkitUserSelect;
+ beforeEach(() => {
+ prevWebkitUserSelect = document.body.style.WebkitUserSelect;
+ });
+
+ afterEach(() => {
+ document.body.style.WebkitUserSelect = prevWebkitUserSelect;
+ });
+
+ it('prevents text-selection during touch-longpress', () => {
+ const enterTouchDelay = 700;
+ const enterDelay = 100;
+ const leaveTouchDelay = 1500;
+ const transitionTimeout = 10;
+ const { getByRole } = render(
+
+
+ ,
+ );
+ document.body.style.WebkitUserSelect = 'revert';
+
+ fireEvent.touchStart(getByRole('button'));
+
+ expect(document.body.style.WebkitUserSelect).to.equal('none');
+
+ act(() => {
+ clock.tick(enterTouchDelay + enterDelay);
+ });
+ expect(document.body.style.WebkitUserSelect.toLowerCase()).to.equal('revert');
+ });
+
+ it('restores user-select when unmounted during longpress', () => {
+ const enterTouchDelay = 700;
+ const enterDelay = 100;
+ const leaveTouchDelay = 1500;
+ const transitionTimeout = 10;
+ const { unmount, getByRole } = render(
+
+
+ ,
+ );
+
+ document.body.style.WebkitUserSelect = 'revert';
+ // Let updates flush before unmounting
+ act(() => {
+ fireEvent.touchStart(getByRole('button'));
+ });
+ unmount();
+
+ expect(document.body.style.WebkitUserSelect.toLowerCase()).to.equal('revert');
+ });
+ });
});