Skip to content

Commit

Permalink
feat(tooltip): add injection token for specifying the default delays (#…
Browse files Browse the repository at this point in the history
…8109)

Adds the `MAT_TOOLTIP_DEFAULT_OPTIONS` provider that allows users to set app-wide defaults for the tooltip delays.

Fixes #7928.
  • Loading branch information
crisbeto authored and andrewseguin committed Dec 13, 2017
1 parent 60ba0a7 commit 3dcf4cd
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 23 deletions.
20 changes: 18 additions & 2 deletions src/lib/tooltip/tooltip-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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 {}
28 changes: 15 additions & 13 deletions src/lib/tooltip/tooltip.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,41 @@ 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.

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.
triggering the tooltip.
37 changes: 36 additions & 1 deletion src/lib/tooltip/tooltip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import {
MatTooltipModule,
SCROLL_THROTTLE_MS,
TOOLTIP_PANEL_CLASS,
TooltipPosition
TooltipPosition,
MAT_TOOLTIP_DEFAULT_OPTIONS,
} from './index';


Expand Down Expand Up @@ -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();
Expand Down
34 changes: 27 additions & 7 deletions src/lib/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<MatTooltipDefaultOptions>('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).
Expand All @@ -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 {
Expand Down Expand Up @@ -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 = '';

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down

0 comments on commit 3dcf4cd

Please sign in to comment.