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 +21 -0
- package/README.md +24 -0
- package/esm2022/lib/focus-trap.mjs +58 -0
- package/esm2022/lib/popup.mjs +66 -0
- package/esm2022/lib/scrollbar.mjs +46 -0
- package/esm2022/lib/transitions/index.mjs +2 -0
- package/esm2022/lib/transitions/transition.mjs +77 -0
- package/esm2022/lib/transitions/util.mjs +7 -0
- package/esm2022/lib/util.mjs +132 -0
- package/esm2022/ng-hub-ui-utils.mjs +5 -0
- package/esm2022/public-api.mjs +9 -0
- package/fesm2022/ng-hub-ui-utils.mjs +387 -0
- package/fesm2022/ng-hub-ui-utils.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/focus-trap.d.ts +20 -0
- package/lib/popup.d.ts +25 -0
- package/lib/scrollbar.d.ts +23 -0
- package/lib/transitions/index.d.ts +1 -0
- package/lib/transitions/transition.d.ts +16 -0
- package/lib/transitions/util.d.ts +1 -0
- package/lib/util.d.ts +67 -0
- package/ng-hub-ui-utils-1.0.0.tgz +0 -0
- package/package.json +25 -0
- package/public-api.d.ts +5 -0
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3V0aWxzL3NyYy9saWIvdXRpbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsVUFBVSxFQUFvQixNQUFNLE1BQU0sQ0FBQztBQUVwRDs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxVQUFVLFNBQVMsQ0FBQyxLQUFVO0lBQ25DLE9BQU8sUUFBUSxDQUFDLEdBQUcsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7QUFDakMsQ0FBQztBQUVELE1BQU0sVUFBVSxRQUFRLENBQUMsS0FBVTtJQUNsQyxPQUFPLEtBQUssS0FBSyxTQUFTLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0FBQ2hFLENBQUM7QUFFRCxNQUFNLFVBQVUsZUFBZSxDQUFDLEtBQWEsRUFBRSxHQUFXLEVBQUUsR0FBRyxHQUFHLENBQUM7SUFDbEUsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQzVDLENBQUM7QUFFRCxNQUFNLFVBQVUsUUFBUSxDQUFDLEtBQVU7SUFDbEMsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUM7QUFDbEMsQ0FBQztBQUVELE1BQU0sVUFBVSxRQUFRLENBQUMsS0FBVTtJQUNsQyxPQUFPLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQ2pDLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEtBQVU7SUFDbkMsT0FBTyxDQUNOLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFDekIsUUFBUSxDQUFDLEtBQUssQ0FBQztRQUNmLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssS0FBSyxDQUMz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QztRQUN2QyxDQUFDLENBQUMsUUFBUSxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IE5nWm9uZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgT3BlcmF0b3JGdW5jdGlvbiB9IGZyb20gJ3J4anMnO1xuXG4vKipcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYW4gaW50ZWdlciB1c2luZyBwYXJzZUludC5cbiAqXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgYHZhbHVlYCBwYXJhbWV0ZXIgaW4gdGhlIGB0b0ludGVnZXJgIGZ1bmN0aW9uIGlzIHRoZSBpbnB1dCB2YWx1ZSB0aGF0IG5lZWRzIHRvIGJlIGNvbnZlcnRlZCB0byBhblxuICogaW50ZWdlci5cbiAqXG4gKiBAcmV0dXJucyBJcyByZXR1cm5pbmcgdGhlIHBhcnNlZCBpbnRlZ2VyIHZhbHVlIG9mIHRoZSBpbnB1dCBgdmFsdWVgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9JbnRlZ2VyKHZhbHVlOiBhbnkpOiBudW1iZXIge1xuXHRyZXR1cm4gcGFyc2VJbnQoYCR7dmFsdWV9YCwgMTApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9TdHJpbmcodmFsdWU6IGFueSk6IHN0cmluZyB7XG5cdHJldHVybiB2YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHZhbHVlICE9PSBudWxsID8gYCR7dmFsdWV9YCA6ICcnO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmFsdWVJblJhbmdlKHZhbHVlOiBudW1iZXIsIG1heDogbnVtYmVyLCBtaW4gPSAwKTogbnVtYmVyIHtcblx0cmV0dXJuIE1hdGgubWF4KE1hdGgubWluKHZhbHVlLCBtYXgpLCBtaW4pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNTdHJpbmcodmFsdWU6IGFueSk6IHZhbHVlIGlzIHN0cmluZyB7XG5cdHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNOdW1iZXIodmFsdWU6IGFueSk6IHZhbHVlIGlzIG51bWJlciB7XG5cdHJldHVybiAhaXNOYU4odG9JbnRlZ2VyKHZhbHVlKSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc0ludGVnZXIodmFsdWU6IGFueSk6IHZhbHVlIGlzIG51bWJlciB7XG5cdHJldHVybiAoXG5cdFx0dHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyAmJlxuXHRcdGlzRmluaXRlKHZhbHVlKSAmJlxuXHRcdE1hdGguZmxvb3IodmFsdWUpID09PSB2YWx1ZVxuXHQpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNEZWZpbmVkKHZhbHVlOiBhbnkpOiBib29sZWFuIHtcblx0cmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgJiYgdmFsdWUgIT09IG51bGw7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgdmFsdWUgaXMgYSBQcm9taXNlLlxuICpcbiAqIEBwYXJhbSB7YW55fSB2IC0gVGhlIHBhcmFtZXRlciBgdmAgaW4gdGhlIGBpc1Byb21pc2VgIGZ1bmN0aW9uIHJlcHJlc2VudHMgYW55IHZhbHVlIHRoYXQgaXMgYmVpbmcgY2hlY2tlZCB0byBkZXRlcm1pbmUgaWYgaXQgaXNcbiAqIGEgUHJvbWlzZS5cbiAqXG4gKiBAcmV0dXJucyBBIGJvb2xlYW4gdmFsdWUgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBpbnB1dCBgdmAgaXMgYSBQcm9taXNlIG9yIG5vdC4gSWYgYHZgIGhhcyBhIGB0aGVuYCBwcm9wZXJ0eSwgaXQgaXMgY29uc2lkZXJlZFxuICogYSBQcm9taXNlIGFuZCB0aGUgZnVuY3Rpb24gcmV0dXJucyBgdHJ1ZWAuIE90aGVyd2lzZSwgaXQgcmV0dXJucyBgZmFsc2VgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNQcm9taXNlPFQ+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":"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"}
|
package/index.d.ts
ADDED
|
@@ -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
|
+
}
|