ng-hub-ui-utils 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Carlos Morcillo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # Utils
2
+
3
+ This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Run `ng generate component component-name --project utils` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project utils`.
8
+ > Note: Don't forget to add `--project utils` or else it will be added to the default project in your `angular.json` file.
9
+
10
+ ## Build
11
+
12
+ Run `ng build utils` to build the project. The build artifacts will be stored in the `dist/` directory.
13
+
14
+ ## Publishing
15
+
16
+ After building your library with `ng build utils`, go to the dist folder `cd dist/utils` and run `npm publish`.
17
+
18
+ ## Running unit tests
19
+
20
+ Run `ng test utils` to execute the unit tests via [Karma](https://karma-runner.github.io).
21
+
22
+ ## Further help
23
+
24
+ To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
@@ -0,0 +1,58 @@
1
+ import { fromEvent } from 'rxjs';
2
+ import { filter, map, takeUntil, withLatestFrom } from 'rxjs/operators';
3
+ export const FOCUSABLE_ELEMENTS_SELECTOR = [
4
+ 'a[href]',
5
+ 'button:not([disabled])',
6
+ 'input:not([disabled]):not([type="hidden"])',
7
+ 'select:not([disabled])',
8
+ 'textarea:not([disabled])',
9
+ '[contenteditable]',
10
+ '[tabindex]:not([tabindex="-1"])'
11
+ ].join(', ');
12
+ /**
13
+ * Returns first and last focusable elements inside of a given element based on specific CSS selector
14
+ */
15
+ export function getFocusableBoundaryElements(element) {
16
+ const list = Array.from(element.querySelectorAll(FOCUSABLE_ELEMENTS_SELECTOR)).filter((el) => el.tabIndex !== -1);
17
+ return [list[0], list[list.length - 1]];
18
+ }
19
+ /**
20
+ * Function that enforces browser focus to be trapped inside a DOM element.
21
+ *
22
+ * Works only for clicks inside the element and navigation with 'Tab', ignoring clicks outside of the element
23
+ *
24
+ * @param zone Angular zone
25
+ * @param element The element around which focus will be trapped inside
26
+ * @param stopFocusTrap$ The observable stream. When completed the focus trap will clean up listeners
27
+ * and free internal resources
28
+ * @param refocusOnClick Put the focus back to the last focused element whenever a click occurs on element (default to
29
+ * false)
30
+ */
31
+ export const hubFocusTrap = (zone, element, stopFocusTrap$, refocusOnClick = false) => {
32
+ zone.runOutsideAngular(() => {
33
+ // last focused element
34
+ const lastFocusedElement$ = fromEvent(element, 'focusin').pipe(takeUntil(stopFocusTrap$), map((e) => e.target));
35
+ // 'tab' / 'shift+tab' stream
36
+ fromEvent(element, 'keydown')
37
+ .pipe(takeUntil(stopFocusTrap$), filter((e) => e.key === 'Tab'), withLatestFrom(lastFocusedElement$))
38
+ .subscribe(([tabEvent, focusedElement]) => {
39
+ const [first, last] = getFocusableBoundaryElements(element);
40
+ if ((focusedElement === first || focusedElement === element) &&
41
+ tabEvent.shiftKey) {
42
+ last.focus();
43
+ tabEvent.preventDefault();
44
+ }
45
+ if (focusedElement === last && !tabEvent.shiftKey) {
46
+ first.focus();
47
+ tabEvent.preventDefault();
48
+ }
49
+ });
50
+ // inside click
51
+ if (refocusOnClick) {
52
+ fromEvent(element, 'click')
53
+ .pipe(takeUntil(stopFocusTrap$), withLatestFrom(lastFocusedElement$), map((arr) => arr[1]))
54
+ .subscribe((lastFocusedElement) => lastFocusedElement.focus());
55
+ }
56
+ });
57
+ };
58
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9jdXMtdHJhcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3V0aWxzL3NyYy9saWIvZm9jdXMtdHJhcC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsU0FBUyxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQzdDLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxjQUFjLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4RSxNQUFNLENBQUMsTUFBTSwyQkFBMkIsR0FBRztJQUMxQyxTQUFTO0lBQ1Qsd0JBQXdCO0lBQ3hCLDRDQUE0QztJQUM1Qyx3QkFBd0I7SUFDeEIsMEJBQTBCO0lBQzFCLG1CQUFtQjtJQUNuQixpQ0FBaUM7Q0FDakMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFFYjs7R0FFRztBQUNILE1BQU0sVUFBVSw0QkFBNEIsQ0FDM0MsT0FBb0I7SUFFcEIsTUFBTSxJQUFJLEdBQWtCLEtBQUssQ0FBQyxJQUFJLENBQ3JDLE9BQU8sQ0FBQyxnQkFBZ0IsQ0FDdkIsMkJBQTJCLENBQ0EsQ0FDNUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxRQUFRLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDekMsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLENBQzNCLElBQVksRUFDWixPQUFvQixFQUNwQixjQUErQixFQUMvQixjQUFjLEdBQUcsS0FBSyxFQUNyQixFQUFFO0lBQ0gsSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsRUFBRTtRQUMzQix1QkFBdUI7UUFDdkIsTUFBTSxtQkFBbUIsR0FBRyxTQUFTLENBQ3BDLE9BQU8sRUFDUCxTQUFTLENBQ1QsQ0FBQyxJQUFJLENBQ0wsU0FBUyxDQUFDLGNBQWMsQ0FBQyxFQUN6QixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FDcEIsQ0FBQztRQUVGLDZCQUE2QjtRQUM3QixTQUFTLENBQWdCLE9BQU8sRUFBRSxTQUFTLENBQUM7YUFDMUMsSUFBSSxDQUNKLFNBQVMsQ0FBQyxjQUFjLENBQUMsRUFDekIsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEtBQUssQ0FBQyxFQUM5QixjQUFjLENBQUMsbUJBQW1CLENBQUMsQ0FDbkM7YUFDQSxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxjQUFjLENBQUMsRUFBRSxFQUFFO1lBQ3pDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLEdBQUcsNEJBQTRCLENBQUMsT0FBTyxDQUFDLENBQUM7WUFFNUQsSUFDQyxDQUFDLGNBQWMsS0FBSyxLQUFLLElBQUksY0FBYyxLQUFLLE9BQU8sQ0FBQztnQkFDeEQsUUFBUSxDQUFDLFFBQVEsRUFDaEI7Z0JBQ0QsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUNiLFFBQVEsQ0FBQyxjQUFjLEVBQUUsQ0FBQzthQUMxQjtZQUVELElBQUksY0FBYyxLQUFLLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUU7Z0JBQ2xELEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztnQkFDZCxRQUFRLENBQUMsY0FBYyxFQUFFLENBQUM7YUFDMUI7UUFDRixDQUFDLENBQUMsQ0FBQztRQUVKLGVBQWU7UUFDZixJQUFJLGNBQWMsRUFBRTtZQUNuQixTQUFTLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQztpQkFDekIsSUFBSSxDQUNKLFNBQVMsQ0FBQyxjQUFjLENBQUMsRUFDekIsY0FBYyxDQUFDLG1CQUFtQixDQUFDLEVBQ25DLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBZ0IsQ0FBQyxDQUNuQztpQkFDQSxTQUFTLENBQUMsQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUMsa0JBQWtCLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQztTQUNoRTtJQUNGLENBQUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdab25lIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IGZyb21FdmVudCwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmlsdGVyLCBtYXAsIHRha2VVbnRpbCwgd2l0aExhdGVzdEZyb20gfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmV4cG9ydCBjb25zdCBGT0NVU0FCTEVfRUxFTUVOVFNfU0VMRUNUT1IgPSBbXG5cdCdhW2hyZWZdJyxcblx0J2J1dHRvbjpub3QoW2Rpc2FibGVkXSknLFxuXHQnaW5wdXQ6bm90KFtkaXNhYmxlZF0pOm5vdChbdHlwZT1cImhpZGRlblwiXSknLFxuXHQnc2VsZWN0Om5vdChbZGlzYWJsZWRdKScsXG5cdCd0ZXh0YXJlYTpub3QoW2Rpc2FibGVkXSknLFxuXHQnW2NvbnRlbnRlZGl0YWJsZV0nLFxuXHQnW3RhYmluZGV4XTpub3QoW3RhYmluZGV4PVwiLTFcIl0pJ1xuXS5qb2luKCcsICcpO1xuXG4vKipcbiAqIFJldHVybnMgZmlyc3QgYW5kIGxhc3QgZm9jdXNhYmxlIGVsZW1lbnRzIGluc2lkZSBvZiBhIGdpdmVuIGVsZW1lbnQgYmFzZWQgb24gc3BlY2lmaWMgQ1NTIHNlbGVjdG9yXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGb2N1c2FibGVCb3VuZGFyeUVsZW1lbnRzKFxuXHRlbGVtZW50OiBIVE1MRWxlbWVudFxuKTogSFRNTEVsZW1lbnRbXSB7XG5cdGNvbnN0IGxpc3Q6IEhUTUxFbGVtZW50W10gPSBBcnJheS5mcm9tKFxuXHRcdGVsZW1lbnQucXVlcnlTZWxlY3RvckFsbChcblx0XHRcdEZPQ1VTQUJMRV9FTEVNRU5UU19TRUxFQ1RPUlxuXHRcdCkgYXMgTm9kZUxpc3RPZjxIVE1MRWxlbWVudD5cblx0KS5maWx0ZXIoKGVsKSA9PiBlbC50YWJJbmRleCAhPT0gLTEpO1xuXHRyZXR1cm4gW2xpc3RbMF0sIGxpc3RbbGlzdC5sZW5ndGggLSAxXV07XG59XG5cbi8qKlxuICogRnVuY3Rpb24gdGhhdCBlbmZvcmNlcyBicm93c2VyIGZvY3VzIHRvIGJlIHRyYXBwZWQgaW5zaWRlIGEgRE9NIGVsZW1lbnQuXG4gKlxuICogV29ya3Mgb25seSBmb3IgY2xpY2tzIGluc2lkZSB0aGUgZWxlbWVudCBhbmQgbmF2aWdhdGlvbiB3aXRoICdUYWInLCBpZ25vcmluZyBjbGlja3Mgb3V0c2lkZSBvZiB0aGUgZWxlbWVudFxuICpcbiAqIEBwYXJhbSB6b25lIEFuZ3VsYXIgem9uZVxuICogQHBhcmFtIGVsZW1lbnQgVGhlIGVsZW1lbnQgYXJvdW5kIHdoaWNoIGZvY3VzIHdpbGwgYmUgdHJhcHBlZCBpbnNpZGVcbiAqIEBwYXJhbSBzdG9wRm9jdXNUcmFwJCBUaGUgb2JzZXJ2YWJsZSBzdHJlYW0uIFdoZW4gY29tcGxldGVkIHRoZSBmb2N1cyB0cmFwIHdpbGwgY2xlYW4gdXAgbGlzdGVuZXJzXG4gKiBhbmQgZnJlZSBpbnRlcm5hbCByZXNvdXJjZXNcbiAqIEBwYXJhbSByZWZvY3VzT25DbGljayBQdXQgdGhlIGZvY3VzIGJhY2sgdG8gdGhlIGxhc3QgZm9jdXNlZCBlbGVtZW50IHdoZW5ldmVyIGEgY2xpY2sgb2NjdXJzIG9uIGVsZW1lbnQgKGRlZmF1bHQgdG9cbiAqIGZhbHNlKVxuICovXG5leHBvcnQgY29uc3QgaHViRm9jdXNUcmFwID0gKFxuXHR6b25lOiBOZ1pvbmUsXG5cdGVsZW1lbnQ6IEhUTUxFbGVtZW50LFxuXHRzdG9wRm9jdXNUcmFwJDogT2JzZXJ2YWJsZTxhbnk+LFxuXHRyZWZvY3VzT25DbGljayA9IGZhbHNlXG4pID0+IHtcblx0em9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG5cdFx0Ly8gbGFzdCBmb2N1c2VkIGVsZW1lbnRcblx0XHRjb25zdCBsYXN0Rm9jdXNlZEVsZW1lbnQkID0gZnJvbUV2ZW50PEZvY3VzRXZlbnQ+KFxuXHRcdFx0ZWxlbWVudCxcblx0XHRcdCdmb2N1c2luJ1xuXHRcdCkucGlwZShcblx0XHRcdHRha2VVbnRpbChzdG9wRm9jdXNUcmFwJCksXG5cdFx0XHRtYXAoKGUpID0+IGUudGFyZ2V0KVxuXHRcdCk7XG5cblx0XHQvLyAndGFiJyAvICdzaGlmdCt0YWInIHN0cmVhbVxuXHRcdGZyb21FdmVudDxLZXlib2FyZEV2ZW50PihlbGVtZW50LCAna2V5ZG93bicpXG5cdFx0XHQucGlwZShcblx0XHRcdFx0dGFrZVVudGlsKHN0b3BGb2N1c1RyYXAkKSxcblx0XHRcdFx0ZmlsdGVyKChlKSA9PiBlLmtleSA9PT0gJ1RhYicpLFxuXHRcdFx0XHR3aXRoTGF0ZXN0RnJvbShsYXN0Rm9jdXNlZEVsZW1lbnQkKVxuXHRcdFx0KVxuXHRcdFx0LnN1YnNjcmliZSgoW3RhYkV2ZW50LCBmb2N1c2VkRWxlbWVudF0pID0+IHtcblx0XHRcdFx0Y29uc3QgW2ZpcnN0LCBsYXN0XSA9IGdldEZvY3VzYWJsZUJvdW5kYXJ5RWxlbWVudHMoZWxlbWVudCk7XG5cblx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdChmb2N1c2VkRWxlbWVudCA9PT0gZmlyc3QgfHwgZm9jdXNlZEVsZW1lbnQgPT09IGVsZW1lbnQpICYmXG5cdFx0XHRcdFx0dGFiRXZlbnQuc2hpZnRLZXlcblx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0bGFzdC5mb2N1cygpO1xuXHRcdFx0XHRcdHRhYkV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoZm9jdXNlZEVsZW1lbnQgPT09IGxhc3QgJiYgIXRhYkV2ZW50LnNoaWZ0S2V5KSB7XG5cdFx0XHRcdFx0Zmlyc3QuZm9jdXMoKTtcblx0XHRcdFx0XHR0YWJFdmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdC8vIGluc2lkZSBjbGlja1xuXHRcdGlmIChyZWZvY3VzT25DbGljaykge1xuXHRcdFx0ZnJvbUV2ZW50KGVsZW1lbnQsICdjbGljaycpXG5cdFx0XHRcdC5waXBlKFxuXHRcdFx0XHRcdHRha2VVbnRpbChzdG9wRm9jdXNUcmFwJCksXG5cdFx0XHRcdFx0d2l0aExhdGVzdEZyb20obGFzdEZvY3VzZWRFbGVtZW50JCksXG5cdFx0XHRcdFx0bWFwKChhcnIpID0+IGFyclsxXSBhcyBIVE1MRWxlbWVudClcblx0XHRcdFx0KVxuXHRcdFx0XHQuc3Vic2NyaWJlKChsYXN0Rm9jdXNlZEVsZW1lbnQpID0+IGxhc3RGb2N1c2VkRWxlbWVudC5mb2N1cygpKTtcblx0XHR9XG5cdH0pO1xufTtcbiJdfQ==
@@ -0,0 +1,66 @@
1
+ import { ApplicationRef, inject, Injector, NgZone, TemplateRef, ViewContainerRef } from '@angular/core';
2
+ import { of } from 'rxjs';
3
+ import { mergeMap, take, tap } from 'rxjs/operators';
4
+ import { DOCUMENT } from '@angular/common';
5
+ import { hubRunTransition } from './transitions';
6
+ export class ContentRef {
7
+ constructor(nodes, viewRef, componentRef) {
8
+ this.nodes = nodes;
9
+ this.viewRef = viewRef;
10
+ this.componentRef = componentRef;
11
+ }
12
+ }
13
+ export class PopupService {
14
+ constructor(_componentType) {
15
+ this._componentType = _componentType;
16
+ this._windowRef = null;
17
+ this._contentRef = null;
18
+ this._document = inject(DOCUMENT);
19
+ this._applicationRef = inject(ApplicationRef);
20
+ this._injector = inject(Injector);
21
+ this._viewContainerRef = inject(ViewContainerRef);
22
+ this._ngZone = inject(NgZone);
23
+ }
24
+ open(content, templateContext, animation = false) {
25
+ if (!this._windowRef) {
26
+ this._contentRef = this._getContentRef(content, templateContext);
27
+ this._windowRef = this._viewContainerRef.createComponent(this._componentType, {
28
+ injector: this._injector,
29
+ projectableNodes: this._contentRef.nodes
30
+ });
31
+ }
32
+ const { nativeElement } = this._windowRef.location;
33
+ const transition$ = this._ngZone.onStable.pipe(take(1), mergeMap(() => hubRunTransition(this._ngZone, nativeElement, ({ classList }) => classList.add('show'), {
34
+ animation,
35
+ runningTransition: 'continue'
36
+ })));
37
+ return { windowRef: this._windowRef, transition$ };
38
+ }
39
+ close(animation = false) {
40
+ if (!this._windowRef) {
41
+ return of(undefined);
42
+ }
43
+ return hubRunTransition(this._ngZone, this._windowRef.location.nativeElement, ({ classList }) => classList.remove('show'), { animation, runningTransition: 'stop' }).pipe(tap(() => {
44
+ this._windowRef?.destroy();
45
+ this._contentRef?.viewRef?.destroy();
46
+ this._windowRef = null;
47
+ this._contentRef = null;
48
+ }));
49
+ }
50
+ _getContentRef(content, templateContext) {
51
+ if (!content) {
52
+ return new ContentRef([]);
53
+ }
54
+ else if (content instanceof TemplateRef) {
55
+ const viewRef = content.createEmbeddedView(templateContext);
56
+ this._applicationRef.attachView(viewRef);
57
+ return new ContentRef([viewRef.rootNodes], viewRef);
58
+ }
59
+ else {
60
+ return new ContentRef([
61
+ [this._document.createTextNode(`${content}`)]
62
+ ]);
63
+ }
64
+ }
65
+ }
66
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9wdXAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy91dGlscy9zcmMvbGliL3BvcHVwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTixjQUFjLEVBRWQsTUFBTSxFQUNOLFFBQVEsRUFDUixNQUFNLEVBQ04sV0FBVyxFQUVYLGdCQUFnQixFQUVoQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQWMsRUFBRSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFakQsTUFBTSxPQUFPLFVBQVU7SUFDdEIsWUFDUSxLQUFlLEVBQ2YsT0FBaUIsRUFDakIsWUFBZ0M7UUFGaEMsVUFBSyxHQUFMLEtBQUssQ0FBVTtRQUNmLFlBQU8sR0FBUCxPQUFPLENBQVU7UUFDakIsaUJBQVksR0FBWixZQUFZLENBQW9CO0lBQ3JDLENBQUM7Q0FDSjtBQUVELE1BQU0sT0FBTyxZQUFZO0lBVXhCLFlBQW9CLGNBQXVCO1FBQXZCLG1CQUFjLEdBQWQsY0FBYyxDQUFTO1FBVG5DLGVBQVUsR0FBMkIsSUFBSSxDQUFDO1FBQzFDLGdCQUFXLEdBQXNCLElBQUksQ0FBQztRQUV0QyxjQUFTLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzdCLG9CQUFlLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3pDLGNBQVMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDN0Isc0JBQWlCLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDN0MsWUFBTyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUVh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XG5cdENvbXBvbmVudFJlZixcblx0aW5qZWN0LFxuXHRJbmplY3Rvcixcblx0Tmdab25lLFxuXHRUZW1wbGF0ZVJlZixcblx0VHlwZSxcblx0Vmlld0NvbnRhaW5lclJlZixcblx0Vmlld1JlZlxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE9ic2VydmFibGUsIG9mIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBtZXJnZU1hcCwgdGFrZSwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRE9DVU1FTlQgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgaHViUnVuVHJhbnNpdGlvbiB9IGZyb20gJy4vdHJhbnNpdGlvbnMnO1xuXG5leHBvcnQgY2xhc3MgQ29udGVudFJlZiB7XG5cdGNvbnN0cnVjdG9yKFxuXHRcdHB1YmxpYyBub2RlczogTm9kZVtdW10sXG5cdFx0cHVibGljIHZpZXdSZWY/OiBWaWV3UmVmLFxuXHRcdHB1YmxpYyBjb21wb25lbnRSZWY/OiBDb21wb25lbnRSZWY8YW55PlxuXHQpIHt9XG59XG5cbmV4cG9ydCBjbGFzcyBQb3B1cFNlcnZpY2U8VD4ge1xuXHRwcml2YXRlIF93aW5kb3dSZWY6IENvbXBvbmVudFJlZjxUPiB8IG51bGwgPSBudWxsO1xuXHRwcml2YXRlIF9jb250ZW50UmVmOiBDb250ZW50UmVmIHwgbnVsbCA9IG51bGw7XG5cblx0cHJpdmF0ZSBfZG9jdW1lbnQgPSBpbmplY3QoRE9DVU1FTlQpO1xuXHRwcml2YXRlIF9hcHBsaWNhdGlvblJlZiA9IGluamVjdChBcHBsaWNhdGlvblJlZik7XG5cdHByaXZhdGUgX2luamVjdG9yID0gaW5qZWN0KEluamVjdG9yKTtcblx0cHJpdmF0ZSBfdmlld0NvbnRhaW5lclJlZiA9IGluamVjdChWaWV3Q29udGFpbmVyUmVmKTtcblx0cHJpdmF0ZSBfbmdab25lID0gaW5qZWN0KE5nWm9uZSk7XG5cblx0Y29uc3RydWN0b3IocHJpdmF0ZSBfY29tcG9uZW50VHlwZTogVHlwZTxUPikge31cblxuXHRvcGVuKFxuXHRcdGNvbnRlbnQ/OiBzdHJpbmcgfCBUZW1wbGF0ZVJlZjxhbnk+LFxuXHRcdHRlbXBsYXRlQ29udGV4dD86IGFueSxcblx0XHRhbmltYXRpb24gPSBmYWxzZVxuXHQpOiB7IHdpbmRvd1JlZjogQ29tcG9uZW50UmVmPFQ+OyB0cmFuc2l0aW9uJDogT2JzZXJ2YWJsZTx2b2lkPiB9IHtcblx0XHRpZiAoIXRoaXMuX3dpbmRvd1JlZikge1xuXHRcdFx0dGhpcy5fY29udGVudFJlZiA9IHRoaXMuX2dldENvbnRlbnRSZWYoY29udGVudCwgdGVtcGxhdGVDb250ZXh0KTtcblx0XHRcdHRoaXMuX3dpbmRvd1JlZiA9IHRoaXMuX3ZpZXdDb250YWluZXJSZWYuY3JlYXRlQ29tcG9uZW50KFxuXHRcdFx0XHR0aGlzLl9jb21wb25lbnRUeXBlLFxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0aW5qZWN0b3I6IHRoaXMuX2luamVjdG9yLFxuXHRcdFx0XHRcdHByb2plY3RhYmxlTm9kZXM6IHRoaXMuX2NvbnRlbnRSZWYubm9kZXNcblx0XHRcdFx0fVxuXHRcdFx0KTtcblx0XHR9XG5cblx0XHRjb25zdCB7IG5hdGl2ZUVsZW1lbnQgfSA9IHRoaXMuX3dpbmRvd1JlZi5sb2NhdGlvbjtcblx0XHRjb25zdCB0cmFuc2l0aW9uJCA9IHRoaXMuX25nWm9uZS5vblN0YWJsZS5waXBlKFxuXHRcdFx0dGFrZSgxKSxcblx0XHRcdG1lcmdlTWFwKCgpID0+XG5cdFx0XHRcdGh1YlJ1blRyYW5zaXRpb24oXG5cdFx0XHRcdFx0dGhpcy5fbmdab25lLFxuXHRcdFx0XHRcdG5hdGl2ZUVsZW1lbnQsXG5cdFx0XHRcdFx0KHsgY2xhc3NMaXN0IH0pID0+IGNsYXNzTGlzdC5hZGQoJ3Nob3cnKSxcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRhbmltYXRpb24sXG5cdFx0XHRcdFx0XHRydW5uaW5nVHJhbnNpdGlvbjogJ2NvbnRpbnVlJ1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0KVxuXHRcdFx0KVxuXHRcdCk7XG5cblx0XHRyZXR1cm4geyB3aW5kb3dSZWY6IHRoaXMuX3dpbmRvd1JlZiwgdHJhbnNpdGlvbiQgfTtcblx0fVxuXG5cdGNsb3NlKGFuaW1hdGlvbiA9IGZhbHNlKTogT2JzZXJ2YWJsZTx2b2lkPiB7XG5cdFx0aWYgKCF0aGlzLl93aW5kb3dSZWYpIHtcblx0XHRcdHJldHVybiBvZih1bmRlZmluZWQpO1xuXHRcdH1cblxuXHRcdHJldHVybiBodWJSdW5UcmFuc2l0aW9uKFxuXHRcdFx0dGhpcy5fbmdab25lLFxuXHRcdFx0dGhpcy5fd2luZG93UmVmLmxvY2F0aW9uLm5hdGl2ZUVsZW1lbnQsXG5cdFx0XHQoeyBjbGFzc0xpc3QgfSkgPT4gY2xhc3NMaXN0LnJlbW92ZSgnc2hvdycpLFxuXHRcdFx0eyBhbmltYXRpb24sIHJ1bm5pbmdUcmFuc2l0aW9uOiAnc3RvcCcgfVxuXHRcdCkucGlwZShcblx0XHRcdHRhcCgoKSA9PiB7XG5cdFx0XHRcdHRoaXMuX3dpbmRvd1JlZj8uZGVzdHJveSgpO1xuXHRcdFx0XHR0aGlzLl9jb250ZW50UmVmPy52aWV3UmVmPy5kZXN0cm95KCk7XG5cdFx0XHRcdHRoaXMuX3dpbmRvd1JlZiA9IG51bGw7XG5cdFx0XHRcdHRoaXMuX2NvbnRlbnRSZWYgPSBudWxsO1xuXHRcdFx0fSlcblx0XHQpO1xuXHR9XG5cblx0cHJpdmF0ZSBfZ2V0Q29udGVudFJlZihcblx0XHRjb250ZW50Pzogc3RyaW5nIHwgVGVtcGxhdGVSZWY8YW55Pixcblx0XHR0ZW1wbGF0ZUNvbnRleHQ/OiBhbnlcblx0KTogQ29udGVudFJlZiB7XG5cdFx0aWYgKCFjb250ZW50KSB7XG5cdFx0XHRyZXR1cm4gbmV3IENvbnRlbnRSZWYoW10pO1xuXHRcdH0gZWxzZSBpZiAoY29udGVudCBpbnN0YW5jZW9mIFRlbXBsYXRlUmVmKSB7XG5cdFx0XHRjb25zdCB2aWV3UmVmID0gY29udGVudC5jcmVhdGVFbWJlZGRlZFZpZXcodGVtcGxhdGVDb250ZXh0KTtcblx0XHRcdHRoaXMuX2FwcGxpY2F0aW9uUmVmLmF0dGFjaFZpZXcodmlld1JlZik7XG5cdFx0XHRyZXR1cm4gbmV3IENvbnRlbnRSZWYoW3ZpZXdSZWYucm9vdE5vZGVzXSwgdmlld1JlZik7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiBuZXcgQ29udGVudFJlZihbXG5cdFx0XHRcdFt0aGlzLl9kb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShgJHtjb250ZW50fWApXVxuXHRcdFx0XSk7XG5cdFx0fVxuXHR9XG59XG4iXX0=
@@ -0,0 +1,46 @@
1
+ import { inject, Injectable } from '@angular/core';
2
+ import { DOCUMENT } from '@angular/common';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Utility to handle the scrollbar.
6
+ *
7
+ * It allows to hide the scrollbar and compensate the lack of a vertical scrollbar
8
+ * by adding an equivalent padding on the right of the body, and to revert this change.
9
+ */
10
+ export class ScrollBar {
11
+ constructor() {
12
+ this._document = inject(DOCUMENT);
13
+ }
14
+ /**
15
+ * To be called to hide a potential vertical scrollbar:
16
+ * - if a scrollbar is there and has a width greater than 0, adds some compensation
17
+ * padding to the body to keep the same layout as when the scrollbar is there
18
+ * - adds overflow: hidden
19
+ *
20
+ * @return a callback used to revert the change
21
+ */
22
+ hide() {
23
+ const scrollbarWidth = Math.abs(window.innerWidth - this._document.documentElement.clientWidth);
24
+ const body = this._document.body;
25
+ const bodyStyle = body.style;
26
+ const { overflow, paddingRight } = bodyStyle;
27
+ if (scrollbarWidth > 0) {
28
+ const actualPadding = parseFloat(window.getComputedStyle(body).paddingRight);
29
+ bodyStyle.paddingRight = `${actualPadding + scrollbarWidth}px`;
30
+ }
31
+ bodyStyle.overflow = 'hidden';
32
+ return () => {
33
+ if (scrollbarWidth > 0) {
34
+ bodyStyle.paddingRight = paddingRight;
35
+ }
36
+ bodyStyle.overflow = overflow;
37
+ };
38
+ }
39
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ScrollBar, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
40
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ScrollBar, providedIn: 'root' }); }
41
+ }
42
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ScrollBar, decorators: [{
43
+ type: Injectable,
44
+ args: [{ providedIn: 'root' }]
45
+ }] });
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nyb2xsYmFyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvdXRpbHMvc3JjL2xpYi9zY3JvbGxiYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDOztBQUszQzs7Ozs7R0FLRztBQUVILE1BQU0sT0FBTyxTQUFTO0lBRHRCO1FBRVMsY0FBUyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztLQTJCckM7SUF6QkE7Ozs7Ozs7T0FPRztJQUNILElBQUk7UUFDSCxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDaEcsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUM7UUFDakMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUM3QixNQUFNLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxHQUFHLFNBQVMsQ0FBQztRQUM3QyxJQUFJLGNBQWMsR0FBRyxDQUFDLEVBQUU7WUFDdkIsTUFBTSxhQUFhLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUM3RSxTQUFTLENBQUMsWUFBWSxHQUFHLEdBQUcsYUFBYSxHQUFHLGNBQWMsSUFBSSxDQUFDO1NBQy9EO1FBQ0QsU0FBUyxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDOUIsT0FBTyxHQUFHLEVBQUU7WUFDWCxJQUFJLGNBQWMsR0FBRyxDQUFDLEVBQUU7Z0JBQ3ZCLFNBQVMsQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO2FBQ3RDO1lBQ0QsU0FBUyxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDL0IsQ0FBQyxDQUFDO0lBQ0gsQ0FBQzs4R0EzQlcsU0FBUztrSEFBVCxTQUFTLGNBREksTUFBTTs7MkZBQ25CLFNBQVM7a0JBRHJCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaW5qZWN0LCBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBET0NVTUVOVCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbi8qKiBUeXBlIGZvciB0aGUgY2FsbGJhY2sgdXNlZCB0byByZXZlcnQgdGhlIHNjcm9sbGJhci4gKi9cbmV4cG9ydCB0eXBlIFNjcm9sbGJhclJldmVydGVyID0gKCkgPT4gdm9pZDtcblxuLyoqXG4gKiBVdGlsaXR5IHRvIGhhbmRsZSB0aGUgc2Nyb2xsYmFyLlxuICpcbiAqIEl0IGFsbG93cyB0byBoaWRlIHRoZSBzY3JvbGxiYXIgYW5kIGNvbXBlbnNhdGUgdGhlIGxhY2sgb2YgYSB2ZXJ0aWNhbCBzY3JvbGxiYXJcbiAqIGJ5IGFkZGluZyBhbiBlcXVpdmFsZW50IHBhZGRpbmcgb24gdGhlIHJpZ2h0IG9mIHRoZSBib2R5LCBhbmQgdG8gcmV2ZXJ0IHRoaXMgY2hhbmdlLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFNjcm9sbEJhciB7XG5cdHByaXZhdGUgX2RvY3VtZW50ID0gaW5qZWN0KERPQ1VNRU5UKTtcblxuXHQvKipcblx0ICogVG8gYmUgY2FsbGVkIHRvIGhpZGUgYSBwb3RlbnRpYWwgdmVydGljYWwgc2Nyb2xsYmFyOlxuXHQgKiAtIGlmIGEgc2Nyb2xsYmFyIGlzIHRoZXJlIGFuZCBoYXMgYSB3aWR0aCBncmVhdGVyIHRoYW4gMCwgYWRkcyBzb21lIGNvbXBlbnNhdGlvblxuXHQgKiBwYWRkaW5nIHRvIHRoZSBib2R5IHRvIGtlZXAgdGhlIHNhbWUgbGF5b3V0IGFzIHdoZW4gdGhlIHNjcm9sbGJhciBpcyB0aGVyZVxuXHQgKiAtIGFkZHMgb3ZlcmZsb3c6IGhpZGRlblxuXHQgKlxuXHQgKiBAcmV0dXJuIGEgY2FsbGJhY2sgdXNlZCB0byByZXZlcnQgdGhlIGNoYW5nZVxuXHQgKi9cblx0aGlkZSgpOiBTY3JvbGxiYXJSZXZlcnRlciB7XG5cdFx0Y29uc3Qgc2Nyb2xsYmFyV2lkdGggPSBNYXRoLmFicyh3aW5kb3cuaW5uZXJXaWR0aCAtIHRoaXMuX2RvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aCk7XG5cdFx0Y29uc3QgYm9keSA9IHRoaXMuX2RvY3VtZW50LmJvZHk7XG5cdFx0Y29uc3QgYm9keVN0eWxlID0gYm9keS5zdHlsZTtcblx0XHRjb25zdCB7IG92ZXJmbG93LCBwYWRkaW5nUmlnaHQgfSA9IGJvZHlTdHlsZTtcblx0XHRpZiAoc2Nyb2xsYmFyV2lkdGggPiAwKSB7XG5cdFx0XHRjb25zdCBhY3R1YWxQYWRkaW5nID0gcGFyc2VGbG9hdCh3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShib2R5KS5wYWRkaW5nUmlnaHQpO1xuXHRcdFx0Ym9keVN0eWxlLnBhZGRpbmdSaWdodCA9IGAke2FjdHVhbFBhZGRpbmcgKyBzY3JvbGxiYXJXaWR0aH1weGA7XG5cdFx0fVxuXHRcdGJvZHlTdHlsZS5vdmVyZmxvdyA9ICdoaWRkZW4nO1xuXHRcdHJldHVybiAoKSA9PiB7XG5cdFx0XHRpZiAoc2Nyb2xsYmFyV2lkdGggPiAwKSB7XG5cdFx0XHRcdGJvZHlTdHlsZS5wYWRkaW5nUmlnaHQgPSBwYWRkaW5nUmlnaHQ7XG5cdFx0XHR9XG5cdFx0XHRib2R5U3R5bGUub3ZlcmZsb3cgPSBvdmVyZmxvdztcblx0XHR9O1xuXHR9XG59XG4iXX0=
@@ -0,0 +1,2 @@
1
+ export * from './transition';
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy91dGlscy9zcmMvbGliL3RyYW5zaXRpb25zL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi90cmFuc2l0aW9uJztcbiJdfQ==
@@ -0,0 +1,77 @@
1
+ import { EMPTY, fromEvent, of, race, Subject, timer } from 'rxjs';
2
+ import { endWith, filter, takeUntil } from 'rxjs/operators';
3
+ import { runInZone } from '../util';
4
+ import { getTransitionDurationMs } from './util';
5
+ const transitionTimerDelayMs = 5;
6
+ const noopFn = () => { };
7
+ const runningTransitions = new Map();
8
+ export const hubRunTransition = (zone, element, startFn, options) => {
9
+ // Getting initial context from options
10
+ let context = options.context || {};
11
+ // Checking if there are already running transitions on the given element.
12
+ const running = runningTransitions.get(element);
13
+ if (running) {
14
+ switch (options.runningTransition) {
15
+ // If there is one running and we want for it to 'continue' to run, we have to cancel the new one.
16
+ // We're not emitting any values, but simply completing the observable (EMPTY).
17
+ case 'continue':
18
+ return EMPTY;
19
+ // If there is one running and we want for it to 'stop', we have to complete the running one.
20
+ // We're simply completing the running one and not emitting any values and merging newly provided context
21
+ // with the one coming from currently running transition.
22
+ case 'stop':
23
+ zone.run(() => running.transition$.complete());
24
+ context = Object.assign(running.context, context);
25
+ runningTransitions.delete(element);
26
+ }
27
+ }
28
+ // Running the start function
29
+ const endFn = startFn(element, options.animation, context) || noopFn;
30
+ // If 'prefer-reduced-motion' is enabled, the 'transition' will be set to 'none'.
31
+ // If animations are disabled, we have to emit a value and complete the observable
32
+ // In this case we have to call the end function, but can finish immediately by emitting a value,
33
+ // completing the observable and executing end functions synchronously.
34
+ if (!options.animation ||
35
+ window.getComputedStyle(element).transitionProperty === 'none') {
36
+ zone.run(() => endFn());
37
+ return of(undefined).pipe(runInZone(zone));
38
+ }
39
+ // Starting a new transition
40
+ const transition$ = new Subject();
41
+ const finishTransition$ = new Subject();
42
+ const stop$ = transition$.pipe(endWith(true));
43
+ runningTransitions.set(element, {
44
+ transition$,
45
+ complete: () => {
46
+ finishTransition$.next();
47
+ finishTransition$.complete();
48
+ },
49
+ context
50
+ });
51
+ const transitionDurationMs = getTransitionDurationMs(element);
52
+ // 1. We have to both listen for the 'transitionend' event and have a 'just-in-case' timer,
53
+ // because 'transitionend' event might not be fired in some browsers, if the transitioning
54
+ // element becomes invisible (ex. when scrolling, making browser tab inactive, etc.). The timer
55
+ // guarantees, that we'll release the DOM element and complete 'hubRunTransition'.
56
+ // 2. We need to filter transition end events, because they might bubble from shorter transitions
57
+ // on inner DOM elements. We're only interested in the transition on the 'element' itself.
58
+ zone.runOutsideAngular(() => {
59
+ const transitionEnd$ = fromEvent(element, 'transitionend').pipe(takeUntil(stop$), filter(({ target }) => target === element));
60
+ const timer$ = timer(transitionDurationMs + transitionTimerDelayMs).pipe(takeUntil(stop$));
61
+ race(timer$, transitionEnd$, finishTransition$)
62
+ .pipe(takeUntil(stop$))
63
+ .subscribe(() => {
64
+ runningTransitions.delete(element);
65
+ zone.run(() => {
66
+ endFn();
67
+ transition$.next();
68
+ transition$.complete();
69
+ });
70
+ });
71
+ });
72
+ return transition$.asObservable();
73
+ };
74
+ export const hubCompleteTransition = (element) => {
75
+ runningTransitions.get(element)?.complete();
76
+ };
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhbnNpdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3V0aWxzL3NyYy9saWIvdHJhbnNpdGlvbnMvdHJhbnNpdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBYyxFQUFFLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDOUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDNUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNwQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFakQsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLENBQUM7QUFxQmpDLE1BQU0sTUFBTSxHQUFvQixHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUM7QUFFekMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEdBQUcsRUFBbUMsQ0FBQztBQUV0RSxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxDQUMvQixJQUFZLEVBQ1osT0FBb0IsRUFDcEIsT0FBNkIsRUFDN0IsT0FBNkIsRUFDVixFQUFFO0lBQ3JCLHVDQUF1QztJQUN2QyxJQUFJLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFPLEVBQUUsQ0FBQztJQUV2QywwRUFBMEU7SUFDMUUsTUFBTSxPQUFPLEdBQUcsa0JBQWtCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ2hELElBQUksT0FBTyxFQUFFO1FBQ1osUUFBUSxPQUFPLENBQUMsaUJBQWlCLEVBQUU7WUFDbEMsa0dBQWtHO1lBQ2xHLCtFQUErRTtZQUMvRSxLQUFLLFVBQVU7Z0JBQ2QsT0FBTyxLQUFLLENBQUM7WUFDZCw2RkFBNkY7WUFDN0YseUdBQXlHO1lBQ3pHLHlEQUF5RDtZQUN6RCxL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QUFHLENBQUMsT0FBb0IsRUFBRSxFQUFFO0lBQzdELGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsRUFBRSxRQUFRLEVBQUUsQ0FBQztBQUM3QyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOZ1pvbmUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEVNUFRZLCBmcm9tRXZlbnQsIE9ic2VydmFibGUsIG9mLCByYWNlLCBTdWJqZWN0LCB0aW1lciB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZW5kV2l0aCwgZmlsdGVyLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQgeyBydW5JblpvbmUgfSBmcm9tICcuLi91dGlsJztcbmltcG9ydCB7IGdldFRyYW5zaXRpb25EdXJhdGlvbk1zIH0gZnJvbSAnLi91dGlsJztcblxuY29uc3QgdHJhbnNpdGlvblRpbWVyRGVsYXlNcyA9IDU7XG5cbmV4cG9ydCB0eXBlIFRyYW5zaXRpb25TdGFydEZuPFQgPSBhbnk+ID0gKFxuXHRlbGVtZW50OiBIVE1MRWxlbWVudCxcblx0YW5pbWF0aW9uOiBib29sZWFuLFxuXHRjb250ZXh0OiBUXG4pID0+IFRyYW5zaXRpb25FbmRGbiB8IHZvaWQ7XG5leHBvcnQgdHlwZSBUcmFuc2l0aW9uRW5kRm4gPSAoKSA9PiB2b2lkO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zaXRpb25PcHRpb25zPFQ+IHtcblx0YW5pbWF0aW9uOiBib29sZWFuO1xuXHRydW5uaW5nVHJhbnNpdGlvbjogJ2NvbnRpbnVlJyB8ICdzdG9wJztcblx0Y29udGV4dD86IFQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNpdGlvbkN0eDxUPiB7XG5cdHRyYW5zaXRpb24kOiBTdWJqZWN0PGFueT47XG5cdGNvbXBsZXRlOiAoKSA9PiB2b2lkO1xuXHRjb250ZXh0OiBUO1xufVxuXG5jb25zdCBub29wRm46IFRyYW5zaXRpb25FbmRGbiA9ICgpID0+IHt9O1xuXG5jb25zdCBydW5uaW5nVHJhbnNpdGlvbnMgPSBuZXcgTWFwPEhUTUxFbGVtZW50LCBUcmFuc2l0aW9uQ3R4PGFueT4+KCk7XG5cbmV4cG9ydCBjb25zdCBodWJSdW5UcmFuc2l0aW9uID0gPFQ+KFxuXHR6b25lOiBOZ1pvbmUsXG5cdGVsZW1lbnQ6IEhUTUxFbGVtZW50LFxuXHRzdGFydEZuOiBUcmFuc2l0aW9uU3RhcnRGbjxUPixcblx0b3B0aW9uczogVHJhbnNpdGlvbk9wdGlvbnM8VD5cbik6IE9ic2VydmFibGU8dm9pZD4gPT4ge1xuXHQvLyBHZXR0aW5nIGluaXRpYWwgY29udGV4dCBmcm9tIG9wdGlvbnNcblx0bGV0IGNvbnRleHQgPSBvcHRpb25zLmNvbnRleHQgfHwgPFQ+e307XG5cblx0Ly8gQ2hlY2tpbmcgaWYgdGhlcmUgYXJlIGFscmVhZHkgcnVubmluZyB0cmFuc2l0aW9ucyBvbiB0aGUgZ2l2ZW4gZWxlbWVudC5cblx0Y29uc3QgcnVubmluZyA9IHJ1bm5pbmdUcmFuc2l0aW9ucy5nZXQoZWxlbWVudCk7XG5cdGlmIChydW5uaW5nKSB7XG5cdFx0c3dpdGNoIChvcHRpb25zLnJ1bm5pbmdUcmFuc2l0aW9uKSB7XG5cdFx0XHQvLyBJZiB0aGVyZSBpcyBvbmUgcnVubmluZyBhbmQgd2Ugd2FudCBmb3IgaXQgdG8gJ2NvbnRpbnVlJyB0byBydW4sIHdlIGhhdmUgdG8gY2FuY2VsIHRoZSBuZXcgb25lLlxuXHRcdFx0Ly8gV2UncmUgbm90IGVtaXR0aW5nIGFueSB2YWx1ZXMsIGJ1dCBzaW1wbHkgY29tcGxldGluZyB0aGUgb2JzZXJ2YWJsZSAoRU1QVFkpLlxuXHRcdFx0Y2FzZSAnY29udGludWUnOlxuXHRcdFx0XHRyZXR1cm4gRU1QVFk7XG5cdFx0XHQvLyBJZiB0aGVyZSBpcyBvbmUgcnVubmluZyBhbmQgd2Ugd2FudCBmb3IgaXQgdG8gJ3N0b3AnLCB3ZSBoYXZlIHRvIGNvbXBsZXRlIHRoZSBydW5uaW5nIG9uZS5cblx0XHRcdC8vIFdlJ3JlIHNpbXBseSBjb21wbGV0aW5nIHRoZSBydW5uaW5nIG9uZSBhbmQgbm90IGVtaXR0aW5nIGFueSB2YWx1ZXMgYW5kIG1lcmdpbmcgbmV3bHkgcHJvdmlkZWQgY29udGV4dFxuXHRcdFx0Ly8gd2l0aCB0aGUgb25lIGNvbWluZyBmcm9tIGN1cnJlbnRseSBydW5uaW5nIHRyYW5zaXRpb24uXG5cdFx0XHRjYXNlICdzdG9wJzpcblx0XHRcdFx0em9uZS5ydW4oKCkgPT4gcnVubmluZy50cmFuc2l0aW9uJC5jb21wbGV0ZSgpKTtcblx0XHRcdFx0Y29udGV4dCA9IE9iamVjdC5hc3NpZ24ocnVubmluZy5jb250ZXh0LCBjb250ZXh0KTtcblx0XHRcdFx0cnVubmluZ1RyYW5zaXRpb25zLmRlbGV0ZShlbGVtZW50KTtcblx0XHR9XG5cdH1cblxuXHQvLyBSdW5uaW5nIHRoZSBzdGFydCBmdW5jdGlvblxuXHRjb25zdCBlbmRGbiA9IHN0YXJ0Rm4oZWxlbWVudCwgb3B0aW9ucy5hbmltYXRpb24sIGNvbnRleHQpIHx8IG5vb3BGbjtcblxuXHQvLyBJZiAncHJlZmVyLXJlZHVjZWQtbW90aW9uJyBpcyBlbmFibGVkLCB0aGUgJ3RyYW5zaXRpb24nIHdpbGwgYmUgc2V0IHRvICdub25lJy5cblx0Ly8gSWYgYW5pbWF0aW9ucyBhcmUgZGlzYWJsZWQsIHdlIGhhdmUgdG8gZW1pdCBhIHZhbHVlIGFuZCBjb21wbGV0ZSB0aGUgb2JzZXJ2YWJsZVxuXHQvLyBJbiB0aGlzIGNhc2Ugd2UgaGF2ZSB0byBjYWxsIHRoZSBlbmQgZnVuY3Rpb24sIGJ1dCBjYW4gZmluaXNoIGltbWVkaWF0ZWx5IGJ5IGVtaXR0aW5nIGEgdmFsdWUsXG5cdC8vIGNvbXBsZXRpbmcgdGhlIG9ic2VydmFibGUgYW5kIGV4ZWN1dGluZyBlbmQgZnVuY3Rpb25zIHN5bmNocm9ub3VzbHkuXG5cdGlmIChcblx0XHQhb3B0aW9ucy5hbmltYXRpb24gfHxcblx0XHR3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbGVtZW50KS50cmFuc2l0aW9uUHJvcGVydHkgPT09ICdub25lJ1xuXHQpIHtcblx0XHR6b25lLnJ1bigoKSA9PiBlbmRGbigpKTtcblx0XHRyZXR1cm4gb2YodW5kZWZpbmVkKS5waXBlKHJ1bkluWm9uZSh6b25lKSk7XG5cdH1cblxuXHQvLyBTdGFydGluZyBhIG5ldyB0cmFuc2l0aW9uXG5cdGNvbnN0IHRyYW5zaXRpb24kID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblx0Y29uc3QgZmluaXNoVHJhbnNpdGlvbiQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXHRjb25zdCBzdG9wJCA9IHRyYW5zaXRpb24kLnBpcGUoZW5kV2l0aCh0cnVlKSk7XG5cdHJ1bm5pbmdUcmFuc2l0aW9ucy5zZXQoZWxlbWVudCwge1xuXHRcdHRyYW5zaXRpb24kLFxuXHRcdGNvbXBsZXRlOiAoKSA9PiB7XG5cdFx0XHRmaW5pc2hUcmFuc2l0aW9uJC5uZXh0KCk7XG5cdFx0XHRmaW5pc2hUcmFuc2l0aW9uJC5jb21wbGV0ZSgpO1xuXHRcdH0sXG5cdFx0Y29udGV4dFxuXHR9KTtcblxuXHRjb25zdCB0cmFuc2l0aW9uRHVyYXRpb25NcyA9IGdldFRyYW5zaXRpb25EdXJhdGlvbk1zKGVsZW1lbnQpO1xuXG5cdC8vIDEuIFdlIGhhdmUgdG8gYm90aCBsaXN0ZW4gZm9yIHRoZSAndHJhbnNpdGlvbmVuZCcgZXZlbnQgYW5kIGhhdmUgYSAnanVzdC1pbi1jYXNlJyB0aW1lcixcblx0Ly8gYmVjYXVzZSAndHJhbnNpdGlvbmVuZCcgZXZlbnQgbWlnaHQgbm90IGJlIGZpcmVkIGluIHNvbWUgYnJvd3NlcnMsIGlmIHRoZSB0cmFuc2l0aW9uaW5nXG5cdC8vIGVsZW1lbnQgYmVjb21lcyBpbnZpc2libGUgKGV4LiB3aGVuIHNjcm9sbGluZywgbWFraW5nIGJyb3dzZXIgdGFiIGluYWN0aXZlLCBldGMuKS4gVGhlIHRpbWVyXG5cdC8vIGd1YXJhbnRlZXMsIHRoYXQgd2UnbGwgcmVsZWFzZSB0aGUgRE9NIGVsZW1lbnQgYW5kIGNvbXBsZXRlICdodWJSdW5UcmFuc2l0aW9uJy5cblx0Ly8gMi4gV2UgbmVlZCB0byBmaWx0ZXIgdHJhbnNpdGlvbiBlbmQgZXZlbnRzLCBiZWNhdXNlIHRoZXkgbWlnaHQgYnViYmxlIGZyb20gc2hvcnRlciB0cmFuc2l0aW9uc1xuXHQvLyBvbiBpbm5lciBET00gZWxlbWVudHMuIFdlJ3JlIG9ubHkgaW50ZXJlc3RlZCBpbiB0aGUgdHJhbnNpdGlvbiBvbiB0aGUgJ2VsZW1lbnQnIGl0c2VsZi5cblx0em9uZS5ydW5PdXRzaWRlQW5ndWxhcigoKSA9PiB7XG5cdFx0Y29uc3QgdHJhbnNpdGlvbkVuZCQgPSBmcm9tRXZlbnQoZWxlbWVudCwgJ3RyYW5zaXRpb25lbmQnKS5waXBlKFxuXHRcdFx0dGFrZVVudGlsKHN0b3AkKSxcblx0XHRcdGZpbHRlcigoeyB0YXJnZXQgfSkgPT4gdGFyZ2V0ID09PSBlbGVtZW50KVxuXHRcdCk7XG5cdFx0Y29uc3QgdGltZXIkID0gdGltZXIoXG5cdFx0XHR0cmFuc2l0aW9uRHVyYXRpb25NcyArIHRyYW5zaXRpb25UaW1lckRlbGF5TXNcblx0XHQpLnBpcGUodGFrZVVudGlsKHN0b3AkKSk7XG5cblx0XHRyYWNlKHRpbWVyJCwgdHJhbnNpdGlvbkVuZCQsIGZpbmlzaFRyYW5zaXRpb24kKVxuXHRcdFx0LnBpcGUodGFrZVVudGlsKHN0b3AkKSlcblx0XHRcdC5zdWJzY3JpYmUoKCkgPT4ge1xuXHRcdFx0XHRydW5uaW5nVHJhbnNpdGlvbnMuZGVsZXRlKGVsZW1lbnQpO1xuXHRcdFx0XHR6b25lLnJ1bigoKSA9PiB7XG5cdFx0XHRcdFx0ZW5kRm4oKTtcblx0XHRcdFx0XHR0cmFuc2l0aW9uJC5uZXh0KCk7XG5cdFx0XHRcdFx0dHJhbnNpdGlvbiQuY29tcGxldGUoKTtcblx0XHRcdFx0fSk7XG5cdFx0XHR9KTtcblx0fSk7XG5cblx0cmV0dXJuIHRyYW5zaXRpb24kLmFzT2JzZXJ2YWJsZSgpO1xufTtcblxuZXhwb3J0IGNvbnN0IGh1YkNvbXBsZXRlVHJhbnNpdGlvbiA9IChlbGVtZW50OiBIVE1MRWxlbWVudCkgPT4ge1xuXHRydW5uaW5nVHJhbnNpdGlvbnMuZ2V0KGVsZW1lbnQpPy5jb21wbGV0ZSgpO1xufTtcbiJdfQ==
@@ -0,0 +1,7 @@
1
+ export function getTransitionDurationMs(element) {
2
+ const { transitionDelay, transitionDuration } = window.getComputedStyle(element);
3
+ const transitionDelaySec = parseFloat(transitionDelay);
4
+ const transitionDurationSec = parseFloat(transitionDuration);
5
+ return (transitionDelaySec + transitionDurationSec) * 1000;
6
+ }
7
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3V0aWxzL3NyYy9saWIvdHJhbnNpdGlvbnMvdXRpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLFVBQVUsdUJBQXVCLENBQUMsT0FBb0I7SUFDM0QsTUFBTSxFQUFFLGVBQWUsRUFBRSxrQkFBa0IsRUFBRSxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNqRixNQUFNLGtCQUFrQixHQUFHLFVBQVUsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUN2RCxNQUFNLHFCQUFxQixHQUFHLFVBQVUsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBRTdELE9BQU8sQ0FBQyxrQkFBa0IsR0FBRyxxQkFBcUIsQ0FBQyxHQUFHLElBQUksQ0FBQztBQUM1RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGZ1bmN0aW9uIGdldFRyYW5zaXRpb25EdXJhdGlvbk1zKGVsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XG5cdGNvbnN0IHsgdHJhbnNpdGlvbkRlbGF5LCB0cmFuc2l0aW9uRHVyYXRpb24gfSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsZW1lbnQpO1xuXHRjb25zdCB0cmFuc2l0aW9uRGVsYXlTZWMgPSBwYXJzZUZsb2F0KHRyYW5zaXRpb25EZWxheSk7XG5cdGNvbnN0IHRyYW5zaXRpb25EdXJhdGlvblNlYyA9IHBhcnNlRmxvYXQodHJhbnNpdGlvbkR1cmF0aW9uKTtcblxuXHRyZXR1cm4gKHRyYW5zaXRpb25EZWxheVNlYyArIHRyYW5zaXRpb25EdXJhdGlvblNlYykgKiAxMDAwO1xufVxuIl19
@@ -0,0 +1,132 @@
1
+ import { Observable } from 'rxjs';
2
+ /**
3
+ * Converts a value to an integer using parseInt.
4
+ *
5
+ * @param {any} value - The `value` parameter in the `toInteger` function is the input value that needs to be converted to an
6
+ * integer.
7
+ *
8
+ * @returns Is returning the parsed integer value of the input `value`.
9
+ */
10
+ export function toInteger(value) {
11
+ return parseInt(`${value}`, 10);
12
+ }
13
+ export function toString(value) {
14
+ return value !== undefined && value !== null ? `${value}` : '';
15
+ }
16
+ export function getValueInRange(value, max, min = 0) {
17
+ return Math.max(Math.min(value, max), min);
18
+ }
19
+ export function isString(value) {
20
+ return typeof value === 'string';
21
+ }
22
+ export function isNumber(value) {
23
+ return !isNaN(toInteger(value));
24
+ }
25
+ export function isInteger(value) {
26
+ return (typeof value === 'number' &&
27
+ isFinite(value) &&
28
+ Math.floor(value) === value);
29
+ }
30
+ export function isDefined(value) {
31
+ return value !== undefined && value !== null;
32
+ }
33
+ /**
34
+ * Checks if a value is a Promise.
35
+ *
36
+ * @param {any} v - The parameter `v` in the `isPromise` function represents any value that is being checked to determine if it is
37
+ * a Promise.
38
+ *
39
+ * @returns A boolean value indicating whether the input `v` is a Promise or not. If `v` has a `then` property, it is considered
40
+ * a Promise and the function returns `true`. Otherwise, it returns `false`.
41
+ */
42
+ export function isPromise(v) {
43
+ return v && v.then;
44
+ }
45
+ /**
46
+ * Pads a number with a leading zero if it is a valid number.
47
+ *
48
+ * @param {number} value - The `padNumber` function takes a number as input and pads it with a leading zero if it is a valid
49
+ * number. If the input is not a number, it returns an empty string.
50
+ *
51
+ * @returns Takes a number as input and pads it with a leading zero if it is a valid number. If the input is a number, the function
52
+ * returns the input value padded with a leading zero and sliced to keep only the last two characters. If the input is not a number,
53
+ * an empty string is returned.
54
+ */
55
+ export function padNumber(value) {
56
+ if (isNumber(value)) {
57
+ return `0${value}`.slice(-2);
58
+ }
59
+ else {
60
+ return '';
61
+ }
62
+ }
63
+ /**
64
+ * Escapes special characters in a given text to be used in a regular expression.
65
+ *
66
+ * @param text - The `regExpEscape` function takes a `text` parameter as input. This function is designed to escape special
67
+ * characters in a given text so that it can be safely used within a regular expression pattern.
68
+ *
69
+ * @returns A new string with any special characters in the input `text` escaped with a backslash.
70
+ */
71
+ export function regExpEscape(text) {
72
+ return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
73
+ }
74
+ export function closest(element, selector) {
75
+ if (!selector) {
76
+ return null;
77
+ }
78
+ /*
79
+ * In certain browsers (e.g. Edge 44.18362.449.0) HTMLDocument does
80
+ * not support `Element.prototype.closest`. To emulate the correct behaviour
81
+ * we return null when the method is missing.
82
+ *
83
+ * Note that in evergreen browsers `closest(document.documentElement, 'html')`
84
+ * will return the document element whilst in Edge null will be returned. This
85
+ * compromise was deemed good enough.
86
+ */
87
+ if (typeof element.closest === 'undefined') {
88
+ return null;
89
+ }
90
+ return element.closest(selector);
91
+ }
92
+ /**
93
+ * Force a browser reflow
94
+ *
95
+ * @param element element where to apply the reflow
96
+ */
97
+ export function reflow(element) {
98
+ return (element || document.body).getBoundingClientRect();
99
+ }
100
+ /**
101
+ * Creates an observable where all callbacks are executed inside a given zone
102
+ *
103
+ * @param zone
104
+ */
105
+ export function runInZone(zone) {
106
+ return (source) => {
107
+ return new Observable((observer) => {
108
+ const next = (value) => zone.run(() => observer.next(value));
109
+ const error = (e) => zone.run(() => observer.error(e));
110
+ const complete = () => zone.run(() => observer.complete());
111
+ return source.subscribe({ next, error, complete });
112
+ });
113
+ };
114
+ }
115
+ export function removeAccents(str) {
116
+ return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
117
+ }
118
+ /**
119
+ * Returns the active element in the given root.
120
+ *
121
+ * If the active element is inside a shadow root, it is searched recursively.
122
+ */
123
+ export function getActiveElement(root = document) {
124
+ const activeEl = root?.activeElement;
125
+ if (!activeEl) {
126
+ return null;
127
+ }
128
+ return activeEl.shadowRoot
129
+ ? getActiveElement(activeEl.shadowRoot)
130
+ : activeEl;
131
+ }
132
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3V0aWxzL3NyYy9saWIvdXRpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsVUFBVSxFQUFvQixNQUFNLE1BQU0sQ0FBQztBQUVwRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxLQUFVO0lBQ25DLE9BQU8sUUFBUSxDQUFDLEdBQUcsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDakMsQ0FBQztBQUVELE1BQU0sVUFBVSxRQUFRLENBQUMsS0FBVTtJQUNsQyxPQUFPLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0FBQ2hFLENBQUM7QUFFRCxNQUFNLFVBQVUsZUFBZSxDQUFDLEtBQWEsRUFBRSxHQUFXLEVBQUUsR0FBRyxHQUFHLENBQUM7SUFDbEUsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQzVDLENBQUM7QUFFRCxNQUFNLFVBQVUsUUFBUSxDQUFDLEtBQVU7SUFDbEMsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUM7QUFDbEMsQ0FBQztBQUVELE1BQU0sVUFBVSxRQUFRLENBQUMsS0FBVTtJQUNsQyxPQUFPLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEtBQVU7SUFDbkMsT0FBTyxDQUNOLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFDekIsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUNmLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssS0FBSyxDQUMzQixDQUFDO0FBQ0gsQ0FBQztBQUVELE1BQU0sVUFBVSxTQUFTLENBQUMsS0FBVTtJQUNuQyxPQUFPLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQztBQUM5QyxDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLFVBQVUsU0FBUyxDQUFJLENBQU07SUFDbEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQztBQUNwQixDQUFDO0FBRUQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxLQUFhO0lBQ3RDLElBQUksUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFO1FBQ3BCLE9BQU8sSUFBSSxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUM3QjtTQUFNO1FBQ04sT0FBTyxFQUFFLENBQUM7S0FDVjtBQUNGLENBQUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLFlBQVksQ0FBQyxJQUFJO0lBQ2hDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBRUQsTUFBTSxVQUFVLE9BQU8sQ0FDdEIsT0FBb0IsRUFDcEIsUUFBaUI7SUFFakIsSUFBSSxDQUFDLFFBQVEsRUFBRTtRQUNkLE9BQU8sSUFBSSxDQUFDO0tBQ1o7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILElBQUksT0FBTyxPQUFPLENBQUMsT0FBTyxLQUFLLFdBQVcsRUFBRTtRQUMzQyxPQUFPLElBQUksQ0FBQztLQUNaO0lBRUQsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQ2xDLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLE1BQU0sQ0FBQyxPQUFvQjtJQUMxQyxPQUFPLENBQUMsT0FBTyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDO0FBQzNELENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBSSxJQUFZO0lBQ3hDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRTtRQUNqQixPQUFPLElBQUksVUFBVSxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUU7WUFDbEMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxLQUFRLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1lBQ2hFLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM1RCxNQUFNLFFBQVEsR0FBRyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQzNELE9BQU8sTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUNwRCxDQUFDLENBQUMsQ0FBQztJQUNKLENBQUMsQ0FBQztBQUNILENBQUM7QUFFRCxNQUFNLFVBQVUsYUFBYSxDQUFDLEdBQVc7SUFDeEMsT0FBTyxHQUFHLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FDL0IsT0FBOEIsUUFBUTtJQUV0QyxNQUFNLFFBQVEsR0FBRyxJQUFJLEVBQUUsYUFBYSxDQUFDO0lBRXJDLElBQUksQ0FBQyxRQUFRLEVBQUU7UUFDZCxPQUFPLElBQUksQ0FBQztLQUNaO0lBRUQsT0FBTyxRQUFRLENBQUMsVUFBVTtRQUN6QixDQUFDLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztRQUN2QyxDQUFDLENBQUMsUUFBUSxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgT3BlcmF0b3JGdW5jdGlvbiB9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYW4gaW50ZWdlciB1c2luZyBwYXJzZUludC5cbiAqXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgYHZhbHVlYCBwYXJhbWV0ZXIgaW4gdGhlIGB0b0ludGVnZXJgIGZ1bmN0aW9uIGlzIHRoZSBpbnB1dCB2YWx1ZSB0aGF0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhblxuICogaW50ZWdlci5cbiAqXG4gKiBAcmV0dXJucyBJcyByZXR1cm5pbmcgdGhlIHBhcnNlZCBpbnRlZ2VyIHZhbHVlIG9mIHRoZSBpbnB1dCBgdmFsdWVgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9JbnRlZ2VyKHZhbHVlOiBhbnkpOiBudW1iZXIge1xuXHRyZXR1cm4gcGFyc2VJbnQoYCR7dmFsdWV9YCwgMTApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9TdHJpbmcodmFsdWU6IGFueSk6IHN0cmluZyB7XG5cdHJldHVybiB2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsID8gYCR7dmFsdWV9YCA6ICcnO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmFsdWVJblJhbmdlKHZhbHVlOiBudW1iZXIsIG1heDogbnVtYmVyLCBtaW4gPSAwKTogbnVtYmVyIHtcblx0cmV0dXJuIE1hdGgubWF4KE1hdGgubWluKHZhbHVlLCBtYXgpLCBtaW4pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNTdHJpbmcodmFsdWU6IGFueSk6IHZhbHVlIGlzIHN0cmluZyB7XG5cdHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNOdW1iZXIodmFsdWU6IGFueSk6IHZhbHVlIGlzIG51bWJlciB7XG5cdHJldHVybiAhaXNOYU4odG9JbnRlZ2VyKHZhbHVlKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0ludGVnZXIodmFsdWU6IGFueSk6IHZhbHVlIGlzIG51bWJlciB7XG5cdHJldHVybiAoXG5cdFx0dHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyAmJlxuXHRcdGlzRmluaXRlKHZhbHVlKSAmJlxuXHRcdE1hdGguZmxvb3IodmFsdWUpID09PSB2YWx1ZVxuXHQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNEZWZpbmVkKHZhbHVlOiBhbnkpOiBib29sZWFuIHtcblx0cmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGw7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYSBQcm9taXNlLlxuICpcbiAqIEBwYXJhbSB7YW55fSB2IC0gVGhlIHBhcmFtZXRlciBgdmAgaW4gdGhlIGBpc1Byb21pc2VgIGZ1bmN0aW9uIHJlcHJlc2VudHMgYW55IHZhbHVlIHRoYXQgaXMgYmVpbmcgY2hlY2tlZCB0byBkZXRlcm1pbmUgaWYgaXQgaXNcbiAqIGEgUHJvbWlzZS5cbiAqXG4gKiBAcmV0dXJucyBBIGJvb2xlYW4gdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBpbnB1dCBgdmAgaXMgYSBQcm9taXNlIG9yIG5vdC4gSWYgYHZgIGhhcyBhIGB0aGVuYCBwcm9wZXJ0eSwgaXQgaXMgY29uc2lkZXJlZFxuICogYSBQcm9taXNlIGFuZCB0aGUgZnVuY3Rpb24gcmV0dXJucyBgdHJ1ZWAuIE90aGVyd2lzZSwgaXQgcmV0dXJucyBgZmFsc2VgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNQcm9taXNlPFQ+KHY6IGFueSk6IHYgaXMgUHJvbWlzZTxUPiB7XG5cdHJldHVybiB2ICYmIHYudGhlbjtcbn1cblxuLyoqXG4gKiBQYWRzIGEgbnVtYmVyIHdpdGggYSBsZWFkaW5nIHplcm8gaWYgaXQgaXMgYSB2YWxpZCBudW1iZXIuXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIGBwYWROdW1iZXJgIGZ1bmN0aW9uIHRha2VzIGEgbnVtYmVyIGFzIGlucHV0IGFuZCBwYWRzIGl0IHdpdGggYSBsZWFkaW5nIHplcm8gaWYgaXQgaXMgYSB2YWxpZFxuICogbnVtYmVyLiBJZiB0aGUgaW5wdXQgaXMgbm90IGEgbnVtYmVyLCBpdCByZXR1cm5zIGFuIGVtcHR5IHN0cmluZy5cbiAqXG4gKiBAcmV0dXJucyBUYWtlcyBhIG51bWJlciBhcyBpbnB1dCBhbmQgcGFkcyBpdCB3aXRoIGEgbGVhZGluZyB6ZXJvIGlmIGl0IGlzIGEgdmFsaWQgbnVtYmVyLiBJZiB0aGUgaW5wdXQgaXMgYSBudW1iZXIsIHRoZSBmdW5jdGlvblxuICogcmV0dXJucyB0aGUgaW5wdXQgdmFsdWUgcGFkZGVkIHdpdGggYSBsZWFkaW5nIHplcm8gYW5kIHNsaWNlZCB0byBrZWVwIG9ubHkgdGhlIGxhc3QgdHdvIGNoYXJhY3RlcnMuIElmIHRoZSBpbnB1dCBpcyBub3QgYSBudW1iZXIsXG4gKiBhbiBlbXB0eSBzdHJpbmcgaXMgcmV0dXJuZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwYWROdW1iZXIodmFsdWU6IG51bWJlcikge1xuXHRpZiAoaXNOdW1iZXIodmFsdWUpKSB7XG5cdFx0cmV0dXJuIGAwJHt2YWx1ZX1gLnNsaWNlKC0yKTtcblx0fSBlbHNlIHtcblx0XHRyZXR1cm4gJyc7XG5cdH1cbn1cblxuLyoqXG4gKiBFc2NhcGVzIHNwZWNpYWwgY2hhcmFjdGVycyBpbiBhIGdpdmVuIHRleHQgdG8gYmUgdXNlZCBpbiBhIHJlZ3VsYXIgZXhwcmVzc2lvbi5cbiAqXG4gKiBAcGFyYW0gdGV4dCAtIFRoZSBgcmVnRXhwRXNjYXBlYCBmdW5jdGlvbiB0YWtlcyBhIGB0ZXh0YCBwYXJhbWV0ZXIgYXMgaW5wdXQuIFRoaXMgZnVuY3Rpb24gaXMgZGVzaWduZWQgdG8gZXNjYXBlIHNwZWNpYWxcbiAqIGNoYXJhY3RlcnMgaW4gYSBnaXZlbiB0ZXh0IHNvIHRoYXQgaXQgY2FuIGJlIHNhZmVseSB1c2VkIHdpdGhpbiBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBwYXR0ZXJuLlxuICpcbiAqIEByZXR1cm5zIEEgbmV3IHN0cmluZyB3aXRoIGFueSBzcGVjaWFsIGNoYXJhY3RlcnMgaW4gdGhlIGlucHV0IGB0ZXh0YCBlc2NhcGVkIHdpdGggYSBiYWNrc2xhc2guXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWdFeHBFc2NhcGUodGV4dCkge1xuXHRyZXR1cm4gdGV4dC5yZXBsYWNlKC9bLVtcXF17fSgpKis/LixcXFxcXiR8I1xcc10vZywgJ1xcXFwkJicpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xvc2VzdChcblx0ZWxlbWVudDogSFRNTEVsZW1lbnQsXG5cdHNlbGVjdG9yPzogc3RyaW5nXG4pOiBIVE1MRWxlbWVudCB8IG51bGwge1xuXHRpZiAoIXNlbGVjdG9yKSB7XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHQvKlxuXHQgKiBJbiBjZXJ0YWluIGJyb3dzZXJzIChlLmcuIEVkZ2UgNDQuMTgzNjIuNDQ5LjApIEhUTUxEb2N1bWVudCBkb2VzXG5cdCAqIG5vdCBzdXBwb3J0IGBFbGVtZW50LnByb3RvdHlwZS5jbG9zZXN0YC4gVG8gZW11bGF0ZSB0aGUgY29ycmVjdCBiZWhhdmlvdXJcblx0ICogd2UgcmV0dXJuIG51bGwgd2hlbiB0aGUgbWV0aG9kIGlzIG1pc3NpbmcuXG5cdCAqXG5cdCAqIE5vdGUgdGhhdCBpbiBldmVyZ3JlZW4gYnJvd3NlcnMgYGNsb3Nlc3QoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LCAnaHRtbCcpYFxuXHQgKiB3aWxsIHJldHVybiB0aGUgZG9jdW1lbnQgZWxlbWVudCB3aGlsc3QgaW4gRWRnZSBudWxsIHdpbGwgYmUgcmV0dXJuZWQuIFRoaXNcblx0ICogY29tcHJvbWlzZSB3YXMgZGVlbWVkIGdvb2QgZW5vdWdoLlxuXHQgKi9cblx0aWYgKHR5cGVvZiBlbGVtZW50LmNsb3Nlc3QgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cblxuXHRyZXR1cm4gZWxlbWVudC5jbG9zZXN0KHNlbGVjdG9yKTtcbn1cblxuLyoqXG4gKiBGb3JjZSBhIGJyb3dzZXIgcmVmbG93XG4gKlxuICogQHBhcmFtIGVsZW1lbnQgZWxlbWVudCB3aGVyZSB0byBhcHBseSB0aGUgcmVmbG93XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWZsb3coZWxlbWVudDogSFRNTEVsZW1lbnQpIHtcblx0cmV0dXJuIChlbGVtZW50IHx8IGRvY3VtZW50LmJvZHkpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYW4gb2JzZXJ2YWJsZSB3aGVyZSBhbGwgY2FsbGJhY2tzIGFyZSBleGVjdXRlZCBpbnNpZGUgYSBnaXZlbiB6b25lXG4gKlxuICogQHBhcmFtIHpvbmVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJ1bkluWm9uZTxUPih6b25lOiBOZ1pvbmUpOiBPcGVyYXRvckZ1bmN0aW9uPFQsIFQ+IHtcblx0cmV0dXJuIChzb3VyY2UpID0+IHtcblx0XHRyZXR1cm4gbmV3IE9ic2VydmFibGUoKG9ic2VydmVyKSA9PiB7XG5cdFx0XHRjb25zdCBuZXh0ID0gKHZhbHVlOiBUKSA9PiB6b25lLnJ1bigoKSA9PiBvYnNlcnZlci5uZXh0KHZhbHVlKSk7XG5cdFx0XHRjb25zdCBlcnJvciA9IChlOiBhbnkpID0+IHpvbmUucnVuKCgpID0+IG9ic2VydmVyLmVycm9yKGUpKTtcblx0XHRcdGNvbnN0IGNvbXBsZXRlID0gKCkgPT4gem9uZS5ydW4oKCkgPT4gb2JzZXJ2ZXIuY29tcGxldGUoKSk7XG5cdFx0XHRyZXR1cm4gc291cmNlLnN1YnNjcmliZSh7IG5leHQsIGVycm9yLCBjb21wbGV0ZSB9KTtcblx0XHR9KTtcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlbW92ZUFjY2VudHMoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRyZXR1cm4gc3RyLm5vcm1hbGl6ZSgnTkZEJykucmVwbGFjZSgvW1xcdTAzMDAtXFx1MDM2Zl0vZywgJycpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGFjdGl2ZSBlbGVtZW50IGluIHRoZSBnaXZlbiByb290LlxuICpcbiAqIElmIHRoZSBhY3RpdmUgZWxlbWVudCBpcyBpbnNpZGUgYSBzaGFkb3cgcm9vdCwgaXQgaXMgc2VhcmNoZWQgcmVjdXJzaXZlbHkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRBY3RpdmVFbGVtZW50KFxuXHRyb290OiBEb2N1bWVudCB8IFNoYWRvd1Jvb3QgPSBkb2N1bWVudFxuKTogRWxlbWVudCB8IG51bGwge1xuXHRjb25zdCBhY3RpdmVFbCA9IHJvb3Q/LmFjdGl2ZUVsZW1lbnQ7XG5cblx0aWYgKCFhY3RpdmVFbCkge1xuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0cmV0dXJuIGFjdGl2ZUVsLnNoYWRvd1Jvb3Rcblx0XHQ/IGdldEFjdGl2ZUVsZW1lbnQoYWN0aXZlRWwuc2hhZG93Um9vdClcblx0XHQ6IGFjdGl2ZUVsO1xufVxuIl19
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './public-api';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctaHViLXVpLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvdXRpbHMvc3JjL25nLWh1Yi11aS11dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3B1YmxpYy1hcGknO1xuIl19
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Public API Surface of utils
3
+ */
4
+ export * from './lib/focus-trap';
5
+ export * from './lib/popup';
6
+ export * from './lib/scrollbar';
7
+ export * from './lib/util';
8
+ export * from './lib/transitions';
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL3V0aWxzL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMsWUFBWSxDQUFDO0FBQzNCLGNBQWMsbUJBQW1CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIHV0aWxzXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvZm9jdXMtdHJhcCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9wb3B1cCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9zY3JvbGxiYXInO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvdXRpbCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi90cmFuc2l0aW9ucyc7XG4iXX0=
@@ -0,0 +1,387 @@
1
+ import { fromEvent, Observable, EMPTY, of, Subject, timer, race } from 'rxjs';
2
+ import { takeUntil, map, filter, withLatestFrom, endWith, take, mergeMap, tap } from 'rxjs/operators';
3
+ import * as i0 from '@angular/core';
4
+ import { inject, ApplicationRef, Injector, ViewContainerRef, NgZone, TemplateRef, Injectable } from '@angular/core';
5
+ import { DOCUMENT } from '@angular/common';
6
+
7
+ const FOCUSABLE_ELEMENTS_SELECTOR = [
8
+ 'a[href]',
9
+ 'button:not([disabled])',
10
+ 'input:not([disabled]):not([type="hidden"])',
11
+ 'select:not([disabled])',
12
+ 'textarea:not([disabled])',
13
+ '[contenteditable]',
14
+ '[tabindex]:not([tabindex="-1"])'
15
+ ].join(', ');
16
+ /**
17
+ * Returns first and last focusable elements inside of a given element based on specific CSS selector
18
+ */
19
+ function getFocusableBoundaryElements(element) {
20
+ const list = Array.from(element.querySelectorAll(FOCUSABLE_ELEMENTS_SELECTOR)).filter((el) => el.tabIndex !== -1);
21
+ return [list[0], list[list.length - 1]];
22
+ }
23
+ /**
24
+ * Function that enforces browser focus to be trapped inside a DOM element.
25
+ *
26
+ * Works only for clicks inside the element and navigation with 'Tab', ignoring clicks outside of the element
27
+ *
28
+ * @param zone Angular zone
29
+ * @param element The element around which focus will be trapped inside
30
+ * @param stopFocusTrap$ The observable stream. When completed the focus trap will clean up listeners
31
+ * and free internal resources
32
+ * @param refocusOnClick Put the focus back to the last focused element whenever a click occurs on element (default to
33
+ * false)
34
+ */
35
+ const hubFocusTrap = (zone, element, stopFocusTrap$, refocusOnClick = false) => {
36
+ zone.runOutsideAngular(() => {
37
+ // last focused element
38
+ const lastFocusedElement$ = fromEvent(element, 'focusin').pipe(takeUntil(stopFocusTrap$), map((e) => e.target));
39
+ // 'tab' / 'shift+tab' stream
40
+ fromEvent(element, 'keydown')
41
+ .pipe(takeUntil(stopFocusTrap$), filter((e) => e.key === 'Tab'), withLatestFrom(lastFocusedElement$))
42
+ .subscribe(([tabEvent, focusedElement]) => {
43
+ const [first, last] = getFocusableBoundaryElements(element);
44
+ if ((focusedElement === first || focusedElement === element) &&
45
+ tabEvent.shiftKey) {
46
+ last.focus();
47
+ tabEvent.preventDefault();
48
+ }
49
+ if (focusedElement === last && !tabEvent.shiftKey) {
50
+ first.focus();
51
+ tabEvent.preventDefault();
52
+ }
53
+ });
54
+ // inside click
55
+ if (refocusOnClick) {
56
+ fromEvent(element, 'click')
57
+ .pipe(takeUntil(stopFocusTrap$), withLatestFrom(lastFocusedElement$), map((arr) => arr[1]))
58
+ .subscribe((lastFocusedElement) => lastFocusedElement.focus());
59
+ }
60
+ });
61
+ };
62
+
63
+ /**
64
+ * Converts a value to an integer using parseInt.
65
+ *
66
+ * @param {any} value - The `value` parameter in the `toInteger` function is the input value that needs to be converted to an
67
+ * integer.
68
+ *
69
+ * @returns Is returning the parsed integer value of the input `value`.
70
+ */
71
+ function toInteger(value) {
72
+ return parseInt(`${value}`, 10);
73
+ }
74
+ function toString(value) {
75
+ return value !== undefined && value !== null ? `${value}` : '';
76
+ }
77
+ function getValueInRange(value, max, min = 0) {
78
+ return Math.max(Math.min(value, max), min);
79
+ }
80
+ function isString(value) {
81
+ return typeof value === 'string';
82
+ }
83
+ function isNumber(value) {
84
+ return !isNaN(toInteger(value));
85
+ }
86
+ function isInteger(value) {
87
+ return (typeof value === 'number' &&
88
+ isFinite(value) &&
89
+ Math.floor(value) === value);
90
+ }
91
+ function isDefined(value) {
92
+ return value !== undefined && value !== null;
93
+ }
94
+ /**
95
+ * Checks if a value is a Promise.
96
+ *
97
+ * @param {any} v - The parameter `v` in the `isPromise` function represents any value that is being checked to determine if it is
98
+ * a Promise.
99
+ *
100
+ * @returns A boolean value indicating whether the input `v` is a Promise or not. If `v` has a `then` property, it is considered
101
+ * a Promise and the function returns `true`. Otherwise, it returns `false`.
102
+ */
103
+ function isPromise(v) {
104
+ return v && v.then;
105
+ }
106
+ /**
107
+ * Pads a number with a leading zero if it is a valid number.
108
+ *
109
+ * @param {number} value - The `padNumber` function takes a number as input and pads it with a leading zero if it is a valid
110
+ * number. If the input is not a number, it returns an empty string.
111
+ *
112
+ * @returns Takes a number as input and pads it with a leading zero if it is a valid number. If the input is a number, the function
113
+ * returns the input value padded with a leading zero and sliced to keep only the last two characters. If the input is not a number,
114
+ * an empty string is returned.
115
+ */
116
+ function padNumber(value) {
117
+ if (isNumber(value)) {
118
+ return `0${value}`.slice(-2);
119
+ }
120
+ else {
121
+ return '';
122
+ }
123
+ }
124
+ /**
125
+ * Escapes special characters in a given text to be used in a regular expression.
126
+ *
127
+ * @param text - The `regExpEscape` function takes a `text` parameter as input. This function is designed to escape special
128
+ * characters in a given text so that it can be safely used within a regular expression pattern.
129
+ *
130
+ * @returns A new string with any special characters in the input `text` escaped with a backslash.
131
+ */
132
+ function regExpEscape(text) {
133
+ return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
134
+ }
135
+ function closest(element, selector) {
136
+ if (!selector) {
137
+ return null;
138
+ }
139
+ /*
140
+ * In certain browsers (e.g. Edge 44.18362.449.0) HTMLDocument does
141
+ * not support `Element.prototype.closest`. To emulate the correct behaviour
142
+ * we return null when the method is missing.
143
+ *
144
+ * Note that in evergreen browsers `closest(document.documentElement, 'html')`
145
+ * will return the document element whilst in Edge null will be returned. This
146
+ * compromise was deemed good enough.
147
+ */
148
+ if (typeof element.closest === 'undefined') {
149
+ return null;
150
+ }
151
+ return element.closest(selector);
152
+ }
153
+ /**
154
+ * Force a browser reflow
155
+ *
156
+ * @param element element where to apply the reflow
157
+ */
158
+ function reflow(element) {
159
+ return (element || document.body).getBoundingClientRect();
160
+ }
161
+ /**
162
+ * Creates an observable where all callbacks are executed inside a given zone
163
+ *
164
+ * @param zone
165
+ */
166
+ function runInZone(zone) {
167
+ return (source) => {
168
+ return new Observable((observer) => {
169
+ const next = (value) => zone.run(() => observer.next(value));
170
+ const error = (e) => zone.run(() => observer.error(e));
171
+ const complete = () => zone.run(() => observer.complete());
172
+ return source.subscribe({ next, error, complete });
173
+ });
174
+ };
175
+ }
176
+ function removeAccents(str) {
177
+ return str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
178
+ }
179
+ /**
180
+ * Returns the active element in the given root.
181
+ *
182
+ * If the active element is inside a shadow root, it is searched recursively.
183
+ */
184
+ function getActiveElement(root = document) {
185
+ const activeEl = root?.activeElement;
186
+ if (!activeEl) {
187
+ return null;
188
+ }
189
+ return activeEl.shadowRoot
190
+ ? getActiveElement(activeEl.shadowRoot)
191
+ : activeEl;
192
+ }
193
+
194
+ function getTransitionDurationMs(element) {
195
+ const { transitionDelay, transitionDuration } = window.getComputedStyle(element);
196
+ const transitionDelaySec = parseFloat(transitionDelay);
197
+ const transitionDurationSec = parseFloat(transitionDuration);
198
+ return (transitionDelaySec + transitionDurationSec) * 1000;
199
+ }
200
+
201
+ const transitionTimerDelayMs = 5;
202
+ const noopFn = () => { };
203
+ const runningTransitions = new Map();
204
+ const hubRunTransition = (zone, element, startFn, options) => {
205
+ // Getting initial context from options
206
+ let context = options.context || {};
207
+ // Checking if there are already running transitions on the given element.
208
+ const running = runningTransitions.get(element);
209
+ if (running) {
210
+ switch (options.runningTransition) {
211
+ // If there is one running and we want for it to 'continue' to run, we have to cancel the new one.
212
+ // We're not emitting any values, but simply completing the observable (EMPTY).
213
+ case 'continue':
214
+ return EMPTY;
215
+ // If there is one running and we want for it to 'stop', we have to complete the running one.
216
+ // We're simply completing the running one and not emitting any values and merging newly provided context
217
+ // with the one coming from currently running transition.
218
+ case 'stop':
219
+ zone.run(() => running.transition$.complete());
220
+ context = Object.assign(running.context, context);
221
+ runningTransitions.delete(element);
222
+ }
223
+ }
224
+ // Running the start function
225
+ const endFn = startFn(element, options.animation, context) || noopFn;
226
+ // If 'prefer-reduced-motion' is enabled, the 'transition' will be set to 'none'.
227
+ // If animations are disabled, we have to emit a value and complete the observable
228
+ // In this case we have to call the end function, but can finish immediately by emitting a value,
229
+ // completing the observable and executing end functions synchronously.
230
+ if (!options.animation ||
231
+ window.getComputedStyle(element).transitionProperty === 'none') {
232
+ zone.run(() => endFn());
233
+ return of(undefined).pipe(runInZone(zone));
234
+ }
235
+ // Starting a new transition
236
+ const transition$ = new Subject();
237
+ const finishTransition$ = new Subject();
238
+ const stop$ = transition$.pipe(endWith(true));
239
+ runningTransitions.set(element, {
240
+ transition$,
241
+ complete: () => {
242
+ finishTransition$.next();
243
+ finishTransition$.complete();
244
+ },
245
+ context
246
+ });
247
+ const transitionDurationMs = getTransitionDurationMs(element);
248
+ // 1. We have to both listen for the 'transitionend' event and have a 'just-in-case' timer,
249
+ // because 'transitionend' event might not be fired in some browsers, if the transitioning
250
+ // element becomes invisible (ex. when scrolling, making browser tab inactive, etc.). The timer
251
+ // guarantees, that we'll release the DOM element and complete 'hubRunTransition'.
252
+ // 2. We need to filter transition end events, because they might bubble from shorter transitions
253
+ // on inner DOM elements. We're only interested in the transition on the 'element' itself.
254
+ zone.runOutsideAngular(() => {
255
+ const transitionEnd$ = fromEvent(element, 'transitionend').pipe(takeUntil(stop$), filter(({ target }) => target === element));
256
+ const timer$ = timer(transitionDurationMs + transitionTimerDelayMs).pipe(takeUntil(stop$));
257
+ race(timer$, transitionEnd$, finishTransition$)
258
+ .pipe(takeUntil(stop$))
259
+ .subscribe(() => {
260
+ runningTransitions.delete(element);
261
+ zone.run(() => {
262
+ endFn();
263
+ transition$.next();
264
+ transition$.complete();
265
+ });
266
+ });
267
+ });
268
+ return transition$.asObservable();
269
+ };
270
+ const hubCompleteTransition = (element) => {
271
+ runningTransitions.get(element)?.complete();
272
+ };
273
+
274
+ class ContentRef {
275
+ constructor(nodes, viewRef, componentRef) {
276
+ this.nodes = nodes;
277
+ this.viewRef = viewRef;
278
+ this.componentRef = componentRef;
279
+ }
280
+ }
281
+ class PopupService {
282
+ constructor(_componentType) {
283
+ this._componentType = _componentType;
284
+ this._windowRef = null;
285
+ this._contentRef = null;
286
+ this._document = inject(DOCUMENT);
287
+ this._applicationRef = inject(ApplicationRef);
288
+ this._injector = inject(Injector);
289
+ this._viewContainerRef = inject(ViewContainerRef);
290
+ this._ngZone = inject(NgZone);
291
+ }
292
+ open(content, templateContext, animation = false) {
293
+ if (!this._windowRef) {
294
+ this._contentRef = this._getContentRef(content, templateContext);
295
+ this._windowRef = this._viewContainerRef.createComponent(this._componentType, {
296
+ injector: this._injector,
297
+ projectableNodes: this._contentRef.nodes
298
+ });
299
+ }
300
+ const { nativeElement } = this._windowRef.location;
301
+ const transition$ = this._ngZone.onStable.pipe(take(1), mergeMap(() => hubRunTransition(this._ngZone, nativeElement, ({ classList }) => classList.add('show'), {
302
+ animation,
303
+ runningTransition: 'continue'
304
+ })));
305
+ return { windowRef: this._windowRef, transition$ };
306
+ }
307
+ close(animation = false) {
308
+ if (!this._windowRef) {
309
+ return of(undefined);
310
+ }
311
+ return hubRunTransition(this._ngZone, this._windowRef.location.nativeElement, ({ classList }) => classList.remove('show'), { animation, runningTransition: 'stop' }).pipe(tap(() => {
312
+ this._windowRef?.destroy();
313
+ this._contentRef?.viewRef?.destroy();
314
+ this._windowRef = null;
315
+ this._contentRef = null;
316
+ }));
317
+ }
318
+ _getContentRef(content, templateContext) {
319
+ if (!content) {
320
+ return new ContentRef([]);
321
+ }
322
+ else if (content instanceof TemplateRef) {
323
+ const viewRef = content.createEmbeddedView(templateContext);
324
+ this._applicationRef.attachView(viewRef);
325
+ return new ContentRef([viewRef.rootNodes], viewRef);
326
+ }
327
+ else {
328
+ return new ContentRef([
329
+ [this._document.createTextNode(`${content}`)]
330
+ ]);
331
+ }
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Utility to handle the scrollbar.
337
+ *
338
+ * It allows to hide the scrollbar and compensate the lack of a vertical scrollbar
339
+ * by adding an equivalent padding on the right of the body, and to revert this change.
340
+ */
341
+ class ScrollBar {
342
+ constructor() {
343
+ this._document = inject(DOCUMENT);
344
+ }
345
+ /**
346
+ * To be called to hide a potential vertical scrollbar:
347
+ * - if a scrollbar is there and has a width greater than 0, adds some compensation
348
+ * padding to the body to keep the same layout as when the scrollbar is there
349
+ * - adds overflow: hidden
350
+ *
351
+ * @return a callback used to revert the change
352
+ */
353
+ hide() {
354
+ const scrollbarWidth = Math.abs(window.innerWidth - this._document.documentElement.clientWidth);
355
+ const body = this._document.body;
356
+ const bodyStyle = body.style;
357
+ const { overflow, paddingRight } = bodyStyle;
358
+ if (scrollbarWidth > 0) {
359
+ const actualPadding = parseFloat(window.getComputedStyle(body).paddingRight);
360
+ bodyStyle.paddingRight = `${actualPadding + scrollbarWidth}px`;
361
+ }
362
+ bodyStyle.overflow = 'hidden';
363
+ return () => {
364
+ if (scrollbarWidth > 0) {
365
+ bodyStyle.paddingRight = paddingRight;
366
+ }
367
+ bodyStyle.overflow = overflow;
368
+ };
369
+ }
370
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ScrollBar, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
371
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ScrollBar, providedIn: 'root' }); }
372
+ }
373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.5", ngImport: i0, type: ScrollBar, decorators: [{
374
+ type: Injectable,
375
+ args: [{ providedIn: 'root' }]
376
+ }] });
377
+
378
+ /*
379
+ * Public API Surface of utils
380
+ */
381
+
382
+ /**
383
+ * Generated bundle index. Do not edit.
384
+ */
385
+
386
+ export { ContentRef, FOCUSABLE_ELEMENTS_SELECTOR, PopupService, ScrollBar, closest, getActiveElement, getFocusableBoundaryElements, getValueInRange, hubCompleteTransition, hubFocusTrap, hubRunTransition, isDefined, isInteger, isNumber, isPromise, isString, padNumber, reflow, regExpEscape, removeAccents, runInZone, toInteger, toString };
387
+ //# sourceMappingURL=ng-hub-ui-utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ng-hub-ui-utils.mjs","sources":["../../../projects/utils/src/lib/focus-trap.ts","../../../projects/utils/src/lib/util.ts","../../../projects/utils/src/lib/transitions/util.ts","../../../projects/utils/src/lib/transitions/transition.ts","../../../projects/utils/src/lib/popup.ts","../../../projects/utils/src/lib/scrollbar.ts","../../../projects/utils/src/public-api.ts","../../../projects/utils/src/ng-hub-ui-utils.ts"],"sourcesContent":["import { NgZone } from '@angular/core';\n\nimport { fromEvent, Observable } from 'rxjs';\nimport { filter, map, takeUntil, withLatestFrom } from 'rxjs/operators';\n\nexport const FOCUSABLE_ELEMENTS_SELECTOR = [\n\t'a[href]',\n\t'button:not([disabled])',\n\t'input:not([disabled]):not([type=\"hidden\"])',\n\t'select:not([disabled])',\n\t'textarea:not([disabled])',\n\t'[contenteditable]',\n\t'[tabindex]:not([tabindex=\"-1\"])'\n].join(', ');\n\n/**\n * Returns first and last focusable elements inside of a given element based on specific CSS selector\n */\nexport function getFocusableBoundaryElements(\n\telement: HTMLElement\n): HTMLElement[] {\n\tconst list: HTMLElement[] = Array.from(\n\t\telement.querySelectorAll(\n\t\t\tFOCUSABLE_ELEMENTS_SELECTOR\n\t\t) as NodeListOf<HTMLElement>\n\t).filter((el) => el.tabIndex !== -1);\n\treturn [list[0], list[list.length - 1]];\n}\n\n/**\n * Function that enforces browser focus to be trapped inside a DOM element.\n *\n * Works only for clicks inside the element and navigation with 'Tab', ignoring clicks outside of the element\n *\n * @param zone Angular zone\n * @param element The element around which focus will be trapped inside\n * @param stopFocusTrap$ The observable stream. When completed the focus trap will clean up listeners\n * and free internal resources\n * @param refocusOnClick Put the focus back to the last focused element whenever a click occurs on element (default to\n * false)\n */\nexport const hubFocusTrap = (\n\tzone: NgZone,\n\telement: HTMLElement,\n\tstopFocusTrap$: Observable<any>,\n\trefocusOnClick = false\n) => {\n\tzone.runOutsideAngular(() => {\n\t\t// last focused element\n\t\tconst lastFocusedElement$ = fromEvent<FocusEvent>(\n\t\t\telement,\n\t\t\t'focusin'\n\t\t).pipe(\n\t\t\ttakeUntil(stopFocusTrap$),\n\t\t\tmap((e) => e.target)\n\t\t);\n\n\t\t// 'tab' / 'shift+tab' stream\n\t\tfromEvent<KeyboardEvent>(element, 'keydown')\n\t\t\t.pipe(\n\t\t\t\ttakeUntil(stopFocusTrap$),\n\t\t\t\tfilter((e) => e.key === 'Tab'),\n\t\t\t\twithLatestFrom(lastFocusedElement$)\n\t\t\t)\n\t\t\t.subscribe(([tabEvent, focusedElement]) => {\n\t\t\t\tconst [first, last] = getFocusableBoundaryElements(element);\n\n\t\t\t\tif (\n\t\t\t\t\t(focusedElement === first || focusedElement === element) &&\n\t\t\t\t\ttabEvent.shiftKey\n\t\t\t\t) {\n\t\t\t\t\tlast.focus();\n\t\t\t\t\ttabEvent.preventDefault();\n\t\t\t\t}\n\n\t\t\t\tif (focusedElement === last && !tabEvent.shiftKey) {\n\t\t\t\t\tfirst.focus();\n\t\t\t\t\ttabEvent.preventDefault();\n\t\t\t\t}\n\t\t\t});\n\n\t\t// inside click\n\t\tif (refocusOnClick) {\n\t\t\tfromEvent(element, 'click')\n\t\t\t\t.pipe(\n\t\t\t\t\ttakeUntil(stopFocusTrap$),\n\t\t\t\t\twithLatestFrom(lastFocusedElement$),\n\t\t\t\t\tmap((arr) => arr[1] as HTMLElement)\n\t\t\t\t)\n\t\t\t\t.subscribe((lastFocusedElement) => lastFocusedElement.focus());\n\t\t}\n\t});\n};\n","import { NgZone } from '@angular/core';\nimport { Observable, OperatorFunction } from 'rxjs';\n\n/**\n * Converts a value to an integer using parseInt.\n *\n * @param {any} value - The `value` parameter in the `toInteger` function is the input value that needs to be converted to an\n * integer.\n *\n * @returns Is returning the parsed integer value of the input `value`.\n */\nexport function toInteger(value: any): number {\n\treturn parseInt(`${value}`, 10);\n}\n\nexport function toString(value: any): string {\n\treturn value !== undefined && value !== null ? `${value}` : '';\n}\n\nexport function getValueInRange(value: number, max: number, min = 0): number {\n\treturn Math.max(Math.min(value, max), min);\n}\n\nexport function isString(value: any): value is string {\n\treturn typeof value === 'string';\n}\n\nexport function isNumber(value: any): value is number {\n\treturn !isNaN(toInteger(value));\n}\n\nexport function isInteger(value: any): value is number {\n\treturn (\n\t\ttypeof value === 'number' &&\n\t\tisFinite(value) &&\n\t\tMath.floor(value) === value\n\t);\n}\n\nexport function isDefined(value: any): boolean {\n\treturn value !== undefined && value !== null;\n}\n\n/**\n * Checks if a value is a Promise.\n *\n * @param {any} v - The parameter `v` in the `isPromise` function represents any value that is being checked to determine if it is\n * a Promise.\n *\n * @returns A boolean value indicating whether the input `v` is a Promise or not. If `v` has a `then` property, it is considered\n * a Promise and the function returns `true`. Otherwise, it returns `false`.\n */\nexport function isPromise<T>(v: any): v is Promise<T> {\n\treturn v && v.then;\n}\n\n/**\n * Pads a number with a leading zero if it is a valid number.\n *\n * @param {number} value - The `padNumber` function takes a number as input and pads it with a leading zero if it is a valid\n * number. If the input is not a number, it returns an empty string.\n *\n * @returns Takes a number as input and pads it with a leading zero if it is a valid number. If the input is a number, the function\n * returns the input value padded with a leading zero and sliced to keep only the last two characters. If the input is not a number,\n * an empty string is returned.\n */\nexport function padNumber(value: number) {\n\tif (isNumber(value)) {\n\t\treturn `0${value}`.slice(-2);\n\t} else {\n\t\treturn '';\n\t}\n}\n\n/**\n * Escapes special characters in a given text to be used in a regular expression.\n *\n * @param text - The `regExpEscape` function takes a `text` parameter as input. This function is designed to escape special\n * characters in a given text so that it can be safely used within a regular expression pattern.\n *\n * @returns A new string with any special characters in the input `text` escaped with a backslash.\n */\nexport function regExpEscape(text) {\n\treturn text.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&');\n}\n\nexport function closest(\n\telement: HTMLElement,\n\tselector?: string\n): HTMLElement | null {\n\tif (!selector) {\n\t\treturn null;\n\t}\n\n\t/*\n\t * In certain browsers (e.g. Edge 44.18362.449.0) HTMLDocument does\n\t * not support `Element.prototype.closest`. To emulate the correct behaviour\n\t * we return null when the method is missing.\n\t *\n\t * Note that in evergreen browsers `closest(document.documentElement, 'html')`\n\t * will return the document element whilst in Edge null will be returned. This\n\t * compromise was deemed good enough.\n\t */\n\tif (typeof element.closest === 'undefined') {\n\t\treturn null;\n\t}\n\n\treturn element.closest(selector);\n}\n\n/**\n * Force a browser reflow\n *\n * @param element element where to apply the reflow\n */\nexport function reflow(element: HTMLElement) {\n\treturn (element || document.body).getBoundingClientRect();\n}\n\n/**\n * Creates an observable where all callbacks are executed inside a given zone\n *\n * @param zone\n */\nexport function runInZone<T>(zone: NgZone): OperatorFunction<T, T> {\n\treturn (source) => {\n\t\treturn new Observable((observer) => {\n\t\t\tconst next = (value: T) => zone.run(() => observer.next(value));\n\t\t\tconst error = (e: any) => zone.run(() => observer.error(e));\n\t\t\tconst complete = () => zone.run(() => observer.complete());\n\t\t\treturn source.subscribe({ next, error, complete });\n\t\t});\n\t};\n}\n\nexport function removeAccents(str: string): string {\n\treturn str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '');\n}\n\n/**\n * Returns the active element in the given root.\n *\n * If the active element is inside a shadow root, it is searched recursively.\n */\nexport function getActiveElement(\n\troot: Document | ShadowRoot = document\n): Element | null {\n\tconst activeEl = root?.activeElement;\n\n\tif (!activeEl) {\n\t\treturn null;\n\t}\n\n\treturn activeEl.shadowRoot\n\t\t? getActiveElement(activeEl.shadowRoot)\n\t\t: activeEl;\n}\n","export function getTransitionDurationMs(element: HTMLElement) {\n\tconst { transitionDelay, transitionDuration } = window.getComputedStyle(element);\n\tconst transitionDelaySec = parseFloat(transitionDelay);\n\tconst transitionDurationSec = parseFloat(transitionDuration);\n\n\treturn (transitionDelaySec + transitionDurationSec) * 1000;\n}\n","import { NgZone } from '@angular/core';\nimport { EMPTY, fromEvent, Observable, of, race, Subject, timer } from 'rxjs';\nimport { endWith, filter, takeUntil } from 'rxjs/operators';\nimport { runInZone } from '../util';\nimport { getTransitionDurationMs } from './util';\n\nconst transitionTimerDelayMs = 5;\n\nexport type TransitionStartFn<T = any> = (\n\telement: HTMLElement,\n\tanimation: boolean,\n\tcontext: T\n) => TransitionEndFn | void;\nexport type TransitionEndFn = () => void;\n\nexport interface TransitionOptions<T> {\n\tanimation: boolean;\n\trunningTransition: 'continue' | 'stop';\n\tcontext?: T;\n}\n\nexport interface TransitionCtx<T> {\n\ttransition$: Subject<any>;\n\tcomplete: () => void;\n\tcontext: T;\n}\n\nconst noopFn: TransitionEndFn = () => {};\n\nconst runningTransitions = new Map<HTMLElement, TransitionCtx<any>>();\n\nexport const hubRunTransition = <T>(\n\tzone: NgZone,\n\telement: HTMLElement,\n\tstartFn: TransitionStartFn<T>,\n\toptions: TransitionOptions<T>\n): Observable<void> => {\n\t// Getting initial context from options\n\tlet context = options.context || <T>{};\n\n\t// Checking if there are already running transitions on the given element.\n\tconst running = runningTransitions.get(element);\n\tif (running) {\n\t\tswitch (options.runningTransition) {\n\t\t\t// If there is one running and we want for it to 'continue' to run, we have to cancel the new one.\n\t\t\t// We're not emitting any values, but simply completing the observable (EMPTY).\n\t\t\tcase 'continue':\n\t\t\t\treturn EMPTY;\n\t\t\t// If there is one running and we want for it to 'stop', we have to complete the running one.\n\t\t\t// We're simply completing the running one and not emitting any values and merging newly provided context\n\t\t\t// with the one coming from currently running transition.\n\t\t\tcase 'stop':\n\t\t\t\tzone.run(() => running.transition$.complete());\n\t\t\t\tcontext = Object.assign(running.context, context);\n\t\t\t\trunningTransitions.delete(element);\n\t\t}\n\t}\n\n\t// Running the start function\n\tconst endFn = startFn(element, options.animation, context) || noopFn;\n\n\t// If 'prefer-reduced-motion' is enabled, the 'transition' will be set to 'none'.\n\t// If animations are disabled, we have to emit a value and complete the observable\n\t// In this case we have to call the end function, but can finish immediately by emitting a value,\n\t// completing the observable and executing end functions synchronously.\n\tif (\n\t\t!options.animation ||\n\t\twindow.getComputedStyle(element).transitionProperty === 'none'\n\t) {\n\t\tzone.run(() => endFn());\n\t\treturn of(undefined).pipe(runInZone(zone));\n\t}\n\n\t// Starting a new transition\n\tconst transition$ = new Subject<void>();\n\tconst finishTransition$ = new Subject<void>();\n\tconst stop$ = transition$.pipe(endWith(true));\n\trunningTransitions.set(element, {\n\t\ttransition$,\n\t\tcomplete: () => {\n\t\t\tfinishTransition$.next();\n\t\t\tfinishTransition$.complete();\n\t\t},\n\t\tcontext\n\t});\n\n\tconst transitionDurationMs = getTransitionDurationMs(element);\n\n\t// 1. We have to both listen for the 'transitionend' event and have a 'just-in-case' timer,\n\t// because 'transitionend' event might not be fired in some browsers, if the transitioning\n\t// element becomes invisible (ex. when scrolling, making browser tab inactive, etc.). The timer\n\t// guarantees, that we'll release the DOM element and complete 'hubRunTransition'.\n\t// 2. We need to filter transition end events, because they might bubble from shorter transitions\n\t// on inner DOM elements. We're only interested in the transition on the 'element' itself.\n\tzone.runOutsideAngular(() => {\n\t\tconst transitionEnd$ = fromEvent(element, 'transitionend').pipe(\n\t\t\ttakeUntil(stop$),\n\t\t\tfilter(({ target }) => target === element)\n\t\t);\n\t\tconst timer$ = timer(\n\t\t\ttransitionDurationMs + transitionTimerDelayMs\n\t\t).pipe(takeUntil(stop$));\n\n\t\trace(timer$, transitionEnd$, finishTransition$)\n\t\t\t.pipe(takeUntil(stop$))\n\t\t\t.subscribe(() => {\n\t\t\t\trunningTransitions.delete(element);\n\t\t\t\tzone.run(() => {\n\t\t\t\t\tendFn();\n\t\t\t\t\ttransition$.next();\n\t\t\t\t\ttransition$.complete();\n\t\t\t\t});\n\t\t\t});\n\t});\n\n\treturn transition$.asObservable();\n};\n\nexport const hubCompleteTransition = (element: HTMLElement) => {\n\trunningTransitions.get(element)?.complete();\n};\n","import {\n\tApplicationRef,\n\tComponentRef,\n\tinject,\n\tInjector,\n\tNgZone,\n\tTemplateRef,\n\tType,\n\tViewContainerRef,\n\tViewRef\n} from '@angular/core';\nimport { Observable, of } from 'rxjs';\nimport { mergeMap, take, tap } from 'rxjs/operators';\nimport { DOCUMENT } from '@angular/common';\nimport { hubRunTransition } from './transitions';\n\nexport class ContentRef {\n\tconstructor(\n\t\tpublic nodes: Node[][],\n\t\tpublic viewRef?: ViewRef,\n\t\tpublic componentRef?: ComponentRef<any>\n\t) {}\n}\n\nexport class PopupService<T> {\n\tprivate _windowRef: ComponentRef<T> | null = null;\n\tprivate _contentRef: ContentRef | null = null;\n\n\tprivate _document = inject(DOCUMENT);\n\tprivate _applicationRef = inject(ApplicationRef);\n\tprivate _injector = inject(Injector);\n\tprivate _viewContainerRef = inject(ViewContainerRef);\n\tprivate _ngZone = inject(NgZone);\n\n\tconstructor(private _componentType: Type<T>) {}\n\n\topen(\n\t\tcontent?: string | TemplateRef<any>,\n\t\ttemplateContext?: any,\n\t\tanimation = false\n\t): { windowRef: ComponentRef<T>; transition$: Observable<void> } {\n\t\tif (!this._windowRef) {\n\t\t\tthis._contentRef = this._getContentRef(content, templateContext);\n\t\t\tthis._windowRef = this._viewContainerRef.createComponent(\n\t\t\t\tthis._componentType,\n\t\t\t\t{\n\t\t\t\t\tinjector: this._injector,\n\t\t\t\t\tprojectableNodes: this._contentRef.nodes\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tconst { nativeElement } = this._windowRef.location;\n\t\tconst transition$ = this._ngZone.onStable.pipe(\n\t\t\ttake(1),\n\t\t\tmergeMap(() =>\n\t\t\t\thubRunTransition(\n\t\t\t\t\tthis._ngZone,\n\t\t\t\t\tnativeElement,\n\t\t\t\t\t({ classList }) => classList.add('show'),\n\t\t\t\t\t{\n\t\t\t\t\t\tanimation,\n\t\t\t\t\t\trunningTransition: 'continue'\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\n\t\treturn { windowRef: this._windowRef, transition$ };\n\t}\n\n\tclose(animation = false): Observable<void> {\n\t\tif (!this._windowRef) {\n\t\t\treturn of(undefined);\n\t\t}\n\n\t\treturn hubRunTransition(\n\t\t\tthis._ngZone,\n\t\t\tthis._windowRef.location.nativeElement,\n\t\t\t({ classList }) => classList.remove('show'),\n\t\t\t{ animation, runningTransition: 'stop' }\n\t\t).pipe(\n\t\t\ttap(() => {\n\t\t\t\tthis._windowRef?.destroy();\n\t\t\t\tthis._contentRef?.viewRef?.destroy();\n\t\t\t\tthis._windowRef = null;\n\t\t\t\tthis._contentRef = null;\n\t\t\t})\n\t\t);\n\t}\n\n\tprivate _getContentRef(\n\t\tcontent?: string | TemplateRef<any>,\n\t\ttemplateContext?: any\n\t): ContentRef {\n\t\tif (!content) {\n\t\t\treturn new ContentRef([]);\n\t\t} else if (content instanceof TemplateRef) {\n\t\t\tconst viewRef = content.createEmbeddedView(templateContext);\n\t\t\tthis._applicationRef.attachView(viewRef);\n\t\t\treturn new ContentRef([viewRef.rootNodes], viewRef);\n\t\t} else {\n\t\t\treturn new ContentRef([\n\t\t\t\t[this._document.createTextNode(`${content}`)]\n\t\t\t]);\n\t\t}\n\t}\n}\n","import { inject, Injectable } from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\n\n/** Type for the callback used to revert the scrollbar. */\nexport type ScrollbarReverter = () => void;\n\n/**\n * Utility to handle the scrollbar.\n *\n * It allows to hide the scrollbar and compensate the lack of a vertical scrollbar\n * by adding an equivalent padding on the right of the body, and to revert this change.\n */\n@Injectable({ providedIn: 'root' })\nexport class ScrollBar {\n\tprivate _document = inject(DOCUMENT);\n\n\t/**\n\t * To be called to hide a potential vertical scrollbar:\n\t * - if a scrollbar is there and has a width greater than 0, adds some compensation\n\t * padding to the body to keep the same layout as when the scrollbar is there\n\t * - adds overflow: hidden\n\t *\n\t * @return a callback used to revert the change\n\t */\n\thide(): ScrollbarReverter {\n\t\tconst scrollbarWidth = Math.abs(window.innerWidth - this._document.documentElement.clientWidth);\n\t\tconst body = this._document.body;\n\t\tconst bodyStyle = body.style;\n\t\tconst { overflow, paddingRight } = bodyStyle;\n\t\tif (scrollbarWidth > 0) {\n\t\t\tconst actualPadding = parseFloat(window.getComputedStyle(body).paddingRight);\n\t\t\tbodyStyle.paddingRight = `${actualPadding + scrollbarWidth}px`;\n\t\t}\n\t\tbodyStyle.overflow = 'hidden';\n\t\treturn () => {\n\t\t\tif (scrollbarWidth > 0) {\n\t\t\t\tbodyStyle.paddingRight = paddingRight;\n\t\t\t}\n\t\t\tbodyStyle.overflow = overflow;\n\t\t};\n\t}\n}\n","/*\n * Public API Surface of utils\n */\n\nexport * from './lib/focus-trap';\nexport * from './lib/popup';\nexport * from './lib/scrollbar';\nexport * from './lib/util';\nexport * from './lib/transitions';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAKa,MAAA,2BAA2B,GAAG;IAC1C,SAAS;IACT,wBAAwB;IACxB,4CAA4C;IAC5C,wBAAwB;IACxB,0BAA0B;IAC1B,mBAAmB;IACnB,iCAAiC;AACjC,CAAA,CAAC,IAAI,CAAC,IAAI,EAAE;AAEb;;AAEG;AACG,SAAU,4BAA4B,CAC3C,OAAoB,EAAA;AAEpB,IAAA,MAAM,IAAI,GAAkB,KAAK,CAAC,IAAI,CACrC,OAAO,CAAC,gBAAgB,CACvB,2BAA2B,CACA,CAC5B,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC;AACrC,IAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;AAWG;AACI,MAAM,YAAY,GAAG,CAC3B,IAAY,EACZ,OAAoB,EACpB,cAA+B,EAC/B,cAAc,GAAG,KAAK,KACnB;AACH,IAAA,IAAI,CAAC,iBAAiB,CAAC,MAAK;;AAE3B,QAAA,MAAM,mBAAmB,GAAG,SAAS,CACpC,OAAO,EACP,SAAS,CACT,CAAC,IAAI,CACL,SAAS,CAAC,cAAc,CAAC,EACzB,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CACpB,CAAC;;AAGF,QAAA,SAAS,CAAgB,OAAO,EAAE,SAAS,CAAC;aAC1C,IAAI,CACJ,SAAS,CAAC,cAAc,CAAC,EACzB,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,EAC9B,cAAc,CAAC,mBAAmB,CAAC,CACnC;aACA,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,KAAI;YACzC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,4BAA4B,CAAC,OAAO,CAAC,CAAC;YAE5D,IACC,CAAC,cAAc,KAAK,KAAK,IAAI,cAAc,KAAK,OAAO;gBACvD,QAAQ,CAAC,QAAQ,EAChB;gBACD,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,QAAQ,CAAC,cAAc,EAAE,CAAC;AAC1B,aAAA;YAED,IAAI,cAAc,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBAClD,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,QAAQ,CAAC,cAAc,EAAE,CAAC;AAC1B,aAAA;AACF,SAAC,CAAC,CAAC;;AAGJ,QAAA,IAAI,cAAc,EAAE;AACnB,YAAA,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;iBACzB,IAAI,CACJ,SAAS,CAAC,cAAc,CAAC,EACzB,cAAc,CAAC,mBAAmB,CAAC,EACnC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAgB,CAAC,CACnC;iBACA,SAAS,CAAC,CAAC,kBAAkB,KAAK,kBAAkB,CAAC,KAAK,EAAE,CAAC,CAAC;AAChE,SAAA;AACF,KAAC,CAAC,CAAC;AACJ;;ACzFA;;;;;;;AAOG;AACG,SAAU,SAAS,CAAC,KAAU,EAAA;IACnC,OAAO,QAAQ,CAAC,CAAG,EAAA,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAEK,SAAU,QAAQ,CAAC,KAAU,EAAA;AAClC,IAAA,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,GAAG,GAAG,KAAK,CAAA,CAAE,GAAG,EAAE,CAAC;AAChE,CAAC;AAEK,SAAU,eAAe,CAAC,KAAa,EAAE,GAAW,EAAE,GAAG,GAAG,CAAC,EAAA;AAClE,IAAA,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAEK,SAAU,QAAQ,CAAC,KAAU,EAAA;AAClC,IAAA,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC;AAClC,CAAC;AAEK,SAAU,QAAQ,CAAC,KAAU,EAAA;IAClC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AACjC,CAAC;AAEK,SAAU,SAAS,CAAC,KAAU,EAAA;AACnC,IAAA,QACC,OAAO,KAAK,KAAK,QAAQ;QACzB,QAAQ,CAAC,KAAK,CAAC;QACf,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK,EAC1B;AACH,CAAC;AAEK,SAAU,SAAS,CAAC,KAAU,EAAA;AACnC,IAAA,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC;AAC9C,CAAC;AAED;;;;;;;;AAQG;AACG,SAAU,SAAS,CAAI,CAAM,EAAA;AAClC,IAAA,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;AACpB,CAAC;AAED;;;;;;;;;AASG;AACG,SAAU,SAAS,CAAC,KAAa,EAAA;AACtC,IAAA,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE;QACpB,OAAO,CAAA,CAAA,EAAI,KAAK,CAAE,CAAA,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7B,KAAA;AAAM,SAAA;AACN,QAAA,OAAO,EAAE,CAAC;AACV,KAAA;AACF,CAAC;AAED;;;;;;;AAOG;AACG,SAAU,YAAY,CAAC,IAAI,EAAA;IAChC,OAAO,IAAI,CAAC,OAAO,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC;AACzD,CAAC;AAEe,SAAA,OAAO,CACtB,OAAoB,EACpB,QAAiB,EAAA;IAEjB,IAAI,CAAC,QAAQ,EAAE;AACd,QAAA,OAAO,IAAI,CAAC;AACZ,KAAA;AAED;;;;;;;;AAQG;AACH,IAAA,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,WAAW,EAAE;AAC3C,QAAA,OAAO,IAAI,CAAC;AACZ,KAAA;AAED,IAAA,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED;;;;AAIG;AACG,SAAU,MAAM,CAAC,OAAoB,EAAA;IAC1C,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,qBAAqB,EAAE,CAAC;AAC3D,CAAC;AAED;;;;AAIG;AACG,SAAU,SAAS,CAAI,IAAY,EAAA;IACxC,OAAO,CAAC,MAAM,KAAI;AACjB,QAAA,OAAO,IAAI,UAAU,CAAC,CAAC,QAAQ,KAAI;YAClC,MAAM,IAAI,GAAG,CAAC,KAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,CAAC,CAAM,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5D,YAAA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC3D,YAAA,OAAO,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;AACpD,SAAC,CAAC,CAAC;AACJ,KAAC,CAAC;AACH,CAAC;AAEK,SAAU,aAAa,CAAC,GAAW,EAAA;AACxC,IAAA,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED;;;;AAIG;AACa,SAAA,gBAAgB,CAC/B,IAAA,GAA8B,QAAQ,EAAA;AAEtC,IAAA,MAAM,QAAQ,GAAG,IAAI,EAAE,aAAa,CAAC;IAErC,IAAI,CAAC,QAAQ,EAAE;AACd,QAAA,OAAO,IAAI,CAAC;AACZ,KAAA;IAED,OAAO,QAAQ,CAAC,UAAU;AACzB,UAAE,gBAAgB,CAAC,QAAQ,CAAC,UAAU,CAAC;UACrC,QAAQ,CAAC;AACb;;AC5JM,SAAU,uBAAuB,CAAC,OAAoB,EAAA;AAC3D,IAAA,MAAM,EAAE,eAAe,EAAE,kBAAkB,EAAE,GAAG,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACjF,IAAA,MAAM,kBAAkB,GAAG,UAAU,CAAC,eAAe,CAAC,CAAC;AACvD,IAAA,MAAM,qBAAqB,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC;AAE7D,IAAA,OAAO,CAAC,kBAAkB,GAAG,qBAAqB,IAAI,IAAI,CAAC;AAC5D;;ACAA,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAqBjC,MAAM,MAAM,GAAoB,MAAK,GAAG,CAAC;AAEzC,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAmC,CAAC;AAE/D,MAAM,gBAAgB,GAAG,CAC/B,IAAY,EACZ,OAAoB,EACpB,OAA6B,EAC7B,OAA6B,KACR;;AAErB,IAAA,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,IAAO,EAAE,CAAC;;IAGvC,MAAM,OAAO,GAAG,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAChD,IAAA,IAAI,OAAO,EAAE;QACZ,QAAQ,OAAO,CAAC,iBAAiB;;;AAGhC,YAAA,KAAK,UAAU;AACd,gBAAA,OAAO,KAAK,CAAC;;;;AAId,YAAA,KAAK,MAAM;AACV,gBAAA,IAAI,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC/C,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAClD,gBAAA,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACpC,SAAA;AACD,KAAA;;AAGD,IAAA,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC;;;;;IAMrE,IACC,CAAC,OAAO,CAAC,SAAS;QAClB,MAAM,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,kBAAkB,KAAK,MAAM,EAC7D;QACD,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC;AACxB,QAAA,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3C,KAAA;;AAGD,IAAA,MAAM,WAAW,GAAG,IAAI,OAAO,EAAQ,CAAC;AACxC,IAAA,MAAM,iBAAiB,GAAG,IAAI,OAAO,EAAQ,CAAC;IAC9C,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,IAAA,kBAAkB,CAAC,GAAG,CAAC,OAAO,EAAE;QAC/B,WAAW;QACX,QAAQ,EAAE,MAAK;YACd,iBAAiB,CAAC,IAAI,EAAE,CAAC;YACzB,iBAAiB,CAAC,QAAQ,EAAE,CAAC;SAC7B;QACD,OAAO;AACP,KAAA,CAAC,CAAC;AAEH,IAAA,MAAM,oBAAoB,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;;;;;;;AAQ9D,IAAA,IAAI,CAAC,iBAAiB,CAAC,MAAK;AAC3B,QAAA,MAAM,cAAc,GAAG,SAAS,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,IAAI,CAC9D,SAAS,CAAC,KAAK,CAAC,EAChB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,MAAM,KAAK,OAAO,CAAC,CAC1C,CAAC;AACF,QAAA,MAAM,MAAM,GAAG,KAAK,CACnB,oBAAoB,GAAG,sBAAsB,CAC7C,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAEzB,QAAA,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,iBAAiB,CAAC;AAC7C,aAAA,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;aACtB,SAAS,CAAC,MAAK;AACf,YAAA,kBAAkB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;AACnC,YAAA,IAAI,CAAC,GAAG,CAAC,MAAK;AACb,gBAAA,KAAK,EAAE,CAAC;gBACR,WAAW,CAAC,IAAI,EAAE,CAAC;gBACnB,WAAW,CAAC,QAAQ,EAAE,CAAC;AACxB,aAAC,CAAC,CAAC;AACJ,SAAC,CAAC,CAAC;AACL,KAAC,CAAC,CAAC;AAEH,IAAA,OAAO,WAAW,CAAC,YAAY,EAAE,CAAC;AACnC,EAAE;AAEW,MAAA,qBAAqB,GAAG,CAAC,OAAoB,KAAI;IAC7D,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC;AAC7C;;MCxGa,UAAU,CAAA;AACtB,IAAA,WAAA,CACQ,KAAe,EACf,OAAiB,EACjB,YAAgC,EAAA;QAFhC,IAAK,CAAA,KAAA,GAAL,KAAK,CAAU;QACf,IAAO,CAAA,OAAA,GAAP,OAAO,CAAU;QACjB,IAAY,CAAA,YAAA,GAAZ,YAAY,CAAoB;KACpC;AACJ,CAAA;MAEY,YAAY,CAAA;AAUxB,IAAA,WAAA,CAAoB,cAAuB,EAAA;QAAvB,IAAc,CAAA,cAAA,GAAd,cAAc,CAAS;QATnC,IAAU,CAAA,UAAA,GAA2B,IAAI,CAAC;QAC1C,IAAW,CAAA,WAAA,GAAsB,IAAI,CAAC;AAEtC,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC7B,QAAA,IAAA,CAAA,eAAe,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AACzC,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC7B,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAC7C,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;KAEc;AAE/C,IAAA,IAAI,CACH,OAAmC,EACnC,eAAqB,EACrB,SAAS,GAAG,KAAK,EAAA;AAEjB,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YACrB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AACjE,YAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC,eAAe,CACvD,IAAI,CAAC,cAAc,EACnB;gBACC,QAAQ,EAAE,IAAI,CAAC,SAAS;AACxB,gBAAA,gBAAgB,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK;AACxC,aAAA,CACD,CAAC;AACF,SAAA;QAED,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AACnD,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAC7C,IAAI,CAAC,CAAC,CAAC,EACP,QAAQ,CAAC,MACR,gBAAgB,CACf,IAAI,CAAC,OAAO,EACZ,aAAa,EACb,CAAC,EAAE,SAAS,EAAE,KAAK,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EACxC;YACC,SAAS;AACT,YAAA,iBAAiB,EAAE,UAAU;SAC7B,CACD,CACD,CACD,CAAC;QAEF,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,CAAC;KACnD;IAED,KAAK,CAAC,SAAS,GAAG,KAAK,EAAA;AACtB,QAAA,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;AACrB,YAAA,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;AACrB,SAAA;AAED,QAAA,OAAO,gBAAgB,CACtB,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,EACtC,CAAC,EAAE,SAAS,EAAE,KAAK,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAC3C,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,CACxC,CAAC,IAAI,CACL,GAAG,CAAC,MAAK;AACR,YAAA,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,CAAC;AAC3B,YAAA,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACrC,YAAA,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;AACvB,YAAA,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;SACxB,CAAC,CACF,CAAC;KACF;IAEO,cAAc,CACrB,OAAmC,EACnC,eAAqB,EAAA;QAErB,IAAI,CAAC,OAAO,EAAE;AACb,YAAA,OAAO,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;AAC1B,SAAA;aAAM,IAAI,OAAO,YAAY,WAAW,EAAE;YAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;AAC5D,YAAA,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YACzC,OAAO,IAAI,UAAU,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;AACpD,SAAA;AAAM,aAAA;YACN,OAAO,IAAI,UAAU,CAAC;gBACrB,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAG,EAAA,OAAO,CAAE,CAAA,CAAC,CAAC;AAC7C,aAAA,CAAC,CAAC;AACH,SAAA;KACD;AACD;;ACrGD;;;;;AAKG;MAEU,SAAS,CAAA;AADtB,IAAA,WAAA,GAAA;AAES,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;AA2BrC,KAAA;AAzBA;;;;;;;AAOG;IACH,IAAI,GAAA;AACH,QAAA,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;AAChG,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;AACjC,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC;AAC7B,QAAA,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;QAC7C,IAAI,cAAc,GAAG,CAAC,EAAE;AACvB,YAAA,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;YAC7E,SAAS,CAAC,YAAY,GAAG,CAAA,EAAG,aAAa,GAAG,cAAc,IAAI,CAAC;AAC/D,SAAA;AACD,QAAA,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC9B,QAAA,OAAO,MAAK;YACX,IAAI,cAAc,GAAG,CAAC,EAAE;AACvB,gBAAA,SAAS,CAAC,YAAY,GAAG,YAAY,CAAC;AACtC,aAAA;AACD,YAAA,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAC/B,SAAC,CAAC;KACF;8GA3BW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA,EAAA;AAAT,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,SAAS,cADI,MAAM,EAAA,CAAA,CAAA,EAAA;;2FACnB,SAAS,EAAA,UAAA,EAAA,CAAA;kBADrB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAA;;;ACZlC;;AAEG;;ACFH;;AAEG;;;;"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="ng-hub-ui-utils" />
5
+ export * from './public-api';
@@ -0,0 +1,20 @@
1
+ import { NgZone } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ export declare const FOCUSABLE_ELEMENTS_SELECTOR: string;
4
+ /**
5
+ * Returns first and last focusable elements inside of a given element based on specific CSS selector
6
+ */
7
+ export declare function getFocusableBoundaryElements(element: HTMLElement): HTMLElement[];
8
+ /**
9
+ * Function that enforces browser focus to be trapped inside a DOM element.
10
+ *
11
+ * Works only for clicks inside the element and navigation with 'Tab', ignoring clicks outside of the element
12
+ *
13
+ * @param zone Angular zone
14
+ * @param element The element around which focus will be trapped inside
15
+ * @param stopFocusTrap$ The observable stream. When completed the focus trap will clean up listeners
16
+ * and free internal resources
17
+ * @param refocusOnClick Put the focus back to the last focused element whenever a click occurs on element (default to
18
+ * false)
19
+ */
20
+ export declare const hubFocusTrap: (zone: NgZone, element: HTMLElement, stopFocusTrap$: Observable<any>, refocusOnClick?: boolean) => void;
package/lib/popup.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import { ComponentRef, TemplateRef, Type, ViewRef } from '@angular/core';
2
+ import { Observable } from 'rxjs';
3
+ export declare class ContentRef {
4
+ nodes: Node[][];
5
+ viewRef?: ViewRef | undefined;
6
+ componentRef?: ComponentRef<any> | undefined;
7
+ constructor(nodes: Node[][], viewRef?: ViewRef | undefined, componentRef?: ComponentRef<any> | undefined);
8
+ }
9
+ export declare class PopupService<T> {
10
+ private _componentType;
11
+ private _windowRef;
12
+ private _contentRef;
13
+ private _document;
14
+ private _applicationRef;
15
+ private _injector;
16
+ private _viewContainerRef;
17
+ private _ngZone;
18
+ constructor(_componentType: Type<T>);
19
+ open(content?: string | TemplateRef<any>, templateContext?: any, animation?: boolean): {
20
+ windowRef: ComponentRef<T>;
21
+ transition$: Observable<void>;
22
+ };
23
+ close(animation?: boolean): Observable<void>;
24
+ private _getContentRef;
25
+ }
@@ -0,0 +1,23 @@
1
+ import * as i0 from "@angular/core";
2
+ /** Type for the callback used to revert the scrollbar. */
3
+ export type ScrollbarReverter = () => void;
4
+ /**
5
+ * Utility to handle the scrollbar.
6
+ *
7
+ * It allows to hide the scrollbar and compensate the lack of a vertical scrollbar
8
+ * by adding an equivalent padding on the right of the body, and to revert this change.
9
+ */
10
+ export declare class ScrollBar {
11
+ private _document;
12
+ /**
13
+ * To be called to hide a potential vertical scrollbar:
14
+ * - if a scrollbar is there and has a width greater than 0, adds some compensation
15
+ * padding to the body to keep the same layout as when the scrollbar is there
16
+ * - adds overflow: hidden
17
+ *
18
+ * @return a callback used to revert the change
19
+ */
20
+ hide(): ScrollbarReverter;
21
+ static ɵfac: i0.ɵɵFactoryDeclaration<ScrollBar, never>;
22
+ static ɵprov: i0.ɵɵInjectableDeclaration<ScrollBar>;
23
+ }
@@ -0,0 +1 @@
1
+ export * from './transition';
@@ -0,0 +1,16 @@
1
+ import { NgZone } from '@angular/core';
2
+ import { Observable, Subject } from 'rxjs';
3
+ export type TransitionStartFn<T = any> = (element: HTMLElement, animation: boolean, context: T) => TransitionEndFn | void;
4
+ export type TransitionEndFn = () => void;
5
+ export interface TransitionOptions<T> {
6
+ animation: boolean;
7
+ runningTransition: 'continue' | 'stop';
8
+ context?: T;
9
+ }
10
+ export interface TransitionCtx<T> {
11
+ transition$: Subject<any>;
12
+ complete: () => void;
13
+ context: T;
14
+ }
15
+ export declare const hubRunTransition: <T>(zone: NgZone, element: HTMLElement, startFn: TransitionStartFn<T>, options: TransitionOptions<T>) => Observable<void>;
16
+ export declare const hubCompleteTransition: (element: HTMLElement) => void;
@@ -0,0 +1 @@
1
+ export declare function getTransitionDurationMs(element: HTMLElement): number;
package/lib/util.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ import { NgZone } from '@angular/core';
2
+ import { OperatorFunction } from 'rxjs';
3
+ /**
4
+ * Converts a value to an integer using parseInt.
5
+ *
6
+ * @param {any} value - The `value` parameter in the `toInteger` function is the input value that needs to be converted to an
7
+ * integer.
8
+ *
9
+ * @returns Is returning the parsed integer value of the input `value`.
10
+ */
11
+ export declare function toInteger(value: any): number;
12
+ export declare function toString(value: any): string;
13
+ export declare function getValueInRange(value: number, max: number, min?: number): number;
14
+ export declare function isString(value: any): value is string;
15
+ export declare function isNumber(value: any): value is number;
16
+ export declare function isInteger(value: any): value is number;
17
+ export declare function isDefined(value: any): boolean;
18
+ /**
19
+ * Checks if a value is a Promise.
20
+ *
21
+ * @param {any} v - The parameter `v` in the `isPromise` function represents any value that is being checked to determine if it is
22
+ * a Promise.
23
+ *
24
+ * @returns A boolean value indicating whether the input `v` is a Promise or not. If `v` has a `then` property, it is considered
25
+ * a Promise and the function returns `true`. Otherwise, it returns `false`.
26
+ */
27
+ export declare function isPromise<T>(v: any): v is Promise<T>;
28
+ /**
29
+ * Pads a number with a leading zero if it is a valid number.
30
+ *
31
+ * @param {number} value - The `padNumber` function takes a number as input and pads it with a leading zero if it is a valid
32
+ * number. If the input is not a number, it returns an empty string.
33
+ *
34
+ * @returns Takes a number as input and pads it with a leading zero if it is a valid number. If the input is a number, the function
35
+ * returns the input value padded with a leading zero and sliced to keep only the last two characters. If the input is not a number,
36
+ * an empty string is returned.
37
+ */
38
+ export declare function padNumber(value: number): string;
39
+ /**
40
+ * Escapes special characters in a given text to be used in a regular expression.
41
+ *
42
+ * @param text - The `regExpEscape` function takes a `text` parameter as input. This function is designed to escape special
43
+ * characters in a given text so that it can be safely used within a regular expression pattern.
44
+ *
45
+ * @returns A new string with any special characters in the input `text` escaped with a backslash.
46
+ */
47
+ export declare function regExpEscape(text: any): any;
48
+ export declare function closest(element: HTMLElement, selector?: string): HTMLElement | null;
49
+ /**
50
+ * Force a browser reflow
51
+ *
52
+ * @param element element where to apply the reflow
53
+ */
54
+ export declare function reflow(element: HTMLElement): DOMRect;
55
+ /**
56
+ * Creates an observable where all callbacks are executed inside a given zone
57
+ *
58
+ * @param zone
59
+ */
60
+ export declare function runInZone<T>(zone: NgZone): OperatorFunction<T, T>;
61
+ export declare function removeAccents(str: string): string;
62
+ /**
63
+ * Returns the active element in the given root.
64
+ *
65
+ * If the active element is inside a shadow root, it is searched recursively.
66
+ */
67
+ export declare function getActiveElement(root?: Document | ShadowRoot): Element | null;
Binary file
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "ng-hub-ui-utils",
3
+ "version": "1.0.0",
4
+ "peerDependencies": {
5
+ "@angular/common": ">=16.0.0",
6
+ "@angular/core": ">=16.0.0"
7
+ },
8
+ "dependencies": {
9
+ "tslib": "^2.3.0"
10
+ },
11
+ "sideEffects": false,
12
+ "module": "fesm2022/ng-hub-ui-utils.mjs",
13
+ "typings": "index.d.ts",
14
+ "exports": {
15
+ "./package.json": {
16
+ "default": "./package.json"
17
+ },
18
+ ".": {
19
+ "types": "./index.d.ts",
20
+ "esm2022": "./esm2022/ng-hub-ui-utils.mjs",
21
+ "esm": "./esm2022/ng-hub-ui-utils.mjs",
22
+ "default": "./fesm2022/ng-hub-ui-utils.mjs"
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,5 @@
1
+ export * from './lib/focus-trap';
2
+ export * from './lib/popup';
3
+ export * from './lib/scrollbar';
4
+ export * from './lib/util';
5
+ export * from './lib/transitions';