@ng-matero/extensions 15.4.2 → 15.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,57 +1,28 @@
1
- import * as i4 from '@angular/cdk/a11y';
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, TemplateRef, ElementRef, Directive, Inject, Input, Optional, Component, ViewEncapsulation, ChangeDetectionStrategy, ViewChild, NgModule } from '@angular/core';
3
+ import * as i5 from '@angular/common';
4
+ import { DOCUMENT, CommonModule } from '@angular/common';
5
+ import * as i3 from '@angular/cdk/a11y';
2
6
  import { A11yModule } from '@angular/cdk/a11y';
3
7
  import * as i1 from '@angular/cdk/overlay';
4
8
  import { Overlay, OverlayModule } from '@angular/cdk/overlay';
5
- import * as i2 from '@angular/cdk/scrolling';
6
9
  import { CdkScrollableModule } from '@angular/cdk/scrolling';
7
- import * as i7 from '@angular/common';
8
- import { CommonModule } from '@angular/common';
9
- import * as i0 from '@angular/core';
10
- import { InjectionToken, TemplateRef, Directive, Inject, Optional, Input, Component, ViewEncapsulation, ChangeDetectionStrategy, NgModule } from '@angular/core';
11
10
  import { MatCommonModule } from '@angular/material/core';
12
- import * as i8 from '@ng-matero/extensions/core';
11
+ import * as i6 from '@ng-matero/extensions/core';
13
12
  import { MtxPipesModule } from '@ng-matero/extensions/core';
14
- import { coerceBooleanProperty } from '@angular/cdk/coercion';
13
+ import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
15
14
  import { ESCAPE, hasModifierKey } from '@angular/cdk/keycodes';
16
- import * as i6 from '@angular/cdk/layout';
17
- import { Breakpoints } from '@angular/cdk/layout';
18
- import * as i3 from '@angular/cdk/platform';
15
+ import * as i2 from '@angular/cdk/platform';
19
16
  import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
20
17
  import { ComponentPortal } from '@angular/cdk/portal';
18
+ import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';
21
19
  import { Subject } from 'rxjs';
22
20
  import { takeUntil, take } from 'rxjs/operators';
23
- import { trigger, state, style, transition, animate, keyframes } from '@angular/animations';
24
- import * as i5 from '@angular/cdk/bidi';
25
-
26
- /**
27
- * Animations used by MtxTooltip.
28
- * @docs-private
29
- */
30
- const mtxTooltipAnimations = {
31
- /** Animation that transitions a tooltip in and out. */
32
- tooltipState: trigger('state', [
33
- state('initial, void, hidden', style({ opacity: 0, transform: 'scale(0)' })),
34
- state('visible', style({ transform: 'scale(1)' })),
35
- transition('* => visible', animate('200ms cubic-bezier(0, 0, 0.2, 1)', keyframes([
36
- style({ opacity: 0, transform: 'scale(0)', offset: 0 }),
37
- style({ opacity: 0.5, transform: 'scale(0.99)', offset: 0.5 }),
38
- style({ opacity: 1, transform: 'scale(1)', offset: 1 }),
39
- ]))),
40
- transition('* => hidden', animate('100ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 0 }))),
41
- ]),
42
- };
21
+ import * as i4 from '@angular/cdk/bidi';
22
+ import { trigger, state, style, transition, animate } from '@angular/animations';
43
23
 
44
24
  /** Time in ms to throttle repositioning after scroll events. */
45
25
  const SCROLL_THROTTLE_MS = 20;
46
- /** CSS class that will be attached to the overlay panel. */
47
- const TOOLTIP_PANEL_CLASS = 'mtx-tooltip-panel';
48
- /** Options used to bind passive event listeners. */
49
- const passiveListenerOptions = normalizePassiveListenerOptions({ passive: true });
50
- /**
51
- * Time between the user putting the pointer on a tooltip
52
- * trigger and the long press event being fired.
53
- */
54
- const LONGPRESS_DELAY = 500;
55
26
  /**
56
27
  * Creates an error to be thrown if the user supplied an invalid tooltip position.
57
28
  * @docs-private
@@ -71,11 +42,6 @@ const MTX_TOOLTIP_SCROLL_STRATEGY_FACTORY_PROVIDER = {
71
42
  deps: [Overlay],
72
43
  useFactory: MTX_TOOLTIP_SCROLL_STRATEGY_FACTORY,
73
44
  };
74
- /** Injection token to be used to override the default options for `matTooltip`. */
75
- const MTX_TOOLTIP_DEFAULT_OPTIONS = new InjectionToken('mtx-tooltip-default-options', {
76
- providedIn: 'root',
77
- factory: MTX_TOOLTIP_DEFAULT_OPTIONS_FACTORY,
78
- });
79
45
  /** @docs-private */
80
46
  function MTX_TOOLTIP_DEFAULT_OPTIONS_FACTORY() {
81
47
  return {
@@ -84,29 +50,55 @@ function MTX_TOOLTIP_DEFAULT_OPTIONS_FACTORY() {
84
50
  touchendHideDelay: 1500,
85
51
  };
86
52
  }
53
+ /** Injection token to be used to override the default options for `mtxTooltip`. */
54
+ const MTX_TOOLTIP_DEFAULT_OPTIONS = new InjectionToken('mtx-tooltip-default-options', {
55
+ providedIn: 'root',
56
+ factory: MTX_TOOLTIP_DEFAULT_OPTIONS_FACTORY,
57
+ });
87
58
  /**
88
- * Directive that attaches a material design tooltip to the host element. Animates the showing and
89
- * hiding of a tooltip provided position (defaults to below the element).
90
- *
91
- * https://material.io/design/components/tooltips.html
59
+ * CSS class that will be attached to the overlay panel.
60
+ * @deprecated
61
+ * @breaking-change 13.0.0 remove this variable
92
62
  */
93
- class MtxTooltip {
63
+ const TOOLTIP_PANEL_CLASS = 'mtx-mdc-tooltip-panel';
64
+ const PANEL_CLASS = 'tooltip-panel';
65
+ /** Options used to bind passive event listeners. */
66
+ const passiveListenerOptions = normalizePassiveListenerOptions({ passive: true });
67
+ /**
68
+ * Time between the user putting the pointer on a tooltip
69
+ * trigger and the long press event being fired.
70
+ */
71
+ const LONGPRESS_DELAY = 500;
72
+ // These constants were taken from MDC's `numbers` object. We can't import them from MDC,
73
+ // because they have some top-level references to `window` which break during SSR.
74
+ const MIN_VIEWPORT_TOOLTIP_THRESHOLD = 8;
75
+ const UNBOUNDED_ANCHOR_GAP = 8;
76
+ const MIN_HEIGHT = 24;
77
+ const MAX_WIDTH = 200;
78
+ class _MtxTooltipBase {
94
79
  /** Allows the user to define the position of the tooltip relative to the parent element */
95
80
  get position() {
96
81
  return this._position;
97
82
  }
98
83
  set position(value) {
84
+ var _a;
99
85
  if (value !== this._position) {
100
86
  this._position = value;
101
87
  if (this._overlayRef) {
102
- this._updatePosition();
103
- if (this._tooltipInstance) {
104
- this._tooltipInstance.show(0);
105
- }
88
+ this._updatePosition(this._overlayRef);
89
+ (_a = this._tooltipInstance) === null || _a === void 0 ? void 0 : _a.show(0);
106
90
  this._overlayRef.updatePosition();
107
91
  }
108
92
  }
109
93
  }
94
+ get positionAtOrigin() {
95
+ return this._positionAtOrigin;
96
+ }
97
+ set positionAtOrigin(value) {
98
+ this._positionAtOrigin = coerceBooleanProperty(value);
99
+ this._detach();
100
+ this._overlayRef = null;
101
+ }
110
102
  /** Disables the display of the tooltip. */
111
103
  get disabled() {
112
104
  return this._disabled;
@@ -121,14 +113,33 @@ class MtxTooltip {
121
113
  this._setupPointerEnterEventsIfNeeded();
122
114
  }
123
115
  }
116
+ /** The default delay in ms before showing the tooltip after show is called */
117
+ get showDelay() {
118
+ return this._showDelay;
119
+ }
120
+ set showDelay(value) {
121
+ this._showDelay = coerceNumberProperty(value);
122
+ }
123
+ /** The default delay in ms before hiding the tooltip after hide is called */
124
+ get hideDelay() {
125
+ return this._hideDelay;
126
+ }
127
+ set hideDelay(value) {
128
+ this._hideDelay = coerceNumberProperty(value);
129
+ if (this._tooltipInstance) {
130
+ this._tooltipInstance._mouseLeaveHideDelay = this._hideDelay;
131
+ }
132
+ }
124
133
  /** The message to be displayed in the tooltip */
125
134
  get message() {
126
135
  return this._message;
127
136
  }
128
137
  set message(value) {
129
- this._ariaDescriber.removeDescription(this._elementRef.nativeElement, this._message);
138
+ this._ariaDescriber.removeDescription(this._elementRef.nativeElement, this._message, 'tooltip');
130
139
  // TODO: If the message is a TemplateRef, it's hard to support a11y.
131
140
  // If the message is not a string (e.g. number), convert it to a string and trim it.
141
+ // Must convert with `String(value)`, not `${value}`, otherwise Closure Compiler optimises
142
+ // away the string-conversion: https://github.com/angular/components/issues/20684
132
143
  this._message = value instanceof TemplateRef ? value : value != null ? `${value}`.trim() : '';
133
144
  if (!this._message && this._isTooltipVisible()) {
134
145
  this.hide(0);
@@ -142,11 +153,19 @@ class MtxTooltip {
142
153
  // has a data-bound `aria-label` or when it'll be set for the first time. We can avoid the
143
154
  // issue by deferring the description by a tick so Angular has time to set the `aria-label`.
144
155
  Promise.resolve().then(() => {
145
- this._ariaDescriber.describe(this._elementRef.nativeElement, this.message);
156
+ this._ariaDescriber.describe(this._elementRef.nativeElement, this.message, 'tooltip');
146
157
  });
147
158
  });
148
159
  }
149
160
  }
161
+ /** Context to be passed to the tooltip. */
162
+ get tooltipContext() {
163
+ return this._tooltipContext;
164
+ }
165
+ set tooltipContext(value) {
166
+ this._tooltipContext = value;
167
+ this._setTooltipContext(this._tooltipContext);
168
+ }
150
169
  /** Classes to be passed to the tooltip. Supports the same syntax as `ngClass`. */
151
170
  get tooltipClass() {
152
171
  return this._tooltipClass;
@@ -157,7 +176,7 @@ class MtxTooltip {
157
176
  this._setTooltipClass(this._tooltipClass);
158
177
  }
159
178
  }
160
- constructor(_overlay, _elementRef, _scrollDispatcher, _viewContainerRef, _ngZone, _platform, _ariaDescriber, _focusMonitor, scrollStrategy, _dir, _defaultOptions) {
179
+ constructor(_overlay, _elementRef, _scrollDispatcher, _viewContainerRef, _ngZone, _platform, _ariaDescriber, _focusMonitor, scrollStrategy, _dir, _defaultOptions, _document) {
161
180
  this._overlay = _overlay;
162
181
  this._elementRef = _elementRef;
163
182
  this._scrollDispatcher = _scrollDispatcher;
@@ -169,13 +188,14 @@ class MtxTooltip {
169
188
  this._dir = _dir;
170
189
  this._defaultOptions = _defaultOptions;
171
190
  this._position = 'below';
191
+ this._positionAtOrigin = false;
172
192
  this._disabled = false;
173
193
  this._viewInitialized = false;
174
194
  this._pointerExitEventsInitialized = false;
175
- /** The default delay in ms before showing the tooltip after show is called */
176
- this.showDelay = this._defaultOptions.showDelay;
177
- /** The default delay in ms before hiding the tooltip after hide is called */
178
- this.hideDelay = this._defaultOptions.hideDelay;
195
+ this._viewportMargin = 8;
196
+ this._cssClassPrefix = 'mtx';
197
+ this._showDelay = this._defaultOptions.showDelay;
198
+ this._hideDelay = this._defaultOptions.hideDelay;
179
199
  /**
180
200
  * How touch gestures should be handled by the tooltip. On touch devices the tooltip directive
181
201
  * uses a long press gesture to show and hide, however it can conflict with the native browser
@@ -196,28 +216,23 @@ class MtxTooltip {
196
216
  this._passiveListeners = [];
197
217
  /** Emits when the component is destroyed. */
198
218
  this._destroyed = new Subject();
199
- /**
200
- * Handles the keydown events on the host element.
201
- * Needs to be an arrow function so that we can use it in addEventListener.
202
- */
203
- this._handleKeydown = (event) => {
204
- if (this._isTooltipVisible() && event.keyCode === ESCAPE && !hasModifierKey(event)) {
205
- event.preventDefault();
206
- event.stopPropagation();
207
- this._ngZone.run(() => this.hide(0));
208
- }
209
- };
210
219
  this._scrollStrategy = scrollStrategy;
220
+ this._document = _document;
211
221
  if (_defaultOptions) {
212
222
  if (_defaultOptions.position) {
213
223
  this.position = _defaultOptions.position;
214
224
  }
225
+ if (_defaultOptions.positionAtOrigin) {
226
+ this.positionAtOrigin = _defaultOptions.positionAtOrigin;
227
+ }
215
228
  if (_defaultOptions.touchGestures) {
216
229
  this.touchGestures = _defaultOptions.touchGestures;
217
230
  }
218
231
  }
219
- _ngZone.runOutsideAngular(() => {
220
- _elementRef.nativeElement.addEventListener('keydown', this._handleKeydown);
232
+ _dir.change.pipe(takeUntil(this._destroyed)).subscribe(() => {
233
+ if (this._overlayRef) {
234
+ this._updatePosition(this._overlayRef);
235
+ }
221
236
  });
222
237
  }
223
238
  ngAfterViewInit() {
@@ -248,66 +263,81 @@ class MtxTooltip {
248
263
  this._tooltipInstance = null;
249
264
  }
250
265
  // Clean up the event listeners set in the constructor
251
- nativeElement.removeEventListener('keydown', this._handleKeydown);
252
266
  this._passiveListeners.forEach(([event, listener]) => {
253
267
  nativeElement.removeEventListener(event, listener, passiveListenerOptions);
254
268
  });
255
269
  this._passiveListeners.length = 0;
256
270
  this._destroyed.next();
257
271
  this._destroyed.complete();
258
- this._ariaDescriber.removeDescription(nativeElement, this.message);
272
+ this._ariaDescriber.removeDescription(nativeElement, this.message, 'tooltip');
259
273
  this._focusMonitor.stopMonitoring(nativeElement);
260
274
  }
261
275
  /** Shows the tooltip after the delay in ms, defaults to tooltip-delay-show or 0ms if no input */
262
- show(delay = this.showDelay) {
263
- if (this.disabled ||
264
- !this.message ||
265
- (this._isTooltipVisible() &&
266
- !this._tooltipInstance._showTimeoutId &&
267
- !this._tooltipInstance._hideTimeoutId)) {
276
+ show(delay = this.showDelay, origin) {
277
+ var _a;
278
+ if (this.disabled || !this.message || this._isTooltipVisible()) {
279
+ (_a = this._tooltipInstance) === null || _a === void 0 ? void 0 : _a._cancelPendingAnimations();
268
280
  return;
269
281
  }
270
- const overlayRef = this._createOverlay();
282
+ const overlayRef = this._createOverlay(origin);
271
283
  this._detach();
272
- this._portal = this._portal || new ComponentPortal(TooltipComponent, this._viewContainerRef);
273
- this._tooltipInstance = overlayRef.attach(this._portal).instance;
274
- this._tooltipInstance
284
+ this._portal =
285
+ this._portal || new ComponentPortal(this._tooltipComponent, this._viewContainerRef);
286
+ const instance = (this._tooltipInstance = overlayRef.attach(this._portal).instance);
287
+ instance._triggerElement = this._elementRef.nativeElement;
288
+ instance._mouseLeaveHideDelay = this._hideDelay;
289
+ instance
275
290
  .afterHidden()
276
291
  .pipe(takeUntil(this._destroyed))
277
292
  .subscribe(() => this._detach());
278
293
  this._setTooltipClass(this._tooltipClass);
294
+ this._setTooltipContext(this._tooltipContext);
279
295
  this._updateTooltipMessage();
280
- this._tooltipInstance.show(delay);
296
+ instance.show(delay);
281
297
  }
282
298
  /** Hides the tooltip after the delay in ms, defaults to tooltip-delay-hide or 0ms if no input */
283
299
  hide(delay = this.hideDelay) {
284
- if (this._tooltipInstance) {
285
- this._tooltipInstance.hide(delay);
300
+ const instance = this._tooltipInstance;
301
+ if (instance) {
302
+ if (instance.isVisible()) {
303
+ instance.hide(delay);
304
+ }
305
+ else {
306
+ instance._cancelPendingAnimations();
307
+ this._detach();
308
+ }
286
309
  }
287
310
  }
288
311
  /** Shows/hides the tooltip */
289
- toggle() {
290
- this._isTooltipVisible() ? this.hide() : this.show();
312
+ toggle(origin) {
313
+ this._isTooltipVisible() ? this.hide() : this.show(undefined, origin);
291
314
  }
292
315
  /** Returns true if the tooltip is currently visible to the user */
293
316
  _isTooltipVisible() {
294
317
  return !!this._tooltipInstance && this._tooltipInstance.isVisible();
295
318
  }
296
319
  /** Create the overlay config and position strategy */
297
- _createOverlay() {
320
+ _createOverlay(origin) {
321
+ var _a;
298
322
  if (this._overlayRef) {
299
- return this._overlayRef;
323
+ const existingStrategy = this._overlayRef.getConfig()
324
+ .positionStrategy;
325
+ if ((!this.positionAtOrigin || !origin) && existingStrategy._origin instanceof ElementRef) {
326
+ return this._overlayRef;
327
+ }
328
+ this._detach();
300
329
  }
301
330
  const scrollableAncestors = this._scrollDispatcher.getAncestorScrollContainers(this._elementRef);
302
331
  // Create connected position strategy that listens for scroll events to reposition.
303
332
  const strategy = this._overlay
304
333
  .position()
305
- .flexibleConnectedTo(this._elementRef)
306
- .withTransformOriginOn('.mtx-tooltip')
334
+ .flexibleConnectedTo(this.positionAtOrigin ? origin || this._elementRef : this._elementRef)
335
+ .withTransformOriginOn(`.${this._cssClassPrefix}-tooltip`)
307
336
  .withFlexibleDimensions(false)
308
- .withViewportMargin(8)
337
+ .withViewportMargin(this._viewportMargin)
309
338
  .withScrollableContainers(scrollableAncestors);
310
339
  strategy.positionChanges.pipe(takeUntil(this._destroyed)).subscribe(change => {
340
+ this._updateCurrentPositionClass(change.connectionPair);
311
341
  if (this._tooltipInstance) {
312
342
  if (change.scrollableViewProperties.isOverlayClipped && this._tooltipInstance.isVisible()) {
313
343
  // After position changes occur and the overlay is clipped by
@@ -319,14 +349,31 @@ class MtxTooltip {
319
349
  this._overlayRef = this._overlay.create({
320
350
  direction: this._dir,
321
351
  positionStrategy: strategy,
322
- panelClass: TOOLTIP_PANEL_CLASS,
352
+ panelClass: `${this._cssClassPrefix}-${PANEL_CLASS}`,
323
353
  scrollStrategy: this._scrollStrategy(),
324
354
  });
325
- this._updatePosition();
355
+ this._updatePosition(this._overlayRef);
326
356
  this._overlayRef
327
357
  .detachments()
328
358
  .pipe(takeUntil(this._destroyed))
329
359
  .subscribe(() => this._detach());
360
+ this._overlayRef
361
+ .outsidePointerEvents()
362
+ .pipe(takeUntil(this._destroyed))
363
+ .subscribe(() => { var _a; return (_a = this._tooltipInstance) === null || _a === void 0 ? void 0 : _a._handleBodyInteraction(); });
364
+ this._overlayRef
365
+ .keydownEvents()
366
+ .pipe(takeUntil(this._destroyed))
367
+ .subscribe(event => {
368
+ if (this._isTooltipVisible() && event.keyCode === ESCAPE && !hasModifierKey(event)) {
369
+ event.preventDefault();
370
+ event.stopPropagation();
371
+ this._ngZone.run(() => this.hide(0));
372
+ }
373
+ });
374
+ if ((_a = this._defaultOptions) === null || _a === void 0 ? void 0 : _a.disableTooltipInteractivity) {
375
+ this._overlayRef.addPanelClass(`${this._cssClassPrefix}-tooltip-panel-non-interactive`);
376
+ }
330
377
  return this._overlayRef;
331
378
  }
332
379
  /** Detaches the currently-attached tooltip. */
@@ -337,35 +384,38 @@ class MtxTooltip {
337
384
  this._tooltipInstance = null;
338
385
  }
339
386
  /** Updates the position of the current tooltip. */
340
- _updatePosition() {
341
- const position = this._overlayRef.getConfig()
342
- .positionStrategy;
387
+ _updatePosition(overlayRef) {
388
+ const position = overlayRef.getConfig().positionStrategy;
343
389
  const origin = this._getOrigin();
344
390
  const overlay = this._getOverlayPosition();
345
391
  position.withPositions([
346
- Object.assign(Object.assign({}, origin.main), overlay.main),
347
- Object.assign(Object.assign({}, origin.fallback), overlay.fallback),
392
+ this._addOffset(Object.assign(Object.assign({}, origin.main), overlay.main)),
393
+ this._addOffset(Object.assign(Object.assign({}, origin.fallback), overlay.fallback)),
348
394
  ]);
349
395
  }
396
+ /** Adds the configured offset to a position. Used as a hook for child classes. */
397
+ _addOffset(position) {
398
+ return position;
399
+ }
350
400
  /**
351
401
  * Returns the origin position and a fallback position based on the user's position preference.
352
402
  * The fallback position is the inverse of the origin (e.g. `'below' -> 'above'`).
353
403
  */
354
404
  _getOrigin() {
355
- const isLtr = !this._dir || this._dir.value === 'ltr';
405
+ const isLtr = !this._dir || this._dir.value == 'ltr';
356
406
  const position = this.position;
357
407
  let originPosition;
358
- if (position === 'above' || position === 'below') {
359
- originPosition = { originX: 'center', originY: position === 'above' ? 'top' : 'bottom' };
408
+ if (position == 'above' || position == 'below') {
409
+ originPosition = { originX: 'center', originY: position == 'above' ? 'top' : 'bottom' };
360
410
  }
361
- else if (position === 'before' ||
362
- (position === 'left' && isLtr) ||
363
- (position === 'right' && !isLtr)) {
411
+ else if (position == 'before' ||
412
+ (position == 'left' && isLtr) ||
413
+ (position == 'right' && !isLtr)) {
364
414
  originPosition = { originX: 'start', originY: 'center' };
365
415
  }
366
- else if (position === 'after' ||
367
- (position === 'right' && isLtr) ||
368
- (position === 'left' && !isLtr)) {
416
+ else if (position == 'after' ||
417
+ (position == 'right' && isLtr) ||
418
+ (position == 'left' && !isLtr)) {
369
419
  originPosition = { originX: 'end', originY: 'center' };
370
420
  }
371
421
  else {
@@ -379,23 +429,23 @@ class MtxTooltip {
379
429
  }
380
430
  /** Returns the overlay position and a fallback position based on the user's preference */
381
431
  _getOverlayPosition() {
382
- const isLtr = !this._dir || this._dir.value === 'ltr';
432
+ const isLtr = !this._dir || this._dir.value == 'ltr';
383
433
  const position = this.position;
384
434
  let overlayPosition;
385
- if (position === 'above') {
435
+ if (position == 'above') {
386
436
  overlayPosition = { overlayX: 'center', overlayY: 'bottom' };
387
437
  }
388
- else if (position === 'below') {
438
+ else if (position == 'below') {
389
439
  overlayPosition = { overlayX: 'center', overlayY: 'top' };
390
440
  }
391
- else if (position === 'before' ||
392
- (position === 'left' && isLtr) ||
393
- (position === 'right' && !isLtr)) {
441
+ else if (position == 'before' ||
442
+ (position == 'left' && isLtr) ||
443
+ (position == 'right' && !isLtr)) {
394
444
  overlayPosition = { overlayX: 'end', overlayY: 'center' };
395
445
  }
396
- else if (position === 'after' ||
397
- (position === 'right' && isLtr) ||
398
- (position === 'left' && !isLtr)) {
446
+ else if (position == 'after' ||
447
+ (position == 'right' && isLtr) ||
448
+ (position == 'left' && !isLtr)) {
399
449
  overlayPosition = { overlayX: 'start', overlayY: 'center' };
400
450
  }
401
451
  else {
@@ -414,16 +464,20 @@ class MtxTooltip {
414
464
  if (this._tooltipInstance) {
415
465
  this._tooltipInstance.message = this.message;
416
466
  this._tooltipInstance._markForCheck();
417
- this._ngZone.onMicrotaskEmpty
418
- .asObservable()
419
- .pipe(take(1), takeUntil(this._destroyed))
420
- .subscribe(() => {
467
+ this._ngZone.onMicrotaskEmpty.pipe(take(1), takeUntil(this._destroyed)).subscribe(() => {
421
468
  if (this._tooltipInstance) {
422
469
  this._overlayRef.updatePosition();
423
470
  }
424
471
  });
425
472
  }
426
473
  }
474
+ /** Updates the tooltip context */
475
+ _setTooltipContext(tooltipContext) {
476
+ if (this._tooltipInstance) {
477
+ this._tooltipInstance.tooltipContext = tooltipContext;
478
+ this._tooltipInstance._markForCheck();
479
+ }
480
+ }
427
481
  /** Updates the tooltip class */
428
482
  _setTooltipClass(tooltipClass) {
429
483
  if (this._tooltipInstance) {
@@ -451,6 +505,36 @@ class MtxTooltip {
451
505
  }
452
506
  return { x, y };
453
507
  }
508
+ /** Updates the class on the overlay panel based on the current position of the tooltip. */
509
+ _updateCurrentPositionClass(connectionPair) {
510
+ const { overlayY, originX, originY } = connectionPair;
511
+ let newPosition;
512
+ // If the overlay is in the middle along the Y axis,
513
+ // it means that it's either before or after.
514
+ if (overlayY === 'center') {
515
+ // Note that since this information is used for styling, we want to
516
+ // resolve `start` and `end` to their real values, otherwise consumers
517
+ // would have to remember to do it themselves on each consumption.
518
+ if (this._dir && this._dir.value === 'rtl') {
519
+ newPosition = originX === 'end' ? 'left' : 'right';
520
+ }
521
+ else {
522
+ newPosition = originX === 'start' ? 'left' : 'right';
523
+ }
524
+ }
525
+ else {
526
+ newPosition = overlayY === 'bottom' && originY === 'top' ? 'above' : 'below';
527
+ }
528
+ if (newPosition !== this._currentPosition) {
529
+ const overlayRef = this._overlayRef;
530
+ if (overlayRef) {
531
+ const classPrefix = `${this._cssClassPrefix}-${PANEL_CLASS}-`;
532
+ overlayRef.removePanelClass(classPrefix + this._currentPosition);
533
+ overlayRef.addPanelClass(classPrefix + newPosition);
534
+ }
535
+ this._currentPosition = newPosition;
536
+ }
537
+ }
454
538
  /** Binds the pointer events to the tooltip trigger. */
455
539
  _setupPointerEnterEventsIfNeeded() {
456
540
  // Optimization: Defer hooking up events if there's no message or the tooltip is disabled.
@@ -465,9 +549,13 @@ class MtxTooltip {
465
549
  if (this._platformSupportsMouseEvents()) {
466
550
  this._passiveListeners.push([
467
551
  'mouseenter',
468
- () => {
552
+ event => {
469
553
  this._setupPointerExitEventsIfNeeded();
470
- this.show();
554
+ let point = undefined;
555
+ if (event.x !== undefined && event.y !== undefined) {
556
+ point = event;
557
+ }
558
+ this.show(undefined, point);
471
559
  },
472
560
  ]);
473
561
  }
@@ -475,12 +563,15 @@ class MtxTooltip {
475
563
  this._disableNativeGesturesIfNecessary();
476
564
  this._passiveListeners.push([
477
565
  'touchstart',
478
- () => {
566
+ event => {
567
+ var _a;
568
+ const touch = (_a = event.targetTouches) === null || _a === void 0 ? void 0 : _a[0];
569
+ const origin = touch ? { x: touch.clientX, y: touch.clientY } : undefined;
479
570
  // Note that it's important that we don't `preventDefault` here,
480
571
  // because it can prevent click events from firing on the element.
481
572
  this._setupPointerExitEventsIfNeeded();
482
573
  clearTimeout(this._touchstartTimeout);
483
- this._touchstartTimeout = setTimeout(() => this.show(), LONGPRESS_DELAY);
574
+ this._touchstartTimeout = setTimeout(() => this.show(undefined, origin), LONGPRESS_DELAY);
484
575
  },
485
576
  ]);
486
577
  }
@@ -493,7 +584,16 @@ class MtxTooltip {
493
584
  this._pointerExitEventsInitialized = true;
494
585
  const exitListeners = [];
495
586
  if (this._platformSupportsMouseEvents()) {
496
- exitListeners.push(['mouseleave', () => this.hide()]);
587
+ exitListeners.push([
588
+ 'mouseleave',
589
+ event => {
590
+ var _a;
591
+ const newTarget = event.relatedTarget;
592
+ if (!newTarget || !((_a = this._overlayRef) === null || _a === void 0 ? void 0 : _a.overlayElement.contains(newTarget))) {
593
+ this.hide();
594
+ }
595
+ },
596
+ ], ['wheel', event => this._wheelListener(event)]);
497
597
  }
498
598
  else if (this.touchGestures !== 'off') {
499
599
  this._disableNativeGesturesIfNecessary();
@@ -514,6 +614,20 @@ class MtxTooltip {
514
614
  _platformSupportsMouseEvents() {
515
615
  return !this._platform.IOS && !this._platform.ANDROID;
516
616
  }
617
+ /** Listener for the `wheel` event on the element. */
618
+ _wheelListener(event) {
619
+ if (this._isTooltipVisible()) {
620
+ const elementUnderPointer = this._document.elementFromPoint(event.clientX, event.clientY);
621
+ const element = this._elementRef.nativeElement;
622
+ // On non-touch devices we depend on the `mouseleave` event to close the tooltip, but it
623
+ // won't fire if the user scrolls away using the wheel without moving their cursor. We
624
+ // work around it by finding the element under the user's cursor and closing the tooltip
625
+ // if it's not the trigger.
626
+ if (elementUnderPointer !== element && !element.contains(elementUnderPointer)) {
627
+ this.hide();
628
+ }
629
+ }
630
+ }
517
631
  /** Disables the native browser gestures, based on how the tooltip has been configured. */
518
632
  _disableNativeGesturesIfNecessary() {
519
633
  const gestures = this.touchGestures;
@@ -535,38 +649,25 @@ class MtxTooltip {
535
649
  style.webkitUserDrag = 'none';
536
650
  }
537
651
  style.touchAction = 'none';
538
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
539
- // @ts-ignore
540
652
  style.webkitTapHighlightColor = 'transparent';
541
653
  }
542
654
  }
543
655
  }
544
- /** @nocollapse */ MtxTooltip.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: MtxTooltip, deps: [{ token: i1.Overlay }, { token: i0.ElementRef }, { token: i2.ScrollDispatcher }, { token: i0.ViewContainerRef }, { token: i0.NgZone }, { token: i3.Platform }, { token: i4.AriaDescriber }, { token: i4.FocusMonitor }, { token: MTX_TOOLTIP_SCROLL_STRATEGY }, { token: i5.Directionality, optional: true }, { token: MTX_TOOLTIP_DEFAULT_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
545
- /** @nocollapse */ MtxTooltip.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: MtxTooltip, selector: "[mtxTooltip]", inputs: { position: ["mtxTooltipPosition", "position"], disabled: ["mtxTooltipDisabled", "disabled"], showDelay: ["mtxTooltipShowDelay", "showDelay"], hideDelay: ["mtxTooltipHideDelay", "hideDelay"], touchGestures: ["mtxTooltipTouchGestures", "touchGestures"], message: ["mtxTooltip", "message"], tooltipClass: ["mtxTooltipClass", "tooltipClass"] }, host: { classAttribute: "mtx-tooltip-trigger" }, exportAs: ["mtxTooltip"], ngImport: i0 });
546
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: MtxTooltip, decorators: [{
547
- type: Directive,
548
- args: [{
549
- selector: '[mtxTooltip]',
550
- exportAs: 'mtxTooltip',
551
- host: {
552
- class: 'mtx-tooltip-trigger',
553
- },
554
- }]
656
+ /** @nocollapse */ _MtxTooltipBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: _MtxTooltipBase, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
657
+ /** @nocollapse */ _MtxTooltipBase.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: _MtxTooltipBase, inputs: { position: ["mtxTooltipPosition", "position"], positionAtOrigin: ["mtxTooltipPositionAtOrigin", "positionAtOrigin"], disabled: ["mtxTooltipDisabled", "disabled"], showDelay: ["mtxTooltipShowDelay", "showDelay"], hideDelay: ["mtxTooltipHideDelay", "hideDelay"], touchGestures: ["mtxTooltipTouchGestures", "touchGestures"], message: ["mtxTooltip", "message"], tooltipContext: ["mtxTooltipContext", "tooltipContext"], tooltipClass: ["mtxTooltipClass", "tooltipClass"] }, ngImport: i0 });
658
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: _MtxTooltipBase, decorators: [{
659
+ type: Directive
555
660
  }], ctorParameters: function () {
556
- return [{ type: i1.Overlay }, { type: i0.ElementRef }, { type: i2.ScrollDispatcher }, { type: i0.ViewContainerRef }, { type: i0.NgZone }, { type: i3.Platform }, { type: i4.AriaDescriber }, { type: i4.FocusMonitor }, { type: undefined, decorators: [{
661
+ return [{ type: i1.Overlay }, { type: i0.ElementRef }, { type: i1.ScrollDispatcher }, { type: i0.ViewContainerRef }, { type: i0.NgZone }, { type: i2.Platform }, { type: i3.AriaDescriber }, { type: i3.FocusMonitor }, { type: undefined }, { type: i4.Directionality }, { type: undefined }, { type: undefined, decorators: [{
557
662
  type: Inject,
558
- args: [MTX_TOOLTIP_SCROLL_STRATEGY]
559
- }] }, { type: i5.Directionality, decorators: [{
560
- type: Optional
561
- }] }, { type: undefined, decorators: [{
562
- type: Optional
563
- }, {
564
- type: Inject,
565
- args: [MTX_TOOLTIP_DEFAULT_OPTIONS]
663
+ args: [DOCUMENT]
566
664
  }] }];
567
665
  }, propDecorators: { position: [{
568
666
  type: Input,
569
667
  args: ['mtxTooltipPosition']
668
+ }], positionAtOrigin: [{
669
+ type: Input,
670
+ args: ['mtxTooltipPositionAtOrigin']
570
671
  }], disabled: [{
571
672
  type: Input,
572
673
  args: ['mtxTooltipDisabled']
@@ -582,26 +683,81 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImpor
582
683
  }], message: [{
583
684
  type: Input,
584
685
  args: ['mtxTooltip']
686
+ }], tooltipContext: [{
687
+ type: Input,
688
+ args: ['mtxTooltipContext']
585
689
  }], tooltipClass: [{
586
690
  type: Input,
587
691
  args: ['mtxTooltipClass']
588
692
  }] } });
589
693
  /**
590
- * Internal component that wraps the tooltip's content.
591
- * @docs-private
694
+ * Directive that attaches a material design tooltip to the host element. Animates the showing and
695
+ * hiding of a tooltip provided position (defaults to below the element).
696
+ *
697
+ * https://material.io/design/components/tooltips.html
592
698
  */
593
- class TooltipComponent {
594
- constructor(_changeDetectorRef, _breakpointObserver) {
699
+ class MtxTooltip extends _MtxTooltipBase {
700
+ constructor(overlay, elementRef, scrollDispatcher, viewContainerRef, ngZone, platform, ariaDescriber, focusMonitor, scrollStrategy, dir, defaultOptions, _document) {
701
+ super(overlay, elementRef, scrollDispatcher, viewContainerRef, ngZone, platform, ariaDescriber, focusMonitor, scrollStrategy, dir, defaultOptions, _document);
702
+ this._tooltipComponent = TooltipComponent;
703
+ this._cssClassPrefix = 'mtx-mdc';
704
+ this._viewportMargin = MIN_VIEWPORT_TOOLTIP_THRESHOLD;
705
+ }
706
+ _addOffset(position) {
707
+ const offset = UNBOUNDED_ANCHOR_GAP;
708
+ const isLtr = !this._dir || this._dir.value == 'ltr';
709
+ if (position.originY === 'top') {
710
+ position.offsetY = -offset;
711
+ }
712
+ else if (position.originY === 'bottom') {
713
+ position.offsetY = offset;
714
+ }
715
+ else if (position.originX === 'start') {
716
+ position.offsetX = isLtr ? -offset : offset;
717
+ }
718
+ else if (position.originX === 'end') {
719
+ position.offsetX = isLtr ? offset : -offset;
720
+ }
721
+ return position;
722
+ }
723
+ }
724
+ /** @nocollapse */ MtxTooltip.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: MtxTooltip, deps: [{ token: i1.Overlay }, { token: i0.ElementRef }, { token: i1.ScrollDispatcher }, { token: i0.ViewContainerRef }, { token: i0.NgZone }, { token: i2.Platform }, { token: i3.AriaDescriber }, { token: i3.FocusMonitor }, { token: MTX_TOOLTIP_SCROLL_STRATEGY }, { token: i4.Directionality, optional: true }, { token: MTX_TOOLTIP_DEFAULT_OPTIONS, optional: true }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
725
+ /** @nocollapse */ MtxTooltip.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: MtxTooltip, selector: "[mtxTooltip]", host: { classAttribute: "mtx-mdc-tooltip-trigger" }, exportAs: ["mtxTooltip"], usesInheritance: true, ngImport: i0 });
726
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: MtxTooltip, decorators: [{
727
+ type: Directive,
728
+ args: [{
729
+ selector: '[mtxTooltip]',
730
+ exportAs: 'mtxTooltip',
731
+ host: {
732
+ class: 'mtx-mdc-tooltip-trigger',
733
+ },
734
+ }]
735
+ }], ctorParameters: function () {
736
+ return [{ type: i1.Overlay }, { type: i0.ElementRef }, { type: i1.ScrollDispatcher }, { type: i0.ViewContainerRef }, { type: i0.NgZone }, { type: i2.Platform }, { type: i3.AriaDescriber }, { type: i3.FocusMonitor }, { type: undefined, decorators: [{
737
+ type: Inject,
738
+ args: [MTX_TOOLTIP_SCROLL_STRATEGY]
739
+ }] }, { type: i4.Directionality, decorators: [{
740
+ type: Optional
741
+ }] }, { type: undefined, decorators: [{
742
+ type: Optional
743
+ }, {
744
+ type: Inject,
745
+ args: [MTX_TOOLTIP_DEFAULT_OPTIONS]
746
+ }] }, { type: undefined, decorators: [{
747
+ type: Inject,
748
+ args: [DOCUMENT]
749
+ }] }];
750
+ } });
751
+ class _TooltipComponentBase {
752
+ constructor(_changeDetectorRef, animationMode) {
595
753
  this._changeDetectorRef = _changeDetectorRef;
596
- this._breakpointObserver = _breakpointObserver;
597
- /** Property watched by the animation framework to show or hide the tooltip */
598
- this._visibility = 'initial';
599
754
  /** Whether interactions on the page should close the tooltip */
600
755
  this._closeOnInteraction = false;
756
+ /** Whether the tooltip is currently visible. */
757
+ this._isVisible = false;
601
758
  /** Subject for notifying that the tooltip has been hidden from the view */
602
759
  this._onHide = new Subject();
603
- /** Stream that emits whether the user has a handset-sized display. */
604
- this._isHandset = this._breakpointObserver.observe(Breakpoints.Handset);
760
+ this._animationsDisabled = animationMode === 'NoopAnimations';
605
761
  }
606
762
  /**
607
763
  * Shows the tooltip with an animation originating from the provided origin
@@ -609,18 +765,10 @@ class TooltipComponent {
609
765
  */
610
766
  show(delay) {
611
767
  // Cancel the delayed hide if it is scheduled
612
- if (this._hideTimeoutId) {
613
- clearTimeout(this._hideTimeoutId);
614
- this._hideTimeoutId = null;
615
- }
616
- // Body interactions should cancel the tooltip if there is a delay in showing.
617
- this._closeOnInteraction = true;
768
+ clearTimeout(this._hideTimeoutId);
618
769
  this._showTimeoutId = setTimeout(() => {
619
- this._visibility = 'visible';
620
- this._showTimeoutId = null;
621
- // Mark for check so if any parent component has set the
622
- // ChangeDetectionStrategy to OnPush it will be checked anyways
623
- this._markForCheck();
770
+ this._toggleVisibility(true);
771
+ this._showTimeoutId = undefined;
624
772
  }, delay);
625
773
  }
626
774
  /**
@@ -629,40 +777,24 @@ class TooltipComponent {
629
777
  */
630
778
  hide(delay) {
631
779
  // Cancel the delayed show if it is scheduled
632
- if (this._showTimeoutId) {
633
- clearTimeout(this._showTimeoutId);
634
- this._showTimeoutId = null;
635
- }
780
+ clearTimeout(this._showTimeoutId);
636
781
  this._hideTimeoutId = setTimeout(() => {
637
- this._visibility = 'hidden';
638
- this._hideTimeoutId = null;
639
- // Mark for check so if any parent component has set the
640
- // ChangeDetectionStrategy to OnPush it will be checked anyways
641
- this._markForCheck();
782
+ this._toggleVisibility(false);
783
+ this._hideTimeoutId = undefined;
642
784
  }, delay);
643
785
  }
644
786
  /** Returns an observable that notifies when the tooltip has been hidden from view. */
645
787
  afterHidden() {
646
- return this._onHide.asObservable();
788
+ return this._onHide;
647
789
  }
648
790
  /** Whether the tooltip is being displayed. */
649
791
  isVisible() {
650
- return this._visibility === 'visible';
792
+ return this._isVisible;
651
793
  }
652
794
  ngOnDestroy() {
795
+ this._cancelPendingAnimations();
653
796
  this._onHide.complete();
654
- }
655
- _animationStart() {
656
- this._closeOnInteraction = false;
657
- }
658
- _animationDone(event) {
659
- const toState = event.toState;
660
- if (toState === 'hidden' && !this.isVisible()) {
661
- this._onHide.next();
662
- }
663
- if (toState === 'visible' || toState === 'hidden') {
664
- this._closeOnInteraction = true;
665
- }
797
+ this._triggerElement = null;
666
798
  }
667
799
  /**
668
800
  * Interactions on the HTML body should close the tooltip immediately as defined in the
@@ -682,19 +814,134 @@ class TooltipComponent {
682
814
  _markForCheck() {
683
815
  this._changeDetectorRef.markForCheck();
684
816
  }
817
+ _handleMouseLeave({ relatedTarget }) {
818
+ if (!relatedTarget || !this._triggerElement.contains(relatedTarget)) {
819
+ if (this.isVisible()) {
820
+ this.hide(this._mouseLeaveHideDelay);
821
+ }
822
+ else {
823
+ this._finalizeAnimation(false);
824
+ }
825
+ }
826
+ }
827
+ /**
828
+ * Callback for when the timeout in this.show() gets completed.
829
+ * This method is only needed by the mdc-tooltip, and so it is only implemented
830
+ * in the mdc-tooltip, not here.
831
+ */
832
+ _onShow() { }
833
+ /** Event listener dispatched when an animation on the tooltip finishes. */
834
+ _handleAnimationEnd({ animationName }) {
835
+ if (animationName === this._showAnimation || animationName === this._hideAnimation) {
836
+ this._finalizeAnimation(animationName === this._showAnimation);
837
+ }
838
+ }
839
+ /** Cancels any pending animation sequences. */
840
+ _cancelPendingAnimations() {
841
+ clearTimeout(this._showTimeoutId);
842
+ clearTimeout(this._hideTimeoutId);
843
+ this._showTimeoutId = this._hideTimeoutId = undefined;
844
+ }
845
+ /** Handles the cleanup after an animation has finished. */
846
+ _finalizeAnimation(toVisible) {
847
+ if (toVisible) {
848
+ this._closeOnInteraction = true;
849
+ }
850
+ else if (!this.isVisible()) {
851
+ this._onHide.next();
852
+ }
853
+ }
854
+ /** Toggles the visibility of the tooltip element. */
855
+ _toggleVisibility(isVisible) {
856
+ // We set the classes directly here ourselves so that toggling the tooltip state
857
+ // isn't bound by change detection. This allows us to hide it even if the
858
+ // view ref has been detached from the CD tree.
859
+ const tooltip = this._tooltip.nativeElement;
860
+ const showClass = this._showAnimation;
861
+ const hideClass = this._hideAnimation;
862
+ tooltip.classList.remove(isVisible ? hideClass : showClass);
863
+ tooltip.classList.add(isVisible ? showClass : hideClass);
864
+ this._isVisible = isVisible;
865
+ // It's common for internal apps to disable animations using `* { animation: none !important }`
866
+ // which can break the opening sequence. Try to detect such cases and work around them.
867
+ if (isVisible && !this._animationsDisabled && typeof getComputedStyle === 'function') {
868
+ const styles = getComputedStyle(tooltip);
869
+ // Use `getPropertyValue` to avoid issues with property renaming.
870
+ if (styles.getPropertyValue('animation-duration') === '0s' ||
871
+ styles.getPropertyValue('animation-name') === 'none') {
872
+ this._animationsDisabled = true;
873
+ }
874
+ }
875
+ if (isVisible) {
876
+ this._onShow();
877
+ }
878
+ if (this._animationsDisabled) {
879
+ tooltip.classList.add('_mtx-animation-noopable');
880
+ this._finalizeAnimation(isVisible);
881
+ }
882
+ }
685
883
  }
686
- /** @nocollapse */ TooltipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: TooltipComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i6.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
687
- /** @nocollapse */ TooltipComponentcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", type: TooltipComponent, selector: "mtx-tooltip-component", host: { attributes: { "aria-hidden": "true" }, listeners: { "body:click": "this._handleBodyInteraction()" }, properties: { "style.zoom": "_visibility === \"visible\" ? 1 : null" } }, ngImport: i0, template: "<div class=\"mtx-tooltip\"\n [ngClass]=\"tooltipClass\"\n [class.mtx-tooltip-handset]=\"(_isHandset | async)?.matches\"\n [@state]=\"_visibility\"\n (@state.start)=\"_animationStart()\"\n (@state.done)=\"_animationDone($event)\">\n <ng-template [ngIf]=\"message | isTemplateRef\" [ngIfElse]=\"msgStrTpl\">\n <ng-template [ngTemplateOutlet]=\"$any(message)\"></ng-template>\n </ng-template>\n <ng-template #msgStrTpl>{{message}}</ng-template>\n</div>\n", styles: [".mtx-tooltip-panel{pointer-events:none!important}.mtx-tooltip{color:#fff;border-radius:4px;margin:14px;max-width:250px;padding-left:8px;padding-right:8px;overflow:hidden;text-overflow:ellipsis}.cdk-high-contrast-active .mtx-tooltip{outline:solid 1px}.mtx-tooltip-handset{margin:24px;padding-left:16px;padding-right:16px}\n"], dependencies: [{ kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.MtxIsTemplateRefPipe, name: "isTemplateRef" }], animations: [mtxTooltipAnimations.tooltipState], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
884
+ /** @nocollapse */ _TooltipComponentBase.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: _TooltipComponentBase, deps: [{ token: i0.ChangeDetectorRef }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
885
+ /** @nocollapse */ _TooltipComponentBasedir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.1", type: _TooltipComponentBase, ngImport: i0 });
886
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: _TooltipComponentBase, decorators: [{
887
+ type: Directive
888
+ }], ctorParameters: function () {
889
+ return [{ type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
890
+ type: Optional
891
+ }, {
892
+ type: Inject,
893
+ args: [ANIMATION_MODULE_TYPE]
894
+ }] }];
895
+ } });
896
+ /**
897
+ * Internal component that wraps the tooltip's content.
898
+ * @docs-private
899
+ */
900
+ class TooltipComponent extends _TooltipComponentBase {
901
+ constructor(changeDetectorRef, _elementRef, animationMode) {
902
+ super(changeDetectorRef, animationMode);
903
+ this._elementRef = _elementRef;
904
+ /* Whether the tooltip text overflows to multiple lines */
905
+ this._isMultiline = false;
906
+ this._showAnimation = 'mtx-mdc-tooltip-show';
907
+ this._hideAnimation = 'mtx-mdc-tooltip-hide';
908
+ }
909
+ _onShow() {
910
+ this._isMultiline = this._isTooltipMultiline();
911
+ this._markForCheck();
912
+ }
913
+ /** Whether the tooltip text has overflown to the next line */
914
+ _isTooltipMultiline() {
915
+ const rect = this._elementRef.nativeElement.getBoundingClientRect();
916
+ return rect.height > MIN_HEIGHT && rect.width >= MAX_WIDTH;
917
+ }
918
+ }
919
+ /** @nocollapse */ TooltipComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: TooltipComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: ANIMATION_MODULE_TYPE, optional: true }], target: i0.ɵɵFactoryTarget.Component });
920
+ /** @nocollapse */ TooltipComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.1", type: TooltipComponent, selector: "mtx-tooltip-component", host: { attributes: { "aria-hidden": "true" }, listeners: { "mouseleave": "_handleMouseLeave($event)" }, properties: { "style.zoom": "isVisible() ? 1 : null" } }, viewQueries: [{ propertyName: "_tooltip", first: true, predicate: ["tooltip"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<div #tooltip\n class=\"mdc-tooltip mdc-tooltip--shown mtx-mdc-tooltip\"\n [ngClass]=\"tooltipClass\"\n (animationend)=\"_handleAnimationEnd($event)\"\n [class.mdc-tooltip--multiline]=\"_isMultiline\">\n <div class=\"mdc-tooltip__surface mdc-tooltip__surface-animation\">\n <ng-template [ngIf]=\"message | isTemplateRef\" [ngIfElse]=\"msgStrTpl\">\n <ng-template [ngTemplateOutlet]=\"$any(message)\"\n [ngTemplateOutletContext]=\"{ $implicit: tooltipContext }\"></ng-template>\n </ng-template>\n <ng-template #msgStrTpl>{{message}}</ng-template>\n </div>\n</div>\n", styles: [".mdc-tooltip__surface{word-break:var(--mdc-tooltip-word-break, normal);overflow-wrap:anywhere}.mdc-tooltip{position:fixed;display:none;z-index:9}.mdc-tooltip-wrapper--rich{position:relative}.mdc-tooltip--shown,.mdc-tooltip--showing,.mdc-tooltip--hide{display:inline-flex}.mdc-tooltip--shown.mdc-tooltip--rich,.mdc-tooltip--showing.mdc-tooltip--rich,.mdc-tooltip--hide.mdc-tooltip--rich{display:inline-block;left:-320px;position:absolute}.mdc-tooltip__surface{line-height:16px;padding:4px 8px;min-width:40px;max-width:200px;min-height:24px;max-height:40vh;box-sizing:border-box;overflow:hidden;text-align:center}.mdc-tooltip__surface:before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:\"\";pointer-events:none}@media screen and (forced-colors: active){.mdc-tooltip__surface:before{border-color:CanvasText}}.mdc-tooltip--rich .mdc-tooltip__surface{align-items:flex-start;display:flex;flex-direction:column;min-height:24px;min-width:40px;max-width:320px;position:relative}.mdc-tooltip--multiline .mdc-tooltip__surface{text-align:left}[dir=rtl] .mdc-tooltip--multiline .mdc-tooltip__surface,.mdc-tooltip--multiline .mdc-tooltip__surface[dir=rtl]{text-align:right}.mdc-tooltip__surface .mdc-tooltip__title{margin:0 8px}.mdc-tooltip__surface .mdc-tooltip__content{max-width:184px;margin:8px;text-align:left}[dir=rtl] .mdc-tooltip__surface .mdc-tooltip__content,.mdc-tooltip__surface .mdc-tooltip__content[dir=rtl]{text-align:right}.mdc-tooltip--rich .mdc-tooltip__surface .mdc-tooltip__content{max-width:304px;align-self:stretch}.mdc-tooltip__surface .mdc-tooltip__content-link{text-decoration:none}.mdc-tooltip--rich-actions,.mdc-tooltip__content,.mdc-tooltip__title{z-index:1}.mdc-tooltip__surface-animation{opacity:0;transform:scale(.8);will-change:transform,opacity}.mdc-tooltip--shown .mdc-tooltip__surface-animation{transform:scale(1);opacity:1}.mdc-tooltip--hide .mdc-tooltip__surface-animation{transform:scale(1)}.mdc-tooltip__caret-surface-top,.mdc-tooltip__caret-surface-bottom{position:absolute;height:24px;width:24px;transform:rotate(35deg) skewY(20deg) scaleX(.9396926208)}.mdc-tooltip__caret-surface-top .mdc-elevation-overlay,.mdc-tooltip__caret-surface-bottom .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-tooltip__caret-surface-bottom{outline:1px solid transparent;z-index:-1}@media screen and (forced-colors: active){.mdc-tooltip__caret-surface-bottom{outline-color:CanvasText}}.mdc-tooltip__surface{background-color:var(--mdc-plain-tooltip-container-color, #fff)}.mdc-tooltip__surface,.mdc-tooltip__caret-surface-top,.mdc-tooltip__caret-surface-bottom{border-radius:var(--mdc-plain-tooltip-container-shape, var(--mdc-shape-small, 4px))}.mdc-tooltip__surface{color:var(--mdc-plain-tooltip-supporting-text-color, #000)}.mdc-tooltip__surface{font-family:var(--mdc-plain-tooltip-supporting-text-font, inherit);font-size:var(--mdc-plain-tooltip-supporting-text-size, inherit);font-weight:var(--mdc-plain-tooltip-supporting-text-weight, inherit);letter-spacing:var(--mdc-plain-tooltip-supporting-text-tracking, inherit)}.mtx-mdc-tooltip{position:relative;transform:scale(0)}.mtx-mdc-tooltip:before{content:\"\";inset:0;z-index:-1;position:absolute}.mtx-mdc-tooltip-panel-below .mtx-mdc-tooltip:before{top:-8px}.mtx-mdc-tooltip-panel-above .mtx-mdc-tooltip:before{bottom:-8px}.mtx-mdc-tooltip-panel-right .mtx-mdc-tooltip:before{left:-8px}.mtx-mdc-tooltip-panel-left .mtx-mdc-tooltip:before{right:-8px}.mtx-mdc-tooltip._mtx-animation-noopable{animation:none;transform:scale(1)}.mtx-mdc-tooltip-panel-non-interactive{pointer-events:none}@keyframes mtx-mdc-tooltip-show{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes mtx-mdc-tooltip-hide{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.8)}}.mtx-mdc-tooltip-show{animation:mtx-mdc-tooltip-show .15s cubic-bezier(0,0,.2,1) forwards}.mtx-mdc-tooltip-hide{animation:mtx-mdc-tooltip-hide 75ms cubic-bezier(.4,0,1,1) forwards}\n"], dependencies: [{ kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i6.MtxIsTemplateRefPipe, name: "isTemplateRef" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
688
921
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImport: i0, type: TooltipComponent, decorators: [{
689
922
  type: Component,
690
- args: [{ selector: 'mtx-tooltip-component', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, animations: [mtxTooltipAnimations.tooltipState], host: {
923
+ args: [{ selector: 'mtx-tooltip-component', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
691
924
  // Forces the element to have a layout in IE and Edge. This fixes issues where the element
692
925
  // won't be rendered if the animations are disabled or there is no web animations polyfill.
693
- '[style.zoom]': '_visibility === "visible" ? 1 : null',
694
- '(body:click)': 'this._handleBodyInteraction()',
926
+ '[style.zoom]': 'isVisible() ? 1 : null',
927
+ '(mouseleave)': '_handleMouseLeave($event)',
695
928
  'aria-hidden': 'true',
696
- }, template: "<div class=\"mtx-tooltip\"\n [ngClass]=\"tooltipClass\"\n [class.mtx-tooltip-handset]=\"(_isHandset | async)?.matches\"\n [@state]=\"_visibility\"\n (@state.start)=\"_animationStart()\"\n (@state.done)=\"_animationDone($event)\">\n <ng-template [ngIf]=\"message | isTemplateRef\" [ngIfElse]=\"msgStrTpl\">\n <ng-template [ngTemplateOutlet]=\"$any(message)\"></ng-template>\n </ng-template>\n <ng-template #msgStrTpl>{{message}}</ng-template>\n</div>\n", styles: [".mtx-tooltip-panel{pointer-events:none!important}.mtx-tooltip{color:#fff;border-radius:4px;margin:14px;max-width:250px;padding-left:8px;padding-right:8px;overflow:hidden;text-overflow:ellipsis}.cdk-high-contrast-active .mtx-tooltip{outline:solid 1px}.mtx-tooltip-handset{margin:24px;padding-left:16px;padding-right:16px}\n"] }]
697
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: i6.BreakpointObserver }]; } });
929
+ }, template: "<div #tooltip\n class=\"mdc-tooltip mdc-tooltip--shown mtx-mdc-tooltip\"\n [ngClass]=\"tooltipClass\"\n (animationend)=\"_handleAnimationEnd($event)\"\n [class.mdc-tooltip--multiline]=\"_isMultiline\">\n <div class=\"mdc-tooltip__surface mdc-tooltip__surface-animation\">\n <ng-template [ngIf]=\"message | isTemplateRef\" [ngIfElse]=\"msgStrTpl\">\n <ng-template [ngTemplateOutlet]=\"$any(message)\"\n [ngTemplateOutletContext]=\"{ $implicit: tooltipContext }\"></ng-template>\n </ng-template>\n <ng-template #msgStrTpl>{{message}}</ng-template>\n </div>\n</div>\n", styles: [".mdc-tooltip__surface{word-break:var(--mdc-tooltip-word-break, normal);overflow-wrap:anywhere}.mdc-tooltip{position:fixed;display:none;z-index:9}.mdc-tooltip-wrapper--rich{position:relative}.mdc-tooltip--shown,.mdc-tooltip--showing,.mdc-tooltip--hide{display:inline-flex}.mdc-tooltip--shown.mdc-tooltip--rich,.mdc-tooltip--showing.mdc-tooltip--rich,.mdc-tooltip--hide.mdc-tooltip--rich{display:inline-block;left:-320px;position:absolute}.mdc-tooltip__surface{line-height:16px;padding:4px 8px;min-width:40px;max-width:200px;min-height:24px;max-height:40vh;box-sizing:border-box;overflow:hidden;text-align:center}.mdc-tooltip__surface:before{position:absolute;box-sizing:border-box;width:100%;height:100%;top:0;left:0;border:1px solid transparent;border-radius:inherit;content:\"\";pointer-events:none}@media screen and (forced-colors: active){.mdc-tooltip__surface:before{border-color:CanvasText}}.mdc-tooltip--rich .mdc-tooltip__surface{align-items:flex-start;display:flex;flex-direction:column;min-height:24px;min-width:40px;max-width:320px;position:relative}.mdc-tooltip--multiline .mdc-tooltip__surface{text-align:left}[dir=rtl] .mdc-tooltip--multiline .mdc-tooltip__surface,.mdc-tooltip--multiline .mdc-tooltip__surface[dir=rtl]{text-align:right}.mdc-tooltip__surface .mdc-tooltip__title{margin:0 8px}.mdc-tooltip__surface .mdc-tooltip__content{max-width:184px;margin:8px;text-align:left}[dir=rtl] .mdc-tooltip__surface .mdc-tooltip__content,.mdc-tooltip__surface .mdc-tooltip__content[dir=rtl]{text-align:right}.mdc-tooltip--rich .mdc-tooltip__surface .mdc-tooltip__content{max-width:304px;align-self:stretch}.mdc-tooltip__surface .mdc-tooltip__content-link{text-decoration:none}.mdc-tooltip--rich-actions,.mdc-tooltip__content,.mdc-tooltip__title{z-index:1}.mdc-tooltip__surface-animation{opacity:0;transform:scale(.8);will-change:transform,opacity}.mdc-tooltip--shown .mdc-tooltip__surface-animation{transform:scale(1);opacity:1}.mdc-tooltip--hide .mdc-tooltip__surface-animation{transform:scale(1)}.mdc-tooltip__caret-surface-top,.mdc-tooltip__caret-surface-bottom{position:absolute;height:24px;width:24px;transform:rotate(35deg) skewY(20deg) scaleX(.9396926208)}.mdc-tooltip__caret-surface-top .mdc-elevation-overlay,.mdc-tooltip__caret-surface-bottom .mdc-elevation-overlay{width:100%;height:100%;top:0;left:0}.mdc-tooltip__caret-surface-bottom{outline:1px solid transparent;z-index:-1}@media screen and (forced-colors: active){.mdc-tooltip__caret-surface-bottom{outline-color:CanvasText}}.mdc-tooltip__surface{background-color:var(--mdc-plain-tooltip-container-color, #fff)}.mdc-tooltip__surface,.mdc-tooltip__caret-surface-top,.mdc-tooltip__caret-surface-bottom{border-radius:var(--mdc-plain-tooltip-container-shape, var(--mdc-shape-small, 4px))}.mdc-tooltip__surface{color:var(--mdc-plain-tooltip-supporting-text-color, #000)}.mdc-tooltip__surface{font-family:var(--mdc-plain-tooltip-supporting-text-font, inherit);font-size:var(--mdc-plain-tooltip-supporting-text-size, inherit);font-weight:var(--mdc-plain-tooltip-supporting-text-weight, inherit);letter-spacing:var(--mdc-plain-tooltip-supporting-text-tracking, inherit)}.mtx-mdc-tooltip{position:relative;transform:scale(0)}.mtx-mdc-tooltip:before{content:\"\";inset:0;z-index:-1;position:absolute}.mtx-mdc-tooltip-panel-below .mtx-mdc-tooltip:before{top:-8px}.mtx-mdc-tooltip-panel-above .mtx-mdc-tooltip:before{bottom:-8px}.mtx-mdc-tooltip-panel-right .mtx-mdc-tooltip:before{left:-8px}.mtx-mdc-tooltip-panel-left .mtx-mdc-tooltip:before{right:-8px}.mtx-mdc-tooltip._mtx-animation-noopable{animation:none;transform:scale(1)}.mtx-mdc-tooltip-panel-non-interactive{pointer-events:none}@keyframes mtx-mdc-tooltip-show{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes mtx-mdc-tooltip-hide{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.8)}}.mtx-mdc-tooltip-show{animation:mtx-mdc-tooltip-show .15s cubic-bezier(0,0,.2,1) forwards}.mtx-mdc-tooltip-hide{animation:mtx-mdc-tooltip-hide 75ms cubic-bezier(.4,0,1,1) forwards}\n"] }]
930
+ }], ctorParameters: function () {
931
+ return [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: undefined, decorators: [{
932
+ type: Optional
933
+ }, {
934
+ type: Inject,
935
+ args: [ANIMATION_MODULE_TYPE]
936
+ }] }];
937
+ }, propDecorators: { _tooltip: [{
938
+ type: ViewChild,
939
+ args: ['tooltip', {
940
+ // Use a static query here since we interact directly with
941
+ // the DOM which can happen before `ngAfterViewInit`.
942
+ static: true,
943
+ }]
944
+ }] } });
698
945
 
699
946
  class MtxTooltipModule {
700
947
  }
@@ -711,9 +958,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.1", ngImpor
711
958
  }]
712
959
  }] });
713
960
 
961
+ /**
962
+ * Animations used by MatTooltip.
963
+ * @docs-private
964
+ */
965
+ const matTooltipAnimations = {
966
+ /** Animation that transitions a tooltip in and out. */
967
+ tooltipState: trigger('state', [
968
+ // TODO(crisbeto): these values are based on MDC's CSS.
969
+ // We should be able to use their styles directly once we land #19432.
970
+ state('initial, void, hidden', style({ opacity: 0, transform: 'scale(0.8)' })),
971
+ state('visible', style({ transform: 'scale(1)' })),
972
+ transition('* => visible', animate('150ms cubic-bezier(0, 0, 0.2, 1)')),
973
+ transition('* => hidden', animate('75ms cubic-bezier(0.4, 0, 1, 1)')),
974
+ ]),
975
+ };
976
+
714
977
  /**
715
978
  * Generated bundle index. Do not edit.
716
979
  */
717
980
 
718
- export { MTX_TOOLTIP_DEFAULT_OPTIONS, MTX_TOOLTIP_DEFAULT_OPTIONS_FACTORY, MTX_TOOLTIP_SCROLL_STRATEGY, MTX_TOOLTIP_SCROLL_STRATEGY_FACTORY, MTX_TOOLTIP_SCROLL_STRATEGY_FACTORY_PROVIDER, MtxTooltip, MtxTooltipModule, SCROLL_THROTTLE_MS, TOOLTIP_PANEL_CLASS, TooltipComponent, getMtxTooltipInvalidPositionError, mtxTooltipAnimations };
981
+ export { MTX_TOOLTIP_DEFAULT_OPTIONS, MTX_TOOLTIP_DEFAULT_OPTIONS_FACTORY, MTX_TOOLTIP_SCROLL_STRATEGY, MTX_TOOLTIP_SCROLL_STRATEGY_FACTORY, MTX_TOOLTIP_SCROLL_STRATEGY_FACTORY_PROVIDER, MtxTooltip, MtxTooltipModule, SCROLL_THROTTLE_MS, TOOLTIP_PANEL_CLASS, TooltipComponent, _MtxTooltipBase, _TooltipComponentBase, getMtxTooltipInvalidPositionError, matTooltipAnimations };
719
982
  //# sourceMappingURL=mtxTooltip.mjs.map