@skyux/core 5.9.5 → 5.10.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.
Files changed (39) hide show
  1. package/bundles/skyux-core-testing.umd.js +30 -0
  2. package/bundles/skyux-core.umd.js +764 -739
  3. package/documentation.json +149 -146
  4. package/esm2015/lib/modules/adapter-service/adapter.service.js +10 -6
  5. package/esm2015/lib/modules/adapter-service/adapter.service.js.map +1 -1
  6. package/esm2015/lib/modules/affix/affix.service.js +6 -2
  7. package/esm2015/lib/modules/affix/affix.service.js.map +1 -1
  8. package/esm2015/lib/modules/numeric/numeric.pipe.js +3 -4
  9. package/esm2015/lib/modules/numeric/numeric.pipe.js.map +1 -1
  10. package/esm2015/lib/modules/numeric/numeric.service.js +1 -1
  11. package/esm2015/lib/modules/numeric/numeric.service.js.map +1 -1
  12. package/esm2015/lib/modules/resize-observer/resize-observer-media-query.service.js +42 -29
  13. package/esm2015/lib/modules/resize-observer/resize-observer-media-query.service.js.map +1 -1
  14. package/esm2015/lib/modules/resize-observer/resize-observer.service.js +16 -10
  15. package/esm2015/lib/modules/resize-observer/resize-observer.service.js.map +1 -1
  16. package/esm2015/lib/modules/scrollable-host/scrollable-host.service.js +28 -25
  17. package/esm2015/lib/modules/scrollable-host/scrollable-host.service.js.map +1 -1
  18. package/esm2015/testing/core-testing.module.js +29 -0
  19. package/esm2015/testing/core-testing.module.js.map +1 -0
  20. package/esm2015/testing/mock-media-query.service.js +2 -0
  21. package/esm2015/testing/mock-media-query.service.js.map +1 -1
  22. package/esm2015/testing/mock-ui-config.service.js.map +1 -1
  23. package/esm2015/testing/public-api.js +1 -0
  24. package/esm2015/testing/public-api.js.map +1 -1
  25. package/fesm2015/skyux-core-testing.js +28 -2
  26. package/fesm2015/skyux-core-testing.js.map +1 -1
  27. package/fesm2015/skyux-core.js +103 -77
  28. package/fesm2015/skyux-core.js.map +1 -1
  29. package/lib/modules/adapter-service/adapter.service.d.ts +1 -1
  30. package/lib/modules/affix/affix.service.d.ts +1 -1
  31. package/lib/modules/numeric/numeric.pipe.d.ts +3 -4
  32. package/lib/modules/numeric/numeric.service.d.ts +1 -1
  33. package/lib/modules/resize-observer/resize-observer-media-query.service.d.ts +2 -5
  34. package/lib/modules/resize-observer/resize-observer.service.d.ts +1 -2
  35. package/lib/modules/scrollable-host/scrollable-host.service.d.ts +7 -4
  36. package/package.json +2 -2
  37. package/testing/core-testing.module.d.ts +6 -0
  38. package/testing/mock-ui-config.service.d.ts +2 -1
  39. package/testing/public-api.d.ts +1 -0
@@ -1,5 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { NgModule, Injectable, EventEmitter, Directive, Input, Output, Injector, ViewContainerRef, Component, ChangeDetectionStrategy, ViewChild, Pipe, ElementRef, Optional } from '@angular/core';
3
+ import { __classPrivateFieldSet, __classPrivateFieldGet } from 'tslib';
3
4
  import * as i4 from '@angular/common';
4
5
  import { CommonModule } from '@angular/common';
5
6
  import { Subject, fromEvent, BehaviorSubject, ReplaySubject, Observable, of } from 'rxjs';
@@ -44,6 +45,7 @@ var SkyMediaBreakpoints;
44
45
  SkyMediaBreakpoints[SkyMediaBreakpoints["lg"] = 4] = "lg";
45
46
  })(SkyMediaBreakpoints || (SkyMediaBreakpoints = {}));
46
47
 
48
+ var _SkyCoreAdapterService_renderer;
47
49
  const SKY_TABBABLE_SELECTOR = [
48
50
  'a[href]',
49
51
  'area[href]',
@@ -60,7 +62,8 @@ const SKY_TABBABLE_SELECTOR = [
60
62
  class SkyCoreAdapterService {
61
63
  constructor(rendererFactory) {
62
64
  this.rendererFactory = rendererFactory;
63
- this.renderer = this.rendererFactory.createRenderer(undefined, undefined);
65
+ _SkyCoreAdapterService_renderer.set(this, void 0);
66
+ __classPrivateFieldSet(this, _SkyCoreAdapterService_renderer, this.rendererFactory.createRenderer(undefined, null), "f");
64
67
  }
65
68
  /**
66
69
  * Set the responsive container CSS class for a given element.
@@ -71,10 +74,10 @@ class SkyCoreAdapterService {
71
74
  */
72
75
  setResponsiveContainerClass(elementRef, breakpoint) {
73
76
  const nativeEl = elementRef.nativeElement;
74
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-xs');
75
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-sm');
76
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-md');
77
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-lg');
77
+ __classPrivateFieldGet(this, _SkyCoreAdapterService_renderer, "f").removeClass(nativeEl, 'sky-responsive-container-xs');
78
+ __classPrivateFieldGet(this, _SkyCoreAdapterService_renderer, "f").removeClass(nativeEl, 'sky-responsive-container-sm');
79
+ __classPrivateFieldGet(this, _SkyCoreAdapterService_renderer, "f").removeClass(nativeEl, 'sky-responsive-container-md');
80
+ __classPrivateFieldGet(this, _SkyCoreAdapterService_renderer, "f").removeClass(nativeEl, 'sky-responsive-container-lg');
78
81
  let newClass;
79
82
  switch (breakpoint) {
80
83
  case SkyMediaBreakpoints.xs: {
@@ -94,7 +97,7 @@ class SkyCoreAdapterService {
94
97
  break;
95
98
  }
96
99
  }
97
- this.renderer.addClass(nativeEl, newClass);
100
+ __classPrivateFieldGet(this, _SkyCoreAdapterService_renderer, "f").addClass(nativeEl, newClass);
98
101
  }
99
102
  /**
100
103
  * This method temporarily enables/disables pointer events.
@@ -258,6 +261,7 @@ class SkyCoreAdapterService {
258
261
  return hasBounds;
259
262
  }
260
263
  }
264
+ _SkyCoreAdapterService_renderer = new WeakMap();
261
265
  SkyCoreAdapterService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyCoreAdapterService, deps: [{ token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
262
266
  SkyCoreAdapterService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyCoreAdapterService, providedIn: 'root' });
263
267
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyCoreAdapterService, decorators: [{
@@ -719,18 +723,21 @@ class SkyAffixer {
719
723
  }
720
724
  }
721
725
 
726
+ var _SkyAffixService_renderer;
722
727
  class SkyAffixService {
723
728
  constructor(rendererFactory) {
724
- this.renderer = rendererFactory.createRenderer(undefined, undefined);
729
+ _SkyAffixService_renderer.set(this, void 0);
730
+ __classPrivateFieldSet(this, _SkyAffixService_renderer, rendererFactory.createRenderer(undefined, null), "f");
725
731
  }
726
732
  /**
727
733
  * Creates an instance of [[SkyAffixer]].
728
734
  * @param affixed The element to be affixed.
729
735
  */
730
736
  createAffixer(affixed) {
731
- return new SkyAffixer(affixed.nativeElement, this.renderer);
737
+ return new SkyAffixer(affixed.nativeElement, __classPrivateFieldGet(this, _SkyAffixService_renderer, "f"));
732
738
  }
733
739
  }
740
+ _SkyAffixService_renderer = new WeakMap();
734
741
  SkyAffixService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyAffixService, deps: [{ token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
735
742
  SkyAffixService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyAffixService, providedIn: 'root' });
736
743
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyAffixService, decorators: [{
@@ -1736,7 +1743,7 @@ class SkyNumericService {
1736
1743
  return this._locale || 'en-US';
1737
1744
  }
1738
1745
  /**
1739
- * Shortens with or without symbol (K/M/B/T) depending on value of number.
1746
+ * Formats a number based on the provided options.
1740
1747
  * @param value The number to format.
1741
1748
  * @param options Format options.
1742
1749
  */
@@ -1904,10 +1911,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
1904
1911
  * M for millions, B for billions, and T for trillions. The pipe also formats for currency.
1905
1912
  * Be sure you have a space after the two curly brackets opening the pipe and
1906
1913
  * a space before the two curly brackets closing the pipe or it will not work.
1907
- * Usage:
1908
- * ```
1909
- * {{ value | skyNumeric(config) }}
1910
- * ```
1911
1914
  */
1912
1915
  class SkyNumericPipe {
1913
1916
  constructor(localeProvider, numericService, changeDetector) {
@@ -1928,6 +1931,9 @@ class SkyNumericPipe {
1928
1931
  this.ngUnsubscribe.next();
1929
1932
  this.ngUnsubscribe.complete();
1930
1933
  }
1934
+ /**
1935
+ * Formats a number based on the provided options.
1936
+ */
1931
1937
  transform(value, config) {
1932
1938
  var _a;
1933
1939
  const newCacheKey = (config ? JSON.stringify(config, Object.keys(config).sort()) : '') +
@@ -2417,19 +2423,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
2417
2423
  }]
2418
2424
  }] });
2419
2425
 
2426
+ var _SkyResizeObserverService_resizeObserver, _SkyResizeObserverService_tracking;
2420
2427
  /**
2421
2428
  * Service to create rxjs observables for changes to the content box dimensions of elements.
2422
2429
  */
2423
2430
  class SkyResizeObserverService {
2424
2431
  constructor(zone) {
2425
2432
  this.zone = zone;
2426
- this._tracking = [];
2427
- this._resizeObserver = new ResizeObserver((entries) => {
2433
+ _SkyResizeObserverService_resizeObserver.set(this, void 0);
2434
+ _SkyResizeObserverService_tracking.set(this, []);
2435
+ __classPrivateFieldSet(this, _SkyResizeObserverService_resizeObserver, new ResizeObserver((entries) => {
2428
2436
  entries.forEach((entry) => this.callback(entry));
2429
- });
2437
+ }), "f");
2430
2438
  }
2431
2439
  ngOnDestroy() {
2432
- this._resizeObserver.disconnect();
2440
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").disconnect();
2433
2441
  }
2434
2442
  /**
2435
2443
  * Create rxjs observable to get size changes for an element ref.
@@ -2438,22 +2446,22 @@ class SkyResizeObserverService {
2438
2446
  return this.observeAndTrack(element).subjectObservable;
2439
2447
  }
2440
2448
  observeAndTrack(element) {
2441
- const checkTracking = this._tracking.findIndex((value) => {
2449
+ const checkTracking = __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").findIndex((value) => {
2442
2450
  return !value.subject.closed && value.element === element.nativeElement;
2443
2451
  });
2444
2452
  if (checkTracking === -1) {
2445
- this._resizeObserver.observe(element.nativeElement);
2453
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").observe(element.nativeElement);
2446
2454
  }
2447
2455
  const subject = new Subject();
2448
2456
  const subjectObservable = subject.pipe(finalize(() => {
2449
2457
  // Are there any other tracking entries still watching this element?
2450
- const checkTracking = this._tracking.findIndex((value) => {
2458
+ const checkTracking = __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").findIndex((value) => {
2451
2459
  return (value.subject !== subject &&
2452
2460
  !value.subject.closed &&
2453
2461
  value.element === element.nativeElement);
2454
2462
  });
2455
2463
  if (checkTracking === -1) {
2456
- this._resizeObserver.unobserve(element.nativeElement);
2464
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").unobserve(element.nativeElement);
2457
2465
  }
2458
2466
  }));
2459
2467
  const tracking = {
@@ -2461,15 +2469,17 @@ class SkyResizeObserverService {
2461
2469
  subject,
2462
2470
  subjectObservable,
2463
2471
  };
2464
- this._tracking.push(tracking);
2472
+ __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").push(tracking);
2465
2473
  return tracking;
2466
2474
  }
2467
2475
  callback(entry) {
2468
- this._tracking
2476
+ __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f")
2469
2477
  .filter((value) => !(value.subject.closed || value.subject.isStopped))
2470
2478
  .forEach((value) => {
2471
2479
  /* istanbul ignore else */
2472
2480
  if (value.element === entry.target) {
2481
+ // Execute the callback within NgZone because Angular does not "monkey patch"
2482
+ // ResizeObserver like it does for other features in the DOM.
2473
2483
  this.zone.run(() => {
2474
2484
  value.subject.next(entry);
2475
2485
  });
@@ -2477,6 +2487,7 @@ class SkyResizeObserverService {
2477
2487
  });
2478
2488
  }
2479
2489
  }
2490
+ _SkyResizeObserverService_resizeObserver = new WeakMap(), _SkyResizeObserverService_tracking = new WeakMap();
2480
2491
  SkyResizeObserverService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyResizeObserverService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
2481
2492
  SkyResizeObserverService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyResizeObserverService, providedIn: 'any' });
2482
2493
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyResizeObserverService, decorators: [{
@@ -2486,15 +2497,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImpo
2486
2497
  }]
2487
2498
  }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
2488
2499
 
2500
+ var _SkyResizeObserverMediaQueryService_breakpoints, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, _SkyResizeObserverMediaQueryService_stopListening, _SkyResizeObserverMediaQueryService_target;
2489
2501
  /**
2490
2502
  * Acts like `SkyMediaQueryService` for a container element, emitting the same responsive breakpoints.
2491
2503
  */
2492
2504
  class SkyResizeObserverMediaQueryService {
2493
2505
  constructor(resizeObserverService) {
2494
2506
  this.resizeObserverService = resizeObserverService;
2495
- this._breakpoints = [
2507
+ _SkyResizeObserverMediaQueryService_breakpoints.set(this, [
2496
2508
  {
2497
- check: (width) => width <= 767,
2509
+ check: (width) => width > 0 && width <= 767,
2498
2510
  name: SkyMediaBreakpoints.xs,
2499
2511
  },
2500
2512
  {
@@ -2509,11 +2521,12 @@ class SkyResizeObserverMediaQueryService {
2509
2521
  check: (width) => width > 1199,
2510
2522
  name: SkyMediaBreakpoints.lg,
2511
2523
  },
2512
- ];
2513
- this._currentBreakpointObservable = new ReplaySubject(1);
2514
- this._stopListening = new Subject();
2515
- this._stopListening.subscribe(() => {
2516
- this._target = undefined;
2524
+ ]);
2525
+ _SkyResizeObserverMediaQueryService_currentBreakpointObservable.set(this, new ReplaySubject(1));
2526
+ _SkyResizeObserverMediaQueryService_stopListening.set(this, new Subject());
2527
+ _SkyResizeObserverMediaQueryService_target.set(this, void 0);
2528
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").subscribe(() => {
2529
+ __classPrivateFieldSet(this, _SkyResizeObserverMediaQueryService_target, undefined, "f");
2517
2530
  this.updateBreakpoint(undefined);
2518
2531
  });
2519
2532
  }
@@ -2524,10 +2537,10 @@ class SkyResizeObserverMediaQueryService {
2524
2537
  return this._currentBreakpoint;
2525
2538
  }
2526
2539
  ngOnDestroy() {
2527
- this._stopListening.next();
2540
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2528
2541
  this._currentBreakpoint = undefined;
2529
- this._stopListening.complete();
2530
- this._currentBreakpointObservable.complete();
2542
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").complete();
2543
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f").complete();
2531
2544
  }
2532
2545
  /**
2533
2546
  * @internal
@@ -2540,25 +2553,21 @@ class SkyResizeObserverMediaQueryService {
2540
2553
  * time. Any previous subscriptions will be unsubscribed when a new element is observed.
2541
2554
  */
2542
2555
  observe(element) {
2543
- if (this._target) {
2544
- if (this._target === element) {
2556
+ if (__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_target, "f")) {
2557
+ if (__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_target, "f") === element) {
2545
2558
  return this;
2546
2559
  }
2547
- this._stopListening.next();
2548
- }
2549
- this._target = element;
2550
- const width = element.nativeElement.offsetWidth;
2551
- if (width) {
2552
- const breakpoint = this.checkBreakpoint(width);
2553
- this.updateBreakpoint(breakpoint);
2560
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2554
2561
  }
2555
- this._resizeSubscription = this.resizeObserverService
2562
+ __classPrivateFieldSet(this, _SkyResizeObserverMediaQueryService_target, element, "f");
2563
+ this.checkWidth(element);
2564
+ this.resizeObserverService
2556
2565
  .observe(element)
2557
- .pipe(takeUntil(this._stopListening))
2566
+ .pipe(takeUntil(__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f")))
2558
2567
  .subscribe((value) => {
2559
2568
  const breakpoint = this.checkBreakpoint(value.contentRect.width);
2560
2569
  /* istanbul ignore else */
2561
- if (breakpoint !== this._currentBreakpoint) {
2570
+ if (breakpoint !== this.current) {
2562
2571
  this.updateBreakpoint(breakpoint);
2563
2572
  }
2564
2573
  });
@@ -2568,25 +2577,39 @@ class SkyResizeObserverMediaQueryService {
2568
2577
  * Stop watching the container element.
2569
2578
  */
2570
2579
  unobserve() {
2571
- this._stopListening.next();
2580
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2572
2581
  }
2573
2582
  /**
2574
2583
  * Subscribes to element size changes that cross breakpoints.
2575
2584
  */
2576
2585
  subscribe(listener) {
2577
- return this._currentBreakpointObservable
2578
- .pipe(takeUntil(this._stopListening))
2579
- .subscribe(listener);
2586
+ return __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f")
2587
+ .pipe(takeUntil(__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f")))
2588
+ .subscribe((value) => {
2589
+ listener(value);
2590
+ });
2580
2591
  }
2581
2592
  updateBreakpoint(breakpoint) {
2582
2593
  this._currentBreakpoint = breakpoint;
2583
- this._currentBreakpointObservable.next(breakpoint);
2594
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f").next(breakpoint);
2584
2595
  }
2585
2596
  checkBreakpoint(width) {
2586
- var _a;
2587
- return (_a = this._breakpoints.find((breakpoint) => breakpoint.check(width))) === null || _a === void 0 ? void 0 : _a.name;
2597
+ const breakpoint = __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_breakpoints, "f").find((breakpoint) => breakpoint.check(width));
2598
+ /* istanbul ignore else */
2599
+ if (breakpoint) {
2600
+ return breakpoint.name;
2601
+ }
2602
+ }
2603
+ checkWidth(element) {
2604
+ const width = element.nativeElement.offsetWidth || 0;
2605
+ const breakpoint = this.checkBreakpoint(width);
2606
+ /* istanbul ignore else */
2607
+ if (breakpoint !== this._currentBreakpoint) {
2608
+ this.updateBreakpoint(breakpoint);
2609
+ }
2588
2610
  }
2589
2611
  }
2612
+ _SkyResizeObserverMediaQueryService_breakpoints = new WeakMap(), _SkyResizeObserverMediaQueryService_currentBreakpointObservable = new WeakMap(), _SkyResizeObserverMediaQueryService_stopListening = new WeakMap(), _SkyResizeObserverMediaQueryService_target = new WeakMap();
2590
2613
  SkyResizeObserverMediaQueryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyResizeObserverMediaQueryService, deps: [{ token: SkyResizeObserverService }], target: i0.ɵɵFactoryTarget.Injectable });
2591
2614
  SkyResizeObserverMediaQueryService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyResizeObserverMediaQueryService, providedIn: 'any' });
2592
2615
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyResizeObserverMediaQueryService, decorators: [{
@@ -2617,8 +2640,7 @@ class SkyScrollableHostService {
2617
2640
  /**
2618
2641
  * Returns an observable which emits the given element's current scrollable host
2619
2642
  * @param elementRef The element whose scrollable host is being requested
2620
- * @param completionObservable An observable which alerts the internal observers that they should complete
2621
- * @returns An observable which emits the current scrollable host
2643
+ * @returns An observable which emits the current scrollable host element.
2622
2644
  * @internal
2623
2645
  */
2624
2646
  watchScrollableHost(elementRef) {
@@ -2628,11 +2650,13 @@ class SkyScrollableHostService {
2628
2650
  return new Observable((subscriber) => {
2629
2651
  subscribers.push(subscriber);
2630
2652
  let scrollableHost = this.findScrollableHost(elementRef.nativeElement);
2653
+ // Setup mutation observers only once, for all subscribers.
2631
2654
  if (subscribers.length === 1) {
2632
2655
  parentMutationObserver = this.mutationObserverSvc.create(() => {
2633
2656
  const newScrollableHost = this.findScrollableHost(elementRef.nativeElement);
2657
+ // Reset observer if scrollable host changes.
2634
2658
  if (newScrollableHost !== scrollableHost &&
2635
- elementRef.nativeElement.offsetParent) {
2659
+ this.isElementVisible(elementRef)) {
2636
2660
  scrollableHost = newScrollableHost;
2637
2661
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2638
2662
  notifySubscribers(subscribers, scrollableHost);
@@ -2640,7 +2664,9 @@ class SkyScrollableHostService {
2640
2664
  });
2641
2665
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2642
2666
  documentHiddenElementMutationObserver = this.mutationObserverSvc.create(() => {
2643
- if (scrollableHost && !elementRef.nativeElement.offsetParent) {
2667
+ if (scrollableHost && !this.isElementVisible(elementRef)) {
2668
+ // If the scrollable host is not visible, set it to undefined and unsubscribe from its mutation changes.
2669
+ // Then, observe the document element so that a new scrollable host can be found.
2644
2670
  scrollableHost = undefined;
2645
2671
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2646
2672
  notifySubscribers(subscribers, scrollableHost);
@@ -2648,10 +2674,11 @@ class SkyScrollableHostService {
2648
2674
  });
2649
2675
  this.observeDocumentHiddenElementChanges(documentHiddenElementMutationObserver);
2650
2676
  }
2677
+ // Emit the scrollable host to the subscriber.
2651
2678
  subscriber.next(scrollableHost);
2679
+ // Teardown callback for the subscription.
2652
2680
  subscriber.add(() => {
2653
2681
  const subIndex = subscribers.indexOf(subscriber);
2654
- /* sanity check */
2655
2682
  /* istanbul ignore else */
2656
2683
  if (subIndex >= 0) {
2657
2684
  subscribers.splice(subIndex, 1);
@@ -2666,7 +2693,6 @@ class SkyScrollableHostService {
2666
2693
  /**
2667
2694
  * Returns an observable which emits whenever the element's scrollable host emits a scroll event. The observable will always emit the scroll events from the elements current scrollable host and will update based on any scrollable host changes. The observable will also emit once whenever the scrollable host changes.
2668
2695
  * @param elementRef The element whose scrollable host scroll events are being requested
2669
- * @param completionObservable An observable which alerts the internal observers that they should complete
2670
2696
  * @returns An observable which emits when the elements scrollable host is scrolled or is changed
2671
2697
  */
2672
2698
  watchScrollableHostScrollEvents(elementRef) {
@@ -2677,6 +2703,7 @@ class SkyScrollableHostService {
2677
2703
  let scrollEventSubscription;
2678
2704
  return new Observable((subscriber) => {
2679
2705
  subscribers.push(subscriber);
2706
+ // Setup mutation observers only once, for all subscribers.
2680
2707
  if (subscribers.length === 1) {
2681
2708
  scrollableHostSubscription = this.watchScrollableHost(elementRef).subscribe((newScrollableHost) => {
2682
2709
  newScrollableHostObservable.next();
@@ -2686,6 +2713,8 @@ class SkyScrollableHostService {
2686
2713
  }
2687
2714
  scrollableHost = newScrollableHost;
2688
2715
  newScrollableHostObservable = new Subject();
2716
+ // Only subscribe to scroll events if the host element is defined.
2717
+ /* istanbul ignore else */
2689
2718
  if (newScrollableHost) {
2690
2719
  scrollEventSubscription = fromEvent(newScrollableHost, 'scroll')
2691
2720
  .pipe(takeUntil(newScrollableHostObservable))
@@ -2695,9 +2724,9 @@ class SkyScrollableHostService {
2695
2724
  }
2696
2725
  });
2697
2726
  }
2727
+ // Teardown callback for the subscription.
2698
2728
  subscriber.add(() => {
2699
2729
  const subIndex = subscribers.indexOf(subscriber);
2700
- /* sanity check */
2701
2730
  /* istanbul ignore else */
2702
2731
  if (subIndex >= 0) {
2703
2732
  subscribers.splice(subIndex, 1);
@@ -2714,7 +2743,6 @@ class SkyScrollableHostService {
2714
2743
  const regex = /(auto|scroll)/;
2715
2744
  const windowObj = this.windowRef.nativeWindow;
2716
2745
  const bodyObj = windowObj.document.body;
2717
- /* Sanity check */
2718
2746
  if (!element) {
2719
2747
  return windowObj;
2720
2748
  }
@@ -2722,7 +2750,7 @@ class SkyScrollableHostService {
2722
2750
  let parent = element;
2723
2751
  do {
2724
2752
  parent = parent.parentNode;
2725
- /* Sanity check for if this function is called for an element which has been removed from the DOM */
2753
+ // Return `window` if the parent element has been removed from the DOM.
2726
2754
  if (!(parent instanceof HTMLElement)) {
2727
2755
  return windowObj;
2728
2756
  }
@@ -2745,22 +2773,20 @@ class SkyScrollableHostService {
2745
2773
  }
2746
2774
  observeForScrollableHostChanges(element, mutationObserver) {
2747
2775
  mutationObserver.disconnect();
2748
- if (element instanceof HTMLElement) {
2749
- mutationObserver.observe(element, {
2750
- attributes: true,
2751
- attributeFilter: ['class', 'style'],
2752
- childList: true,
2753
- subtree: true,
2754
- });
2755
- }
2756
- else {
2757
- mutationObserver.observe(document.documentElement, {
2758
- attributes: true,
2759
- attributeFilter: ['class', 'style'],
2760
- childList: true,
2761
- subtree: true,
2762
- });
2763
- }
2776
+ const target = element instanceof HTMLElement ? element : document.documentElement;
2777
+ mutationObserver.observe(target, {
2778
+ attributes: true,
2779
+ attributeFilter: ['class', 'style'],
2780
+ childList: true,
2781
+ subtree: true,
2782
+ });
2783
+ }
2784
+ /**
2785
+ * Determines if an element is "visible" in the DOM.
2786
+ * @see https://stackoverflow.com/a/11639664/6178885
2787
+ */
2788
+ isElementVisible(elementRef) {
2789
+ return elementRef.nativeElement.offsetParent;
2764
2790
  }
2765
2791
  }
2766
2792
  SkyScrollableHostService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: SkyScrollableHostService, deps: [{ token: MutationObserverService }, { token: SkyAppWindowRef }], target: i0.ɵɵFactoryTarget.Injectable });