diff --git a/src/lib/tooltip/tooltip-module.ts b/src/lib/tooltip/tooltip-module.ts index 1fe55ef5a9f..fe4db38a49f 100644 --- a/src/lib/tooltip/tooltip-module.ts +++ b/src/lib/tooltip/tooltip-module.ts @@ -12,7 +12,12 @@ import {PlatformModule} from '@angular/cdk/platform'; import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {MatCommonModule} from '@angular/material/core'; -import {MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER, MatTooltip, TooltipComponent} from './tooltip'; +import { + MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER, + MAT_TOOLTIP_DEFAULT_OPTIONS, + MatTooltip, + TooltipComponent, +} from './tooltip'; @NgModule({ @@ -26,6 +31,17 @@ import {MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER, MatTooltip, TooltipComponent} from exports: [MatTooltip, TooltipComponent, MatCommonModule], declarations: [MatTooltip, TooltipComponent], entryComponents: [TooltipComponent], - providers: [MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER, ARIA_DESCRIBER_PROVIDER], + providers: [ + MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER, + ARIA_DESCRIBER_PROVIDER, + { + provide: MAT_TOOLTIP_DEFAULT_OPTIONS, + useValue: { + showDelay: 0, + hideDelay: 0, + touchendHideDelay: 1500 + } + } + ], }) export class MatTooltipModule {} diff --git a/src/lib/tooltip/tooltip.md b/src/lib/tooltip/tooltip.md index d9efd12ad87..f270fbf4909 100644 --- a/src/lib/tooltip/tooltip.md +++ b/src/lib/tooltip/tooltip.md @@ -5,27 +5,28 @@ over or longpresses an element. ### Positioning -The tooltip will be displayed below the element but this can be configured using the `matTooltipPosition` -input. +The tooltip will be displayed below the element but this can be configured using the +`matTooltipPosition` input. The tooltip can be displayed above, below, left, or right of the element. By default the position will be below. If the tooltip should switch left/right positions in an RTL layout direction, then the positions `before` and `after` should be used instead of `left` and `right`, respectively. -| Position | Description | -|-----------|---------------------------------------------------------------------------------------| -| `above` | Always display above the element | -| `below ` | Always display beneath the element | -| `left` | Always display to the left of the element | -| `right` | Always display to the right of the element | -| `before` | Display to the left in left-to-right layout and to the right in right-to-left layout | -| `after` | Display to the right in left-to-right layout and to the right in right-to-left layout | +| Position | Description | +|-----------|--------------------------------------------------------------------------------------| +| `above` | Always display above the element | +| `below ` | Always display beneath the element | +| `left` | Always display to the left of the element | +| `right` | Always display to the right of the element | +| `before` | Display to the left in left-to-right layout and to the right in right-to-left layout | +| `after` | Display to the right in left-to-right layout and to the right in right-to-left layout| ### Showing and hiding The tooltip is immediately shown when the user's mouse hovers over the element and immediately hides when the user's mouse leaves. A delay in showing or hiding the tooltip can be added through -the inputs `matTooltipShowDelay` and `matTooltipHideDelay`. +the inputs `matTooltipShowDelay` and `matTooltipHideDelay`. The default show and hide delays can be +configured through the `MAT_TOOLTIP_DEFAULT_OPTIONS` injection token. On mobile, the tooltip is displayed when the user longpresses the element and hides after a delay of 1500ms. The longpress behavior requires HammerJS to be loaded on the page. @@ -33,11 +34,12 @@ delay of 1500ms. The longpress behavior requires HammerJS to be loaded on the pa The tooltip can also be shown and hidden through the `show` and `hide` directive methods, which both accept a number in milliseconds to delay before applying the display change. -To turn off the tooltip and prevent it from showing to the user, use the `matTooltipDisabled` input flag. +To turn off the tooltip and prevent it from showing to the user, use the `matTooltipDisabled` input +flag. ### Accessibility Elements with the `matTooltip` will add an `aria-describedby` label that provides a reference to a visually hidden element containing the tooltip's message. This provides screenreaders the information needed to read out the tooltip's contents when the end-user focuses on the element -triggering the tooltip. \ No newline at end of file +triggering the tooltip. diff --git a/src/lib/tooltip/tooltip.spec.ts b/src/lib/tooltip/tooltip.spec.ts index 4a3d220ebd4..5291b89b594 100644 --- a/src/lib/tooltip/tooltip.spec.ts +++ b/src/lib/tooltip/tooltip.spec.ts @@ -28,7 +28,8 @@ import { MatTooltipModule, SCROLL_THROTTLE_MS, TOOLTIP_PANEL_CLASS, - TooltipPosition + TooltipPosition, + MAT_TOOLTIP_DEFAULT_OPTIONS, } from './index'; @@ -156,6 +157,40 @@ describe('MatTooltip', () => { expect(overlayContainerElement.textContent).toContain(initialTooltipMessage); })); + it('should be able to override the default show and hide delays', fakeAsync(() => { + TestBed + .resetTestingModule() + .configureTestingModule({ + imports: [MatTooltipModule, OverlayModule, NoopAnimationsModule], + declarations: [BasicTooltipDemo], + providers: [{ + provide: MAT_TOOLTIP_DEFAULT_OPTIONS, + useValue: {showDelay: 1337, hideDelay: 7331} + }] + }) + .compileComponents(); + + fixture = TestBed.createComponent(BasicTooltipDemo); + fixture.detectChanges(); + tooltipDirective = fixture.debugElement.query(By.css('button')).injector.get(MatTooltip); + + tooltipDirective.show(); + fixture.detectChanges(); + tick(); + + expect(tooltipDirective._isTooltipVisible()).toBe(false); + tick(1337); + expect(tooltipDirective._isTooltipVisible()).toBe(true); + + tooltipDirective.hide(); + fixture.detectChanges(); + tick(); + + expect(tooltipDirective._isTooltipVisible()).toBe(true); + tick(7331); + expect(tooltipDirective._isTooltipVisible()).toBe(false); + })); + it('should set a css class on the overlay panel element', fakeAsync(() => { tooltipDirective.show(); fixture.detectChanges(); diff --git a/src/lib/tooltip/tooltip.ts b/src/lib/tooltip/tooltip.ts index 967b93a5c1c..8fa538c13bd 100644 --- a/src/lib/tooltip/tooltip.ts +++ b/src/lib/tooltip/tooltip.ts @@ -48,9 +48,6 @@ import {Subject} from 'rxjs/Subject'; export type TooltipPosition = 'left' | 'right' | 'above' | 'below' | 'before' | 'after'; -/** Time in ms to delay before changing the tooltip visibility to hidden */ -export const TOUCHEND_HIDE_DELAY = 1500; - /** Time in ms to throttle repositioning after scroll events. */ export const SCROLL_THROTTLE_MS = 20; @@ -78,6 +75,18 @@ export const MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER = { deps: [Overlay], useFactory: MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER_FACTORY }; + +/** Default `matTooltip` options that can be overridden. */ +export interface MatTooltipDefaultOptions { + showDelay: number; + hideDelay: number; + touchendHideDelay: number; +} + +/** Injection token to be used to override the default options for `matTooltip`. */ +export const MAT_TOOLTIP_DEFAULT_OPTIONS = + new InjectionToken('mat-tooltip-default-options'); + /** * Directive that attaches a material design tooltip to the host element. Animates the showing and * hiding of a tooltip provided position (defaults to below the element). @@ -90,7 +99,7 @@ export const MAT_TOOLTIP_SCROLL_STRATEGY_PROVIDER = { host: { '(longpress)': 'show()', '(keydown)': '_handleKeydown($event)', - '(touchend)': 'hide(' + TOUCHEND_HIDE_DELAY + ')', + '(touchend)': '_handleTouchend()', }, }) export class MatTooltip implements OnDestroy { @@ -134,10 +143,12 @@ export class MatTooltip implements OnDestroy { set _positionDeprecated(value: TooltipPosition) { this._position = value; } /** The default delay in ms before showing the tooltip after show is called */ - @Input('matTooltipShowDelay') showDelay = 0; + @Input('matTooltipShowDelay') showDelay = + this._defaultOptions ? this._defaultOptions.showDelay : 0; /** The default delay in ms before hiding the tooltip after hide is called */ - @Input('matTooltipHideDelay') hideDelay = 0; + @Input('matTooltipHideDelay') hideDelay = + this._defaultOptions ? this._defaultOptions.hideDelay : 0; private _message = ''; @@ -180,7 +191,11 @@ export class MatTooltip implements OnDestroy { private _ariaDescriber: AriaDescriber, private _focusMonitor: FocusMonitor, @Inject(MAT_TOOLTIP_SCROLL_STRATEGY) private _scrollStrategy, - @Optional() private _dir: Directionality) { + @Optional() private _dir: Directionality, + @Optional() @Inject(MAT_TOOLTIP_DEFAULT_OPTIONS) + private _defaultOptions?: MatTooltipDefaultOptions) { + + // TODO(crisbeto): make the `_defaultOptions` a required param next time we do breaking changes. const element: HTMLElement = _elementRef.nativeElement; @@ -270,6 +285,11 @@ export class MatTooltip implements OnDestroy { } } + /** Handles the touchend events on the host element. */ + _handleTouchend() { + this.hide(this._defaultOptions ? this._defaultOptions.touchendHideDelay : 1500); + } + /** Create the tooltip to display */ private _createTooltip(): void { const overlayRef = this._createOverlay();