Skip to content

Commit

Permalink
[Tooltip] Long press select text on iOS (#23466)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmaddisb authored Nov 12, 2020
1 parent 306dc35 commit a282900
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 7 deletions.
24 changes: 20 additions & 4 deletions packages/material-ui/src/Tooltip/Tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
};
Expand Down
70 changes: 67 additions & 3 deletions packages/material-ui/src/Tooltip/Tooltip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,9 +410,7 @@ describe('<Tooltip />', () => {
title="Hello World"
TransitionProps={{ timeout: transitionTimeout }}
>
<button id="testChild" type="submit">
Hello World
</button>
<button type="submit">Hello World</button>
</Tooltip>,
);
act(() => {
Expand Down Expand Up @@ -1083,4 +1081,70 @@ describe('<Tooltip />', () => {
}
});
});

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(
<Tooltip
enterTouchDelay={enterTouchDelay}
enterDelay={enterDelay}
leaveTouchDelay={leaveTouchDelay}
title="Hello World"
TransitionProps={{ timeout: transitionTimeout }}
>
<button type="submit">Hello World</button>
</Tooltip>,
);
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(
<Tooltip
enterTouchDelay={enterTouchDelay}
enterDelay={enterDelay}
leaveTouchDelay={leaveTouchDelay}
title="Hello World"
TransitionProps={{ timeout: transitionTimeout }}
>
<button type="submit">Hello World</button>
</Tooltip>,
);

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');
});
});
});

0 comments on commit a282900

Please sign in to comment.