@ngutil/floating 0.0.52 → 0.0.55

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,10 +1,10 @@
1
1
  import { AnimationBuilder, style as style$1, animate } from '@angular/animations';
2
- import { Observable, switchMap, tap, timer, take, map, Subject, exhaustMap, combineLatest, takeUntil, distinctUntilChanged, of, filter, share, ReplaySubject, shareReplay, takeWhile, debounceTime, startWith, EMPTY } from 'rxjs';
2
+ import { Observable, switchMap, tap, timer, take, map, fromEvent, filter, from, of, race, exhaustMap, distinctUntilChanged, combineLatest, takeUntil, share, ReplaySubject, shareReplay, takeWhile, debounceTime, startWith, EMPTY } from 'rxjs';
3
3
  import { animationObservable, CoverService } from '@ngutil/graphics';
4
4
  import { Duration, Ease, alignmentToTransformOrigin, DimensionWatcher, rectExpand, rectOrigin, rectMoveOrigin, rectContract, alignmentNormalize, RectWatcher } from '@ngutil/style';
5
+ import { KeystrokeService, FocusService } from '@ngutil/aria';
6
+ import { coerceElement, isElementInput, Lifecycle, toSorted } from '@ngutil/common';
5
7
  import { clamp } from 'lodash';
6
- import { isElementInput, Lifecycle, toSorted } from '@ngutil/common';
7
- import { FocusService, KeystrokeService } from '@ngutil/aria';
8
8
  import * as i0 from '@angular/core';
9
9
  import { ElementRef, Injector, ComponentFactoryResolver, ViewContainerRef, InjectionToken, inject, Directive, Inject, Optional, Injectable, TemplateRef, NgModule } from '@angular/core';
10
10
  import { DomPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
@@ -113,11 +113,6 @@ function dropAnimation(options) {
113
113
  return new AnimationTrait(DropAnimation, options);
114
114
  }
115
115
 
116
- class BackdropState {
117
- constructor() {
118
- this.onClick = new Subject();
119
- }
120
- }
121
116
  class BackdropTrait {
122
117
  constructor(options) {
123
118
  this.options = options;
@@ -127,12 +122,9 @@ class BackdropTrait {
127
122
  return new Observable((dest) => {
128
123
  const animationBuilder = floatingRef.container.injector.get(AnimationBuilder);
129
124
  const options = { ...this.options };
130
- const state = new BackdropState();
131
125
  const backdrop = floatingRef.layerSvc.newBackdrop(floatingRef.container, options);
132
- if (options.closeOnClick) {
133
- dest.add(this.#installClickHandler(floatingRef, backdrop, state));
134
- dest.add(state.onClick.pipe(exhaustMap(() => floatingRef.close())).subscribe());
135
- }
126
+ floatingRef.container.nativeElement.setAttribute("data-floating-has-backdrop", "true");
127
+ backdrop.nativeElement.setAttribute("data-floating-backdrop", floatingRef.uid);
136
128
  backdrop.state.on("showing", () => animationObservable({
137
129
  builder: animationBuilder,
138
130
  element: backdrop.nativeElement,
@@ -146,29 +138,97 @@ class BackdropTrait {
146
138
  backdrop.state.on("disposed", () => dest.complete());
147
139
  floatingRef.state.on("disposing", () => backdrop.dispose());
148
140
  dest.add(backdrop.show().subscribe());
149
- dest.next(state);
141
+ dest.next(backdrop);
150
142
  });
151
143
  }
152
- #installClickHandler(floatingRef, backdrop, state) {
153
- const handler = (event) => {
154
- if (event.defaultPrevented) {
155
- return;
156
- }
157
- if (event.target === backdrop.nativeElement || backdrop.nativeElement.contains(event.target)) {
158
- ;
159
- state.onClick.next();
160
- }
161
- };
162
- document.addEventListener("click", handler);
163
- return () => {
164
- document.removeEventListener("click", handler);
165
- };
166
- }
167
144
  }
168
145
  function backdrop(options) {
169
146
  return new BackdropTrait(options);
170
147
  }
171
148
 
149
+ class CloseTriggerTrait {
150
+ constructor(options = {}) {
151
+ this.options = options;
152
+ this.name = "close-trigger";
153
+ }
154
+ connect(floatingRef) {
155
+ const { keystroke, clickOutside, trigger } = this.options;
156
+ const container = floatingRef.container.nativeElement;
157
+ const triggers = [];
158
+ const selfUid = Number(floatingRef.uid);
159
+ if (keystroke) {
160
+ const ks = floatingRef.container.injector.get(KeystrokeService);
161
+ triggers.push(ks.watch(container, { key: "Escape", state: "up" }).pipe(map(() => {
162
+ return { source: "keystroke" };
163
+ })));
164
+ // TODO: angular auxiliary route
165
+ }
166
+ if (clickOutside) {
167
+ const allowedElements = typeof clickOutside === "boolean" ? [] : clickOutside.allowedElements?.map(coerceElement) || [];
168
+ triggers.push(fromEvent(document, "click", { capture: true, passive: true }).pipe(filter(event => {
169
+ if (!(event.target instanceof HTMLElement)) {
170
+ return false;
171
+ }
172
+ const target = event.target;
173
+ for (const allowed of allowedElements) {
174
+ if (target === allowed || allowed.contains(target)) {
175
+ return false;
176
+ }
177
+ }
178
+ const floatingUid = getFloatingUid(target, "data-floating", "floating");
179
+ const backdropUid = getFloatingUid(target, "data-floating-backdrop", "floatingBackdrop");
180
+ const otherBackdropUid = floatingUid != null && floatingUid !== selfUid
181
+ ? getFloatingUid(document.querySelector(`[data-floating-backdrop="${floatingUid}"]`), "data-floating-backdrop", "floatingBackdrop")
182
+ : undefined;
183
+ // console.log({ floatingUid, backdropUid, otherBackdropUid, self: selfUid })
184
+ if (floatingUid == null && backdropUid == null) {
185
+ return true;
186
+ }
187
+ else {
188
+ return (
189
+ // click on self backdrop
190
+ (backdropUid != null && backdropUid === selfUid) ||
191
+ // click on other floating element, whitout backdrop
192
+ (floatingUid != null && otherBackdropUid == null && floatingUid !== selfUid) ||
193
+ // click on other floating element that opened erlier
194
+ (floatingUid != null && floatingUid < selfUid));
195
+ }
196
+ }), map(() => {
197
+ return { source: "click" };
198
+ })));
199
+ }
200
+ if (trigger) {
201
+ triggers.push(from(trigger).pipe(map(() => {
202
+ return { source: "trigger" };
203
+ })));
204
+ }
205
+ if (triggers.length === 0) {
206
+ return of();
207
+ }
208
+ else {
209
+ return race(...triggers).pipe(exhaustMap(event => floatingRef.close().pipe(map(() => event), distinctUntilChanged())));
210
+ }
211
+ }
212
+ }
213
+ function closeTrigger(options = { clickOutside: true, keystroke: true }) {
214
+ return new CloseTriggerTrait(options);
215
+ }
216
+ function getFloatingUid(el, attr, dataset) {
217
+ if (el == null) {
218
+ return undefined;
219
+ }
220
+ if (el.matches(`[${attr}]`)) {
221
+ return Number(el.dataset[dataset]) || undefined;
222
+ }
223
+ else {
224
+ const parent = el.closest(`[${attr}]`);
225
+ if (parent) {
226
+ return Number(parent.dataset[dataset]) || undefined;
227
+ }
228
+ }
229
+ return undefined;
230
+ }
231
+
172
232
  const DIM_MAP = {
173
233
  maxWidth: { computedRef: "max", dimension: "width" },
174
234
  maxHeight: { computedRef: "max", dimension: "height" },
@@ -275,21 +335,6 @@ function focus(options) {
275
335
  return new FocusTrait(options);
276
336
  }
277
337
 
278
- class KeystrokeTrait {
279
- constructor() {
280
- this.name = "keystroke";
281
- }
282
- connect(floatingRef) {
283
- const ks = floatingRef.container.injector.get(KeystrokeService);
284
- return ks
285
- .watch(floatingRef.container.nativeElement, { key: "Escape", state: "up" })
286
- .pipe(exhaustMap(() => floatingRef.close()));
287
- }
288
- }
289
- function keystroke() {
290
- return new KeystrokeTrait();
291
- }
292
-
293
338
  function computePosition({ floating, anchor, placement, options }) {
294
339
  if (options.anchor.margin) {
295
340
  anchor = rectExpand(anchor, options.anchor.margin);
@@ -411,7 +456,7 @@ class FloatingPosition {
411
456
  }
412
457
  }
413
458
 
414
- function modal(options = {}) {
459
+ function modal() {
415
460
  return [
416
461
  position({
417
462
  anchor: {
@@ -423,9 +468,9 @@ function modal(options = {}) {
423
468
  padding: "16px"
424
469
  }
425
470
  }),
426
- backdrop({ type: "solid", color: "rgba(0, 0, 0, .3)", closeOnClick: options.closeOnBackdropClick }),
471
+ backdrop({ type: "solid", color: "rgba(0, 0, 0, .3)" }),
427
472
  focus({ trap: true }),
428
- keystroke(),
473
+ closeTrigger(),
429
474
  fallAnimation()
430
475
  ];
431
476
  }
@@ -718,10 +763,10 @@ class LayerService {
718
763
  }
719
764
  }
720
765
  }
721
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: LayerService, deps: [{ token: LAYER_ZINDEX_START, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
722
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.6", type: LayerService, ngImport: i0 }); }
766
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: LayerService, deps: [{ token: LAYER_ZINDEX_START, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
767
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.6", type: LayerService, ngImport: i0 }); }
723
768
  }
724
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: LayerService, decorators: [{
769
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: LayerService, decorators: [{
725
770
  type: Directive
726
771
  }], ctorParameters: () => [{ type: undefined, decorators: [{
727
772
  type: Inject,
@@ -730,10 +775,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImpor
730
775
  type: Optional
731
776
  }] }] });
732
777
  class RootLayer extends LayerService {
733
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: RootLayer, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
734
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.6", type: RootLayer, isStandalone: true, selector: "body", providers: [{ provide: LayerService, useExisting: RootLayer }], usesInheritance: true, ngImport: i0 }); }
778
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: RootLayer, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
779
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.6", type: RootLayer, isStandalone: true, selector: "body", providers: [{ provide: LayerService, useExisting: RootLayer }], usesInheritance: true, ngImport: i0 }); }
735
780
  }
736
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: RootLayer, decorators: [{
781
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: RootLayer, decorators: [{
737
782
  type: Directive,
738
783
  args: [{
739
784
  selector: "body",
@@ -742,10 +787,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImpor
742
787
  }]
743
788
  }] });
744
789
  class IndividualLayer extends LayerService {
745
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: IndividualLayer, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
746
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.6", type: IndividualLayer, isStandalone: true, providers: [{ provide: LayerService, useExisting: IndividualLayer }], usesInheritance: true, ngImport: i0 }); }
790
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: IndividualLayer, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
791
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.6", type: IndividualLayer, isStandalone: true, providers: [{ provide: LayerService, useExisting: IndividualLayer }], usesInheritance: true, ngImport: i0 }); }
747
792
  }
748
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: IndividualLayer, decorators: [{
793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: IndividualLayer, decorators: [{
749
794
  type: Directive,
750
795
  args: [{
751
796
  standalone: true,
@@ -786,6 +831,7 @@ function getAlwaysOnTop(child) {
786
831
  }
787
832
 
788
833
  const TRAITS = new InjectionToken("TRAITS");
834
+ let UID_COUNTER = 0;
789
835
  class FloatingRef {
790
836
  #traits;
791
837
  #untilCleanup;
@@ -806,8 +852,13 @@ class FloatingRef {
806
852
  this.#traits = {};
807
853
  this.#untilCleanup = this.state.onExecute("cleanup");
808
854
  this.#untilDisposed = this.state.onExecute("disposed");
809
- container.nativeElement.style.overflow = "hidden";
810
- container.nativeElement.style.visibility = "hidden";
855
+ this.uid = `${++UID_COUNTER}`;
856
+ Object.assign(container.nativeElement.style, {
857
+ overflow: "hidden",
858
+ visibility: "hidden",
859
+ pointerEvents: "none"
860
+ });
861
+ container.nativeElement.setAttribute("data-floating", this.uid);
811
862
  this.#traits = traits;
812
863
  this.traitState$ = this.#traitState().pipe(shareReplay(1));
813
864
  this.state.current$.pipe(takeWhile(state => state !== "cleanup", true)).subscribe(state => {
@@ -816,9 +867,8 @@ class FloatingRef {
816
867
  this.state.on("init", () => this.traitState$.pipe(takeUntil(this.#untilCleanup), debounceTime(5), take(1)));
817
868
  this.state.on("showing", () => {
818
869
  container.nativeElement.style.visibility = "visible";
819
- container.nativeElement.style.pointerEvents = "none";
820
870
  });
821
- this.state.on("showing", () => {
871
+ this.state.on("shown", () => {
822
872
  container.nativeElement.style.pointerEvents = null;
823
873
  });
824
874
  this.state.on("disposing", () => {
@@ -869,10 +919,10 @@ class FloatingRef {
869
919
  return combineLatest(src).pipe(shareReplay(1));
870
920
  }
871
921
  }
872
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: FloatingRef, deps: [{ token: LayerService }, { token: ContainerRef }, { token: TRAITS }], target: i0.ɵɵFactoryTarget.Injectable }); }
873
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: FloatingRef }); }
922
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FloatingRef, deps: [{ token: LayerService }, { token: ContainerRef }, { token: TRAITS }], target: i0.ɵɵFactoryTarget.Injectable }); }
923
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FloatingRef }); }
874
924
  }
875
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: FloatingRef, decorators: [{
925
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FloatingRef, decorators: [{
876
926
  type: Injectable
877
927
  }], ctorParameters: () => [{ type: LayerService }, { type: ContainerRef }, { type: undefined, decorators: [{
878
928
  type: Inject,
@@ -999,19 +1049,19 @@ class FloatingService {
999
1049
  return new FloatingComponentFactory(this, value, opts);
1000
1050
  }
1001
1051
  }
1002
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: FloatingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1003
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: FloatingService }); }
1052
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FloatingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1053
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FloatingService }); }
1004
1054
  }
1005
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: FloatingService, decorators: [{
1055
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FloatingService, decorators: [{
1006
1056
  type: Injectable
1007
1057
  }] });
1008
1058
 
1009
1059
  class NuFloating {
1010
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: NuFloating, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1011
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.6", ngImport: i0, type: NuFloating, imports: [RootLayer], exports: [RootLayer] }); }
1012
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: NuFloating, providers: [FloatingService] }); }
1060
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: NuFloating, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1061
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.6", ngImport: i0, type: NuFloating, imports: [RootLayer], exports: [RootLayer] }); }
1062
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: NuFloating, providers: [FloatingService] }); }
1013
1063
  }
1014
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImport: i0, type: NuFloating, decorators: [{
1064
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: NuFloating, decorators: [{
1015
1065
  type: NgModule,
1016
1066
  args: [{
1017
1067
  providers: [FloatingService],
@@ -1024,5 +1074,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.6", ngImpor
1024
1074
  * Generated bundle index. Do not edit.
1025
1075
  */
1026
1076
 
1027
- export { AlwaysOnTop, AnimationTrait, AttributeTrait, BackdropRef, BackdropState, BackdropTrait, ChildRef, ComponentPortalRef, ContainerRef, DimensionConstraintTrait, DropAnimation, FadeAnimation, FallAnimation, FloatingAnchorRef, FloatingComponentFactory, FloatingFactory, FloatingPlacementRef, FloatingPosition, FloatingRef, FloatingService, FloatingTemplateFactory, FocusTrait, IndividualLayer, KeystrokeTrait, LAYER_ZINDEX_START, LayerService, NuFloating, PortalRef, PositionTrait, RootLayer, StyleTrait, TRAITS, TemplatePortalRef, attribute, backdrop, computePosition, dropAnimation, fadeAnimation, fallAnimation, focus, keystroke, maxHeight, maxWidth, minHeight, minWidth, modal, position, style };
1077
+ export { AlwaysOnTop, AnimationTrait, AttributeTrait, BackdropRef, BackdropTrait, ChildRef, ComponentPortalRef, ContainerRef, DimensionConstraintTrait, DropAnimation, FadeAnimation, FallAnimation, FloatingAnchorRef, FloatingComponentFactory, FloatingFactory, FloatingPlacementRef, FloatingPosition, FloatingRef, FloatingService, FloatingTemplateFactory, FocusTrait, IndividualLayer, LAYER_ZINDEX_START, LayerService, NuFloating, PortalRef, PositionTrait, RootLayer, StyleTrait, TRAITS, TemplatePortalRef, attribute, backdrop, closeTrigger, computePosition, dropAnimation, fadeAnimation, fallAnimation, focus, maxHeight, maxWidth, minHeight, minWidth, modal, position, style };
1028
1078
  //# sourceMappingURL=ngutil-floating.mjs.map