angular-movement 0.0.1 → 0.1.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/README.md +115 -33
- package/fesm2022/angular-movement.mjs +509 -119
- package/fesm2022/angular-movement.mjs.map +1 -1
- package/package.json +3 -2
- package/types/angular-movement.d.ts +95 -16
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { isPlatformBrowser, DOCUMENT } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { InjectionToken, inject, PLATFORM_ID, Injectable, input, ElementRef,
|
|
3
|
+
import { InjectionToken, inject, PLATFORM_ID, Injectable, input, ElementRef, computed, effect, forwardRef, Directive, afterEveryRender, NgZone, signal, ViewContainerRef, TemplateRef, Renderer2, makeEnvironmentProviders } from '@angular/core';
|
|
4
4
|
|
|
5
5
|
const MOVEMENT_DEFAULTS = {
|
|
6
6
|
duration: 300,
|
|
7
7
|
easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
|
|
8
8
|
delay: 0,
|
|
9
9
|
disabled: false,
|
|
10
|
+
iterations: 1,
|
|
10
11
|
};
|
|
11
12
|
const MOVEMENT_CONFIG = new InjectionToken('MOVEMENT_CONFIG', {
|
|
12
13
|
factory: () => ({ ...MOVEMENT_DEFAULTS }),
|
|
@@ -52,6 +53,18 @@ function getInterpolated(arr, i1, i2, p) {
|
|
|
52
53
|
const v2 = arr[Math.min(i2, arr.length - 1)];
|
|
53
54
|
return v1 + (v2 - v1) * p;
|
|
54
55
|
}
|
|
56
|
+
const KNOWN_KEYS = new Set([
|
|
57
|
+
'opacity',
|
|
58
|
+
'x',
|
|
59
|
+
'y',
|
|
60
|
+
'scale',
|
|
61
|
+
'scaleX',
|
|
62
|
+
'scaleY',
|
|
63
|
+
'rotate',
|
|
64
|
+
'rotateX',
|
|
65
|
+
'rotateY',
|
|
66
|
+
'blur',
|
|
67
|
+
]);
|
|
55
68
|
function buildKeyframe(frames, getVal) {
|
|
56
69
|
const keyframe = {};
|
|
57
70
|
const opacity = getVal(frames.opacity);
|
|
@@ -87,6 +100,16 @@ function buildKeyframe(frames, getVal) {
|
|
|
87
100
|
if (rotateX !== undefined || rotateY !== undefined) {
|
|
88
101
|
keyframe.transform = `perspective(${DEFAULT_PERSPECTIVE}) rotateX(${rotateX ?? 0}deg) rotateY(${rotateY ?? 0}deg)`;
|
|
89
102
|
}
|
|
103
|
+
// Passthrough arbitrary properties for WAAPI (e.g. strokeDashoffset)
|
|
104
|
+
for (const key in frames) {
|
|
105
|
+
if (KNOWN_KEYS.has(key))
|
|
106
|
+
continue;
|
|
107
|
+
const arr = frames[key];
|
|
108
|
+
const val = getVal(arr);
|
|
109
|
+
if (val !== undefined) {
|
|
110
|
+
keyframe[key] = val;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
90
113
|
return keyframe;
|
|
91
114
|
}
|
|
92
115
|
function composeKeyframeAt(frames, index) {
|
|
@@ -101,27 +124,51 @@ function composeInitialStyle(frames) {
|
|
|
101
124
|
function composeFinalStyle(frames) {
|
|
102
125
|
return buildKeyframe(frames, (arr) => (arr && arr.length > 0 ? arr[arr.length - 1] : undefined));
|
|
103
126
|
}
|
|
127
|
+
const KNOWN_STYLE_KEYS = new Set([
|
|
128
|
+
'opacity',
|
|
129
|
+
'translate',
|
|
130
|
+
'scale',
|
|
131
|
+
'rotate',
|
|
132
|
+
'transform',
|
|
133
|
+
'filter',
|
|
134
|
+
]);
|
|
104
135
|
function applyComposedStyle(el, style) {
|
|
136
|
+
const styledEl = el;
|
|
105
137
|
if (style.opacity !== undefined)
|
|
106
|
-
|
|
138
|
+
styledEl.style.opacity = `${style.opacity}`;
|
|
107
139
|
if (style.translate !== undefined)
|
|
108
|
-
|
|
140
|
+
styledEl.style.translate = style.translate;
|
|
109
141
|
if (style.scale !== undefined)
|
|
110
|
-
|
|
142
|
+
styledEl.style.scale = style.scale;
|
|
111
143
|
if (style.rotate !== undefined)
|
|
112
|
-
|
|
144
|
+
styledEl.style.rotate = style.rotate;
|
|
113
145
|
if (style.transform !== undefined)
|
|
114
|
-
|
|
146
|
+
styledEl.style.transform = style.transform;
|
|
115
147
|
if (style.filter !== undefined)
|
|
116
|
-
|
|
148
|
+
styledEl.style.filter = style.filter;
|
|
149
|
+
// Passthrough arbitrary properties (e.g. strokeDashoffset)
|
|
150
|
+
for (const key in style) {
|
|
151
|
+
if (KNOWN_STYLE_KEYS.has(key))
|
|
152
|
+
continue;
|
|
153
|
+
const val = style[key];
|
|
154
|
+
if (val !== undefined) {
|
|
155
|
+
styledEl.style[key] = String(val);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
117
158
|
}
|
|
118
|
-
function clearComposedStyle(el) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
159
|
+
function clearComposedStyle(el, extraKeys) {
|
|
160
|
+
const styledEl = el;
|
|
161
|
+
styledEl.style.opacity = '';
|
|
162
|
+
styledEl.style.translate = '';
|
|
163
|
+
styledEl.style.scale = '';
|
|
164
|
+
styledEl.style.rotate = '';
|
|
165
|
+
styledEl.style.transform = '';
|
|
166
|
+
styledEl.style.filter = '';
|
|
167
|
+
if (extraKeys) {
|
|
168
|
+
for (const key of extraKeys) {
|
|
169
|
+
styledEl.style[key] = '';
|
|
170
|
+
}
|
|
171
|
+
}
|
|
125
172
|
}
|
|
126
173
|
|
|
127
174
|
const DEFAULT_FADE_OPACITY = [0, 1];
|
|
@@ -178,6 +225,7 @@ const MOVE_PRESETS = {
|
|
|
178
225
|
'bounce-in': {
|
|
179
226
|
enter: { opacity: DEFAULT_FADE_OPACITY, y: [30, 0], scale: [0.85, 1] },
|
|
180
227
|
leave: { opacity: DEFAULT_LEAVE_OPACITY, y: [0, -20], scale: [1, 0.9] },
|
|
228
|
+
loop: { y: [0, -10, 0], scale: [1, 0.95, 1] },
|
|
181
229
|
},
|
|
182
230
|
'blur-in': {
|
|
183
231
|
enter: { opacity: DEFAULT_FADE_OPACITY, blur: [10, 0] },
|
|
@@ -186,10 +234,81 @@ const MOVE_PRESETS = {
|
|
|
186
234
|
spin: {
|
|
187
235
|
enter: { opacity: DEFAULT_FADE_OPACITY, rotate: [-360, 0] },
|
|
188
236
|
leave: { opacity: DEFAULT_LEAVE_OPACITY, rotate: [0, 360] },
|
|
237
|
+
loop: { rotate: [0, 360] },
|
|
189
238
|
},
|
|
190
239
|
pulse: {
|
|
191
240
|
enter: { scale: [1, 1.05, 1] },
|
|
192
241
|
leave: { scale: [1, 0.95, 1] },
|
|
242
|
+
loop: { scale: [1, 1.05, 1] },
|
|
243
|
+
},
|
|
244
|
+
shake: {
|
|
245
|
+
enter: { opacity: DEFAULT_FADE_OPACITY, x: [0, -10, 10, -10, 10, -5, 5, -5, 5, 0] },
|
|
246
|
+
leave: { opacity: DEFAULT_LEAVE_OPACITY, x: [0, 10, -10, 10, -10, 5, -5, 5, -5, 0] },
|
|
247
|
+
},
|
|
248
|
+
swing: {
|
|
249
|
+
enter: { opacity: DEFAULT_FADE_OPACITY, rotate: [0, 15, -10, 5, -5, 0] },
|
|
250
|
+
leave: { opacity: DEFAULT_LEAVE_OPACITY, rotate: [0, -15, 10, -5, 5, 0] },
|
|
251
|
+
},
|
|
252
|
+
wobble: {
|
|
253
|
+
enter: {
|
|
254
|
+
opacity: DEFAULT_FADE_OPACITY,
|
|
255
|
+
x: [0, -25, 20, -15, 10, -5, 0],
|
|
256
|
+
rotate: [0, -5, 3, -3, 2, -1, 0],
|
|
257
|
+
},
|
|
258
|
+
leave: {
|
|
259
|
+
opacity: DEFAULT_LEAVE_OPACITY,
|
|
260
|
+
x: [0, 25, -20, 15, -10, 5, 0],
|
|
261
|
+
rotate: [0, 5, -3, 3, -2, 1, 0],
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
'rubber-band': {
|
|
265
|
+
enter: {
|
|
266
|
+
opacity: DEFAULT_FADE_OPACITY,
|
|
267
|
+
scaleX: [1, 1.25, 0.75, 1.15, 0.95, 1.05, 1],
|
|
268
|
+
scaleY: [1, 0.75, 1.25, 0.85, 1.05, 0.95, 1],
|
|
269
|
+
},
|
|
270
|
+
leave: {
|
|
271
|
+
opacity: DEFAULT_LEAVE_OPACITY,
|
|
272
|
+
scaleX: [1, 1.25, 0.75, 1.15, 0.95, 1.05, 1],
|
|
273
|
+
scaleY: [1, 0.75, 1.25, 0.85, 1.05, 0.95, 1],
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
'heart-beat': {
|
|
277
|
+
enter: { opacity: DEFAULT_FADE_OPACITY, scale: [1, 1.3, 1, 1.3, 1] },
|
|
278
|
+
leave: { opacity: DEFAULT_LEAVE_OPACITY, scale: [1, 1.3, 1, 1.3, 1] },
|
|
279
|
+
loop: { scale: [1, 1.3, 1, 1.3, 1] },
|
|
280
|
+
},
|
|
281
|
+
tada: {
|
|
282
|
+
enter: {
|
|
283
|
+
opacity: DEFAULT_FADE_OPACITY,
|
|
284
|
+
scale: [1, 0.9, 1.1, 1.1, 1.1, 1],
|
|
285
|
+
rotate: [0, -3, 3, -3, 3, 0],
|
|
286
|
+
},
|
|
287
|
+
leave: {
|
|
288
|
+
opacity: DEFAULT_LEAVE_OPACITY,
|
|
289
|
+
scale: [1, 0.9, 1.1, 1.1, 1.1, 1],
|
|
290
|
+
rotate: [0, 3, -3, 3, -3, 0],
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
jello: {
|
|
294
|
+
enter: {
|
|
295
|
+
opacity: DEFAULT_FADE_OPACITY,
|
|
296
|
+
scaleX: [1, 1.25, 0.75, 1.15, 0.95, 1.05, 1],
|
|
297
|
+
scaleY: [1, 0.75, 1.25, 0.85, 1.05, 0.95, 1],
|
|
298
|
+
},
|
|
299
|
+
leave: {
|
|
300
|
+
opacity: DEFAULT_LEAVE_OPACITY,
|
|
301
|
+
scaleX: [1, 1.25, 0.75, 1.15, 0.95, 1.05, 1],
|
|
302
|
+
scaleY: [1, 0.75, 1.25, 0.85, 1.05, 0.95, 1],
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
'light-speed': {
|
|
306
|
+
enter: { opacity: [0, 1], x: [200, 0], scaleX: [0, 1] },
|
|
307
|
+
leave: { opacity: [1, 0], x: [0, 200], scaleX: [1, 0] },
|
|
308
|
+
},
|
|
309
|
+
'roll-in': {
|
|
310
|
+
enter: { opacity: [0, 1], x: [-100, 0], rotate: [-120, 0] },
|
|
311
|
+
leave: { opacity: [1, 0], x: [0, 100], rotate: [0, 120] },
|
|
193
312
|
},
|
|
194
313
|
none: {
|
|
195
314
|
enter: { opacity: [1, 1] },
|
|
@@ -207,6 +326,7 @@ function resolveMovementConfig(defaults, overrides, reducedMotion) {
|
|
|
207
326
|
easing: overrides.easing ?? defaults.easing,
|
|
208
327
|
delay: Math.max(0, overrides.delay ?? defaults.delay),
|
|
209
328
|
disabled: reducedMotion || (overrides.disabled ?? defaults.disabled),
|
|
329
|
+
iterations: overrides.iterations ?? defaults.iterations,
|
|
210
330
|
};
|
|
211
331
|
}
|
|
212
332
|
function resolveMoveFrames(value, phase) {
|
|
@@ -216,9 +336,9 @@ function resolveMoveFrames(value, phase) {
|
|
|
216
336
|
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
217
337
|
console.warn(`[Movement] Unknown preset: "${value}". Using "none" preset.`);
|
|
218
338
|
}
|
|
219
|
-
return MOVE_PRESETS['none'][phase];
|
|
339
|
+
return MOVE_PRESETS['none'][phase] ?? MOVE_PRESETS['none'].enter;
|
|
220
340
|
}
|
|
221
|
-
return preset[phase];
|
|
341
|
+
return preset[phase] ?? preset.enter;
|
|
222
342
|
}
|
|
223
343
|
return value;
|
|
224
344
|
}
|
|
@@ -259,6 +379,63 @@ function applyInitialStyles(el, frames) {
|
|
|
259
379
|
function clearInitialStyles(el) {
|
|
260
380
|
clearComposedStyle(el);
|
|
261
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Validates MoveSpring configuration and returns sanitized values.
|
|
384
|
+
* Warns in development mode for invalid values.
|
|
385
|
+
*/
|
|
386
|
+
function validateSpring(spring) {
|
|
387
|
+
if (!spring)
|
|
388
|
+
return undefined;
|
|
389
|
+
const validated = {};
|
|
390
|
+
if (spring.stiffness !== undefined) {
|
|
391
|
+
if (spring.stiffness <= 0 && typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
392
|
+
console.warn('[Movement] Spring stiffness must be > 0. Using default.');
|
|
393
|
+
}
|
|
394
|
+
validated.stiffness = spring.stiffness > 0 ? spring.stiffness : 100;
|
|
395
|
+
}
|
|
396
|
+
if (spring.damping !== undefined) {
|
|
397
|
+
if (spring.damping < 0 && typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
398
|
+
console.warn('[Movement] Spring damping must be >= 0. Using default.');
|
|
399
|
+
}
|
|
400
|
+
validated.damping = spring.damping >= 0 ? spring.damping : 10;
|
|
401
|
+
}
|
|
402
|
+
if (spring.mass !== undefined) {
|
|
403
|
+
if (spring.mass <= 0 && typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
404
|
+
console.warn('[Movement] Spring mass must be > 0. Using default.');
|
|
405
|
+
}
|
|
406
|
+
validated.mass = spring.mass > 0 ? spring.mass : 1;
|
|
407
|
+
}
|
|
408
|
+
if (spring.velocity !== undefined) {
|
|
409
|
+
validated.velocity = spring.velocity;
|
|
410
|
+
}
|
|
411
|
+
return validated;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Validates scroll offset string format "elFraction viewFraction".
|
|
415
|
+
* Returns true if valid, warns in dev mode if invalid.
|
|
416
|
+
*/
|
|
417
|
+
function isValidScrollOffset(offset) {
|
|
418
|
+
const parts = offset.split(' ').map(parseFloat);
|
|
419
|
+
if (parts.length !== 2 || parts.some(Number.isNaN)) {
|
|
420
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
421
|
+
console.warn(`[Movement] Invalid scroll offset: "${offset}". Expected format "elFraction viewFraction" (e.g. "0 1").`);
|
|
422
|
+
}
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Validates drag elastic factor. Must be between 0 and 1.
|
|
429
|
+
*/
|
|
430
|
+
function validateDragElastic(elastic) {
|
|
431
|
+
if (elastic < 0 || elastic > 1) {
|
|
432
|
+
if (typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
433
|
+
console.warn(`[Movement] Drag elastic must be between 0 and 1. Got ${elastic}. Clamping to range.`);
|
|
434
|
+
}
|
|
435
|
+
return Math.max(0, Math.min(1, elastic));
|
|
436
|
+
}
|
|
437
|
+
return elastic;
|
|
438
|
+
}
|
|
262
439
|
|
|
263
440
|
class WaapiPlayer {
|
|
264
441
|
#animation = null;
|
|
@@ -273,12 +450,18 @@ class WaapiPlayer {
|
|
|
273
450
|
return;
|
|
274
451
|
}
|
|
275
452
|
const keyframes = this.#toWAAPIKeyframes(frames);
|
|
453
|
+
const iterations = config.iterations ?? 1;
|
|
276
454
|
this.#animation = host.animate(keyframes, {
|
|
277
455
|
duration: config.duration,
|
|
278
456
|
easing: config.easing,
|
|
279
457
|
delay: config.delay,
|
|
280
458
|
fill: 'both',
|
|
459
|
+
iterations,
|
|
281
460
|
});
|
|
461
|
+
if (iterations === Infinity) {
|
|
462
|
+
// Infinite loops never finish; consumer must call cancel() manually.
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
282
465
|
this.#animation.addEventListener('finish', () => {
|
|
283
466
|
this.#animation?.commitStyles?.();
|
|
284
467
|
this.#animation?.cancel();
|
|
@@ -328,22 +511,28 @@ class SpringPlayer {
|
|
|
328
511
|
host;
|
|
329
512
|
frames;
|
|
330
513
|
delay;
|
|
514
|
+
iterations;
|
|
331
515
|
onDone;
|
|
332
516
|
#resolveFinished;
|
|
333
517
|
finished = new Promise((resolve) => {
|
|
334
518
|
this.#resolveFinished = resolve;
|
|
335
519
|
});
|
|
336
520
|
#animation = null;
|
|
337
|
-
constructor(host, frames, userConfig, delay, onDone) {
|
|
521
|
+
constructor(host, frames, userConfig, delay, iterations = 1, onDone) {
|
|
338
522
|
this.host = host;
|
|
339
523
|
this.frames = frames;
|
|
340
524
|
this.delay = delay;
|
|
525
|
+
this.iterations = iterations;
|
|
341
526
|
this.onDone = onDone;
|
|
342
527
|
if (typeof host.animate !== 'function') {
|
|
343
528
|
this.#resolveFinished();
|
|
344
529
|
onDone?.();
|
|
345
530
|
return;
|
|
346
531
|
}
|
|
532
|
+
if (this.iterations !== 1 && typeof ngDevMode !== 'undefined' && ngDevMode) {
|
|
533
|
+
console.warn('[Movement] Spring animations with iterations !== 1 may produce visual glitches. ' +
|
|
534
|
+
'Consider using WaapiPlayer (no spring) for loops.');
|
|
535
|
+
}
|
|
347
536
|
const config = {
|
|
348
537
|
stiffness: 100,
|
|
349
538
|
damping: 10,
|
|
@@ -366,7 +555,12 @@ class SpringPlayer {
|
|
|
366
555
|
delay: this.delay,
|
|
367
556
|
fill: 'both',
|
|
368
557
|
easing: 'linear', // Spring physics already has the easing baked into the frames
|
|
558
|
+
iterations: this.iterations,
|
|
369
559
|
});
|
|
560
|
+
if (this.iterations === Infinity) {
|
|
561
|
+
// Infinite loops never finish; consumer must call cancel() manually.
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
370
564
|
this.#animation.addEventListener('finish', () => {
|
|
371
565
|
this.#animation?.commitStyles?.();
|
|
372
566
|
this.#animation?.cancel();
|
|
@@ -453,14 +647,18 @@ class AnimationEngine {
|
|
|
453
647
|
return null;
|
|
454
648
|
}
|
|
455
649
|
if (options.disabled) {
|
|
650
|
+
this.#prepareSvgStrokeDraw(host, frames);
|
|
456
651
|
this.#applyFinalStyles(host, frames);
|
|
457
652
|
options.onDone?.();
|
|
458
653
|
return null;
|
|
459
654
|
}
|
|
655
|
+
this.#prepareSvgStrokeDraw(host, frames);
|
|
460
656
|
const config = options.config ?? this.#defaults;
|
|
461
|
-
const
|
|
657
|
+
const spring = validateSpring(options.spring);
|
|
658
|
+
const isSpring = spring || config.easing === 'spring';
|
|
659
|
+
const iterations = options.iterations ?? config.iterations;
|
|
462
660
|
if (isSpring) {
|
|
463
|
-
return new SpringPlayer(host, frames,
|
|
661
|
+
return new SpringPlayer(host, frames, spring ?? {}, options.delay ?? config.delay, iterations, options.onDone);
|
|
464
662
|
}
|
|
465
663
|
else {
|
|
466
664
|
return new WaapiPlayer(host, frames, {
|
|
@@ -468,12 +666,36 @@ class AnimationEngine {
|
|
|
468
666
|
easing: config.easing,
|
|
469
667
|
delay: options.delay ?? config.delay,
|
|
470
668
|
disabled: false,
|
|
669
|
+
iterations,
|
|
471
670
|
}, options.onDone);
|
|
472
671
|
}
|
|
473
672
|
}
|
|
474
673
|
#applyFinalStyles(host, frames) {
|
|
475
674
|
applyComposedStyle(host, composeFinalStyle(frames));
|
|
476
675
|
}
|
|
676
|
+
#prepareSvgStrokeDraw(host, frames) {
|
|
677
|
+
if (!frames['strokeDashoffset'] || !this.#isSvgGeometryElement(host)) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
let length = 28;
|
|
681
|
+
try {
|
|
682
|
+
length = host.getTotalLength() || length;
|
|
683
|
+
}
|
|
684
|
+
catch {
|
|
685
|
+
length = 28;
|
|
686
|
+
}
|
|
687
|
+
const styledHost = host;
|
|
688
|
+
styledHost.style.strokeDasharray = `${length}`;
|
|
689
|
+
styledHost.style.strokeDashoffset = `${length}`;
|
|
690
|
+
}
|
|
691
|
+
#isSvgGeometryElement(host) {
|
|
692
|
+
const view = host.ownerDocument?.defaultView;
|
|
693
|
+
const SvgGeometryElement = view?.SVGGeometryElement;
|
|
694
|
+
if (typeof SvgGeometryElement === 'function' && host instanceof SvgGeometryElement) {
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
return typeof host.getTotalLength === 'function';
|
|
698
|
+
}
|
|
477
699
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: AnimationEngine, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
478
700
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: AnimationEngine, providedIn: 'root' });
|
|
479
701
|
}
|
|
@@ -486,6 +708,81 @@ const MOVE_STAGGER_PARENT = new InjectionToken('MOVE_STAGGER_PARENT');
|
|
|
486
708
|
|
|
487
709
|
const MOVE_PRESENCE_PARENT = new InjectionToken('MOVE_PRESENCE_PARENT');
|
|
488
710
|
|
|
711
|
+
const MOVE_VARIANTS_PARENT = new InjectionToken('MOVE_VARIANTS_PARENT');
|
|
712
|
+
class MoveVariantsDirective {
|
|
713
|
+
moveVariants = input.required(...(ngDevMode ? [{ debugName: "moveVariants" }] : /* istanbul ignore next */ []));
|
|
714
|
+
moveAnimate = input(undefined, ...(ngDevMode ? [{ debugName: "moveAnimate" }] : /* istanbul ignore next */ []));
|
|
715
|
+
moveDuration = input(undefined, ...(ngDevMode ? [{ debugName: "moveDuration" }] : /* istanbul ignore next */ []));
|
|
716
|
+
moveEasing = input(undefined, ...(ngDevMode ? [{ debugName: "moveEasing" }] : /* istanbul ignore next */ []));
|
|
717
|
+
moveDelay = input(undefined, ...(ngDevMode ? [{ debugName: "moveDelay" }] : /* istanbul ignore next */ []));
|
|
718
|
+
moveDisabled = input(undefined, ...(ngDevMode ? [{ debugName: "moveDisabled" }] : /* istanbul ignore next */ []));
|
|
719
|
+
moveSpring = input(undefined, ...(ngDevMode ? [{ debugName: "moveSpring" }] : /* istanbul ignore next */ []));
|
|
720
|
+
#parent = inject(MOVE_VARIANTS_PARENT, { optional: true, skipSelf: true });
|
|
721
|
+
#engine = inject(AnimationEngine);
|
|
722
|
+
#defaults = inject(MOVEMENT_CONFIG);
|
|
723
|
+
#documentRef = inject(DOCUMENT);
|
|
724
|
+
#host = inject((ElementRef));
|
|
725
|
+
#stagger = inject(MOVE_STAGGER_PARENT, { optional: true });
|
|
726
|
+
#currentPlayer = null;
|
|
727
|
+
#isReducedMotion = false;
|
|
728
|
+
activeVariant = computed(() => {
|
|
729
|
+
return this.moveAnimate() ?? this.#parent?.activeVariant();
|
|
730
|
+
}, ...(ngDevMode ? [{ debugName: "activeVariant" }] : /* istanbul ignore next */ []));
|
|
731
|
+
constructor() {
|
|
732
|
+
this.#isReducedMotion = prefersReducedMotion(this.#documentRef);
|
|
733
|
+
this.#stagger?.register(this.#host.nativeElement);
|
|
734
|
+
effect(() => {
|
|
735
|
+
const variantName = this.activeVariant();
|
|
736
|
+
if (!variantName)
|
|
737
|
+
return;
|
|
738
|
+
const variants = this.moveVariants();
|
|
739
|
+
if (!variants)
|
|
740
|
+
return;
|
|
741
|
+
const state = variants[variantName];
|
|
742
|
+
if (!state)
|
|
743
|
+
return;
|
|
744
|
+
this.#currentPlayer?.cancel();
|
|
745
|
+
const { spring, duration, easing, delay, ...keyframesMap } = state;
|
|
746
|
+
const keyframes = keyframesMap;
|
|
747
|
+
const staggerDelay = this.#stagger?.getDelay(this.#host.nativeElement) ?? 0;
|
|
748
|
+
const config = resolveMovementConfig(this.#defaults, {
|
|
749
|
+
duration: duration ?? this.moveDuration(),
|
|
750
|
+
easing: easing ?? this.moveEasing(),
|
|
751
|
+
delay: (delay ?? this.moveDelay() ?? 0) + staggerDelay,
|
|
752
|
+
disabled: this.moveDisabled(),
|
|
753
|
+
}, this.#isReducedMotion);
|
|
754
|
+
this.#currentPlayer = this.#engine.play(this.#host.nativeElement, keyframes, {
|
|
755
|
+
config,
|
|
756
|
+
spring: spring ?? this.moveSpring(),
|
|
757
|
+
disabled: config.disabled,
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
ngOnDestroy() {
|
|
762
|
+
this.#stagger?.unregister(this.#host.nativeElement);
|
|
763
|
+
this.#currentPlayer?.cancel();
|
|
764
|
+
}
|
|
765
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveVariantsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
766
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: MoveVariantsDirective, isStandalone: true, selector: "[moveVariants]", inputs: { moveVariants: { classPropertyName: "moveVariants", publicName: "moveVariants", isSignal: true, isRequired: true, transformFunction: null }, moveAnimate: { classPropertyName: "moveAnimate", publicName: "moveAnimate", isSignal: true, isRequired: false, transformFunction: null }, moveDuration: { classPropertyName: "moveDuration", publicName: "moveDuration", isSignal: true, isRequired: false, transformFunction: null }, moveEasing: { classPropertyName: "moveEasing", publicName: "moveEasing", isSignal: true, isRequired: false, transformFunction: null }, moveDelay: { classPropertyName: "moveDelay", publicName: "moveDelay", isSignal: true, isRequired: false, transformFunction: null }, moveDisabled: { classPropertyName: "moveDisabled", publicName: "moveDisabled", isSignal: true, isRequired: false, transformFunction: null }, moveSpring: { classPropertyName: "moveSpring", publicName: "moveSpring", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
767
|
+
{
|
|
768
|
+
provide: MOVE_VARIANTS_PARENT,
|
|
769
|
+
useExisting: forwardRef(() => MoveVariantsDirective),
|
|
770
|
+
},
|
|
771
|
+
], ngImport: i0 });
|
|
772
|
+
}
|
|
773
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveVariantsDirective, decorators: [{
|
|
774
|
+
type: Directive,
|
|
775
|
+
args: [{
|
|
776
|
+
selector: '[moveVariants]',
|
|
777
|
+
providers: [
|
|
778
|
+
{
|
|
779
|
+
provide: MOVE_VARIANTS_PARENT,
|
|
780
|
+
useExisting: forwardRef(() => MoveVariantsDirective),
|
|
781
|
+
},
|
|
782
|
+
],
|
|
783
|
+
}]
|
|
784
|
+
}], ctorParameters: () => [], propDecorators: { moveVariants: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveVariants", required: true }] }], moveAnimate: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveAnimate", required: false }] }], moveDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDuration", required: false }] }], moveEasing: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveEasing", required: false }] }], moveDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDelay", required: false }] }], moveDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDisabled", required: false }] }], moveSpring: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveSpring", required: false }] }] } });
|
|
785
|
+
|
|
489
786
|
class MoveAnimateDirective {
|
|
490
787
|
move = input(undefined, ...(ngDevMode ? [{ debugName: "move" }] : /* istanbul ignore next */ []));
|
|
491
788
|
moveAnimate = input(undefined, ...(ngDevMode ? [{ debugName: "moveAnimate" }] : /* istanbul ignore next */ []));
|
|
@@ -501,10 +798,15 @@ class MoveAnimateDirective {
|
|
|
501
798
|
#engine = inject(AnimationEngine);
|
|
502
799
|
#stagger = inject(MOVE_STAGGER_PARENT, { optional: true });
|
|
503
800
|
#presence = inject(MOVE_PRESENCE_PARENT, { optional: true });
|
|
801
|
+
#variantsParent = inject(MOVE_VARIANTS_PARENT, { optional: true });
|
|
504
802
|
#config = this.#defaults;
|
|
505
803
|
#enterPlayer = null;
|
|
506
804
|
#leavePlayer = null;
|
|
507
805
|
ngOnInit() {
|
|
806
|
+
// If moveVariants is on the same host, let it handle animation
|
|
807
|
+
if (this.#variantsParent) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
508
810
|
this.#stagger?.register(this.#host.nativeElement);
|
|
509
811
|
this.#presence?.register(this);
|
|
510
812
|
Promise.resolve().then(() => {
|
|
@@ -530,7 +832,7 @@ class MoveAnimateDirective {
|
|
|
530
832
|
this.#leavePlayer?.cancel();
|
|
531
833
|
}
|
|
532
834
|
playLeave() {
|
|
533
|
-
if (this.#config.disabled) {
|
|
835
|
+
if (this.#variantsParent || this.#config.disabled) {
|
|
534
836
|
return Promise.resolve();
|
|
535
837
|
}
|
|
536
838
|
this.#enterPlayer?.cancel();
|
|
@@ -871,81 +1173,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
|
|
|
871
1173
|
}]
|
|
872
1174
|
}], propDecorators: { moveWhileTap: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveWhileTap", required: true }] }], moveDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDuration", required: false }] }], moveEasing: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveEasing", required: false }] }], moveDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDelay", required: false }] }], moveDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDisabled", required: false }] }], moveSpring: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveSpring", required: false }] }] } });
|
|
873
1175
|
|
|
874
|
-
const MOVE_VARIANTS_PARENT = new InjectionToken('MOVE_VARIANTS_PARENT');
|
|
875
|
-
class MoveVariantsDirective {
|
|
876
|
-
moveVariants = input.required(...(ngDevMode ? [{ debugName: "moveVariants" }] : /* istanbul ignore next */ []));
|
|
877
|
-
moveAnimate = input(undefined, ...(ngDevMode ? [{ debugName: "moveAnimate" }] : /* istanbul ignore next */ []));
|
|
878
|
-
moveDuration = input(undefined, ...(ngDevMode ? [{ debugName: "moveDuration" }] : /* istanbul ignore next */ []));
|
|
879
|
-
moveEasing = input(undefined, ...(ngDevMode ? [{ debugName: "moveEasing" }] : /* istanbul ignore next */ []));
|
|
880
|
-
moveDelay = input(undefined, ...(ngDevMode ? [{ debugName: "moveDelay" }] : /* istanbul ignore next */ []));
|
|
881
|
-
moveDisabled = input(undefined, ...(ngDevMode ? [{ debugName: "moveDisabled" }] : /* istanbul ignore next */ []));
|
|
882
|
-
moveSpring = input(undefined, ...(ngDevMode ? [{ debugName: "moveSpring" }] : /* istanbul ignore next */ []));
|
|
883
|
-
#parent = inject(MOVE_VARIANTS_PARENT, { optional: true, skipSelf: true });
|
|
884
|
-
#engine = inject(AnimationEngine);
|
|
885
|
-
#defaults = inject(MOVEMENT_CONFIG);
|
|
886
|
-
#documentRef = inject(DOCUMENT);
|
|
887
|
-
#host = inject((ElementRef));
|
|
888
|
-
#stagger = inject(MOVE_STAGGER_PARENT, { optional: true });
|
|
889
|
-
#currentPlayer = null;
|
|
890
|
-
#isReducedMotion = false;
|
|
891
|
-
activeVariant = computed(() => {
|
|
892
|
-
return this.moveAnimate() ?? this.#parent?.activeVariant();
|
|
893
|
-
}, ...(ngDevMode ? [{ debugName: "activeVariant" }] : /* istanbul ignore next */ []));
|
|
894
|
-
constructor() {
|
|
895
|
-
this.#isReducedMotion = prefersReducedMotion(this.#documentRef);
|
|
896
|
-
this.#stagger?.register(this.#host.nativeElement);
|
|
897
|
-
effect(() => {
|
|
898
|
-
const variantName = this.activeVariant();
|
|
899
|
-
if (!variantName)
|
|
900
|
-
return;
|
|
901
|
-
const variants = this.moveVariants();
|
|
902
|
-
if (!variants)
|
|
903
|
-
return;
|
|
904
|
-
const state = variants[variantName];
|
|
905
|
-
if (!state)
|
|
906
|
-
return;
|
|
907
|
-
this.#currentPlayer?.cancel();
|
|
908
|
-
const { spring, duration, easing, delay, ...keyframesMap } = state;
|
|
909
|
-
const keyframes = keyframesMap;
|
|
910
|
-
const staggerDelay = this.#stagger?.getDelay(this.#host.nativeElement) ?? 0;
|
|
911
|
-
const config = resolveMovementConfig(this.#defaults, {
|
|
912
|
-
duration: duration ?? this.moveDuration(),
|
|
913
|
-
easing: easing ?? this.moveEasing(),
|
|
914
|
-
delay: (delay ?? this.moveDelay() ?? 0) + staggerDelay,
|
|
915
|
-
disabled: this.moveDisabled(),
|
|
916
|
-
}, this.#isReducedMotion);
|
|
917
|
-
this.#currentPlayer = this.#engine.play(this.#host.nativeElement, keyframes, {
|
|
918
|
-
config,
|
|
919
|
-
spring: spring ?? this.moveSpring(),
|
|
920
|
-
disabled: config.disabled,
|
|
921
|
-
});
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
ngOnDestroy() {
|
|
925
|
-
this.#stagger?.unregister(this.#host.nativeElement);
|
|
926
|
-
this.#currentPlayer?.cancel();
|
|
927
|
-
}
|
|
928
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveVariantsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
929
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: MoveVariantsDirective, isStandalone: true, selector: "[moveVariants]", inputs: { moveVariants: { classPropertyName: "moveVariants", publicName: "moveVariants", isSignal: true, isRequired: true, transformFunction: null }, moveAnimate: { classPropertyName: "moveAnimate", publicName: "moveAnimate", isSignal: true, isRequired: false, transformFunction: null }, moveDuration: { classPropertyName: "moveDuration", publicName: "moveDuration", isSignal: true, isRequired: false, transformFunction: null }, moveEasing: { classPropertyName: "moveEasing", publicName: "moveEasing", isSignal: true, isRequired: false, transformFunction: null }, moveDelay: { classPropertyName: "moveDelay", publicName: "moveDelay", isSignal: true, isRequired: false, transformFunction: null }, moveDisabled: { classPropertyName: "moveDisabled", publicName: "moveDisabled", isSignal: true, isRequired: false, transformFunction: null }, moveSpring: { classPropertyName: "moveSpring", publicName: "moveSpring", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
930
|
-
{
|
|
931
|
-
provide: MOVE_VARIANTS_PARENT,
|
|
932
|
-
useExisting: forwardRef(() => MoveVariantsDirective),
|
|
933
|
-
},
|
|
934
|
-
], ngImport: i0 });
|
|
935
|
-
}
|
|
936
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveVariantsDirective, decorators: [{
|
|
937
|
-
type: Directive,
|
|
938
|
-
args: [{
|
|
939
|
-
selector: '[moveVariants]',
|
|
940
|
-
providers: [
|
|
941
|
-
{
|
|
942
|
-
provide: MOVE_VARIANTS_PARENT,
|
|
943
|
-
useExisting: forwardRef(() => MoveVariantsDirective),
|
|
944
|
-
},
|
|
945
|
-
],
|
|
946
|
-
}]
|
|
947
|
-
}], ctorParameters: () => [], propDecorators: { moveVariants: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveVariants", required: true }] }], moveAnimate: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveAnimate", required: false }] }], moveDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDuration", required: false }] }], moveEasing: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveEasing", required: false }] }], moveDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDelay", required: false }] }], moveDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDisabled", required: false }] }], moveSpring: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveSpring", required: false }] }] } });
|
|
948
|
-
|
|
949
1176
|
class MoveStaggerDirective {
|
|
950
1177
|
moveStagger = input.required(...(ngDevMode ? [{ debugName: "moveStagger" }] : /* istanbul ignore next */ []));
|
|
951
1178
|
moveStaggerDirection = input('first', ...(ngDevMode ? [{ debugName: "moveStaggerDirection" }] : /* istanbul ignore next */ []));
|
|
@@ -960,9 +1187,14 @@ class MoveStaggerDirective {
|
|
|
960
1187
|
if (!this.#children.has(el))
|
|
961
1188
|
return 0;
|
|
962
1189
|
const list = Array.from(this.#children).sort((a, b) => {
|
|
963
|
-
|
|
1190
|
+
if (a === b)
|
|
1191
|
+
return 0;
|
|
964
1192
|
const pos = a.compareDocumentPosition(b);
|
|
965
|
-
|
|
1193
|
+
if (pos & Node.DOCUMENT_POSITION_PRECEDING)
|
|
1194
|
+
return 1;
|
|
1195
|
+
if (pos & Node.DOCUMENT_POSITION_FOLLOWING)
|
|
1196
|
+
return -1;
|
|
1197
|
+
return 0;
|
|
966
1198
|
});
|
|
967
1199
|
const index = list.indexOf(el);
|
|
968
1200
|
if (index === -1)
|
|
@@ -1029,7 +1261,11 @@ class MoveLayoutDirective {
|
|
|
1029
1261
|
this.#isAnimating) {
|
|
1030
1262
|
return null;
|
|
1031
1263
|
}
|
|
1032
|
-
const
|
|
1264
|
+
const el = this.#host.nativeElement;
|
|
1265
|
+
if (typeof el.getBoundingClientRect !== 'function') {
|
|
1266
|
+
return null;
|
|
1267
|
+
}
|
|
1268
|
+
const currentRect = el.getBoundingClientRect();
|
|
1033
1269
|
if (this.#snapshot) {
|
|
1034
1270
|
const dx = this.#snapshot.left - currentRect.left;
|
|
1035
1271
|
const dy = this.#snapshot.top - currentRect.top;
|
|
@@ -1337,8 +1573,13 @@ class MoveScrollDirective {
|
|
|
1337
1573
|
const view = this.#documentRef.defaultView;
|
|
1338
1574
|
if (!view)
|
|
1339
1575
|
return;
|
|
1576
|
+
// Validate scroll offsets
|
|
1577
|
+
const offsets = this.moveScrollOffset();
|
|
1578
|
+
if (!isValidScrollOffset(offsets[0]) || !isValidScrollOffset(offsets[1])) {
|
|
1579
|
+
return;
|
|
1580
|
+
}
|
|
1340
1581
|
this.#player = this.#engine.play(this.#host.nativeElement, keyframes, {
|
|
1341
|
-
config: { duration: 1000, easing: 'linear', delay: 0, disabled: false },
|
|
1582
|
+
config: { duration: 1000, easing: 'linear', delay: 0, disabled: false, iterations: 1 },
|
|
1342
1583
|
});
|
|
1343
1584
|
this.#player?.pause();
|
|
1344
1585
|
// Sync the new player to the current scroll position immediately.
|
|
@@ -1579,7 +1820,9 @@ class MoveDragDirective {
|
|
|
1579
1820
|
return;
|
|
1580
1821
|
this.#isDragging = true;
|
|
1581
1822
|
this.#pointerId = e.pointerId;
|
|
1582
|
-
this.#host.nativeElement.setPointerCapture
|
|
1823
|
+
if (typeof this.#host.nativeElement.setPointerCapture === 'function') {
|
|
1824
|
+
this.#host.nativeElement.setPointerCapture(e.pointerId);
|
|
1825
|
+
}
|
|
1583
1826
|
this.#player?.cancel();
|
|
1584
1827
|
// read bounds cleanly before next render
|
|
1585
1828
|
this.#dragBounds = this.resolveBounds();
|
|
@@ -1600,7 +1843,9 @@ class MoveDragDirective {
|
|
|
1600
1843
|
if (!this.#isDragging || e.pointerId !== this.#pointerId)
|
|
1601
1844
|
return;
|
|
1602
1845
|
this.#isDragging = false;
|
|
1603
|
-
this.#host.nativeElement.releasePointerCapture
|
|
1846
|
+
if (typeof this.#host.nativeElement.releasePointerCapture === 'function') {
|
|
1847
|
+
this.#host.nativeElement.releasePointerCapture(e.pointerId);
|
|
1848
|
+
}
|
|
1604
1849
|
this.#pointerId = null;
|
|
1605
1850
|
this.#host.nativeElement.style.touchAction = '';
|
|
1606
1851
|
this.#host.nativeElement.style.userSelect = '';
|
|
@@ -1629,7 +1874,7 @@ class MoveDragDirective {
|
|
|
1629
1874
|
let x = this.#_x;
|
|
1630
1875
|
let y = this.#_y;
|
|
1631
1876
|
if (this.#dragBounds) {
|
|
1632
|
-
const elastic = this.moveDragElastic();
|
|
1877
|
+
const elastic = validateDragElastic(this.moveDragElastic());
|
|
1633
1878
|
if (this.#dragBounds.left !== undefined && x < this.#dragBounds.left) {
|
|
1634
1879
|
x = this.#dragBounds.left - (this.#dragBounds.left - x) * elastic;
|
|
1635
1880
|
}
|
|
@@ -1663,7 +1908,7 @@ class MoveDragDirective {
|
|
|
1663
1908
|
// Find the currently visible coordinates (which include elasticity)
|
|
1664
1909
|
let currentVisX = this.#_x;
|
|
1665
1910
|
let currentVisY = this.#_y;
|
|
1666
|
-
const elastic = this.moveDragElastic();
|
|
1911
|
+
const elastic = validateDragElastic(this.moveDragElastic());
|
|
1667
1912
|
if (this.#dragBounds.left !== undefined && this.#_x < this.#dragBounds.left) {
|
|
1668
1913
|
currentVisX = this.#dragBounds.left - (this.#dragBounds.left - this.#_x) * elastic;
|
|
1669
1914
|
}
|
|
@@ -1689,6 +1934,19 @@ class MoveDragDirective {
|
|
|
1689
1934
|
}
|
|
1690
1935
|
}
|
|
1691
1936
|
ngOnDestroy() {
|
|
1937
|
+
if (this.#pointerId !== null) {
|
|
1938
|
+
try {
|
|
1939
|
+
if (typeof this.#host.nativeElement.releasePointerCapture === 'function') {
|
|
1940
|
+
this.#host.nativeElement.releasePointerCapture(this.#pointerId);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
catch {
|
|
1944
|
+
// Element may already be detached
|
|
1945
|
+
}
|
|
1946
|
+
this.#pointerId = null;
|
|
1947
|
+
}
|
|
1948
|
+
this.#host.nativeElement.style.touchAction = '';
|
|
1949
|
+
this.#host.nativeElement.style.userSelect = '';
|
|
1692
1950
|
this.#player?.cancel();
|
|
1693
1951
|
}
|
|
1694
1952
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveDragDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -1809,6 +2067,7 @@ class MoveTextDirective {
|
|
|
1809
2067
|
#platformId = inject(PLATFORM_ID);
|
|
1810
2068
|
#host = inject((ElementRef));
|
|
1811
2069
|
#engine = inject(AnimationEngine);
|
|
2070
|
+
#renderer = inject(Renderer2);
|
|
1812
2071
|
#players = [];
|
|
1813
2072
|
#spans = [];
|
|
1814
2073
|
#observer = null;
|
|
@@ -1869,21 +2128,24 @@ class MoveTextDirective {
|
|
|
1869
2128
|
#splitText() {
|
|
1870
2129
|
const el = this.#host.nativeElement;
|
|
1871
2130
|
const text = (el.textContent ?? '').trim();
|
|
1872
|
-
|
|
1873
|
-
el.
|
|
2131
|
+
// Clear existing content safely via Renderer2
|
|
2132
|
+
while (el.firstChild) {
|
|
2133
|
+
this.#renderer.removeChild(el, el.firstChild);
|
|
2134
|
+
}
|
|
2135
|
+
this.#renderer.setAttribute(el, 'aria-label', text);
|
|
1874
2136
|
const byChars = this.moveTextSplit() === 'chars';
|
|
1875
2137
|
if (byChars) {
|
|
1876
2138
|
// Split character by character, preserving spaces as text nodes
|
|
1877
2139
|
[...text].forEach((char) => {
|
|
1878
2140
|
if (char === ' ') {
|
|
1879
|
-
|
|
2141
|
+
this.#renderer.appendChild(el, this.#documentRef.createTextNode(' '));
|
|
1880
2142
|
return;
|
|
1881
2143
|
}
|
|
1882
|
-
const span = this.#
|
|
1883
|
-
|
|
1884
|
-
span
|
|
1885
|
-
span
|
|
1886
|
-
|
|
2144
|
+
const span = this.#renderer.createElement('span');
|
|
2145
|
+
this.#renderer.setAttribute(span, 'aria-hidden', 'true');
|
|
2146
|
+
this.#renderer.setStyle(span, 'display', 'inline-block');
|
|
2147
|
+
this.#renderer.setProperty(span, 'textContent', char);
|
|
2148
|
+
this.#renderer.appendChild(el, span);
|
|
1887
2149
|
this.#spans.push(span);
|
|
1888
2150
|
});
|
|
1889
2151
|
}
|
|
@@ -1891,12 +2153,12 @@ class MoveTextDirective {
|
|
|
1891
2153
|
// Split word by word
|
|
1892
2154
|
const words = text.split(/\s+/);
|
|
1893
2155
|
words.forEach((word, index) => {
|
|
1894
|
-
const span = this.#
|
|
1895
|
-
|
|
1896
|
-
span
|
|
1897
|
-
span
|
|
1898
|
-
span
|
|
1899
|
-
|
|
2156
|
+
const span = this.#renderer.createElement('span');
|
|
2157
|
+
this.#renderer.setAttribute(span, 'aria-hidden', 'true');
|
|
2158
|
+
this.#renderer.setStyle(span, 'display', 'inline-block');
|
|
2159
|
+
this.#renderer.setStyle(span, 'white-space', 'pre');
|
|
2160
|
+
this.#renderer.setProperty(span, 'textContent', index < words.length - 1 ? word + ' ' : word);
|
|
2161
|
+
this.#renderer.appendChild(el, span);
|
|
1900
2162
|
this.#spans.push(span);
|
|
1901
2163
|
});
|
|
1902
2164
|
}
|
|
@@ -1904,6 +2166,8 @@ class MoveTextDirective {
|
|
|
1904
2166
|
ngOnDestroy() {
|
|
1905
2167
|
this.#observer?.disconnect();
|
|
1906
2168
|
this.#players.forEach((p) => p.cancel());
|
|
2169
|
+
this.#players = [];
|
|
2170
|
+
this.#spans = [];
|
|
1907
2171
|
}
|
|
1908
2172
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveTextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
1909
2173
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: MoveTextDirective, isStandalone: true, selector: "[moveText]", inputs: { moveText: { classPropertyName: "moveText", publicName: "moveText", isSignal: true, isRequired: false, transformFunction: null }, moveTextSplit: { classPropertyName: "moveTextSplit", publicName: "moveTextSplit", isSignal: true, isRequired: false, transformFunction: null }, moveTextStagger: { classPropertyName: "moveTextStagger", publicName: "moveTextStagger", isSignal: true, isRequired: false, transformFunction: null }, moveDuration: { classPropertyName: "moveDuration", publicName: "moveDuration", isSignal: true, isRequired: false, transformFunction: null }, moveEasing: { classPropertyName: "moveEasing", publicName: "moveEasing", isSignal: true, isRequired: false, transformFunction: null }, moveDelay: { classPropertyName: "moveDelay", publicName: "moveDelay", isSignal: true, isRequired: false, transformFunction: null }, moveDisabled: { classPropertyName: "moveDisabled", publicName: "moveDisabled", isSignal: true, isRequired: false, transformFunction: null }, moveSpring: { classPropertyName: "moveSpring", publicName: "moveSpring", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
@@ -2101,7 +2365,7 @@ class MoveParallaxDirective {
|
|
|
2101
2365
|
}
|
|
2102
2366
|
this.#player?.cancel();
|
|
2103
2367
|
this.#player = this.#engine.play(this.#host.nativeElement, frames, {
|
|
2104
|
-
config: { duration: 1000, delay: 0, easing: 'linear', disabled: false },
|
|
2368
|
+
config: { duration: 1000, delay: 0, easing: 'linear', disabled: false, iterations: 1 },
|
|
2105
2369
|
});
|
|
2106
2370
|
this.#player?.pause();
|
|
2107
2371
|
if (this.#player) {
|
|
@@ -2146,6 +2410,130 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImpor
|
|
|
2146
2410
|
}]
|
|
2147
2411
|
}], ctorParameters: () => [], propDecorators: { moveParallax: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveParallax", required: false }] }], moveParallaxAxis: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveParallaxAxis", required: false }] }] } });
|
|
2148
2412
|
|
|
2413
|
+
class MoveLoopDirective {
|
|
2414
|
+
moveLoop = input('none', ...(ngDevMode ? [{ debugName: "moveLoop" }] : /* istanbul ignore next */ []));
|
|
2415
|
+
moveDuration = input(undefined, ...(ngDevMode ? [{ debugName: "moveDuration" }] : /* istanbul ignore next */ []));
|
|
2416
|
+
moveEasing = input(undefined, ...(ngDevMode ? [{ debugName: "moveEasing" }] : /* istanbul ignore next */ []));
|
|
2417
|
+
moveDelay = input(undefined, ...(ngDevMode ? [{ debugName: "moveDelay" }] : /* istanbul ignore next */ []));
|
|
2418
|
+
moveDisabled = input(undefined, ...(ngDevMode ? [{ debugName: "moveDisabled" }] : /* istanbul ignore next */ []));
|
|
2419
|
+
moveSpring = input(undefined, ...(ngDevMode ? [{ debugName: "moveSpring" }] : /* istanbul ignore next */ []));
|
|
2420
|
+
#defaults = inject(MOVEMENT_CONFIG);
|
|
2421
|
+
#documentRef = inject(DOCUMENT);
|
|
2422
|
+
#host = inject((ElementRef));
|
|
2423
|
+
#engine = inject(AnimationEngine);
|
|
2424
|
+
#player = null;
|
|
2425
|
+
ngOnInit() {
|
|
2426
|
+
const frames = resolveMoveFrames(this.moveLoop(), 'loop');
|
|
2427
|
+
// Skip noop presets to avoid creating an infinite animation that does nothing
|
|
2428
|
+
if (this.moveLoop() === 'none' || Object.keys(frames).length === 0) {
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
const isReduced = prefersReducedMotion(this.#documentRef);
|
|
2432
|
+
const config = resolveMovementConfig(this.#defaults, {
|
|
2433
|
+
duration: this.moveDuration(),
|
|
2434
|
+
easing: this.moveEasing(),
|
|
2435
|
+
delay: this.moveDelay(),
|
|
2436
|
+
disabled: this.moveDisabled(),
|
|
2437
|
+
}, isReduced);
|
|
2438
|
+
this.#player = this.#engine.play(this.#host.nativeElement, frames, {
|
|
2439
|
+
config,
|
|
2440
|
+
spring: this.moveSpring(),
|
|
2441
|
+
disabled: config.disabled,
|
|
2442
|
+
iterations: Infinity,
|
|
2443
|
+
});
|
|
2444
|
+
}
|
|
2445
|
+
ngOnDestroy() {
|
|
2446
|
+
this.#player?.cancel();
|
|
2447
|
+
}
|
|
2448
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveLoopDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2449
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: MoveLoopDirective, isStandalone: true, selector: "[moveLoop]", inputs: { moveLoop: { classPropertyName: "moveLoop", publicName: "moveLoop", isSignal: true, isRequired: false, transformFunction: null }, moveDuration: { classPropertyName: "moveDuration", publicName: "moveDuration", isSignal: true, isRequired: false, transformFunction: null }, moveEasing: { classPropertyName: "moveEasing", publicName: "moveEasing", isSignal: true, isRequired: false, transformFunction: null }, moveDelay: { classPropertyName: "moveDelay", publicName: "moveDelay", isSignal: true, isRequired: false, transformFunction: null }, moveDisabled: { classPropertyName: "moveDisabled", publicName: "moveDisabled", isSignal: true, isRequired: false, transformFunction: null }, moveSpring: { classPropertyName: "moveSpring", publicName: "moveSpring", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
2450
|
+
}
|
|
2451
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveLoopDirective, decorators: [{
|
|
2452
|
+
type: Directive,
|
|
2453
|
+
args: [{
|
|
2454
|
+
selector: '[moveLoop]',
|
|
2455
|
+
}]
|
|
2456
|
+
}], propDecorators: { moveLoop: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveLoop", required: false }] }], moveDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDuration", required: false }] }], moveEasing: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveEasing", required: false }] }], moveDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDelay", required: false }] }], moveDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDisabled", required: false }] }], moveSpring: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveSpring", required: false }] }] } });
|
|
2457
|
+
|
|
2458
|
+
function optionalNumberAttribute(value) {
|
|
2459
|
+
if (value === undefined || value === null || value === '') {
|
|
2460
|
+
return undefined;
|
|
2461
|
+
}
|
|
2462
|
+
return Number(value);
|
|
2463
|
+
}
|
|
2464
|
+
class MoveTargetDirective {
|
|
2465
|
+
moveTarget = input.required(...(ngDevMode ? [{ debugName: "moveTarget" }] : /* istanbul ignore next */ []));
|
|
2466
|
+
moveFrames = input.required(...(ngDevMode ? [{ debugName: "moveFrames" }] : /* istanbul ignore next */ []));
|
|
2467
|
+
moveDuration = input(undefined, { ...(ngDevMode ? { debugName: "moveDuration" } : /* istanbul ignore next */ {}), transform: optionalNumberAttribute });
|
|
2468
|
+
moveEasing = input(undefined, ...(ngDevMode ? [{ debugName: "moveEasing" }] : /* istanbul ignore next */ []));
|
|
2469
|
+
moveDelay = input(undefined, { ...(ngDevMode ? { debugName: "moveDelay" } : /* istanbul ignore next */ {}), transform: optionalNumberAttribute });
|
|
2470
|
+
moveSpring = input(undefined, ...(ngDevMode ? [{ debugName: "moveSpring" }] : /* istanbul ignore next */ []));
|
|
2471
|
+
moveDisabled = input(undefined, ...(ngDevMode ? [{ debugName: "moveDisabled" }] : /* istanbul ignore next */ []));
|
|
2472
|
+
moveReverseDuration = input(undefined, { ...(ngDevMode ? { debugName: "moveReverseDuration" } : /* istanbul ignore next */ {}), transform: optionalNumberAttribute });
|
|
2473
|
+
moveReverseEasing = input(undefined, ...(ngDevMode ? [{ debugName: "moveReverseEasing" }] : /* istanbul ignore next */ []));
|
|
2474
|
+
#defaults = inject(MOVEMENT_CONFIG);
|
|
2475
|
+
#documentRef = inject(DOCUMENT);
|
|
2476
|
+
#host = inject((ElementRef));
|
|
2477
|
+
#engine = inject(AnimationEngine);
|
|
2478
|
+
#currentPlayer = null;
|
|
2479
|
+
#hasPlayedForward = false;
|
|
2480
|
+
#targetEffect = effect(() => {
|
|
2481
|
+
const active = this.moveTarget();
|
|
2482
|
+
const frames = this.moveFrames();
|
|
2483
|
+
if (active) {
|
|
2484
|
+
this.#playForward(frames);
|
|
2485
|
+
this.#hasPlayedForward = true;
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
if (this.#hasPlayedForward) {
|
|
2489
|
+
this.#playReverse(frames);
|
|
2490
|
+
}
|
|
2491
|
+
}, ...(ngDevMode ? [{ debugName: "#targetEffect" }] : /* istanbul ignore next */ []));
|
|
2492
|
+
#playForward(frames) {
|
|
2493
|
+
this.#currentPlayer?.cancel();
|
|
2494
|
+
const isReduced = prefersReducedMotion(this.#documentRef);
|
|
2495
|
+
const config = resolveMovementConfig(this.#defaults, {
|
|
2496
|
+
duration: this.moveDuration(),
|
|
2497
|
+
easing: this.moveEasing(),
|
|
2498
|
+
delay: this.moveDelay(),
|
|
2499
|
+
disabled: this.moveDisabled(),
|
|
2500
|
+
}, isReduced);
|
|
2501
|
+
this.#currentPlayer = this.#engine.play(this.#host.nativeElement, frames, {
|
|
2502
|
+
config,
|
|
2503
|
+
spring: this.moveSpring(),
|
|
2504
|
+
disabled: config.disabled,
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
#playReverse(frames) {
|
|
2508
|
+
this.#currentPlayer?.cancel();
|
|
2509
|
+
const isReduced = prefersReducedMotion(this.#documentRef);
|
|
2510
|
+
const config = resolveMovementConfig({ ...this.#defaults, duration: 200, easing: 'ease-out', delay: 0 }, {
|
|
2511
|
+
duration: this.moveReverseDuration() ?? this.moveDuration(),
|
|
2512
|
+
easing: this.moveReverseEasing(),
|
|
2513
|
+
delay: 0,
|
|
2514
|
+
disabled: this.moveDisabled(),
|
|
2515
|
+
}, isReduced);
|
|
2516
|
+
this.#currentPlayer = this.#engine.play(this.#host.nativeElement, reverseFrames(frames), {
|
|
2517
|
+
config,
|
|
2518
|
+
spring: this.moveSpring(),
|
|
2519
|
+
disabled: config.disabled,
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
ngOnDestroy() {
|
|
2523
|
+
this.#targetEffect.destroy();
|
|
2524
|
+
this.#currentPlayer?.cancel();
|
|
2525
|
+
}
|
|
2526
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveTargetDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2527
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.2", type: MoveTargetDirective, isStandalone: true, selector: "[moveTarget]", inputs: { moveTarget: { classPropertyName: "moveTarget", publicName: "moveTarget", isSignal: true, isRequired: true, transformFunction: null }, moveFrames: { classPropertyName: "moveFrames", publicName: "moveFrames", isSignal: true, isRequired: true, transformFunction: null }, moveDuration: { classPropertyName: "moveDuration", publicName: "moveDuration", isSignal: true, isRequired: false, transformFunction: null }, moveEasing: { classPropertyName: "moveEasing", publicName: "moveEasing", isSignal: true, isRequired: false, transformFunction: null }, moveDelay: { classPropertyName: "moveDelay", publicName: "moveDelay", isSignal: true, isRequired: false, transformFunction: null }, moveSpring: { classPropertyName: "moveSpring", publicName: "moveSpring", isSignal: true, isRequired: false, transformFunction: null }, moveDisabled: { classPropertyName: "moveDisabled", publicName: "moveDisabled", isSignal: true, isRequired: false, transformFunction: null }, moveReverseDuration: { classPropertyName: "moveReverseDuration", publicName: "moveReverseDuration", isSignal: true, isRequired: false, transformFunction: null }, moveReverseEasing: { classPropertyName: "moveReverseEasing", publicName: "moveReverseEasing", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
2528
|
+
}
|
|
2529
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.2", ngImport: i0, type: MoveTargetDirective, decorators: [{
|
|
2530
|
+
type: Directive,
|
|
2531
|
+
args: [{
|
|
2532
|
+
selector: '[moveTarget]',
|
|
2533
|
+
standalone: true,
|
|
2534
|
+
}]
|
|
2535
|
+
}], propDecorators: { moveTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveTarget", required: true }] }], moveFrames: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveFrames", required: true }] }], moveDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDuration", required: false }] }], moveEasing: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveEasing", required: false }] }], moveDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDelay", required: false }] }], moveSpring: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveSpring", required: false }] }], moveDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveDisabled", required: false }] }], moveReverseDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveReverseDuration", required: false }] }], moveReverseEasing: [{ type: i0.Input, args: [{ isSignal: true, alias: "moveReverseEasing", required: false }] }] } });
|
|
2536
|
+
|
|
2149
2537
|
function provideMovement(config = {}) {
|
|
2150
2538
|
return makeEnvironmentProviders([
|
|
2151
2539
|
{
|
|
@@ -2176,6 +2564,8 @@ const MOVEMENT_DIRECTIVES = [
|
|
|
2176
2564
|
MoveFocusDirective,
|
|
2177
2565
|
MoveParallaxDirective,
|
|
2178
2566
|
MoveAnimationDirective,
|
|
2567
|
+
MoveLoopDirective,
|
|
2568
|
+
MoveTargetDirective,
|
|
2179
2569
|
];
|
|
2180
2570
|
|
|
2181
2571
|
/*
|
|
@@ -2186,5 +2576,5 @@ const MOVEMENT_DIRECTIVES = [
|
|
|
2186
2576
|
* Generated bundle index. Do not edit.
|
|
2187
2577
|
*/
|
|
2188
2578
|
|
|
2189
|
-
export { AnimationEngine, MOVEMENT_CONFIG, MOVEMENT_DEFAULTS, MOVEMENT_DIRECTIVES, MOVE_PRESENCE_PARENT, MOVE_PRESETS, MOVE_STAGGER_PARENT, MOVE_VARIANTS_PARENT, MoveAnimateDirective, MoveAnimationDirective, MoveDragDirective, MoveEnterDirective, MoveFocusDirective, MoveHoverDirective, MoveInViewDirective, MoveLayoutDirective, MoveLeaveDirective, MoveParallaxDirective, MovePresenceDirective, MoveScrollDirective, MoveSmoothScrollDirective, MoveStaggerDirective, MoveTapDirective, MoveTextDirective, MoveVariantsDirective, SmoothScrollService, SpringPlayer, WaapiPlayer, provideMovement };
|
|
2579
|
+
export { AnimationEngine, MOVEMENT_CONFIG, MOVEMENT_DEFAULTS, MOVEMENT_DIRECTIVES, MOVE_PRESENCE_PARENT, MOVE_PRESETS, MOVE_STAGGER_PARENT, MOVE_VARIANTS_PARENT, MoveAnimateDirective, MoveAnimationDirective, MoveDragDirective, MoveEnterDirective, MoveFocusDirective, MoveHoverDirective, MoveInViewDirective, MoveLayoutDirective, MoveLeaveDirective, MoveLoopDirective, MoveParallaxDirective, MovePresenceDirective, MoveScrollDirective, MoveSmoothScrollDirective, MoveStaggerDirective, MoveTapDirective, MoveTargetDirective, MoveTextDirective, MoveVariantsDirective, SmoothScrollService, SpringPlayer, WaapiPlayer, applyInitialStyles, clearInitialStyles, isValidScrollOffset, prefersReducedMotion, provideMovement, resolveMoveFrames, resolveMovementConfig, reverseFrames, validateDragElastic, validateSpring };
|
|
2190
2580
|
//# sourceMappingURL=angular-movement.mjs.map
|