@ngutil/floating 0.0.64 → 0.0.66

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, fromEvent, filter, from, of, race, exhaustMap, distinctUntilChanged, combineLatest, takeUntil, share, ReplaySubject, shareReplay, takeWhile, debounceTime, startWith, EMPTY } from 'rxjs';
2
+ import { Observable, switchMap, tap, of, take, map, fromEvent, filter, from, race, exhaustMap, distinctUntilChanged, combineLatest, takeUntil, isObservable, share, ReplaySubject, shareReplay, takeWhile, debounceTime, startWith, EMPTY } from 'rxjs';
3
3
  import { animationObservable, CoverService } from '@ngutil/graphics';
4
- import { Duration, Ease, alignmentToTransformOrigin, DimensionWatcher, rectExpand, rectOrigin, rectMoveOrigin, rectContract, alignmentNormalize, RectWatcher } from '@ngutil/style';
4
+ import { Duration, Ease, floatingPositionDirection, DimensionWatcher, RectWatcher, floatingPosition, floatingPositionToStyle } from '@ngutil/style';
5
5
  import { KeystrokeService, FocusService } from '@ngutil/aria';
6
6
  import { coerceElement, isElementInput, Lifecycle, toSorted } from '@ngutil/common';
7
- import { clamp } from 'lodash';
7
+ import { isEqual } from 'lodash';
8
8
  import * as i0 from '@angular/core';
9
9
  import { ElementRef, Injector, InjectionToken, inject, Directive, Injectable, ComponentFactoryResolver, ViewContainerRef, ApplicationRef, Inject, TemplateRef } from '@angular/core';
10
10
  import { DOCUMENT } from '@angular/common';
@@ -13,49 +13,42 @@ import { DomPortalOutlet, ComponentPortal, TemplatePortal } from '@angular/cdk/p
13
13
  // https://tympanus.net/Development/ModalWindowEffects/
14
14
  const timing = `${Duration.FastMs}ms ${Ease.Deceleration}`;
15
15
  class AnimationTrait {
16
- constructor(animation, options) {
16
+ constructor(animation, params) {
17
17
  this.animation = animation;
18
- this.options = options;
18
+ this.params = params;
19
19
  this.name = "animation";
20
20
  }
21
21
  connect(floatingRef) {
22
22
  return new Observable((dst) => {
23
23
  const builder = floatingRef.container.injector.get(AnimationBuilder);
24
24
  const element = floatingRef.container.nativeElement;
25
- const options = this.options || {};
26
- floatingRef.state.on("showing", () => animationParams(floatingRef, 0, options.params).pipe(switchMap(params => animationObservable({
25
+ floatingRef.state.on("showing", () => animationParams(floatingRef, this.params).pipe(switchMap(params => animationObservable({
27
26
  builder,
28
27
  element,
29
28
  animation: this.animation.show,
30
- options: { ...options, params }
29
+ options: { params }
31
30
  }))));
32
- floatingRef.state.on("disposing", () => animationParams(floatingRef, 0, options.params).pipe(switchMap(params => animationObservable({
31
+ floatingRef.state.on("disposing", () => animationParams(floatingRef, this.params).pipe(switchMap(params => animationObservable({
33
32
  builder,
34
33
  element,
35
34
  animation: this.animation.hide,
36
- options: { ...options, params }
35
+ options: { params }
37
36
  })), tap(() => (element.style.display = "none"))));
38
37
  floatingRef.state.on("disposing", () => dst.complete());
39
38
  dst.next();
40
39
  });
41
40
  }
42
41
  }
43
- function animationParams(floatingRef, delay, overrides) {
44
- const src = delay > 0
45
- ? timer(delay).pipe(switchMap(() => floatingRef.watchTrait("position")))
46
- : floatingRef.watchTrait("position");
47
- return src.pipe(take(1), map(position => {
48
- const origin = position.computed ? alignmentToTransformOrigin(position.computed.content.align) : "center";
49
- return {
50
- origin,
51
- ...overrides
52
- };
53
- }));
42
+ function animationParams(floatingRef, params) {
43
+ if (params == null) {
44
+ return of({});
45
+ }
46
+ return floatingRef.watchTrait("position").pipe(take(1), map(params));
54
47
  }
55
48
  const FallAnimation = {
56
49
  show: [
57
50
  style$1({
58
- transform: "scale(1.5)",
51
+ transform: "scale({{ scale }})",
59
52
  visibility: "visible",
60
53
  opacity: "0"
61
54
  }),
@@ -66,52 +59,58 @@ const FallAnimation = {
66
59
  ],
67
60
  hide: [
68
61
  animate(timing, style$1({
69
- transform: "scale(1.5)",
62
+ transform: "scale({{ scale }})",
70
63
  visibility: "visible",
71
64
  opacity: "0"
72
65
  }))
73
66
  ]
74
67
  };
75
- function fallAnimation(options) {
76
- return new AnimationTrait(FallAnimation, options);
68
+ function fallAnimation(scale = 1.5) {
69
+ return new AnimationTrait(FallAnimation, () => {
70
+ return { scale };
71
+ });
77
72
  }
78
73
  const FadeAnimation = {
79
74
  show: [style$1({ opacity: 0 }), animate(timing, style$1({ opacity: 1 }))],
80
75
  hide: [animate(timing, style$1({ opacity: 0 }))]
81
76
  };
82
- function fadeAnimation(options) {
83
- return new AnimationTrait(FadeAnimation, options);
77
+ function fadeAnimation() {
78
+ return new AnimationTrait(FadeAnimation);
84
79
  }
85
- const DropAnimation = {
80
+ const SlideAnimation = {
86
81
  show: [
87
82
  style$1({
88
- transform: "translate({{ translateX }}, {{ translateY }})",
83
+ transform: "translate({{ tx }}, {{ ty }})",
89
84
  opacity: "0",
90
- transformOrigin: "{{ origin }}",
85
+ // transformOrigin: "{{ origin }}",
91
86
  visibility: "visible"
92
87
  }),
93
88
  animate(timing, style$1({
94
89
  opacity: "1",
95
- transform: "scale(1, 1) translate(0px, 0px)"
90
+ transform: "translate(0px, 0px)"
96
91
  }))
97
92
  ],
98
- hide: [
99
- animate(timing, style$1({ opacity: 0, transform: "translate(calc({{ translateX }} * -1), calc({{ translateY }} * -1))" }))
100
- ]
93
+ hide: [animate(timing, style$1({ opacity: 0, transform: "translate(calc({{ tx }} * -1), calc({{ ty }} * -1))" }))]
101
94
  };
102
- function dropAnimation(options) {
103
- if (!options) {
104
- options = {};
105
- }
106
- if (!options.params) {
107
- options.params = {};
108
- }
109
- else {
110
- options.params = { ...options.params };
111
- }
112
- options.params["translateX"] = "0px";
113
- options.params["translateY"] = "-40px";
114
- return new AnimationTrait(DropAnimation, options);
95
+ const SlideAnimationParams = {
96
+ center: { tx: 0, ty: 0 },
97
+ up: { tx: 0, ty: 1 },
98
+ down: { tx: 0, ty: -1 },
99
+ left: { tx: 1, ty: 0 },
100
+ right: { tx: -1, ty: 0 }
101
+ };
102
+ function slideAnimation(size) {
103
+ return new AnimationTrait(SlideAnimation, position => {
104
+ const direction = floatingPositionDirection(position);
105
+ const { tx, ty } = SlideAnimationParams[direction];
106
+ return { tx: `${tx * size}px`, ty: `${ty * size}px` };
107
+ });
108
+ }
109
+ function slideNearAnimation(size = 40) {
110
+ return slideAnimation(size * -1);
111
+ }
112
+ function slideAwayAnimation(size = 40) {
113
+ return slideAnimation(size);
115
114
  }
116
115
 
117
116
  class BackdropTrait {
@@ -234,68 +233,6 @@ function getFloatingUid(el, attr, dataset) {
234
233
  return undefined;
235
234
  }
236
235
 
237
- const DIM_MAP = {
238
- maxWidth: { computedRef: "max", dimension: "width" },
239
- maxHeight: { computedRef: "max", dimension: "height" },
240
- minWidth: { computedRef: "min", dimension: "width" },
241
- minHeight: { computedRef: "min", dimension: "height" }
242
- };
243
- class DimensionConstraintTrait {
244
- #map;
245
- constructor(name, value) {
246
- this.value = value;
247
- this.name = name;
248
- this.#map = DIM_MAP[name];
249
- }
250
- connect(floatingRef) {
251
- return new Observable((dst) => {
252
- if (isElementInput(this.value)) {
253
- const watcher = floatingRef.container.injector.get(DimensionWatcher);
254
- const refDim = watcher.watch(this.value, "border-box").pipe(map(value => value[this.#map.dimension]));
255
- return combineLatest({
256
- refDim: refDim,
257
- position: floatingRef.watchTrait("position")
258
- }).subscribe(({ refDim, position }) => {
259
- const floating = position.computed?.content;
260
- if (!floating) {
261
- return;
262
- }
263
- dst.next(clamp(refDim, floating.min[this.#map.dimension] || 0, floating.max[this.#map.dimension] || Infinity));
264
- });
265
- }
266
- else {
267
- return floatingRef.watchTrait("position").subscribe(position => {
268
- const floating = position.computed?.content;
269
- if (!floating) {
270
- return;
271
- }
272
- if (isNaN(this.value)) {
273
- dst.next(floating[this.#map.computedRef][this.#map.dimension]);
274
- }
275
- else {
276
- dst.next(clamp(this.value, floating.min[this.#map.dimension] || 0, floating.max[this.#map.dimension] || Infinity));
277
- }
278
- });
279
- }
280
- }).pipe(takeUntil(floatingRef.state.onExecute("disposing")), distinctUntilChanged(), tap(value => {
281
- const floatingEl = floatingRef.container.nativeElement;
282
- floatingEl.style[this.name] = `${value}px`;
283
- }));
284
- }
285
- }
286
- function maxWidth(value) {
287
- return new DimensionConstraintTrait("maxWidth", value);
288
- }
289
- function maxHeight(value) {
290
- return new DimensionConstraintTrait("maxHeight", value);
291
- }
292
- function minWidth(value) {
293
- return new DimensionConstraintTrait("minWidth", value);
294
- }
295
- function minHeight(value) {
296
- return new DimensionConstraintTrait("minHeight", value);
297
- }
298
-
299
236
  class FocusTrait {
300
237
  constructor(options) {
301
238
  this.options = options;
@@ -340,48 +277,6 @@ function focus(options) {
340
277
  return new FocusTrait(options);
341
278
  }
342
279
 
343
- function computePosition({ floating, anchor, placement, options }) {
344
- if (options.anchor.margin) {
345
- anchor = rectExpand(anchor, options.anchor.margin);
346
- }
347
- const anchorPoint = rectOrigin(anchor, options.anchor.align);
348
- let contentRect = rectMoveOrigin(floating, options.content.align, anchorPoint);
349
- if (options.content.margin) {
350
- contentRect = rectContract(contentRect, options.content.margin);
351
- }
352
- if (options.placement.padding) {
353
- placement = rectContract(placement, options.placement.padding);
354
- }
355
- return {
356
- content: {
357
- ...addTLRB(contentRect, placement),
358
- align: alignmentNormalize(options.content.align),
359
- connect: anchorPoint,
360
- max: { width: placement.width - contentRect.x, height: placement.height - contentRect.y },
361
- min: { width: 0, height: 0 }
362
- },
363
- anchor: {
364
- ...addTLRB(anchor, placement),
365
- align: alignmentNormalize(options.anchor.align),
366
- connect: anchorPoint
367
- },
368
- placement: addTLRB(placement, placement)
369
- };
370
- }
371
- function addTLRB(rect, container) {
372
- return {
373
- ...rect,
374
- top: rect.y,
375
- left: rect.x,
376
- right: container.width - (rect.x + rect.width),
377
- bottom: container.height - (rect.y + rect.height)
378
- };
379
- }
380
-
381
- class FloatingAnchorRef extends ElementRef {
382
- }
383
- class FloatingPlacementRef extends ElementRef {
384
- }
385
280
  class PositionTrait {
386
281
  constructor(options) {
387
282
  this.name = "position";
@@ -390,10 +285,10 @@ class PositionTrait {
390
285
  cloned.placement = { ref: "viewport" };
391
286
  }
392
287
  if (!cloned.anchor) {
393
- cloned.anchor = { ref: cloned.placement.ref, align: "center middle" };
288
+ cloned.anchor = { ref: cloned.placement.ref, link: "center middle" };
394
289
  }
395
290
  if (!cloned.content) {
396
- cloned.content = { align: "center middle" };
291
+ cloned.content = { link: "center middle" };
397
292
  }
398
293
  this.options = cloned;
399
294
  }
@@ -402,15 +297,27 @@ class PositionTrait {
402
297
  const injector = floatingRef.container.injector;
403
298
  const dimWatcher = injector.get(DimensionWatcher);
404
299
  const rectWatcher = injector.get(RectWatcher);
300
+ const constraints = this.options.content.constraints || {};
301
+ const constraintsWatches = {
302
+ minWidth: sizeWatcher(dimWatcher, "width", constraints.minWidth),
303
+ maxWidth: sizeWatcher(dimWatcher, "width", constraints.maxWidth),
304
+ minHeight: sizeWatcher(dimWatcher, "height", constraints.minHeight),
305
+ maxHeight: sizeWatcher(dimWatcher, "height", constraints.maxHeight)
306
+ };
405
307
  const watches = {
406
- floating: dimWatcher.watch(floatingRef.container, "border-box"),
308
+ content: dimWatcher.watch(floatingRef.container, "border-box"),
407
309
  anchor: refWatcher(rectWatcher, this.options.anchor.ref, floatingRef),
408
- placement: refWatcher(rectWatcher, this.options.placement.ref, floatingRef)
310
+ placement: refWatcher(rectWatcher, this.options.placement.ref, floatingRef),
311
+ constraints: combineLatest(constraintsWatches)
409
312
  };
410
- return combineLatest(watches).subscribe(({ floating, anchor, placement }) => {
411
- const res = new FloatingPosition(this.options, floating, anchor, placement);
412
- res.apply(floatingRef);
413
- dest.next(res);
313
+ return combineLatest(watches)
314
+ .pipe(distinctUntilChanged(isEqual))
315
+ .subscribe(dims => {
316
+ const pos = floatingPosition({ dims, options: this.options });
317
+ const floatingEl = floatingRef.container.nativeElement;
318
+ Object.assign(floatingEl.style, floatingPositionToStyle(pos));
319
+ Object.assign(floatingEl.style, constraintsToStyle(pos, dims.constraints));
320
+ dest.next(pos);
414
321
  });
415
322
  }).pipe(takeUntil(floatingRef.state.onExecute("disposing")));
416
323
  }
@@ -426,39 +333,30 @@ function refWatcher(rectWatcher, ref, floatingRef) {
426
333
  return rectWatcher.watch(ref, "border-box");
427
334
  }
428
335
  }
429
- function position(options) {
430
- return [new PositionTrait(options), maxWidth(NaN), maxHeight(NaN)];
431
- }
432
- class FloatingPosition {
433
- constructor(options, floating, anchor, placement) {
434
- this.options = options;
435
- this.floating = floating;
436
- this.anchor = anchor;
437
- this.placement = placement;
438
- // const frect: Rect = { x: 0, y: 0, ...floating }
439
- this.computed = computePosition({ floating, anchor, placement, options });
440
- }
441
- apply(floatingRef) {
442
- if (this.computed == null) {
443
- return;
444
- }
445
- const floatingEl = floatingRef.container.nativeElement;
446
- const computedContent = this.computed.content;
447
- const style = { top: null, right: null, bottom: null, left: null };
448
- if (computedContent.align.horizontal === "right") {
449
- style["right"] = `${computedContent.right}px`;
450
- }
451
- else {
452
- style["left"] = `${computedContent.left}px`;
453
- }
454
- if (computedContent.align.vertical === "bottom") {
455
- style["bottom"] = `${computedContent.bottom}px`;
456
- }
457
- else {
458
- style["top"] = `${computedContent.top}px`;
459
- }
460
- Object.assign(floatingEl.style, style);
336
+ function sizeWatcher(dimWatcher, prop, size) {
337
+ if (typeof size === "number") {
338
+ return of(size);
461
339
  }
340
+ else if (isElementInput(size)) {
341
+ return dimWatcher.watch(size, "border-box").pipe(map(value => value[prop]));
342
+ }
343
+ else if (isObservable(size)) {
344
+ return size.pipe(switchMap(value => sizeWatcher(dimWatcher, prop, value)));
345
+ }
346
+ return of(NaN);
347
+ }
348
+ function constraintsToStyle(pos, sizes) {
349
+ const { minWidth, maxWidth, minHeight, maxHeight } = sizes;
350
+ const { width, height } = pos.placement.area;
351
+ return {
352
+ minWidth: isNaN(minWidth) ? "auto" : `${Math.min(width, minWidth)}px`,
353
+ minHeight: isNaN(minHeight) ? "auto" : `${Math.min(height, minHeight)}px`,
354
+ maxWidth: isNaN(maxWidth) ? `${width}px` : `${Math.min(width, maxWidth)}px`,
355
+ maxHeight: isNaN(maxHeight) ? `${height}px` : `${Math.min(height, maxHeight)}px`
356
+ };
357
+ }
358
+ function position(options) {
359
+ return new PositionTrait(options);
462
360
  }
463
361
 
464
362
  function modal() {
@@ -466,7 +364,7 @@ function modal() {
466
364
  position({
467
365
  anchor: {
468
366
  ref: "viewport",
469
- align: "center middle"
367
+ link: "center middle"
470
368
  },
471
369
  placement: {
472
370
  ref: "viewport",
@@ -614,6 +512,7 @@ function createElement(options) {
614
512
  div.style.flexDirection = "column";
615
513
  div.style.alignItems = "stretch";
616
514
  div.style.justifyContent = "stretch";
515
+ div.style.boxSizing = "border-box";
617
516
  if (options.classes) {
618
517
  div.classList.add(...options.classes);
619
518
  }
@@ -1101,5 +1000,5 @@ function provideFloating(options = {}) {
1101
1000
  * Generated bundle index. Do not edit.
1102
1001
  */
1103
1002
 
1104
- export { AlwaysOnTop, AnimationTrait, AttributeTrait, BackdropRef, BackdropTrait, ChildRef, ComponentPortalRef, ContainerRef, DimensionConstraintTrait, DropAnimation, FadeAnimation, FallAnimation, FloatingAnchorRef, FloatingComponentFactory, FloatingFactory, FloatingPlacementRef, FloatingPosition, FloatingRef, FloatingService, FloatingTemplateFactory, FocusTrait, IndividualLayer, LAYER_CONTAINER_ZINDEX_START, LayerContainer, LayerService, PortalRef, PositionTrait, RootLayer, StyleTrait, TRAITS, TemplatePortalRef, attribute, backdrop, closeTrigger, computePosition, dropAnimation, fadeAnimation, fallAnimation, focus, maxHeight, maxWidth, minHeight, minWidth, modal, position, provideFloating, style };
1003
+ export { AlwaysOnTop, AnimationTrait, AttributeTrait, BackdropRef, BackdropTrait, ChildRef, ComponentPortalRef, ContainerRef, FadeAnimation, FallAnimation, FloatingComponentFactory, FloatingFactory, FloatingRef, FloatingService, FloatingTemplateFactory, FocusTrait, IndividualLayer, LAYER_CONTAINER_ZINDEX_START, LayerContainer, LayerService, PortalRef, PositionTrait, RootLayer, StyleTrait, TRAITS, TemplatePortalRef, attribute, backdrop, closeTrigger, fadeAnimation, fallAnimation, focus, modal, position, provideFloating, slideAwayAnimation, slideNearAnimation, style };
1105
1004
  //# sourceMappingURL=ngutil-floating.mjs.map