@skyux/core 6.0.1 → 6.2.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 (27) hide show
  1. package/documentation.json +104 -104
  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/resize-observer/resize-observer-media-query.service.mjs +29 -22
  5. package/esm2020/lib/modules/resize-observer/resize-observer.service.mjs +17 -11
  6. package/esm2020/lib/modules/scrollable-host/scrollable-host.service.mjs +29 -26
  7. package/esm2020/testing/core-testing.module.mjs +29 -0
  8. package/esm2020/testing/mock-media-query.service.mjs +3 -1
  9. package/esm2020/testing/mock-ui-config.service.mjs +1 -1
  10. package/esm2020/testing/public-api.mjs +2 -1
  11. package/fesm2015/skyux-core-testing.mjs +28 -2
  12. package/fesm2015/skyux-core-testing.mjs.map +1 -1
  13. package/fesm2015/skyux-core.mjs +85 -65
  14. package/fesm2015/skyux-core.mjs.map +1 -1
  15. package/fesm2020/skyux-core-testing.mjs +28 -2
  16. package/fesm2020/skyux-core-testing.mjs.map +1 -1
  17. package/fesm2020/skyux-core.mjs +85 -64
  18. package/fesm2020/skyux-core.mjs.map +1 -1
  19. package/lib/modules/adapter-service/adapter.service.d.ts +1 -1
  20. package/lib/modules/affix/affix.service.d.ts +1 -1
  21. package/lib/modules/resize-observer/resize-observer-media-query.service.d.ts +1 -4
  22. package/lib/modules/resize-observer/resize-observer.service.d.ts +1 -2
  23. package/lib/modules/scrollable-host/scrollable-host.service.d.ts +7 -4
  24. package/package.json +2 -2
  25. package/testing/core-testing.module.d.ts +6 -0
  26. package/testing/mock-ui-config.service.d.ts +2 -1
  27. 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: [{
@@ -2487,19 +2493,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
2487
2493
  }]
2488
2494
  }] });
2489
2495
 
2496
+ var _SkyResizeObserverService_resizeObserver, _SkyResizeObserverService_tracking;
2490
2497
  /**
2491
2498
  * Service to create rxjs observables for changes to the content box dimensions of elements.
2492
2499
  */
2493
2500
  class SkyResizeObserverService {
2494
2501
  constructor(zone) {
2495
2502
  this.zone = zone;
2496
- this._tracking = [];
2497
- 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) => {
2498
2506
  entries.forEach((entry) => this.callback(entry));
2499
- });
2507
+ }), "f");
2500
2508
  }
2501
2509
  ngOnDestroy() {
2502
- this._resizeObserver.disconnect();
2510
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").disconnect();
2503
2511
  }
2504
2512
  /**
2505
2513
  * Create rxjs observable to get size changes for an element ref.
@@ -2508,22 +2516,22 @@ class SkyResizeObserverService {
2508
2516
  return this.observeAndTrack(element).subjectObservable;
2509
2517
  }
2510
2518
  observeAndTrack(element) {
2511
- const checkTracking = this._tracking.findIndex((value) => {
2519
+ const checkTracking = __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").findIndex((value) => {
2512
2520
  return !value.subject.closed && value.element === element.nativeElement;
2513
2521
  });
2514
2522
  if (checkTracking === -1) {
2515
- this._resizeObserver.observe(element.nativeElement);
2523
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").observe(element.nativeElement);
2516
2524
  }
2517
2525
  const subject = new Subject();
2518
2526
  const subjectObservable = subject.pipe(finalize(() => {
2519
2527
  // Are there any other tracking entries still watching this element?
2520
- const checkTracking = this._tracking.findIndex((value) => {
2528
+ const checkTracking = __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").findIndex((value) => {
2521
2529
  return (value.subject !== subject &&
2522
2530
  !value.subject.closed &&
2523
2531
  value.element === element.nativeElement);
2524
2532
  });
2525
2533
  if (checkTracking === -1) {
2526
- this._resizeObserver.unobserve(element.nativeElement);
2534
+ __classPrivateFieldGet(this, _SkyResizeObserverService_resizeObserver, "f").unobserve(element.nativeElement);
2527
2535
  }
2528
2536
  }));
2529
2537
  const tracking = {
@@ -2531,15 +2539,17 @@ class SkyResizeObserverService {
2531
2539
  subject,
2532
2540
  subjectObservable,
2533
2541
  };
2534
- this._tracking.push(tracking);
2542
+ __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f").push(tracking);
2535
2543
  return tracking;
2536
2544
  }
2537
2545
  callback(entry) {
2538
- this._tracking
2546
+ __classPrivateFieldGet(this, _SkyResizeObserverService_tracking, "f")
2539
2547
  .filter((value) => !(value.subject.closed || value.subject.isStopped))
2540
2548
  .forEach((value) => {
2541
2549
  /* istanbul ignore else */
2542
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.
2543
2553
  this.zone.run(() => {
2544
2554
  value.subject.next(entry);
2545
2555
  });
@@ -2547,6 +2557,7 @@ class SkyResizeObserverService {
2547
2557
  });
2548
2558
  }
2549
2559
  }
2560
+ _SkyResizeObserverService_resizeObserver = new WeakMap(), _SkyResizeObserverService_tracking = new WeakMap();
2550
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 });
2551
2562
  SkyResizeObserverService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverService, providedIn: 'any' });
2552
2563
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverService, decorators: [{
@@ -2556,13 +2567,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImpor
2556
2567
  }]
2557
2568
  }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
2558
2569
 
2570
+ var _SkyResizeObserverMediaQueryService_breakpoints, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, _SkyResizeObserverMediaQueryService_stopListening, _SkyResizeObserverMediaQueryService_target;
2559
2571
  /**
2560
2572
  * Acts like `SkyMediaQueryService` for a container element, emitting the same responsive breakpoints.
2561
2573
  */
2562
2574
  class SkyResizeObserverMediaQueryService {
2563
2575
  constructor(resizeObserverService) {
2564
2576
  this.resizeObserverService = resizeObserverService;
2565
- this._breakpoints = [
2577
+ _SkyResizeObserverMediaQueryService_breakpoints.set(this, [
2566
2578
  {
2567
2579
  check: (width) => width > 0 && width <= 767,
2568
2580
  name: SkyMediaBreakpoints.xs,
@@ -2579,11 +2591,12 @@ class SkyResizeObserverMediaQueryService {
2579
2591
  check: (width) => width > 1199,
2580
2592
  name: SkyMediaBreakpoints.lg,
2581
2593
  },
2582
- ];
2583
- this._currentBreakpointObservable = new ReplaySubject(1);
2584
- this._stopListening = new Subject();
2585
- this._stopListening.subscribe(() => {
2586
- 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");
2587
2600
  this.updateBreakpoint(undefined);
2588
2601
  });
2589
2602
  }
@@ -2594,10 +2607,10 @@ class SkyResizeObserverMediaQueryService {
2594
2607
  return this._currentBreakpoint;
2595
2608
  }
2596
2609
  ngOnDestroy() {
2597
- this._stopListening.next();
2610
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2598
2611
  this._currentBreakpoint = undefined;
2599
- this._stopListening.complete();
2600
- this._currentBreakpointObservable.complete();
2612
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").complete();
2613
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f").complete();
2601
2614
  }
2602
2615
  /**
2603
2616
  * @internal
@@ -2610,21 +2623,21 @@ class SkyResizeObserverMediaQueryService {
2610
2623
  * time. Any previous subscriptions will be unsubscribed when a new element is observed.
2611
2624
  */
2612
2625
  observe(element) {
2613
- if (this._target) {
2614
- if (this._target === element) {
2626
+ if (__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_target, "f")) {
2627
+ if (__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_target, "f") === element) {
2615
2628
  return this;
2616
2629
  }
2617
- this._stopListening.next();
2630
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2618
2631
  }
2619
- this._target = element;
2632
+ __classPrivateFieldSet(this, _SkyResizeObserverMediaQueryService_target, element, "f");
2620
2633
  this.checkWidth(element);
2621
2634
  this.resizeObserverService
2622
2635
  .observe(element)
2623
- .pipe(takeUntil(this._stopListening))
2636
+ .pipe(takeUntil(__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f")))
2624
2637
  .subscribe((value) => {
2625
2638
  const breakpoint = this.checkBreakpoint(value.contentRect.width);
2626
2639
  /* istanbul ignore else */
2627
- if (breakpoint !== this._currentBreakpoint) {
2640
+ if (breakpoint !== this.current) {
2628
2641
  this.updateBreakpoint(breakpoint);
2629
2642
  }
2630
2643
  });
@@ -2634,25 +2647,28 @@ class SkyResizeObserverMediaQueryService {
2634
2647
  * Stop watching the container element.
2635
2648
  */
2636
2649
  unobserve() {
2637
- this._stopListening.next();
2650
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f").next();
2638
2651
  }
2639
2652
  /**
2640
2653
  * Subscribes to element size changes that cross breakpoints.
2641
2654
  */
2642
2655
  subscribe(listener) {
2643
- return this._currentBreakpointObservable
2644
- .pipe(takeUntil(this._stopListening))
2656
+ return __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f")
2657
+ .pipe(takeUntil(__classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_stopListening, "f")))
2645
2658
  .subscribe((value) => {
2646
2659
  listener(value);
2647
2660
  });
2648
2661
  }
2649
2662
  updateBreakpoint(breakpoint) {
2650
2663
  this._currentBreakpoint = breakpoint;
2651
- this._currentBreakpointObservable.next(breakpoint);
2664
+ __classPrivateFieldGet(this, _SkyResizeObserverMediaQueryService_currentBreakpointObservable, "f").next(breakpoint);
2652
2665
  }
2653
2666
  checkBreakpoint(width) {
2654
- var _a;
2655
- 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
+ }
2656
2672
  }
2657
2673
  checkWidth(element) {
2658
2674
  const width = element.nativeElement.offsetWidth || 0;
@@ -2663,6 +2679,7 @@ class SkyResizeObserverMediaQueryService {
2663
2679
  }
2664
2680
  }
2665
2681
  }
2682
+ _SkyResizeObserverMediaQueryService_breakpoints = new WeakMap(), _SkyResizeObserverMediaQueryService_currentBreakpointObservable = new WeakMap(), _SkyResizeObserverMediaQueryService_stopListening = new WeakMap(), _SkyResizeObserverMediaQueryService_target = new WeakMap();
2666
2683
  SkyResizeObserverMediaQueryService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverMediaQueryService, deps: [{ token: SkyResizeObserverService }], target: i0.ɵɵFactoryTarget.Injectable });
2667
2684
  SkyResizeObserverMediaQueryService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverMediaQueryService, providedIn: 'any' });
2668
2685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: SkyResizeObserverMediaQueryService, decorators: [{
@@ -2693,8 +2710,7 @@ class SkyScrollableHostService {
2693
2710
  /**
2694
2711
  * Returns an observable which emits the given element's current scrollable host
2695
2712
  * @param elementRef The element whose scrollable host is being requested
2696
- * @param completionObservable An observable which alerts the internal observers that they should complete
2697
- * @returns An observable which emits the current scrollable host
2713
+ * @returns An observable which emits the current scrollable host element.
2698
2714
  * @internal
2699
2715
  */
2700
2716
  watchScrollableHost(elementRef) {
@@ -2704,11 +2720,13 @@ class SkyScrollableHostService {
2704
2720
  return new Observable((subscriber) => {
2705
2721
  subscribers.push(subscriber);
2706
2722
  let scrollableHost = this.findScrollableHost(elementRef.nativeElement);
2723
+ // Setup mutation observers only once, for all subscribers.
2707
2724
  if (subscribers.length === 1) {
2708
2725
  parentMutationObserver = this.mutationObserverSvc.create(() => {
2709
2726
  const newScrollableHost = this.findScrollableHost(elementRef.nativeElement);
2727
+ // Reset observer if scrollable host changes.
2710
2728
  if (newScrollableHost !== scrollableHost &&
2711
- elementRef.nativeElement.offsetParent) {
2729
+ this.isElementVisible(elementRef)) {
2712
2730
  scrollableHost = newScrollableHost;
2713
2731
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2714
2732
  notifySubscribers(subscribers, scrollableHost);
@@ -2716,7 +2734,9 @@ class SkyScrollableHostService {
2716
2734
  });
2717
2735
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2718
2736
  documentHiddenElementMutationObserver = this.mutationObserverSvc.create(() => {
2719
- 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.
2720
2740
  scrollableHost = undefined;
2721
2741
  this.observeForScrollableHostChanges(scrollableHost, parentMutationObserver);
2722
2742
  notifySubscribers(subscribers, scrollableHost);
@@ -2724,10 +2744,11 @@ class SkyScrollableHostService {
2724
2744
  });
2725
2745
  this.observeDocumentHiddenElementChanges(documentHiddenElementMutationObserver);
2726
2746
  }
2747
+ // Emit the scrollable host to the subscriber.
2727
2748
  subscriber.next(scrollableHost);
2749
+ // Teardown callback for the subscription.
2728
2750
  subscriber.add(() => {
2729
2751
  const subIndex = subscribers.indexOf(subscriber);
2730
- /* sanity check */
2731
2752
  /* istanbul ignore else */
2732
2753
  if (subIndex >= 0) {
2733
2754
  subscribers.splice(subIndex, 1);
@@ -2742,7 +2763,6 @@ class SkyScrollableHostService {
2742
2763
  /**
2743
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.
2744
2765
  * @param elementRef The element whose scrollable host scroll events are being requested
2745
- * @param completionObservable An observable which alerts the internal observers that they should complete
2746
2766
  * @returns An observable which emits when the elements scrollable host is scrolled or is changed
2747
2767
  */
2748
2768
  watchScrollableHostScrollEvents(elementRef) {
@@ -2753,6 +2773,7 @@ class SkyScrollableHostService {
2753
2773
  let scrollEventSubscription;
2754
2774
  return new Observable((subscriber) => {
2755
2775
  subscribers.push(subscriber);
2776
+ // Setup mutation observers only once, for all subscribers.
2756
2777
  if (subscribers.length === 1) {
2757
2778
  scrollableHostSubscription = this.watchScrollableHost(elementRef).subscribe((newScrollableHost) => {
2758
2779
  newScrollableHostObservable.next();
@@ -2762,6 +2783,8 @@ class SkyScrollableHostService {
2762
2783
  }
2763
2784
  scrollableHost = newScrollableHost;
2764
2785
  newScrollableHostObservable = new Subject();
2786
+ // Only subscribe to scroll events if the host element is defined.
2787
+ /* istanbul ignore else */
2765
2788
  if (newScrollableHost) {
2766
2789
  scrollEventSubscription = fromEvent(newScrollableHost, 'scroll')
2767
2790
  .pipe(takeUntil(newScrollableHostObservable))
@@ -2771,9 +2794,9 @@ class SkyScrollableHostService {
2771
2794
  }
2772
2795
  });
2773
2796
  }
2797
+ // Teardown callback for the subscription.
2774
2798
  subscriber.add(() => {
2775
2799
  const subIndex = subscribers.indexOf(subscriber);
2776
- /* sanity check */
2777
2800
  /* istanbul ignore else */
2778
2801
  if (subIndex >= 0) {
2779
2802
  subscribers.splice(subIndex, 1);
@@ -2790,7 +2813,6 @@ class SkyScrollableHostService {
2790
2813
  const regex = /(auto|scroll)/;
2791
2814
  const windowObj = this.windowRef.nativeWindow;
2792
2815
  const bodyObj = windowObj.document.body;
2793
- /* Sanity check */
2794
2816
  if (!element) {
2795
2817
  return windowObj;
2796
2818
  }
@@ -2798,7 +2820,7 @@ class SkyScrollableHostService {
2798
2820
  let parent = element;
2799
2821
  do {
2800
2822
  parent = parent.parentNode;
2801
- /* 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.
2802
2824
  if (!(parent instanceof HTMLElement)) {
2803
2825
  return windowObj;
2804
2826
  }
@@ -2821,22 +2843,20 @@ class SkyScrollableHostService {
2821
2843
  }
2822
2844
  observeForScrollableHostChanges(element, mutationObserver) {
2823
2845
  mutationObserver.disconnect();
2824
- if (element instanceof HTMLElement) {
2825
- mutationObserver.observe(element, {
2826
- attributes: true,
2827
- attributeFilter: ['class', 'style'],
2828
- childList: true,
2829
- subtree: true,
2830
- });
2831
- }
2832
- else {
2833
- mutationObserver.observe(document.documentElement, {
2834
- attributes: true,
2835
- attributeFilter: ['class', 'style'],
2836
- childList: true,
2837
- subtree: true,
2838
- });
2839
- }
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;
2840
2860
  }
2841
2861
  }
2842
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 });