@skyux/core 9.12.1 → 9.13.1

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.
@@ -2,8 +2,8 @@ import * as i0 from '@angular/core';
2
2
  import { NgModule, Injectable, inject, RendererFactory2, NgZone, EventEmitter, Directive, Input, Output, EnvironmentInjector, createEnvironmentInjector, createComponent, ChangeDetectorRef, ElementRef, ViewContainerRef, Component, ChangeDetectionStrategy, ViewChild, InjectionToken, Optional, Inject, Pipe, HostBinding, ApplicationRef, Renderer2 } from '@angular/core';
3
3
  import * as i1$1 from '@angular/common';
4
4
  import { DOCUMENT, CommonModule } from '@angular/common';
5
- import { Subject, Subscription, ReplaySubject, fromEvent, BehaviorSubject, Observable, of, concat, animationFrameScheduler } from 'rxjs';
6
- import { takeUntil, debounceTime, finalize, switchMap, map } from 'rxjs/operators';
5
+ import { Subject, Subscription, ReplaySubject, fromEvent, BehaviorSubject, Observable, filter, map, distinctUntilChanged, shareReplay, throttle, animationFrames, take, takeUntil as takeUntil$1, of, concat, animationFrameScheduler } from 'rxjs';
6
+ import { takeUntil, debounceTime, switchMap, map as map$1 } from 'rxjs/operators';
7
7
  import { ViewportRuler } from '@angular/cdk/overlay';
8
8
  import * as i1 from '@skyux/i18n';
9
9
  import { SkyLibResourcesService, getLibStringForLocale, SkyI18nModule, SKY_LIB_RESOURCES_PROVIDERS, SkyIntlNumberFormatStyle, SkyIntlNumberFormatter } from '@skyux/i18n';
@@ -546,7 +546,9 @@ class SkyAffixer {
546
546
  }
547
547
  }
548
548
  #getOffsetParentRect() {
549
- if (this.#affixedElement.offsetParent) {
549
+ // Firefox sets the offsetParent to document.body if the element uses fixed positioning.
550
+ if (this.#config.position === 'absolute' &&
551
+ this.#affixedElement.offsetParent) {
550
552
  return getOuterRect(this.#affixedElement.offsetParent);
551
553
  }
552
554
  else {
@@ -2988,80 +2990,106 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImpor
2988
2990
  }]
2989
2991
  }] });
2990
2992
 
2993
+ const errorTest = /ResizeObserver loop completed with undelivered notifications/i;
2994
+ let errorLogRegistered = false;
2995
+ let originalOnError = undefined;
2996
+ const errorHandler = (event) => {
2997
+ if (errorTest.test(event.message)) {
2998
+ event.stopImmediatePropagation();
2999
+ event.stopPropagation();
3000
+ event.preventDefault();
3001
+ return false;
3002
+ }
3003
+ return undefined;
3004
+ };
3005
+ const onError = (event) => {
3006
+ const message = typeof event === 'string' ? event : event.message;
3007
+ // This is necessary to prevent the test runner from failing on errors, but challenging to reliably test.
3008
+ /* istanbul ignore next */
3009
+ if (errorTest.test(message)) {
3010
+ if (event instanceof ErrorEvent) {
3011
+ event.stopImmediatePropagation();
3012
+ event.stopPropagation();
3013
+ event.preventDefault();
3014
+ }
3015
+ return false;
3016
+ }
3017
+ return originalOnError?.call(window, event);
3018
+ };
2991
3019
  /**
2992
3020
  * Service to create rxjs observables for changes to the content box dimensions of elements.
2993
3021
  */
2994
3022
  class SkyResizeObserverService {
2995
- #next = new Map();
2996
- #resizeObserver = new ResizeObserver((entries) => {
2997
- entries.forEach((entry) => this.#callback(entry));
2998
- });
2999
- #tracking = [];
3023
+ #ngUnsubscribe = new Subject();
3024
+ #resizeObserver = new ResizeObserver((entries) => this.#resizeSubject.next(entries));
3025
+ #resizeSubject = new Subject();
3026
+ #tracking = new Map();
3000
3027
  #window = inject(SkyAppWindowRef);
3001
3028
  #zone = inject(NgZone);
3029
+ constructor() {
3030
+ this.#expectWindowError();
3031
+ // Because the resize observer is a native browser API, it does not shut down
3032
+ // synchronously when the service is destroyed. Leave the error handling
3033
+ // accommodation in place until the application is destroyed. This also works
3034
+ // for the test runner.
3035
+ inject(ApplicationRef).onDestroy(() => this.#resetWindowError());
3036
+ }
3002
3037
  ngOnDestroy() {
3003
- this.#next.forEach((value) => this.#window.nativeWindow.cancelAnimationFrame(value));
3004
- this.#tracking.forEach((value) => {
3005
- value.subject.complete();
3006
- this.#resizeObserver.unobserve(value.element);
3007
- });
3038
+ this.#ngUnsubscribe.next();
3039
+ this.#ngUnsubscribe.complete();
3008
3040
  this.#resizeObserver.disconnect();
3009
3041
  }
3010
3042
  /**
3011
3043
  * Create rxjs observable to get size changes for an element ref.
3012
3044
  */
3013
3045
  observe(element) {
3014
- return this.#observeAndTrack(element).subjectObservable;
3015
- }
3016
- #observeAndTrack(element) {
3017
- const checkTracking = this.#tracking.findIndex((value) => {
3018
- return !value.subject.closed && value.element === element.nativeElement;
3019
- });
3020
- if (checkTracking === -1) {
3021
- this.#resizeObserver.observe(element.nativeElement);
3022
- }
3023
- const subject = new Subject();
3024
- const subjectObservable = subject.pipe(finalize(() => {
3025
- // Are there any other tracking entries still watching this element?
3026
- const checkTracking = this.#tracking.findIndex((value) => {
3027
- return (value.subject !== subject &&
3028
- !value.subject.closed &&
3029
- value.element === element.nativeElement);
3030
- });
3031
- if (checkTracking === -1) {
3032
- this.#resizeObserver.unobserve(element.nativeElement);
3033
- const deleteTracking = this.#tracking.findIndex((value) => value.subject === subject);
3034
- if (deleteTracking > -1) {
3035
- this.#tracking.splice(deleteTracking, 1);
3036
- }
3037
- }
3038
- }));
3039
- const tracking = {
3040
- element: element.nativeElement,
3041
- subject,
3042
- subjectObservable,
3043
- };
3044
- this.#tracking.push(tracking);
3045
- return tracking;
3046
- }
3047
- #callback(entry) {
3048
- this.#tracking
3049
- .filter((value) => !value.subject.closed)
3050
- .forEach((value) => {
3051
- /* istanbul ignore else */
3052
- if (value.element === entry.target) {
3053
- // Execute the callback within NgZone because Angular does not "monkey patch"
3054
- // ResizeObserver like it does for other features in the DOM.
3055
- if (this.#next.has(value.subject)) {
3056
- this.#window.nativeWindow.cancelAnimationFrame(this.#next.get(value.subject));
3057
- }
3058
- this.#next.set(value.subject, this.#window.nativeWindow.requestAnimationFrame(() => {
3059
- this.#zone.run(() => {
3060
- value.subject.next(entry);
3061
- });
3062
- }));
3063
- }
3064
- });
3046
+ const checkTracking = this.#tracking.has(element.nativeElement);
3047
+ if (!checkTracking) {
3048
+ this.#tracking.set(element.nativeElement, new Observable((observer) => {
3049
+ const subscription = this.#resizeSubject.subscribe(observer);
3050
+ this.#resizeObserver?.observe(element.nativeElement);
3051
+ return () => {
3052
+ this.#resizeObserver?.unobserve(element.nativeElement);
3053
+ subscription.unsubscribe();
3054
+ this.#tracking.delete(element.nativeElement);
3055
+ };
3056
+ }).pipe(filter(Boolean), filter((entries) => entries.some((entry) => entry.target === element.nativeElement)), map((entries) => entries.find((entry) => entry.target === element.nativeElement)),
3057
+ // Ignore subpixel changes.
3058
+ distinctUntilChanged((a, b) => Math.round(a.contentRect.width) ===
3059
+ Math.round(b.contentRect.width) &&
3060
+ Math.round(a.contentRect.height) ===
3061
+ Math.round(b.contentRect.height)),
3062
+ // Emit the last value for late subscribers. Track references so it
3063
+ // un-observes when all subscribers are gone.
3064
+ shareReplay({ bufferSize: 1, refCount: true }),
3065
+ // Only emit prior to an animation frame to prevent layout thrashing.
3066
+ throttle(() => animationFrames().pipe(take(1)), {
3067
+ leading: false,
3068
+ trailing: true,
3069
+ }), takeUntil$1(this.#ngUnsubscribe)));
3070
+ }
3071
+ return this.#tracking.get(element.nativeElement);
3072
+ }
3073
+ #expectWindowError() {
3074
+ if (!errorLogRegistered) {
3075
+ errorLogRegistered = true;
3076
+ // ResizeObserver throws an error when it is disconnected while it is
3077
+ // still observing an element. When an element is no longer observed, this
3078
+ // is not a concern.
3079
+ this.#zone.runOutsideAngular(() => this.#window.nativeWindow.addEventListener('error', errorHandler));
3080
+ }
3081
+ if (this.#window.nativeWindow.onerror !== onError) {
3082
+ originalOnError = this.#window.nativeWindow.onerror;
3083
+ this.#window.nativeWindow.onerror = onError;
3084
+ }
3085
+ }
3086
+ #resetWindowError() {
3087
+ this.#window.nativeWindow.removeEventListener('error', errorHandler);
3088
+ if (originalOnError) {
3089
+ this.#window.nativeWindow.onerror = originalOnError;
3090
+ originalOnError = undefined;
3091
+ }
3092
+ errorLogRegistered = false;
3065
3093
  }
3066
3094
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: SkyResizeObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3067
3095
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.9", ngImport: i0, type: SkyResizeObserverService, providedIn: 'root' }); }
@@ -3071,7 +3099,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.9", ngImpor
3071
3099
  args: [{
3072
3100
  providedIn: 'root',
3073
3101
  }]
3074
- }] });
3102
+ }], ctorParameters: function () { return []; } });
3075
3103
 
3076
3104
  const DEFAULT_BREAKPOINT = SkyMediaBreakpoints.md;
3077
3105
  /**
@@ -3407,7 +3435,7 @@ class SkyScrollableHostService {
3407
3435
  return concat([
3408
3436
  of(undefined),
3409
3437
  this.#resizeObserverSvc.observe({ nativeElement: scrollableHost }),
3410
- ]).pipe(debounceTime(0, animationFrameScheduler), map(() => {
3438
+ ]).pipe(debounceTime(0, animationFrameScheduler), map$1(() => {
3411
3439
  const viewportSize = this.#getViewportSize();
3412
3440
  const { top, left, width, height } = scrollableHost.getBoundingClientRect();
3413
3441
  const right = Math.max(viewportSize.width - left - width, 0);
@@ -4085,7 +4113,7 @@ class Version {
4085
4113
  /**
4086
4114
  * Represents the version of @skyux/core.
4087
4115
  */
4088
- const VERSION = new Version('9.12.1');
4116
+ const VERSION = new Version('9.13.1');
4089
4117
 
4090
4118
  /**
4091
4119
  * Generated bundle index. Do not edit.