@ethlete/core 0.2.0-next.20 → 0.2.0-next.21

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.
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, HostBinding, InjectionToken, Injectable, Inject, Optional, ElementRef, EventEmitter, Directive, Output, NgZone, Pipe, QueryList } from '@angular/core';
2
+ import { inject, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, HostBinding, InjectionToken, Injectable, ElementRef, Inject, Optional, EventEmitter, Directive, Output, NgZone, Pipe, QueryList } from '@angular/core';
3
3
  import { DomSanitizer, Meta, Title } from '@angular/platform-browser';
4
4
  import { coerceElement, coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
5
- import { fromEvent, Observable, Subject, BehaviorSubject, filter, distinctUntilChanged, map, pairwise, combineLatest, shareReplay, takeUntil, startWith, debounceTime, tap, take } from 'rxjs';
5
+ import { fromEvent, Observable, Subject, takeUntil, distinctUntilChanged, BehaviorSubject, filter, map, combineLatest, pairwise, debounceTime, shareReplay, startWith, tap, take } from 'rxjs';
6
6
  import { DOCUMENT } from '@angular/common';
7
7
  import { Router, NavigationEnd } from '@angular/router';
8
8
  import { __decorate, __metadata } from 'tslib';
@@ -346,641 +346,674 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImpor
346
346
  args: [{ providedIn: 'root' }]
347
347
  }], ctorParameters: function () { return [{ type: ResizeObserverFactory }]; } });
348
348
 
349
- const routerDisableScrollTop = (config = {}) => {
350
- if (!config.asReturnRoute) {
351
- return {
352
- disableScrollTop: true,
353
- };
349
+ const clamp = (value, min = 0, max = 100) => {
350
+ return Math.max(min, Math.min(max, value));
351
+ };
352
+
353
+ /* eslint-disable @typescript-eslint/no-explicit-any */
354
+ /* eslint-disable no-var */
355
+ /**
356
+ * Stolen from klona to avoid adding a dependency
357
+ * https://github.com/lukeed/klona
358
+ *
359
+ * MIT License
360
+ *
361
+ * Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
362
+ *
363
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
364
+ *
365
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
366
+ *
367
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
368
+ */
369
+ const set = (obj, key, val) => {
370
+ if (typeof val.value === 'object')
371
+ val.value = clone(val.value);
372
+ if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') {
373
+ Object.defineProperty(obj, key, val);
354
374
  }
355
- return {
356
- disableScrollTopAsReturnRoute: true,
357
- };
375
+ else
376
+ obj[key] = val.value;
358
377
  };
359
- class RouterStateService {
360
- get route$() {
361
- return this._route$.asObservable();
378
+ const clone = (original) => {
379
+ if (typeof original !== 'object')
380
+ return original;
381
+ var _og = original;
382
+ var i = 0, k, list, tmp, str = Object.prototype.toString.call(_og);
383
+ if (str === '[object Object]') {
384
+ tmp = Object.create(_og.__proto__ || null);
362
385
  }
363
- get state$() {
364
- return this._state$.asObservable();
386
+ else if (str === '[object Array]') {
387
+ tmp = Array(_og.length);
365
388
  }
366
- constructor() {
367
- this._isScrollTopOnNavigationEnabled = false;
368
- this._router = inject(Router);
369
- this._route$ = new BehaviorSubject('/');
370
- this._state$ = new BehaviorSubject({
371
- title: undefined,
372
- data: {},
373
- pathParams: {},
374
- queryParams: {},
389
+ else if (str === '[object Set]') {
390
+ tmp = new Set();
391
+ _og.forEach(function (val) {
392
+ tmp.add(clone(val));
375
393
  });
376
- this._router.events
377
- .pipe(filter((event) => event instanceof NavigationEnd), distinctUntilChanged((a, b) => a.url === b.url), map((event) => event.url))
378
- .subscribe(this._route$);
379
- this._route$
380
- .pipe(map(() => {
381
- let route = this._router.routerState.snapshot.root;
382
- while (route.firstChild) {
383
- route = route.firstChild;
384
- }
385
- const { data, params, queryParams, title } = route;
386
- return {
387
- data,
388
- pathParams: params,
389
- queryParams,
390
- title,
391
- };
392
- }))
393
- .subscribe(this._state$);
394
394
  }
395
- enableScrollTopOnNavigation(config = {}) {
396
- if (this._isScrollTopOnNavigationEnabled) {
397
- return;
398
- }
399
- this._isScrollTopOnNavigationEnabled = true;
400
- this._state$.pipe(pairwise()).subscribe(([oldData, newData]) => {
401
- if (!(newData.data['disableScrollTopAsReturnRoute'] && oldData.data['disableScrollTop']) &&
402
- !newData.data['disableScrollTop']) {
403
- (config.scrollElement ?? document.documentElement).scrollTop = 0;
404
- }
395
+ else if (str === '[object Map]') {
396
+ tmp = new Map();
397
+ _og.forEach(function (val, key) {
398
+ tmp.set(clone(key), clone(val));
405
399
  });
406
400
  }
407
- selectQueryParam(key) {
408
- return this._state$.pipe(map((state) => state.queryParams[key]));
409
- }
410
- selectPathParam(key) {
411
- return this._state$.pipe(map((state) => state.pathParams[key]));
412
- }
413
- selectData(key) {
414
- return this._state$.pipe(map((state) => state.data[key]));
415
- }
416
- }
417
- RouterStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: RouterStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
418
- RouterStateService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: RouterStateService, providedIn: 'root' });
419
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: RouterStateService, decorators: [{
420
- type: Injectable,
421
- args: [{
422
- providedIn: 'root',
423
- }]
424
- }], ctorParameters: function () { return []; } });
425
-
426
- class ViewportService {
427
- get isXs$() {
428
- return this._isXs$.asObservable();
429
- }
430
- get isXs() {
431
- return this._isXs$.value;
432
- }
433
- get isSm$() {
434
- return this._isSm$.asObservable();
435
- }
436
- get isSm() {
437
- return this._isSm$.value;
401
+ else if (str === '[object Date]') {
402
+ tmp = new Date(+_og);
438
403
  }
439
- get isMd$() {
440
- return this._isMd$.asObservable();
404
+ else if (str === '[object RegExp]') {
405
+ tmp = new RegExp(_og.source, _og.flags);
441
406
  }
442
- get isMd() {
443
- return this._isMd$.value;
407
+ else if (str === '[object DataView]') {
408
+ tmp = new _og.constructor(clone(_og.buffer));
444
409
  }
445
- get isLg$() {
446
- return this._isLg$.asObservable();
410
+ else if (str === '[object ArrayBuffer]') {
411
+ tmp = _og.slice(0);
447
412
  }
448
- get isLg() {
449
- return this._isLg$.value;
413
+ else if (str.slice(-6) === 'Array]') {
414
+ // ArrayBuffer.isView(x)
415
+ // ~> `new` bcuz `Buffer.slice` => ref
416
+ tmp = new _og.constructor(_og);
450
417
  }
451
- get isXl$() {
452
- return this._isXl$.asObservable();
418
+ if (tmp) {
419
+ for (list = Object.getOwnPropertySymbols(_og); i < list.length; i++) {
420
+ set(tmp, list[i], Object.getOwnPropertyDescriptor(_og, list[i]));
421
+ }
422
+ for (i = 0, list = Object.getOwnPropertyNames(_og); i < list.length; i++) {
423
+ if (Object.hasOwnProperty.call(tmp, (k = list[i])) && tmp[k] === _og[k])
424
+ continue;
425
+ set(tmp, k, Object.getOwnPropertyDescriptor(_og, k));
426
+ }
453
427
  }
454
- get isXl() {
455
- return this._isXl$.value;
428
+ return tmp || _og;
429
+ };
430
+
431
+ const hasCookie = (name) => {
432
+ if (typeof document === 'undefined') {
433
+ return false;
456
434
  }
457
- get is2Xl$() {
458
- return this._is2Xl$.asObservable();
435
+ return document.cookie.split(';').some((c) => {
436
+ return c.trim().startsWith(name + '=');
437
+ });
438
+ };
439
+ const getCookie = (name) => {
440
+ if (typeof document === 'undefined') {
441
+ return null;
459
442
  }
460
- get is2Xl() {
461
- return this._is2Xl$.value;
443
+ // From https://stackoverflow.com/questions/10730362/get-cookie-by-name
444
+ return ('; ' + document.cookie).split(`; ${name}=`).pop()?.split(';')[0];
445
+ };
446
+ const setCookie = (name, data, expiresInDays = 30, domain = getDomain()) => {
447
+ if (typeof document === 'undefined') {
448
+ return;
462
449
  }
463
- get currentViewport() {
464
- return this.getCurrentViewport([this.isXs, this.isSm, this.isMd, this.isLg, this.isXl, this.is2Xl]);
450
+ const date = new Date();
451
+ date.setTime(date.getTime() + expiresInDays * 24 * 60 * 60 * 1000);
452
+ document.cookie = `${name}=${data}; path=/; expires=${date.toUTCString()}; domain=${domain}; SameSite=Lax;`;
453
+ };
454
+ const deleteCookie = (name, path, domain = getDomain()) => {
455
+ if (hasCookie(name)) {
456
+ document.cookie =
457
+ name +
458
+ '=' +
459
+ (path ? ';path=' + path : '') +
460
+ (domain ? ';domain=' + domain : '') +
461
+ ';expires=Thu, 01 Jan 1970 00:00:01 GMT';
465
462
  }
466
- constructor(_viewportConfig, _breakpointObserver) {
467
- this._breakpointObserver = _breakpointObserver;
468
- this._isXs$ = new BehaviorSubject(false);
469
- this._isSm$ = new BehaviorSubject(false);
470
- this._isMd$ = new BehaviorSubject(false);
471
- this._isLg$ = new BehaviorSubject(false);
472
- this._isXl$ = new BehaviorSubject(false);
473
- this._is2Xl$ = new BehaviorSubject(false);
474
- this.currentViewport$ = combineLatest([this.isXs$, this.isSm$, this.isMd$, this.isLg$, this.isXl$, this.is2Xl$]).pipe(map((val) => this.getCurrentViewport(val)), shareReplay());
475
- this._viewportConfig = _viewportConfig || DEFAULT_VIEWPORT_CONFIG;
476
- this._observeDefaultBreakpoints();
463
+ };
464
+ const getDomain = () => {
465
+ if (typeof navigator === 'undefined') {
466
+ return null;
477
467
  }
478
- observe(options) {
479
- const mediaQuery = this._buildMediaQuery(options);
480
- return this._breakpointObserver.observe(mediaQuery).pipe(map((x) => x.matches), shareReplay());
468
+ const hostname = window.location.hostname;
469
+ if (hostname.includes('localhost')) {
470
+ return 'localhost';
481
471
  }
482
- isMatched(options) {
483
- const mediaQuery = this._buildMediaQuery(options);
484
- return this._breakpointObserver.isMatched(mediaQuery);
472
+ const splitHost = hostname.split('.');
473
+ if (splitHost.length > 2) {
474
+ return `${splitHost[splitHost.length - 2]}.${splitHost[splitHost.length - 1]}`;
485
475
  }
486
- _observeDefaultBreakpoints() {
487
- this.observe({ max: 'xs' }).subscribe(this._isXs$);
488
- this.observe({ min: 'sm', max: 'sm' }).subscribe(this._isSm$);
489
- this.observe({ min: 'md', max: 'md' }).subscribe(this._isMd$);
490
- this.observe({ min: 'lg', max: 'lg' }).subscribe(this._isLg$);
491
- this.observe({ min: 'xl', max: 'xl' }).subscribe(this._isXl$);
492
- this.observe({ min: '2xl' }).subscribe(this._is2Xl$);
476
+ return hostname;
477
+ };
478
+
479
+ /* eslint-disable @typescript-eslint/no-explicit-any */
480
+ /* eslint-disable no-var */
481
+ /**
482
+ * Stolen from dequal to avoid adding a dependency
483
+ * https://github.com/lukeed/dequal
484
+ *
485
+ * The MIT License (MIT)
486
+ *
487
+ * Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
488
+ *
489
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
490
+ * of this software and associated documentation files (the "Software"), to deal
491
+ * in the Software without restriction, including without limitation the rights
492
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
493
+ * copies of the Software, and to permit persons to whom the Software is
494
+ * furnished to do so, subject to the following conditions:
495
+ *
496
+ * The above copyright notice and this permission notice shall be included in
497
+ * all copies or substantial portions of the Software.
498
+ *
499
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
500
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
501
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
502
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
503
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
504
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
505
+ * THE SOFTWARE.
506
+ */
507
+ const has = Object.prototype.hasOwnProperty;
508
+ function find(iter, tar, key) {
509
+ for (key of iter.keys()) {
510
+ if (equal(key, tar))
511
+ return key;
493
512
  }
494
- _getViewportSize(type, option) {
495
- const index = option === 'min' ? 0 : 1;
496
- const size = this._viewportConfig.breakpoints[type][index];
497
- if (size === Infinity || size === 0) {
498
- return size;
499
- }
500
- if (option === 'min') {
501
- return size;
502
- }
503
- // Due to scaling, the actual size of the viewport may be a decimal number.
504
- // Eg. on Windows 11 with 150% scaling, the viewport size may be 1535.33px
505
- // and thus not matching any of the default breakpoints.
506
- return size + 0.9;
507
- }
508
- _buildMediaQuery(options) {
509
- if (!options.min && !options.max) {
510
- throw new Error('At least one of min or max must be defined');
513
+ }
514
+ const equal = (foo, bar) => {
515
+ var ctor, len, tmp;
516
+ if (foo === bar)
517
+ return true;
518
+ if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
519
+ if (ctor === Date)
520
+ return foo.getTime() === bar.getTime();
521
+ if (ctor === RegExp)
522
+ return foo.toString() === bar.toString();
523
+ if (ctor === Array) {
524
+ if ((len = foo.length) === bar.length) {
525
+ while (len-- && equal(foo[len], bar[len]))
526
+ ;
527
+ }
528
+ return len === -1;
511
529
  }
512
- const mediaQueryParts = [];
513
- if (options.min) {
514
- if (typeof options.min === 'number') {
515
- mediaQueryParts.push(`(min-width: ${options.min}px)`);
530
+ if (ctor === Set) {
531
+ if (foo.size !== bar.size) {
532
+ return false;
516
533
  }
517
- else {
518
- mediaQueryParts.push(`(min-width: ${this._getViewportSize(options.min, 'min')}px)`);
534
+ for (len of foo) {
535
+ tmp = len;
536
+ if (tmp && typeof tmp === 'object') {
537
+ tmp = find(bar, tmp);
538
+ if (!tmp)
539
+ return false;
540
+ }
541
+ if (!bar.has(tmp))
542
+ return false;
519
543
  }
544
+ return true;
520
545
  }
521
- if (options.min && options.max) {
522
- mediaQueryParts.push('and');
523
- }
524
- if (options.max) {
525
- if (typeof options.max === 'number') {
526
- mediaQueryParts.push(`(max-width: ${options.max}px)`);
546
+ if (ctor === Map) {
547
+ if (foo.size !== bar.size) {
548
+ return false;
527
549
  }
528
- else {
529
- mediaQueryParts.push(`(max-width: ${this._getViewportSize(options.max, 'max')}px)`);
550
+ for (len of foo) {
551
+ tmp = len[0];
552
+ if (tmp && typeof tmp === 'object') {
553
+ tmp = find(bar, tmp);
554
+ if (!tmp)
555
+ return false;
556
+ }
557
+ if (!equal(len[1], bar.get(tmp))) {
558
+ return false;
559
+ }
530
560
  }
561
+ return true;
531
562
  }
532
- return mediaQueryParts.join(' ');
533
- }
534
- getCurrentViewport([isXs, isSm, isMd, isLg, isXl, is2Xl]) {
535
- if (isXs) {
536
- return 'xs';
563
+ if (ctor === ArrayBuffer) {
564
+ foo = new Uint8Array(foo);
565
+ bar = new Uint8Array(bar);
537
566
  }
538
- else if (isSm) {
539
- return 'sm';
567
+ else if (ctor === DataView) {
568
+ if ((len = foo.byteLength) === bar.byteLength) {
569
+ while (len-- && foo.getInt8(len) === bar.getInt8(len))
570
+ ;
571
+ }
572
+ return len === -1;
540
573
  }
541
- else if (isMd) {
542
- return 'md';
574
+ if (ArrayBuffer.isView(foo)) {
575
+ if ((len = foo.byteLength) === bar.byteLength) {
576
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
577
+ //@ts-ignore
578
+ while (len-- && foo[len] === bar[len])
579
+ ;
580
+ }
581
+ return len === -1;
543
582
  }
544
- else if (isLg) {
545
- return 'lg';
583
+ if (!ctor || typeof foo === 'object') {
584
+ len = 0;
585
+ for (ctor in foo) {
586
+ if (has.call(foo, ctor) && ++len && !has.call(bar, ctor))
587
+ return false;
588
+ if (!(ctor in bar) || !equal(foo[ctor], bar[ctor]))
589
+ return false;
590
+ }
591
+ return Object.keys(bar).length === len;
546
592
  }
547
- else if (isXl) {
548
- return 'xl';
593
+ }
594
+ return foo !== foo && bar !== bar;
595
+ };
596
+
597
+ const isAttributeRenderBinding = (value) => typeof value === 'boolean';
598
+ const isAttributeValueBinding = (value) => typeof value === 'object';
599
+ const createReactiveBindings = (...values) => {
600
+ const rootElementRef = inject(ElementRef);
601
+ const destroy$ = inject(DestroyService, { host: true }).destroy$;
602
+ const subscriptions = [];
603
+ const pushedAttributes = [];
604
+ const defaults = {};
605
+ const push = (value) => {
606
+ const { attribute, observable, elementRef } = value;
607
+ const elRef = elementRef || rootElementRef;
608
+ const attributes = Array.isArray(attribute) ? attribute : [attribute];
609
+ pushedAttributes.push(attributes);
610
+ for (const attribute of attributes) {
611
+ if (!defaults[attribute]) {
612
+ defaults[attribute] = elRef.nativeElement.getAttribute(attribute) || undefined;
613
+ }
549
614
  }
550
- else if (is2Xl) {
551
- return '2xl';
615
+ const subscription = observable
616
+ .pipe(takeUntil(destroy$), distinctUntilChanged((a, b) => {
617
+ if (isAttributeRenderBinding(a) && isAttributeRenderBinding(b)) {
618
+ return a === b;
619
+ }
620
+ else if (isAttributeValueBinding(a) && isAttributeValueBinding(b)) {
621
+ return a.render === b.render && a.value === b.value;
622
+ }
623
+ return false;
624
+ }))
625
+ .subscribe((value) => {
626
+ const currentAttributes = pushedAttributes.find((s) => s.some((current) => attributes.includes(current))) || [];
627
+ for (const attribute of currentAttributes) {
628
+ const isSingleClassMutation = attribute.startsWith('class.');
629
+ const isMultipleClassMutation = attribute === 'class';
630
+ const render = isAttributeRenderBinding(value) ? value : value.render;
631
+ if (isSingleClassMutation) {
632
+ const className = attribute.replace('class.', '');
633
+ if (!className) {
634
+ continue;
635
+ }
636
+ if (!render) {
637
+ elRef.nativeElement.classList.remove(className);
638
+ }
639
+ else {
640
+ elRef.nativeElement.classList.add(className);
641
+ }
642
+ }
643
+ else if (isMultipleClassMutation) {
644
+ const classes = isAttributeRenderBinding(value) ? '' : `${value.value}`;
645
+ if (!classes) {
646
+ continue;
647
+ }
648
+ if (!render) {
649
+ elRef.nativeElement.classList.remove(...classes.split(' '));
650
+ }
651
+ else {
652
+ elRef.nativeElement.classList.add(...classes.split(' '));
653
+ }
654
+ }
655
+ else {
656
+ const attributeValue = isAttributeRenderBinding(value) ? true : `${value.value}`;
657
+ if (!attribute) {
658
+ continue;
659
+ }
660
+ if (!render) {
661
+ elRef.nativeElement.removeAttribute(attribute);
662
+ }
663
+ else {
664
+ elRef.nativeElement.setAttribute(attribute, `${attributeValue}`);
665
+ }
666
+ }
667
+ }
668
+ });
669
+ subscriptions.push({ attributes, subscription });
670
+ };
671
+ const remove = (...attributes) => {
672
+ for (const attribute of attributes) {
673
+ const sub = subscriptions.find((s) => s.attributes.includes(attribute));
674
+ const attributeStack = pushedAttributes.find((a) => a.includes(attribute));
675
+ if (sub) {
676
+ sub.attributes = sub.attributes.filter((a) => a !== attribute);
677
+ attributeStack?.splice(attributeStack.indexOf(attribute), 1);
678
+ if (sub.attributes.length === 0) {
679
+ sub.subscription.unsubscribe();
680
+ subscriptions.splice(subscriptions.indexOf(sub), 1);
681
+ }
682
+ }
552
683
  }
553
- return 'xs';
684
+ };
685
+ const reset = () => {
686
+ for (const attribute in defaults) {
687
+ if (defaults[attribute] === undefined) {
688
+ rootElementRef.nativeElement.removeAttribute(attribute);
689
+ }
690
+ else {
691
+ rootElementRef.nativeElement.setAttribute(attribute, defaults[attribute]);
692
+ }
693
+ }
694
+ };
695
+ for (const value of values) {
696
+ push(value);
554
697
  }
555
- }
556
- ViewportService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ViewportService, deps: [{ token: VIEWPORT_CONFIG, optional: true }, { token: i1.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Injectable });
557
- ViewportService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ViewportService, providedIn: 'root' });
558
- __decorate([
559
- Memo(),
560
- __metadata("design:type", Function),
561
- __metadata("design:paramtypes", [String, String]),
562
- __metadata("design:returntype", void 0)
563
- ], ViewportService.prototype, "_getViewportSize", null);
564
- __decorate([
565
- Memo({
566
- resolver: (v) => {
567
- return `${v.min ?? ''}-${v.max ?? ''}`;
568
- },
569
- }),
570
- __metadata("design:type", Function),
571
- __metadata("design:paramtypes", [Object]),
572
- __metadata("design:returntype", void 0)
573
- ], ViewportService.prototype, "_buildMediaQuery", null);
574
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ViewportService, decorators: [{
575
- type: Injectable,
576
- args: [{
577
- providedIn: 'root',
578
- }]
579
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
580
- type: Inject,
581
- args: [VIEWPORT_CONFIG]
582
- }, {
583
- type: Optional
584
- }] }, { type: i1.BreakpointObserver }]; }, propDecorators: { _getViewportSize: [], _buildMediaQuery: [] } });
698
+ return {
699
+ push,
700
+ remove,
701
+ reset,
702
+ };
703
+ };
585
704
 
586
- class ClickOutsideDirective {
705
+ const elementCanScroll = (element) => {
706
+ const { scrollHeight, clientHeight, scrollWidth, clientWidth } = element;
707
+ return scrollHeight > clientHeight || scrollWidth > clientWidth;
708
+ };
709
+
710
+ const provideViewportConfig = (viewportConfig) => {
711
+ return { provide: VIEWPORT_CONFIG, useValue: viewportConfig };
712
+ };
713
+
714
+ const routerDisableScrollTop = (config = {}) => {
715
+ if (!config.asReturnRoute) {
716
+ return {
717
+ disableScrollTop: true,
718
+ };
719
+ }
720
+ return {
721
+ disableScrollTopAsReturnRoute: true,
722
+ };
723
+ };
724
+ class RouterStateService {
725
+ get route$() {
726
+ return this._route$.asObservable();
727
+ }
728
+ get state$() {
729
+ return this._state$.asObservable();
730
+ }
587
731
  constructor() {
588
- this._elementRef = inject(ElementRef);
589
- this._clickObserverService = inject(ClickObserverService);
590
- this._subscription = null;
591
- this.etClickOutside = new EventEmitter();
732
+ this._isScrollTopOnNavigationEnabled = false;
733
+ this._router = inject(Router);
734
+ this._route$ = new BehaviorSubject('/');
735
+ this._state$ = new BehaviorSubject({
736
+ title: null,
737
+ fragment: null,
738
+ data: {},
739
+ pathParams: {},
740
+ queryParams: {},
741
+ });
742
+ this._router.events
743
+ .pipe(filter((event) => event instanceof NavigationEnd), distinctUntilChanged((a, b) => a.url === b.url), map((event) => {
744
+ const { url } = event;
745
+ const urlWithoutQueryParams = url.split('?')[0];
746
+ const withoutFragment = urlWithoutQueryParams.split('#')[0];
747
+ return withoutFragment;
748
+ }))
749
+ .subscribe(this._route$);
750
+ this._route$
751
+ .pipe(map(() => {
752
+ let route = this._router.routerState.snapshot.root;
753
+ while (route.firstChild) {
754
+ route = route.firstChild;
755
+ }
756
+ const { data, params, queryParams, title, fragment } = route;
757
+ return {
758
+ data,
759
+ pathParams: params,
760
+ queryParams,
761
+ title: title ?? null,
762
+ fragment,
763
+ };
764
+ }))
765
+ .subscribe(this._state$);
592
766
  }
593
- ngOnInit() {
594
- setTimeout(() => {
595
- this._subscription = this._clickObserverService.observe(this._elementRef.nativeElement).subscribe((event) => {
596
- const activeElement = event.target;
597
- const isInside = this._elementRef.nativeElement.contains(activeElement);
598
- if (!isInside) {
599
- this.etClickOutside.emit(event);
767
+ enableScrollEnhancements(config = {}) {
768
+ if (this._isScrollTopOnNavigationEnabled) {
769
+ return;
770
+ }
771
+ this._isScrollTopOnNavigationEnabled = true;
772
+ combineLatest([this._state$.pipe(pairwise()), this._route$.pipe(pairwise())])
773
+ .pipe(debounceTime(1))
774
+ .subscribe(([[prevState, currState], [prevRoute, currRoute]]) => {
775
+ const sameUrlNavigation = prevRoute === currRoute && equal(prevState.pathParams, currState.pathParams);
776
+ const didFragmentChange = prevState.fragment !== currState.fragment;
777
+ if (sameUrlNavigation) {
778
+ const allQueryParams = [
779
+ ...new Set(Object.keys(prevState.queryParams).concat(Object.keys(currState.queryParams))),
780
+ ];
781
+ const changedQueryParams = allQueryParams.filter((key) => currState.queryParams[key] !== prevState.queryParams[key]);
782
+ if (!config.queryParamTriggerList?.length && !didFragmentChange) {
783
+ return;
600
784
  }
601
- });
785
+ const caseQueryParams = changedQueryParams.some((key) => config.queryParamTriggerList?.includes(key));
786
+ const caseFragment = didFragmentChange && config.fragment?.enabled;
787
+ if (caseQueryParams) {
788
+ (config.scrollElement ?? document.documentElement).scrollTop = 0;
789
+ }
790
+ else if (caseFragment) {
791
+ const fragmentElement = document.getElementById(currState.fragment ?? '');
792
+ if (fragmentElement) {
793
+ fragmentElement.scrollIntoView({ behavior: config.fragment?.smooth ? 'smooth' : 'auto' });
794
+ }
795
+ }
796
+ }
797
+ else {
798
+ if (!(currState.data['disableScrollTopAsReturnRoute'] && prevState.data['disableScrollTop']) &&
799
+ !currState.data['disableScrollTop']) {
800
+ (config.scrollElement ?? document.documentElement).scrollTop = 0;
801
+ }
802
+ }
602
803
  });
603
804
  }
604
- ngOnDestroy() {
605
- this._subscription?.unsubscribe();
805
+ selectQueryParam(key) {
806
+ return this._state$.pipe(map((state) => state.queryParams[key]));
807
+ }
808
+ selectPathParam(key) {
809
+ return this._state$.pipe(map((state) => state.pathParams[key]));
810
+ }
811
+ selectData(key) {
812
+ return this._state$.pipe(map((state) => state.data[key]));
606
813
  }
607
814
  }
608
- ClickOutsideDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ClickOutsideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
609
- ClickOutsideDirectivedir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.4", type: ClickOutsideDirective, isStandalone: true, selector: "[etClickOutside]", outputs: { etClickOutside: "etClickOutside" }, ngImport: i0 });
610
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ClickOutsideDirective, decorators: [{
611
- type: Directive,
815
+ RouterStateService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: RouterStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
816
+ RouterStateServiceprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: RouterStateService, providedIn: 'root' });
817
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: RouterStateService, decorators: [{
818
+ type: Injectable,
612
819
  args: [{
613
- selector: '[etClickOutside]',
614
- standalone: true,
820
+ providedIn: 'root',
615
821
  }]
616
- }], propDecorators: { etClickOutside: [{
617
- type: Output
618
- }] } });
619
-
620
- const clamp = (value, min = 0, max = 100) => {
621
- return Math.max(min, Math.min(max, value));
622
- };
822
+ }], ctorParameters: function () { return []; } });
623
823
 
624
- /* eslint-disable @typescript-eslint/no-explicit-any */
625
- /* eslint-disable no-var */
626
- /**
627
- * Stolen from klona to avoid adding a dependency
628
- * https://github.com/lukeed/klona
629
- *
630
- * MIT License
631
- *
632
- * Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
633
- *
634
- * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
635
- *
636
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
637
- *
638
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
639
- */
640
- const set = (obj, key, val) => {
641
- if (typeof val.value === 'object')
642
- val.value = clone(val.value);
643
- if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') {
644
- Object.defineProperty(obj, key, val);
645
- }
646
- else
647
- obj[key] = val.value;
648
- };
649
- const clone = (original) => {
650
- if (typeof original !== 'object')
651
- return original;
652
- var _og = original;
653
- var i = 0, k, list, tmp, str = Object.prototype.toString.call(_og);
654
- if (str === '[object Object]') {
655
- tmp = Object.create(_og.__proto__ || null);
824
+ class ViewportService {
825
+ get isXs$() {
826
+ return this._isXs$.asObservable();
656
827
  }
657
- else if (str === '[object Array]') {
658
- tmp = Array(_og.length);
828
+ get isXs() {
829
+ return this._isXs$.value;
659
830
  }
660
- else if (str === '[object Set]') {
661
- tmp = new Set();
662
- _og.forEach(function (val) {
663
- tmp.add(clone(val));
664
- });
831
+ get isSm$() {
832
+ return this._isSm$.asObservable();
665
833
  }
666
- else if (str === '[object Map]') {
667
- tmp = new Map();
668
- _og.forEach(function (val, key) {
669
- tmp.set(clone(key), clone(val));
670
- });
834
+ get isSm() {
835
+ return this._isSm$.value;
671
836
  }
672
- else if (str === '[object Date]') {
673
- tmp = new Date(+_og);
837
+ get isMd$() {
838
+ return this._isMd$.asObservable();
674
839
  }
675
- else if (str === '[object RegExp]') {
676
- tmp = new RegExp(_og.source, _og.flags);
840
+ get isMd() {
841
+ return this._isMd$.value;
677
842
  }
678
- else if (str === '[object DataView]') {
679
- tmp = new _og.constructor(clone(_og.buffer));
843
+ get isLg$() {
844
+ return this._isLg$.asObservable();
680
845
  }
681
- else if (str === '[object ArrayBuffer]') {
682
- tmp = _og.slice(0);
846
+ get isLg() {
847
+ return this._isLg$.value;
683
848
  }
684
- else if (str.slice(-6) === 'Array]') {
685
- // ArrayBuffer.isView(x)
686
- // ~> `new` bcuz `Buffer.slice` => ref
687
- tmp = new _og.constructor(_og);
849
+ get isXl$() {
850
+ return this._isXl$.asObservable();
688
851
  }
689
- if (tmp) {
690
- for (list = Object.getOwnPropertySymbols(_og); i < list.length; i++) {
691
- set(tmp, list[i], Object.getOwnPropertyDescriptor(_og, list[i]));
692
- }
693
- for (i = 0, list = Object.getOwnPropertyNames(_og); i < list.length; i++) {
694
- if (Object.hasOwnProperty.call(tmp, (k = list[i])) && tmp[k] === _og[k])
695
- continue;
696
- set(tmp, k, Object.getOwnPropertyDescriptor(_og, k));
697
- }
852
+ get isXl() {
853
+ return this._isXl$.value;
698
854
  }
699
- return tmp || _og;
700
- };
701
-
702
- const hasCookie = (name) => {
703
- if (typeof document === 'undefined') {
704
- return false;
855
+ get is2Xl$() {
856
+ return this._is2Xl$.asObservable();
705
857
  }
706
- return document.cookie.split(';').some((c) => {
707
- return c.trim().startsWith(name + '=');
708
- });
709
- };
710
- const getCookie = (name) => {
711
- if (typeof document === 'undefined') {
712
- return null;
858
+ get is2Xl() {
859
+ return this._is2Xl$.value;
713
860
  }
714
- // From https://stackoverflow.com/questions/10730362/get-cookie-by-name
715
- return ('; ' + document.cookie).split(`; ${name}=`).pop()?.split(';')[0];
716
- };
717
- const setCookie = (name, data, expiresInDays = 30, domain = getDomain()) => {
718
- if (typeof document === 'undefined') {
719
- return;
861
+ get currentViewport() {
862
+ return this.getCurrentViewport([this.isXs, this.isSm, this.isMd, this.isLg, this.isXl, this.is2Xl]);
720
863
  }
721
- const date = new Date();
722
- date.setTime(date.getTime() + expiresInDays * 24 * 60 * 60 * 1000);
723
- document.cookie = `${name}=${data}; path=/; expires=${date.toUTCString()}; domain=${domain}; SameSite=Lax;`;
724
- };
725
- const deleteCookie = (name, path, domain = getDomain()) => {
726
- if (hasCookie(name)) {
727
- document.cookie =
728
- name +
729
- '=' +
730
- (path ? ';path=' + path : '') +
731
- (domain ? ';domain=' + domain : '') +
732
- ';expires=Thu, 01 Jan 1970 00:00:01 GMT';
864
+ constructor(_viewportConfig, _breakpointObserver) {
865
+ this._breakpointObserver = _breakpointObserver;
866
+ this._isXs$ = new BehaviorSubject(false);
867
+ this._isSm$ = new BehaviorSubject(false);
868
+ this._isMd$ = new BehaviorSubject(false);
869
+ this._isLg$ = new BehaviorSubject(false);
870
+ this._isXl$ = new BehaviorSubject(false);
871
+ this._is2Xl$ = new BehaviorSubject(false);
872
+ this.currentViewport$ = combineLatest([this.isXs$, this.isSm$, this.isMd$, this.isLg$, this.isXl$, this.is2Xl$]).pipe(map((val) => this.getCurrentViewport(val)), shareReplay());
873
+ this._viewportConfig = _viewportConfig || DEFAULT_VIEWPORT_CONFIG;
874
+ this._observeDefaultBreakpoints();
733
875
  }
734
- };
735
- const getDomain = () => {
736
- if (typeof navigator === 'undefined') {
737
- return null;
876
+ observe(options) {
877
+ const mediaQuery = this._buildMediaQuery(options);
878
+ return this._breakpointObserver.observe(mediaQuery).pipe(map((x) => x.matches), shareReplay());
738
879
  }
739
- const hostname = window.location.hostname;
740
- if (hostname.includes('localhost')) {
741
- return 'localhost';
880
+ isMatched(options) {
881
+ const mediaQuery = this._buildMediaQuery(options);
882
+ return this._breakpointObserver.isMatched(mediaQuery);
742
883
  }
743
- const splitHost = hostname.split('.');
744
- if (splitHost.length > 2) {
745
- return `${splitHost[splitHost.length - 2]}.${splitHost[splitHost.length - 1]}`;
884
+ _observeDefaultBreakpoints() {
885
+ this.observe({ max: 'xs' }).subscribe(this._isXs$);
886
+ this.observe({ min: 'sm', max: 'sm' }).subscribe(this._isSm$);
887
+ this.observe({ min: 'md', max: 'md' }).subscribe(this._isMd$);
888
+ this.observe({ min: 'lg', max: 'lg' }).subscribe(this._isLg$);
889
+ this.observe({ min: 'xl', max: 'xl' }).subscribe(this._isXl$);
890
+ this.observe({ min: '2xl' }).subscribe(this._is2Xl$);
746
891
  }
747
- return hostname;
748
- };
749
-
750
- /* eslint-disable @typescript-eslint/no-explicit-any */
751
- /* eslint-disable no-var */
752
- /**
753
- * Stolen from dequal to avoid adding a dependency
754
- * https://github.com/lukeed/dequal
755
- *
756
- * The MIT License (MIT)
757
- *
758
- * Copyright (c) Luke Edwards <luke.edwards05@gmail.com> (lukeed.com)
759
- *
760
- * Permission is hereby granted, free of charge, to any person obtaining a copy
761
- * of this software and associated documentation files (the "Software"), to deal
762
- * in the Software without restriction, including without limitation the rights
763
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
764
- * copies of the Software, and to permit persons to whom the Software is
765
- * furnished to do so, subject to the following conditions:
766
- *
767
- * The above copyright notice and this permission notice shall be included in
768
- * all copies or substantial portions of the Software.
769
- *
770
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
771
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
772
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
773
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
774
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
775
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
776
- * THE SOFTWARE.
777
- */
778
- const has = Object.prototype.hasOwnProperty;
779
- function find(iter, tar, key) {
780
- for (key of iter.keys()) {
781
- if (equal(key, tar))
782
- return key;
892
+ _getViewportSize(type, option) {
893
+ const index = option === 'min' ? 0 : 1;
894
+ const size = this._viewportConfig.breakpoints[type][index];
895
+ if (size === Infinity || size === 0) {
896
+ return size;
897
+ }
898
+ if (option === 'min') {
899
+ return size;
900
+ }
901
+ // Due to scaling, the actual size of the viewport may be a decimal number.
902
+ // Eg. on Windows 11 with 150% scaling, the viewport size may be 1535.33px
903
+ // and thus not matching any of the default breakpoints.
904
+ return size + 0.9;
783
905
  }
784
- }
785
- const equal = (foo, bar) => {
786
- var ctor, len, tmp;
787
- if (foo === bar)
788
- return true;
789
- if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
790
- if (ctor === Date)
791
- return foo.getTime() === bar.getTime();
792
- if (ctor === RegExp)
793
- return foo.toString() === bar.toString();
794
- if (ctor === Array) {
795
- if ((len = foo.length) === bar.length) {
796
- while (len-- && equal(foo[len], bar[len]))
797
- ;
798
- }
799
- return len === -1;
906
+ _buildMediaQuery(options) {
907
+ if (!options.min && !options.max) {
908
+ throw new Error('At least one of min or max must be defined');
800
909
  }
801
- if (ctor === Set) {
802
- if (foo.size !== bar.size) {
803
- return false;
910
+ const mediaQueryParts = [];
911
+ if (options.min) {
912
+ if (typeof options.min === 'number') {
913
+ mediaQueryParts.push(`(min-width: ${options.min}px)`);
804
914
  }
805
- for (len of foo) {
806
- tmp = len;
807
- if (tmp && typeof tmp === 'object') {
808
- tmp = find(bar, tmp);
809
- if (!tmp)
810
- return false;
811
- }
812
- if (!bar.has(tmp))
813
- return false;
915
+ else {
916
+ mediaQueryParts.push(`(min-width: ${this._getViewportSize(options.min, 'min')}px)`);
814
917
  }
815
- return true;
816
918
  }
817
- if (ctor === Map) {
818
- if (foo.size !== bar.size) {
819
- return false;
919
+ if (options.min && options.max) {
920
+ mediaQueryParts.push('and');
921
+ }
922
+ if (options.max) {
923
+ if (typeof options.max === 'number') {
924
+ mediaQueryParts.push(`(max-width: ${options.max}px)`);
820
925
  }
821
- for (len of foo) {
822
- tmp = len[0];
823
- if (tmp && typeof tmp === 'object') {
824
- tmp = find(bar, tmp);
825
- if (!tmp)
826
- return false;
827
- }
828
- if (!equal(len[1], bar.get(tmp))) {
829
- return false;
830
- }
926
+ else {
927
+ mediaQueryParts.push(`(max-width: ${this._getViewportSize(options.max, 'max')}px)`);
831
928
  }
832
- return true;
833
929
  }
834
- if (ctor === ArrayBuffer) {
835
- foo = new Uint8Array(foo);
836
- bar = new Uint8Array(bar);
930
+ return mediaQueryParts.join(' ');
931
+ }
932
+ getCurrentViewport([isXs, isSm, isMd, isLg, isXl, is2Xl]) {
933
+ if (isXs) {
934
+ return 'xs';
837
935
  }
838
- else if (ctor === DataView) {
839
- if ((len = foo.byteLength) === bar.byteLength) {
840
- while (len-- && foo.getInt8(len) === bar.getInt8(len))
841
- ;
842
- }
843
- return len === -1;
936
+ else if (isSm) {
937
+ return 'sm';
844
938
  }
845
- if (ArrayBuffer.isView(foo)) {
846
- if ((len = foo.byteLength) === bar.byteLength) {
847
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
848
- //@ts-ignore
849
- while (len-- && foo[len] === bar[len])
850
- ;
851
- }
852
- return len === -1;
939
+ else if (isMd) {
940
+ return 'md';
853
941
  }
854
- if (!ctor || typeof foo === 'object') {
855
- len = 0;
856
- for (ctor in foo) {
857
- if (has.call(foo, ctor) && ++len && !has.call(bar, ctor))
858
- return false;
859
- if (!(ctor in bar) || !equal(foo[ctor], bar[ctor]))
860
- return false;
861
- }
862
- return Object.keys(bar).length === len;
942
+ else if (isLg) {
943
+ return 'lg';
944
+ }
945
+ else if (isXl) {
946
+ return 'xl';
947
+ }
948
+ else if (is2Xl) {
949
+ return '2xl';
863
950
  }
951
+ return 'xs';
864
952
  }
865
- return foo !== foo && bar !== bar;
866
- };
953
+ }
954
+ ViewportService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ViewportService, deps: [{ token: VIEWPORT_CONFIG, optional: true }, { token: i1.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Injectable });
955
+ ViewportService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ViewportService, providedIn: 'root' });
956
+ __decorate([
957
+ Memo(),
958
+ __metadata("design:type", Function),
959
+ __metadata("design:paramtypes", [String, String]),
960
+ __metadata("design:returntype", void 0)
961
+ ], ViewportService.prototype, "_getViewportSize", null);
962
+ __decorate([
963
+ Memo({
964
+ resolver: (v) => {
965
+ return `${v.min ?? ''}-${v.max ?? ''}`;
966
+ },
967
+ }),
968
+ __metadata("design:type", Function),
969
+ __metadata("design:paramtypes", [Object]),
970
+ __metadata("design:returntype", void 0)
971
+ ], ViewportService.prototype, "_buildMediaQuery", null);
972
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ViewportService, decorators: [{
973
+ type: Injectable,
974
+ args: [{
975
+ providedIn: 'root',
976
+ }]
977
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
978
+ type: Inject,
979
+ args: [VIEWPORT_CONFIG]
980
+ }, {
981
+ type: Optional
982
+ }] }, { type: i1.BreakpointObserver }]; }, propDecorators: { _getViewportSize: [], _buildMediaQuery: [] } });
867
983
 
868
- const isAttributeRenderBinding = (value) => typeof value === 'boolean';
869
- const isAttributeValueBinding = (value) => typeof value === 'object';
870
- const createReactiveBindings = (...values) => {
871
- const rootElementRef = inject(ElementRef);
872
- const destroy$ = inject(DestroyService, { host: true }).destroy$;
873
- const subscriptions = [];
874
- const pushedAttributes = [];
875
- const defaults = {};
876
- const push = (value) => {
877
- const { attribute, observable, elementRef } = value;
878
- const elRef = elementRef || rootElementRef;
879
- const attributes = Array.isArray(attribute) ? attribute : [attribute];
880
- pushedAttributes.push(attributes);
881
- for (const attribute of attributes) {
882
- if (!defaults[attribute]) {
883
- defaults[attribute] = elRef.nativeElement.getAttribute(attribute) || undefined;
884
- }
885
- }
886
- const subscription = observable
887
- .pipe(takeUntil(destroy$), distinctUntilChanged((a, b) => {
888
- if (isAttributeRenderBinding(a) && isAttributeRenderBinding(b)) {
889
- return a === b;
890
- }
891
- else if (isAttributeValueBinding(a) && isAttributeValueBinding(b)) {
892
- return a.render === b.render && a.value === b.value;
893
- }
894
- return false;
895
- }))
896
- .subscribe((value) => {
897
- const currentAttributes = pushedAttributes.find((s) => s.some((current) => attributes.includes(current))) || [];
898
- for (const attribute of currentAttributes) {
899
- const isSingleClassMutation = attribute.startsWith('class.');
900
- const isMultipleClassMutation = attribute === 'class';
901
- const render = isAttributeRenderBinding(value) ? value : value.render;
902
- if (isSingleClassMutation) {
903
- const className = attribute.replace('class.', '');
904
- if (!className) {
905
- continue;
906
- }
907
- if (!render) {
908
- elRef.nativeElement.classList.remove(className);
909
- }
910
- else {
911
- elRef.nativeElement.classList.add(className);
912
- }
913
- }
914
- else if (isMultipleClassMutation) {
915
- const classes = isAttributeRenderBinding(value) ? '' : `${value.value}`;
916
- if (!classes) {
917
- continue;
918
- }
919
- if (!render) {
920
- elRef.nativeElement.classList.remove(...classes.split(' '));
921
- }
922
- else {
923
- elRef.nativeElement.classList.add(...classes.split(' '));
924
- }
925
- }
926
- else {
927
- const attributeValue = isAttributeRenderBinding(value) ? true : `${value.value}`;
928
- if (!attribute) {
929
- continue;
930
- }
931
- if (!render) {
932
- elRef.nativeElement.removeAttribute(attribute);
933
- }
934
- else {
935
- elRef.nativeElement.setAttribute(attribute, `${attributeValue}`);
936
- }
984
+ class ClickOutsideDirective {
985
+ constructor() {
986
+ this._elementRef = inject(ElementRef);
987
+ this._clickObserverService = inject(ClickObserverService);
988
+ this._subscription = null;
989
+ this.etClickOutside = new EventEmitter();
990
+ }
991
+ ngOnInit() {
992
+ setTimeout(() => {
993
+ this._subscription = this._clickObserverService.observe(this._elementRef.nativeElement).subscribe((event) => {
994
+ const activeElement = event.target;
995
+ const isInside = this._elementRef.nativeElement.contains(activeElement);
996
+ if (!isInside) {
997
+ this.etClickOutside.emit(event);
937
998
  }
938
- }
999
+ });
939
1000
  });
940
- subscriptions.push({ attributes, subscription });
941
- };
942
- const remove = (...attributes) => {
943
- for (const attribute of attributes) {
944
- const sub = subscriptions.find((s) => s.attributes.includes(attribute));
945
- const attributeStack = pushedAttributes.find((a) => a.includes(attribute));
946
- if (sub) {
947
- sub.attributes = sub.attributes.filter((a) => a !== attribute);
948
- attributeStack?.splice(attributeStack.indexOf(attribute), 1);
949
- if (sub.attributes.length === 0) {
950
- sub.subscription.unsubscribe();
951
- subscriptions.splice(subscriptions.indexOf(sub), 1);
952
- }
953
- }
954
- }
955
- };
956
- const reset = () => {
957
- for (const attribute in defaults) {
958
- if (defaults[attribute] === undefined) {
959
- rootElementRef.nativeElement.removeAttribute(attribute);
960
- }
961
- else {
962
- rootElementRef.nativeElement.setAttribute(attribute, defaults[attribute]);
963
- }
964
- }
965
- };
966
- for (const value of values) {
967
- push(value);
968
1001
  }
969
- return {
970
- push,
971
- remove,
972
- reset,
973
- };
974
- };
975
-
976
- const elementCanScroll = (element) => {
977
- const { scrollHeight, clientHeight, scrollWidth, clientWidth } = element;
978
- return scrollHeight > clientHeight || scrollWidth > clientWidth;
979
- };
980
-
981
- const provideViewportConfig = (viewportConfig) => {
982
- return { provide: VIEWPORT_CONFIG, useValue: viewportConfig };
983
- };
1002
+ ngOnDestroy() {
1003
+ this._subscription?.unsubscribe();
1004
+ }
1005
+ }
1006
+ ClickOutsideDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ClickOutsideDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1007
+ ClickOutsideDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.1.4", type: ClickOutsideDirective, isStandalone: true, selector: "[etClickOutside]", outputs: { etClickOutside: "etClickOutside" }, ngImport: i0 });
1008
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: ClickOutsideDirective, decorators: [{
1009
+ type: Directive,
1010
+ args: [{
1011
+ selector: '[etClickOutside]',
1012
+ standalone: true,
1013
+ }]
1014
+ }], propDecorators: { etClickOutside: [{
1015
+ type: Output
1016
+ }] } });
984
1017
 
985
1018
  const CURSOR_DRAG_SCROLLING_CLASS = 'et-cursor-drag-scroll--scrolling';
986
1019
  const CURSOR_DRAG_SCROLLING_PREPARED_CLASS = 'et-cursor-drag-scroll--prepared';