@skyux/core 6.0.0 → 6.1.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 (31) hide show
  1. package/documentation.json +137 -134
  2. package/esm2020/lib/modules/adapter-service/adapter.service.mjs +11 -7
  3. package/esm2020/lib/modules/affix/affix.service.mjs +7 -3
  4. package/esm2020/lib/modules/numeric/numeric.pipe.mjs +4 -5
  5. package/esm2020/lib/modules/numeric/numeric.service.mjs +2 -2
  6. package/esm2020/lib/modules/resize-observer/resize-observer-media-query.service.mjs +42 -29
  7. package/esm2020/lib/modules/resize-observer/resize-observer.service.mjs +17 -11
  8. package/esm2020/lib/modules/scrollable-host/scrollable-host.service.mjs +29 -26
  9. package/esm2020/testing/core-testing.module.mjs +29 -0
  10. package/esm2020/testing/mock-media-query.service.mjs +3 -1
  11. package/esm2020/testing/mock-ui-config.service.mjs +1 -1
  12. package/esm2020/testing/public-api.mjs +2 -1
  13. package/fesm2015/skyux-core-testing.mjs +28 -2
  14. package/fesm2015/skyux-core-testing.mjs.map +1 -1
  15. package/fesm2015/skyux-core.mjs +102 -77
  16. package/fesm2015/skyux-core.mjs.map +1 -1
  17. package/fesm2020/skyux-core-testing.mjs +28 -2
  18. package/fesm2020/skyux-core-testing.mjs.map +1 -1
  19. package/fesm2020/skyux-core.mjs +102 -76
  20. package/fesm2020/skyux-core.mjs.map +1 -1
  21. package/lib/modules/adapter-service/adapter.service.d.ts +1 -1
  22. package/lib/modules/affix/affix.service.d.ts +1 -1
  23. package/lib/modules/numeric/numeric.pipe.d.ts +3 -4
  24. package/lib/modules/numeric/numeric.service.d.ts +1 -1
  25. package/lib/modules/resize-observer/resize-observer-media-query.service.d.ts +2 -4
  26. package/lib/modules/resize-observer/resize-observer.service.d.ts +1 -2
  27. package/lib/modules/scrollable-host/scrollable-host.service.d.ts +7 -4
  28. package/package.json +2 -2
  29. package/testing/core-testing.module.d.ts +6 -0
  30. package/testing/mock-ui-config.service.d.ts +2 -1
  31. package/testing/public-api.d.ts +1 -0
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { NgModule, Injectable, EventEmitter, Directive, Input, Output, Injector, ViewContainerRef, Component, ChangeDetectionStrategy, ViewChild, InjectionToken, Optional, Inject, Pipe, ElementRef } from '@angular/core';
3
+ import { __classPrivateFieldSet, __classPrivateFieldGet, __awaiter } 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';
6
7
  import { takeUntil, debounceTime, finalize } from 'rxjs/operators';
7
- import { __awaiter } from 'tslib';
8
8
  import * as i1 from '@skyux/i18n';
9
9
  import { getLibStringForLocale, SkyI18nModule, SKY_LIB_RESOURCES_PROVIDERS, SkyIntlNumberFormatStyle, SkyIntlNumberFormatter } from '@skyux/i18n';
10
10
  import * as i3 from '@angular/router';
@@ -45,6 +45,7 @@ var SkyMediaBreakpoints;
45
45
  SkyMediaBreakpoints[SkyMediaBreakpoints["lg"] = 4] = "lg";
46
46
  })(SkyMediaBreakpoints || (SkyMediaBreakpoints = {}));
47
47
 
48
+ var _SkyCoreAdapterService_renderer;
48
49
  const SKY_TABBABLE_SELECTOR = [
49
50
  'a[href]',
50
51
  'area[href]',
@@ -61,7 +62,8 @@ const SKY_TABBABLE_SELECTOR = [
61
62
  class SkyCoreAdapterService {
62
63
  constructor(rendererFactory) {
63
64
  this.rendererFactory = rendererFactory;
64
- 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");
65
67
  }
66
68
  /**
67
69
  * Set the responsive container CSS class for a given element.
@@ -72,10 +74,10 @@ class SkyCoreAdapterService {
72
74
  */
73
75
  setResponsiveContainerClass(elementRef, breakpoint) {
74
76
  const nativeEl = elementRef.nativeElement;
75
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-xs');
76
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-sm');
77
- this.renderer.removeClass(nativeEl, 'sky-responsive-container-md');
78
- 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');
79
81
  let newClass;
80
82
  switch (breakpoint) {
81
83
  case SkyMediaBreakpoints.xs: {
@@ -95,7 +97,7 @@ class SkyCoreAdapterService {
95
97
  break;
96
98
  }
97
99
  }
98
- this.renderer.addClass(nativeEl, newClass);
100
+ __classPrivateFieldGet(this, _SkyCoreAdapterService_renderer, "f").addClass(nativeEl, newClass);
99
101
  }
100
102
  /**
101
103
  * This method temporarily enables/disables pointer events.
@@ -258,6 +260,7 @@ class SkyCoreAdapterService {
258
260
  return hasBounds;
259
261
  }
260
262
  }
263
+ _SkyCoreAdapterService_renderer = new WeakMap();
261
264
  SkyCoreAdapterService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyCoreAdapterService, deps: [{ token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
262
265
  SkyCoreAdapterService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyCoreAdapterService, providedIn: 'root' });
263
266
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyCoreAdapterService, decorators: [{
@@ -716,18 +719,21 @@ class SkyAffixer {
716
719
  }
717
720
  }
718
721
 
722
+ var _SkyAffixService_renderer;
719
723
  class SkyAffixService {
720
724
  constructor(rendererFactory) {
721
- this.renderer = rendererFactory.createRenderer(undefined, undefined);
725
+ _SkyAffixService_renderer.set(this, void 0);
726
+ __classPrivateFieldSet(this, _SkyAffixService_renderer, rendererFactory.createRenderer(undefined, null), "f");
722
727
  }
723
728
  /**
724
729
  * Creates an instance of [[SkyAffixer]].
725
730
  * @param affixed The element to be affixed.
726
731
  */
727
732
  createAffixer(affixed) {
728
- return new SkyAffixer(affixed.nativeElement, this.renderer);
733
+ return new SkyAffixer(affixed.nativeElement, __classPrivateFieldGet(this, _SkyAffixService_renderer, "f"));
729
734
  }
730
735
  }
736
+ _SkyAffixService_renderer = new WeakMap();
731
737
  SkyAffixService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyAffixService, deps: [{ token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
732
738
  SkyAffixService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyAffixService, providedIn: 'root' });
733
739
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyAffixService, decorators: [{
@@ -1816,7 +1822,7 @@ class SkyNumericService {
1816
1822
  return this._locale || 'en-US';
1817
1823
  }
1818
1824
  /**
1819
- * Shortens with or without symbol (K/M/B/T) depending on value of number.
1825
+ * Formats a number based on the provided options.
1820
1826
  * @param value The number to format.
1821
1827
  * @param options Format options.
1822
1828
  */
@@ -1982,10 +1988,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
1982
1988
  * M for millions, B for billions, and T for trillions. The pipe also formats for currency.
1983
1989
  * Be sure you have a space after the two curly brackets opening the pipe and
1984
1990
  * a space before the two curly brackets closing the pipe or it will not work.
1985
- * Usage:
1986
- * ```
1987
- * {{ value | skyNumeric(config) }}
1988
- * ```
1989
1991
  */
1990
1992
  class SkyNumericPipe {
1991
1993
  constructor(localeProvider, numericService, changeDetector) {
@@ -2006,6 +2008,9 @@ class SkyNumericPipe {
2006
2008
  this.ngUnsubscribe.next();
2007
2009
  this.ngUnsubscribe.complete();
2008
2010
  }
2011
+ /**
2012
+ * Formats a number based on the provided options.
2013
+ */
2009
2014
  transform(value, config) {
2010
2015
  const newCacheKey = (config ? JSON.stringify(config, Object.keys(config).sort()) : '') +
2011
2016
  `${value}_${(config === null || config === void 0 ? void 0 : config.locale) || this.providerLocale}`;
@@ -2488,19 +2493,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
2488
2493
  }]
2489
2494
  }] });
2490
2495
 
2496
+ var _SkyResizeObserverService_resizeObserver, _SkyResizeObserverService_tracking;
2491
2497
  /**
2492
2498
  * Service to create rxjs observables for changes to the content box dimensions of elements.
2493
2499
  */
2494
2500
  class SkyResizeObserverService {
2495
2501
  constructor(zone) {
2496
2502
  this.zone = zone;
2497
- this._tracking = [];
2498
- this._resizeObserver = new ResizeObserver((entries) => {
2503
+ _SkyResizeObserverService_resizeObserver.set(this, void 0);
2504
+ _SkyResizeObserverService_tracking.set(this, []);
2505
+ __classPrivateFieldSet(this, _SkyResizeObserverService_resizeObserver, new ResizeObserver((entries) => {
2499
2506
  entries.forEach((entry) => this.callback(entry));
2500
- });
2507
+ }), "f");
2501
2508
  }
2502
2509
  ngOnDestroy() {
2503
- this._resizeObserver.disconnect();
2510
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").disconnect();
2504
2511
  }
2505
2512
  /**
2506
2513
  * Create rxjs observable to get size changes for an element ref.
@@ -2509,22 +2516,22 @@ class SkyResizeObserverService {
2509
2516
  return this.observeAndTrack(element).subjectObservable;
2510
2517
  }
2511
2518
  observeAndTrack(element) {
2512
- const checkTracking = this._tracking.findIndex((value) => {
2519
+ const checkTracking = __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").findIndex((value) => {
2513
2520
  return !value.subject.closed && value.element === element.nativeElement;
2514
2521
  });
2515
2522
  if (checkTracking === -1) {
2516
- this._resizeObserver.observe(element.nativeElement);
2523
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").observe(element.nativeElement);
2517
2524
  }
2518
2525
  const subject = new Subject();
2519
2526
  const subjectObservable = subject.pipe(finalize(() => {
2520
2527
  // Are there any other tracking entries still watching this element?
2521
- const checkTracking = this._tracking.findIndex((value) => {
2528
+ const checkTracking = __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").findIndex((value) => {
2522
2529
  return (value.subject !== subject &&
2523
2530
  !value.subject.closed &&
2524
2531
  value.element === element.nativeElement);
2525
2532
  });
2526
2533
  if (checkTracking === -1) {
2527
- this._resizeObserver.unobserve(element.nativeElement);
2534
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").unobserve(element.nativeElement);
2528
2535
  }
2529
2536
  }));
2530
2537
  const tracking = {
@@ -2532,15 +2539,17 @@ class SkyResizeObserverService {
2532
2539
  subject,
2533
2540
  subjectObservable,
2534
2541
  };
2535
- this._tracking.push(tracking);
2542
+ __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").push(tracking);
2536
2543
  return tracking;
2537
2544
  }
2538
2545
  callback(entry) {
2539
- this._tracking
2546
+ __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f")
2540
2547
  .filter((value) => !(value.subject.closed || value.subject.isStopped))
2541
2548
  .forEach((value) => {
2542
2549
  /* istanbul ignore else */
2543
2550
  if (value.element === entry.target) {
2551
+ // Execute the callback within NgZone because Angular does not "monkey patch"
2552
+ // ResizeObserver like it does for other features in the DOM.
2544
2553
  this.zone.run(() => {
2545
2554
  value.subject.next(entry);
2546
2555
  });
@@ -2548,6 +2557,7 @@ class SkyResizeObserverService {
2548
2557
  });
2549
2558
  }
2550
2559
  }
2560
+ _SkyResizeObserverService_resizeObserver = new WeakMap(), _SkyResizeObserverService_tracking = new WeakMap();
2551
2561
  SkyResizeObserverService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
2552
2562
  SkyResizeObserverService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverService, providedIn: 'any' });
2553
2563
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverService, decorators: [{
@@ -2557,15 +2567,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
2557
2567
  }]
2558
2568
  }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
2559
2569
 
2570
+ var _SkyResizeObserverMediaQueryService_breakpoints, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, _SkyResizeObserverMediaQueryService_stopListening, _SkyResizeObserverMediaQueryService_target;
2560
2571
  /**
2561
2572
  * Acts like `SkyMediaQueryService` for a container element, emitting the same responsive breakpoints.
2562
2573
  */
2563
2574
  class SkyResizeObserverMediaQueryService {
2564
2575
  constructor(resizeObserverService) {
2565
2576
  this.resizeObserverService = resizeObserverService;
2566
- this._breakpoints = [
2577
+ _SkyResizeObserverMediaQueryService_breakpoints.set(this, [
2567
2578
  {
2568
- check: (width) => width <= 767,
2579
+ check: (width) => width > 0 && width <= 767,
2569
2580
  name: SkyMediaBreakpoints.xs,
2570
2581
  },
2571
2582
  {
@@ -2580,11 +2591,12 @@ class SkyResizeObserverMediaQueryService {
2580
2591
  check: (width) => width > 1199,
2581
2592
  name: SkyMediaBreakpoints.lg,
2582
2593
  },
2583
- ];
2584
- this._currentBreakpointObservable = new ReplaySubject(1);
2585
- this._stopListening = new Subject();
2586
- this._stopListening.subscribe(() => {
2587
- this._target = undefined;
2594
+ ]);
2595
+ _SkyResizeObserverMediaQueryService_currentBreakpointObservable.set(this, new ReplaySubject(1));
2596
+ _SkyResizeObserverMediaQueryService_stopListening.set(this, new Subject());
2597
+ _SkyResizeObserverMediaQueryService_target.set(this, void 0);
2598
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").subscribe(() => {
2599
+ __classPrivateFieldSet(this, _SkyResizeObserverMediaQueryService_target, undefined, "f");
2588
2600
  this.updateBreakpoint(undefined);
2589
2601
  });
2590
2602
  }
@@ -2595,10 +2607,10 @@ class SkyResizeObserverMediaQueryService {
2595
2607
  return this._currentBreakpoint;
2596
2608
  }
2597
2609
  ngOnDestroy() {
2598
- this._stopListening.next();
2610
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2599
2611
  this._currentBreakpoint = undefined;
2600
- this._stopListening.complete();
2601
- this._currentBreakpointObservable.complete();
2612
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").complete();
2613
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f").complete();
2602
2614
  }
2603
2615
  /**
2604
2616
  * @internal
@@ -2611,25 +2623,21 @@ class SkyResizeObserverMediaQueryService {
2611
2623
  * time. Any previous subscriptions will be unsubscribed when a new element is observed.
2612
2624
  */
2613
2625
  observe(element) {
2614
- if (this._target) {
2615
- if (this._target === element) {
2626
+ if (__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_target, "f")) {
2627
+ if (__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_target, "f") === element) {
2616
2628
  return this;
2617
2629
  }
2618
- this._stopListening.next();
2619
- }
2620
- this._target = element;
2621
- const width = element.nativeElement.offsetWidth;
2622
- if (width) {
2623
- const breakpoint = this.checkBreakpoint(width);
2624
- this.updateBreakpoint(breakpoint);
2630
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2625
2631
  }
2632
+ __classPrivateFieldSet(this, _SkyResizeObserverMediaQueryService_target, element, "f");
2633
+ this.checkWidth(element);
2626
2634
  this.resizeObserverService
2627
2635
  .observe(element)
2628
- .pipe(takeUntil(this._stopListening))
2636
+ .pipe(takeUntil(__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f")))
2629
2637
  .subscribe((value) => {
2630
2638
  const breakpoint = this.checkBreakpoint(value.contentRect.width);
2631
2639
  /* istanbul ignore else */
2632
- if (breakpoint !== this._currentBreakpoint) {
2640
+ if (breakpoint !== this.current) {
2633
2641
  this.updateBreakpoint(breakpoint);
2634
2642
  }
2635
2643
  });
@@ -2639,25 +2647,39 @@ class SkyResizeObserverMediaQueryService {
2639
2647
  * Stop watching the container element.
2640
2648
  */
2641
2649
  unobserve() {
2642
- this._stopListening.next();
2650
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2643
2651
  }
2644
2652
  /**
2645
2653
  * Subscribes to element size changes that cross breakpoints.
2646
2654
  */
2647
2655
  subscribe(listener) {
2648
- return this._currentBreakpointObservable
2649
- .pipe(takeUntil(this._stopListening))
2650
- .subscribe(listener);
2656
+ return __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f")
2657
+ .pipe(takeUntil(__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f")))
2658
+ .subscribe((value) => {
2659
+ listener(value);
2660
+ });
2651
2661
  }
2652
2662
  updateBreakpoint(breakpoint) {
2653
2663
  this._currentBreakpoint = breakpoint;
2654
- this._currentBreakpointObservable.next(breakpoint);
2664
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f").next(breakpoint);
2655
2665
  }
2656
2666
  checkBreakpoint(width) {
2657
- var _a;
2658
- return (_a = this._breakpoints.find((breakpoint) => breakpoint.check(width))) === null || _a === void 0 ? void 0 : _a.name;
2667
+ const breakpoint = __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_breakpoints, "f").find((breakpoint) => breakpoint.check(width));
2668
+ /* istanbul ignore else */
2669
+ if (breakpoint) {
2670
+ return breakpoint.name;
2671
+ }
2672
+ }
2673
+ checkWidth(element) {
2674
+ const width = element.nativeElement.offsetWidth || 0;
2675
+ const breakpoint = this.checkBreakpoint(width);
2676
+ /* istanbul ignore else */
2677
+ if (breakpoint !== this._currentBreakpoint) {
2678
+ this.updateBreakpoint(breakpoint);
2679
+ }
2659
2680
  }
2660
2681
  }
2682
+ _SkyResizeObserverMediaQueryService_breakpoints = new WeakMap(), _SkyResizeObserverMediaQueryService_currentBreakpointObservable = new WeakMap(), _SkyResizeObserverMediaQueryService_stopListening = new WeakMap(), _SkyResizeObserverMediaQueryService_target = new WeakMap();
2661
2683
  SkyResizeObserverMediaQueryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverMediaQueryService, deps: [{ token: SkyResizeObserverService }], target: i0.ɵɵFactoryTarget.Injectable });
2662
2684
  SkyResizeObserverMediaQueryService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverMediaQueryService, providedIn: 'any' });
2663
2685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverMediaQueryService, decorators: [{
@@ -2688,8 +2710,7 @@ class SkyScrollableHostService {
2688
2710
  /**
2689
2711
  * Returns an observable which emits the given element's current scrollable host
2690
2712
  * @param elementRef The element whose scrollable host is being requested
2691
- * @param completionObservable An observable which alerts the internal observers that they should complete
2692
- * @returns An observable which emits the current scrollable host
2713
+ * @returns An observable which emits the current scrollable host element.
2693
2714
  * @internal
2694
2715
  */
2695
2716
  watchScrollableHost(elementRef) {
@@ -2699,11 +2720,13 @@ class SkyScrollableHostService {
2699
2720
  return new Observable((subscriber) => {
2700
2721
  subscribers.push(subscriber);
2701
2722
  let scrollableHost = this.findScrollableHost(elementRef.nativeElement);
2723
+ // Setup mutation observers only once, for all subscribers.
2702
2724
  if (subscribers.length === 1) {
2703
2725
  parentMutationObserver = this.mutationObserverSvc.create(() => {
2704
2726
  const newScrollableHost = this.findScrollableHost(elementRef.nativeElement);
2727
+ // Reset observer if scrollable host changes.
2705
2728
  if (newScrollableHost !== scrollableHost &&
2706
- elementRef.nativeElement.offsetParent) {
2729
+ this.isElementVisible(elementRef)) {
2707
2730
  scrollableHost = newScrollableHost;
2708
2731
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2709
2732
  notifySubscribers(subscribers, scrollableHost);
@@ -2711,7 +2734,9 @@ class SkyScrollableHostService {
2711
2734
  });
2712
2735
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2713
2736
  documentHiddenElementMutationObserver = this.mutationObserverSvc.create(() => {
2714
- if (scrollableHost && !elementRef.nativeElement.offsetParent) {
2737
+ if (scrollableHost && !this.isElementVisible(elementRef)) {
2738
+ // If the scrollable host is not visible, set it to undefined and unsubscribe from its mutation changes.
2739
+ // Then, observe the document element so that a new scrollable host can be found.
2715
2740
  scrollableHost = undefined;
2716
2741
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2717
2742
  notifySubscribers(subscribers, scrollableHost);
@@ -2719,10 +2744,11 @@ class SkyScrollableHostService {
2719
2744
  });
2720
2745
  this.observeDocumentHiddenElementChanges(documentHiddenElementMutationObserver);
2721
2746
  }
2747
+ // Emit the scrollable host to the subscriber.
2722
2748
  subscriber.next(scrollableHost);
2749
+ // Teardown callback for the subscription.
2723
2750
  subscriber.add(() => {
2724
2751
  const subIndex = subscribers.indexOf(subscriber);
2725
- /* sanity check */
2726
2752
  /* istanbul ignore else */
2727
2753
  if (subIndex >= 0) {
2728
2754
  subscribers.splice(subIndex, 1);
@@ -2737,7 +2763,6 @@ class SkyScrollableHostService {
2737
2763
  /**
2738
2764
  * 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.
2739
2765
  * @param elementRef The element whose scrollable host scroll events are being requested
2740
- * @param completionObservable An observable which alerts the internal observers that they should complete
2741
2766
  * @returns An observable which emits when the elements scrollable host is scrolled or is changed
2742
2767
  */
2743
2768
  watchScrollableHostScrollEvents(elementRef) {
@@ -2748,6 +2773,7 @@ class SkyScrollableHostService {
2748
2773
  let scrollEventSubscription;
2749
2774
  return new Observable((subscriber) => {
2750
2775
  subscribers.push(subscriber);
2776
+ // Setup mutation observers only once, for all subscribers.
2751
2777
  if (subscribers.length === 1) {
2752
2778
  scrollableHostSubscription = this.watchScrollableHost(elementRef).subscribe((newScrollableHost) => {
2753
2779
  newScrollableHostObservable.next();
@@ -2757,6 +2783,8 @@ class SkyScrollableHostService {
2757
2783
  }
2758
2784
  scrollableHost = newScrollableHost;
2759
2785
  newScrollableHostObservable = new Subject();
2786
+ // Only subscribe to scroll events if the host element is defined.
2787
+ /* istanbul ignore else */
2760
2788
  if (newScrollableHost) {
2761
2789
  scrollEventSubscription = fromEvent(newScrollableHost, 'scroll')
2762
2790
  .pipe(takeUntil(newScrollableHostObservable))
@@ -2766,9 +2794,9 @@ class SkyScrollableHostService {
2766
2794
  }
2767
2795
  });
2768
2796
  }
2797
+ // Teardown callback for the subscription.
2769
2798
  subscriber.add(() => {
2770
2799
  const subIndex = subscribers.indexOf(subscriber);
2771
- /* sanity check */
2772
2800
  /* istanbul ignore else */
2773
2801
  if (subIndex >= 0) {
2774
2802
  subscribers.splice(subIndex, 1);
@@ -2785,7 +2813,6 @@ class SkyScrollableHostService {
2785
2813
  const regex = /(auto|scroll)/;
2786
2814
  const windowObj = this.windowRef.nativeWindow;
2787
2815
  const bodyObj = windowObj.document.body;
2788
- /* Sanity check */
2789
2816
  if (!element) {
2790
2817
  return windowObj;
2791
2818
  }
@@ -2793,7 +2820,7 @@ class SkyScrollableHostService {
2793
2820
  let parent = element;
2794
2821
  do {
2795
2822
  parent = parent.parentNode;
2796
- /* Sanity check for if this function is called for an element which has been removed from the DOM */
2823
+ // Return `window` if the parent element has been removed from the DOM.
2797
2824
  if (!(parent instanceof HTMLElement)) {
2798
2825
  return windowObj;
2799
2826
  }
@@ -2816,22 +2843,20 @@ class SkyScrollableHostService {
2816
2843
  }
2817
2844
  observeForScrollableHostChanges(element, mutationObserver) {
2818
2845
  mutationObserver.disconnect();
2819
- if (element instanceof HTMLElement) {
2820
- mutationObserver.observe(element, {
2821
- attributes: true,
2822
- attributeFilter: ['class', 'style'],
2823
- childList: true,
2824
- subtree: true,
2825
- });
2826
- }
2827
- else {
2828
- mutationObserver.observe(document.documentElement, {
2829
- attributes: true,
2830
- attributeFilter: ['class', 'style'],
2831
- childList: true,
2832
- subtree: true,
2833
- });
2834
- }
2846
+ const target = element instanceof HTMLElement ? element : document.documentElement;
2847
+ mutationObserver.observe(target, {
2848
+ attributes: true,
2849
+ attributeFilter: ['class', 'style'],
2850
+ childList: true,
2851
+ subtree: true,
2852
+ });
2853
+ }
2854
+ /**
2855
+ * Determines if an element is "visible" in the DOM.
2856
+ * @see https://stackoverflow.com/a/11639664/6178885
2857
+ */
2858
+ isElementVisible(elementRef) {
2859
+ return elementRef.nativeElement.offsetParent;
2835
2860
  }
2836
2861
  }
2837
2862
  SkyScrollableHostService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyScrollableHostService, deps: [{ token: MutationObserverService }, { token: SkyAppWindowRef }], target: i0.ɵɵFactoryTarget.Injectable });