Skip to content

Commit

Permalink
fix(tooltip): unable to type in input with tooltip on iOS (#8534)
Browse files Browse the repository at this point in the history
Fixes an issue, caused by HammerJS adding `user-select: none` to the trigger element, that prevents users from being able to type inside inputs on iOS, if they have a tooltip.

Fixes #8331.
  • Loading branch information
crisbeto authored and tinayuangao committed Nov 29, 2017
1 parent d6fec35 commit 75c665a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 2 deletions.
40 changes: 39 additions & 1 deletion src/lib/tooltip/tooltip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ describe('MatTooltip', () => {
BasicTooltipDemo,
ScrollableTooltipDemo,
OnPushTooltipDemo,
DynamicTooltipsDemo
DynamicTooltipsDemo,
TooltipOnTextFields
],
providers: [
{provide: Platform, useValue: {IOS: false, isBrowser: true}},
Expand Down Expand Up @@ -679,6 +680,25 @@ describe('MatTooltip', () => {
}));
});

describe('special cases', () => {
it('should clear the `user-select` when a tooltip is set on a text field in iOS', () => {
TestBed.overrideProvider(Platform, {
useValue: {IOS: true, isBrowser: true}
});

const fixture = TestBed.createComponent(TooltipOnTextFields);
const instance = fixture.componentInstance;

fixture.detectChanges();

expect(instance.input.nativeElement.style.userSelect).toBeFalsy();
expect(instance.input.nativeElement.style.webkitUserSelect).toBeFalsy();

expect(instance.textarea.nativeElement.style.userSelect).toBeFalsy();
expect(instance.textarea.nativeElement.style.webkitUserSelect).toBeFalsy();
});
});

});

@Component({
Expand Down Expand Up @@ -764,6 +784,24 @@ class DynamicTooltipsDemo {
}
}

@Component({
template: `
<input
#input
style="user-select: none; -webkit-user-select: none"
matTooltip="Something">
<textarea
#textarea
style="user-select: none; -webkit-user-select: none"
matTooltip="Another thing"></textarea>
`,
})
class TooltipOnTextFields {
@ViewChild('input') input: ElementRef;
@ViewChild('textarea') textarea: ElementRef;
}

/** Asserts whether a tooltip directive has a tooltip instance. */
function assertTooltipInstance(tooltip: MatTooltip, shouldExist: boolean): void {
// Note that we have to cast this to a boolean, because Jasmine will go into an infinite loop
Expand Down
11 changes: 10 additions & 1 deletion src/lib/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ export class MatTooltip implements OnDestroy {
@Inject(MAT_TOOLTIP_SCROLL_STRATEGY) private _scrollStrategy,
@Optional() private _dir: Directionality) {

const element: HTMLElement = _elementRef.nativeElement;

// The mouse events shouldn't be bound on iOS devices, because
// they can prevent the first tap from firing its click event.
if (!_platform.IOS) {
Expand All @@ -190,9 +192,16 @@ export class MatTooltip implements OnDestroy {

this._manualListeners
.forEach((listener, event) => _elementRef.nativeElement.addEventListener(event, listener));
} else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
// When we bind a gesture event on an element (in this case `longpress`), HammerJS
// will add some inline styles by default, including `user-select: none`. This is
// problematic on iOS, because it will prevent users from typing in inputs. If
// we're on iOS and the tooltip is attached on an input or textarea, we clear
// the `user-select` to avoid these issues.
element.style.webkitUserSelect = element.style.userSelect = '';
}

_focusMonitor.monitor(_elementRef.nativeElement, false).subscribe(origin => {
_focusMonitor.monitor(element, false).subscribe(origin => {
// Note that the focus monitor runs outside the Angular zone.
if (!origin) {
_ngZone.run(() => this.hide(0));
Expand Down

0 comments on commit 75c665a

Please sign in to comment.