1 | (function (global, factory) {
|
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
3 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Motion = {}));
|
5 | }(this, (function (exports) { 'use strict';
|
6 |
|
7 | const data = new WeakMap();
|
8 | function getAnimationData(element) {
|
9 | if (!data.has(element)) {
|
10 | data.set(element, {
|
11 | activeTransforms: [],
|
12 | activeAnimations: {},
|
13 | });
|
14 | }
|
15 | return data.get(element);
|
16 | }
|
17 |
|
18 | function addUniqueItem(array, item) {
|
19 | array.indexOf(item) === -1 && array.push(item);
|
20 | }
|
21 | function removeItem(arr, item) {
|
22 | const index = arr.indexOf(item);
|
23 | index > -1 && arr.splice(index, 1);
|
24 | }
|
25 |
|
26 | const noop = () => { };
|
27 | const noopReturn = (v) => v;
|
28 |
|
29 | |
30 |
|
31 |
|
32 |
|
33 | const axes = ["", "X", "Y", "Z"];
|
34 | |
35 |
|
36 |
|
37 |
|
38 | const order = ["translate", "scale", "rotate", "skew"];
|
39 | const transformAlias = {
|
40 | x: "translateX",
|
41 | y: "translateY",
|
42 | z: "translateZ",
|
43 | };
|
44 | const rotation = {
|
45 | syntax: "<angle>",
|
46 | initialValue: "0deg",
|
47 | toDefaultUnit: (v) => v + "deg",
|
48 | };
|
49 | const baseTransformProperties = {
|
50 | translate: {
|
51 | syntax: "<length-percentage>",
|
52 | initialValue: "0px",
|
53 | toDefaultUnit: (v) => v + "px",
|
54 | },
|
55 | rotate: rotation,
|
56 | scale: {
|
57 | syntax: "<number>",
|
58 | initialValue: 1,
|
59 | toDefaultUnit: noopReturn,
|
60 | },
|
61 | skew: rotation,
|
62 | };
|
63 | const transformPropertyDefinitions = new Map();
|
64 | const asTransformCssVar = (name) => `--motion-${name}`;
|
65 | |
66 |
|
67 |
|
68 | const transforms = ["x", "y", "z"];
|
69 | order.forEach((name) => {
|
70 | axes.forEach((axis) => {
|
71 | transforms.push(name + axis);
|
72 | transformPropertyDefinitions.set(asTransformCssVar(name + axis), baseTransformProperties[name]);
|
73 | });
|
74 | });
|
75 | |
76 |
|
77 |
|
78 | const compareTransformOrder = (a, b) => transforms.indexOf(a) - transforms.indexOf(b);
|
79 | |
80 |
|
81 |
|
82 | const transformLookup = new Set(transforms);
|
83 | const isTransform = (name) => transformLookup.has(name);
|
84 | const addTransformToElement = (element, name) => {
|
85 | const { activeTransforms } = getAnimationData(element);
|
86 | addUniqueItem(activeTransforms, name);
|
87 | element.style.transform = buildTransformTemplate(activeTransforms);
|
88 | };
|
89 | const buildTransformTemplate = (activeTransforms) => activeTransforms
|
90 | .sort(compareTransformOrder)
|
91 | .reduce(transformListToString, "")
|
92 | .trim();
|
93 | const transformListToString = (template, name) => `${template} ${name}(var(${asTransformCssVar(name)}))`;
|
94 |
|
95 | const isCssVar = (name) => name.startsWith("--");
|
96 | const registeredProperties = new Set();
|
97 | function registerCssVariable(name) {
|
98 | if (registeredProperties.has(name))
|
99 | return;
|
100 | registeredProperties.add(name);
|
101 | try {
|
102 | const { syntax, initialValue } = transformPropertyDefinitions.has(name)
|
103 | ? transformPropertyDefinitions.get(name)
|
104 | : {};
|
105 | CSS.registerProperty({
|
106 | name,
|
107 | inherits: false,
|
108 | syntax,
|
109 | initialValue,
|
110 | });
|
111 | }
|
112 | catch (e) { }
|
113 | }
|
114 |
|
115 | const ms = (seconds) => seconds * 1000;
|
116 |
|
117 | function stopAnimation(animation) {
|
118 |
|
119 | try {
|
120 | animation.commitStyles();
|
121 | animation.cancel();
|
122 | }
|
123 | catch (e) { }
|
124 | }
|
125 |
|
126 | const isCubicBezier = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
127 | const isEasingList = (easing) => Array.isArray(easing) && typeof easing[0] !== "number";
|
128 | const convertEasing = (easing) => isCubicBezier(easing) ? cubicBezierAsString(easing) : easing;
|
129 | const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
|
130 |
|
131 | const testAnimation = (keyframes) => document.createElement("div").animate(keyframes, { duration: 0.001 });
|
132 | const featureTests = {
|
133 | cssRegisterProperty: () => typeof CSS !== "undefined" &&
|
134 | Object.hasOwnProperty.call(CSS, "registerProperty"),
|
135 | waapi: () => Object.hasOwnProperty.call(Element.prototype, "animate"),
|
136 | partialKeyframes: () => {
|
137 | try {
|
138 | testAnimation({ opacity: [1] });
|
139 | }
|
140 | catch (e) {
|
141 | return false;
|
142 | }
|
143 | return true;
|
144 | },
|
145 | finished: () => Boolean(testAnimation({ opacity: [0, 1] }).finished),
|
146 | };
|
147 | const results = {};
|
148 | const supports = Object.keys(featureTests).reduce((acc, key) => {
|
149 | acc[key] = () => {
|
150 | if (results[key] === undefined)
|
151 | results[key] = featureTests[key]();
|
152 | return results[key];
|
153 | };
|
154 | return acc;
|
155 | }, {});
|
156 |
|
157 | const createCssVariableRenderer = (element, name) => {
|
158 | return (latest) => element.style.setProperty(name, latest);
|
159 | };
|
160 | const createStyleRenderer = (element, name) => {
|
161 | return (latest) => (element.style[name] = latest);
|
162 | };
|
163 |
|
164 | const defaults = {
|
165 | duration: 0.3,
|
166 | delay: 0,
|
167 | endDelay: 0,
|
168 | repeat: 0,
|
169 | easing: "ease",
|
170 | };
|
171 |
|
172 | |
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 | const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) * t;
|
194 | const subdivisionPrecision = 0.0000001;
|
195 | const subdivisionMaxIterations = 12;
|
196 | function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
197 | let currentX;
|
198 | let currentT;
|
199 | let i = 0;
|
200 | do {
|
201 | currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
202 | currentX = calcBezier(currentT, mX1, mX2) - x;
|
203 | if (currentX > 0.0) {
|
204 | upperBound = currentT;
|
205 | }
|
206 | else {
|
207 | lowerBound = currentT;
|
208 | }
|
209 | } while (Math.abs(currentX) > subdivisionPrecision &&
|
210 | ++i < subdivisionMaxIterations);
|
211 | return currentT;
|
212 | }
|
213 | function cubicBezier(mX1, mY1, mX2, mY2) {
|
214 |
|
215 | if (mX1 === mY1 && mX2 === mY2)
|
216 | return noopReturn;
|
217 | const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
|
218 |
|
219 | return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
|
220 | }
|
221 |
|
222 | |
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 | function __rest(s, e) {
|
238 | var t = {};
|
239 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
240 | t[p] = s[p];
|
241 | if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
242 | for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
243 | if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
244 | t[p[i]] = s[p[i]];
|
245 | }
|
246 | return t;
|
247 | }
|
248 |
|
249 | var clamp = function (min, max, v) {
|
250 | return Math.min(Math.max(v, min), max);
|
251 | };
|
252 |
|
253 | var progress = function (from, to, value) {
|
254 | var toFromDifference = to - from;
|
255 | return toFromDifference === 0 ? 1 : (value - from) / toFromDifference;
|
256 | };
|
257 |
|
258 | var mix = function (from, to, progress) {
|
259 | return -progress * from + progress * to + from;
|
260 | };
|
261 |
|
262 | var wrap = function (min, max, v) {
|
263 | var rangeSize = max - min;
|
264 | return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min;
|
265 | };
|
266 |
|
267 | var steps = function (steps, direction) {
|
268 | if (direction === void 0) { direction = 'end'; }
|
269 | return function (progress) {
|
270 | progress =
|
271 | direction === 'end' ? Math.min(progress, 0.999) : Math.max(progress, 0.001);
|
272 | var expanded = progress * steps;
|
273 | var rounded = direction === 'end' ? Math.floor(expanded) : Math.ceil(expanded);
|
274 | return clamp(0, 1, rounded / steps);
|
275 | };
|
276 | };
|
277 |
|
278 | const namedEasings = {
|
279 | ease: cubicBezier(0.25, 0.1, 0.25, 1.0),
|
280 | "ease-in": cubicBezier(0.42, 0.0, 1.0, 1.0),
|
281 | "ease-in-out": cubicBezier(0.42, 0.0, 0.58, 1.0),
|
282 | "ease-out": cubicBezier(0.0, 0.0, 0.58, 1.0),
|
283 | };
|
284 | const functionArgsRegex = /\((.*?)\)/;
|
285 | function getEasingFunction(definition) {
|
286 |
|
287 | if (typeof definition === "function")
|
288 | return definition;
|
289 |
|
290 | if (Array.isArray(definition))
|
291 | return cubicBezier(...definition);
|
292 |
|
293 | if (namedEasings[definition])
|
294 | return namedEasings[definition];
|
295 |
|
296 | if (definition.startsWith("steps")) {
|
297 | const args = functionArgsRegex.exec(definition);
|
298 | if (args) {
|
299 | const argsArray = args[1].split(",");
|
300 | return steps(parseFloat(argsArray[0]), argsArray[1].trim());
|
301 | }
|
302 | }
|
303 | return noopReturn;
|
304 | }
|
305 |
|
306 | function getEasingForSegment(easing, i) {
|
307 | return isEasingList(easing)
|
308 | ? easing[wrap(0, easing.length, i)]
|
309 | : easing;
|
310 | }
|
311 |
|
312 | function fillOffset(offset, remaining) {
|
313 | const min = offset[offset.length - 1];
|
314 | for (let i = 1; i <= remaining; i++) {
|
315 | const offsetProgress = progress(0, remaining, i);
|
316 | offset.push(mix(min, 1, offsetProgress));
|
317 | }
|
318 | }
|
319 | function defaultOffset(length) {
|
320 | const offset = [0];
|
321 | fillOffset(offset, length - 1);
|
322 | return offset;
|
323 | }
|
324 |
|
325 | const clampProgress = (p) => Math.min(1, Math.max(p, 0));
|
326 | function slowInterpolateNumbers(output, input = defaultOffset(output.length), easing = noopReturn) {
|
327 | const length = output.length;
|
328 | |
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | const remainder = length - input.length;
|
335 | remainder > 0 && fillOffset(input, remainder);
|
336 | return (t) => {
|
337 | let i = 0;
|
338 | for (; i < length - 2; i++) {
|
339 | if (t < input[i + 1])
|
340 | break;
|
341 | }
|
342 | let progressInRange = clampProgress(progress(input[i], input[i + 1], t));
|
343 | const segmentEasing = getEasingForSegment(easing, i);
|
344 | progressInRange = segmentEasing(progressInRange);
|
345 | return mix(output[i], output[i + 1], progressInRange);
|
346 | };
|
347 | }
|
348 |
|
349 | class Animation {
|
350 | constructor(output, keyframes,
|
351 | // TODO Merge in defaults
|
352 | { easing = defaults.easing, duration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, offset, repeat = defaults.repeat, direction = "normal", }) {
|
353 | this.startTime = 0;
|
354 | this.rate = 1;
|
355 | this.t = 0;
|
356 | this.cancelT = 0;
|
357 | this.playState = "idle";
|
358 | this.finished = new Promise((resolve, reject) => {
|
359 | this.resolve = resolve;
|
360 | this.reject = reject;
|
361 | });
|
362 | const totalDuration = duration * (repeat + 1);
|
363 | const interpolate = slowInterpolateNumbers(keyframes, offset, isEasingList(easing)
|
364 | ? easing.map(getEasingFunction)
|
365 | : getEasingFunction(easing));
|
366 | this.tick = (timestamp) => {
|
367 | if (this.playState === "finished") {
|
368 | const latest = interpolate(1);
|
369 | output(latest);
|
370 | this.resolve(latest);
|
371 | return;
|
372 | }
|
373 | if (this.pauseTime) {
|
374 | timestamp = this.pauseTime;
|
375 | }
|
376 | let t = (timestamp - this.startTime) * this.rate;
|
377 | this.t = t;
|
378 |
|
379 | t /= 1000;
|
380 |
|
381 | t = Math.max(t - delay, 0);
|
382 | const progress = t / duration;
|
383 |
|
384 | let currentIteration = Math.floor(progress);
|
385 | let iterationProgress = progress % 1.0;
|
386 | if (!iterationProgress && progress >= 1) {
|
387 | iterationProgress = 1;
|
388 | }
|
389 | if (iterationProgress === 1) {
|
390 | currentIteration--;
|
391 | }
|
392 |
|
393 | const iterationIsOdd = currentIteration % 2;
|
394 | if (direction === "reverse" ||
|
395 | (direction === "alternate" && iterationIsOdd) ||
|
396 | (direction === "alternate-reverse" && !iterationIsOdd)) {
|
397 | iterationProgress = 1 - iterationProgress;
|
398 | }
|
399 | const interpolationIsFinished = t >= totalDuration;
|
400 | const interpolationProgress = interpolationIsFinished
|
401 | ? 1
|
402 | : Math.min(iterationProgress, 1);
|
403 | const latest = interpolate(interpolationProgress);
|
404 | output(latest);
|
405 | const isFinished = t >= totalDuration + endDelay;
|
406 | if (isFinished) {
|
407 | this.playState = "finished";
|
408 | this.resolve(latest);
|
409 | }
|
410 | else if (this.playState !== "idle") {
|
411 | requestAnimationFrame(this.tick);
|
412 | }
|
413 | };
|
414 | this.play();
|
415 | }
|
416 | play() {
|
417 | const now = performance.now();
|
418 | this.playState = "running";
|
419 | if (this.pauseTime) {
|
420 | this.startTime = now - (this.pauseTime - this.startTime);
|
421 | }
|
422 | else if (!this.startTime) {
|
423 | this.startTime = now;
|
424 | }
|
425 | this.pauseTime = undefined;
|
426 | requestAnimationFrame(this.tick);
|
427 | }
|
428 | pause() {
|
429 | this.playState = "paused";
|
430 | this.pauseTime = performance.now();
|
431 | }
|
432 | finish() {
|
433 | this.playState = "finished";
|
434 | this.tick(0);
|
435 | }
|
436 | cancel() {
|
437 | this.playState = "idle";
|
438 | this.tick(this.cancelT);
|
439 | this.reject(false);
|
440 | }
|
441 | reverse() {
|
442 | this.rate *= -1;
|
443 | }
|
444 | commitStyles() {
|
445 | this.cancelT = this.t;
|
446 | }
|
447 | get currentTime() {
|
448 | return this.t;
|
449 | }
|
450 | set currentTime(t) {
|
451 | if (this.pauseTime || this.rate === 0) {
|
452 | this.pauseTime = t;
|
453 | }
|
454 | else {
|
455 | this.startTime = performance.now() - t / this.rate;
|
456 | }
|
457 | }
|
458 | get playbackRate() {
|
459 | return this.rate;
|
460 | }
|
461 | set playbackRate(rate) {
|
462 | this.rate = rate;
|
463 | }
|
464 | }
|
465 | function animateNumber(output, keyframes = [0, 1], options = {}) {
|
466 | return new Animation(output, keyframes, options);
|
467 | }
|
468 |
|
469 | const style = {
|
470 | get: (element, name) => {
|
471 | let value = isCssVar(name)
|
472 | ? element.style.getPropertyValue(name)
|
473 | : getComputedStyle(element)[name];
|
474 | if (!value && value !== 0) {
|
475 | const definition = transformPropertyDefinitions.get(name);
|
476 | if (definition)
|
477 | value = definition.initialValue;
|
478 | }
|
479 | return value;
|
480 | },
|
481 | };
|
482 |
|
483 | function hydrateKeyframes(keyframes, element, name) {
|
484 | for (let i = 0; i < keyframes.length; i++) {
|
485 | if (keyframes[i] === null) {
|
486 | keyframes[i] = i ? keyframes[i - 1] : style.get(element, name);
|
487 | }
|
488 | }
|
489 | return keyframes;
|
490 | }
|
491 | const keyframesList = (keyframes) => Array.isArray(keyframes) ? keyframes : [keyframes];
|
492 |
|
493 | function animateStyle(element, name, keyframesDefinition, options = {}) {
|
494 | let { duration = defaults.duration, delay = defaults.delay, endDelay = defaults.endDelay, repeat = defaults.repeat, easing = defaults.easing, direction, offset, allowWebkitAcceleration = false, } = options;
|
495 | const data = getAnimationData(element);
|
496 | let canAnimateNatively = supports.waapi();
|
497 | let render = noop;
|
498 | const valueIsTransform = isTransform(name);
|
499 | |
500 |
|
501 |
|
502 |
|
503 | if (valueIsTransform) {
|
504 | if (transformAlias[name])
|
505 | name = transformAlias[name];
|
506 | addTransformToElement(element, name);
|
507 | name = asTransformCssVar(name);
|
508 | }
|
509 | |
510 |
|
511 |
|
512 |
|
513 | const definition = transformPropertyDefinitions.get(name);
|
514 | |
515 |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 |
|
521 |
|
522 | let keyframes = hydrateKeyframes(keyframesList(keyframesDefinition), element, name);
|
523 | stopCurrentAnimation(data, name);
|
524 | |
525 |
|
526 |
|
527 |
|
528 |
|
529 | if (isCssVar(name)) {
|
530 | render = createCssVariableRenderer(element, name);
|
531 | if (supports.cssRegisterProperty()) {
|
532 | registerCssVariable(name);
|
533 | }
|
534 | else {
|
535 | canAnimateNatively = false;
|
536 | }
|
537 | }
|
538 | else {
|
539 | render = createStyleRenderer(element, name);
|
540 | }
|
541 | let animation;
|
542 | |
543 |
|
544 |
|
545 |
|
546 | if (canAnimateNatively) {
|
547 | |
548 |
|
549 |
|
550 |
|
551 | if (definition) {
|
552 | keyframes = keyframes.map((value) => typeof value === "number" ? definition.toDefaultUnit(value) : value);
|
553 | }
|
554 | if (!supports.partialKeyframes() && keyframes.length === 1) {
|
555 | keyframes.unshift(style.get(element, name));
|
556 | }
|
557 | const animationOptions = {
|
558 | delay: ms(delay),
|
559 | duration: ms(duration),
|
560 | endDelay: ms(endDelay),
|
561 | easing: !isEasingList(easing) ? convertEasing(easing) : undefined,
|
562 | direction,
|
563 | iterations: repeat + 1,
|
564 | };
|
565 | animation = element.animate({
|
566 | [name]: keyframes,
|
567 | offset,
|
568 | easing: isEasingList(easing) ? easing.map(convertEasing) : undefined,
|
569 | }, animationOptions);
|
570 | |
571 |
|
572 |
|
573 | if (!animation.finished) {
|
574 | animation.finished = new Promise((resolve, reject) => {
|
575 | animation.onfinish = resolve;
|
576 | animation.oncancel = reject;
|
577 | });
|
578 | }
|
579 | const target = keyframes[keyframes.length - 1];
|
580 | animation.finished.then(() => render(target)).catch(noop);
|
581 | |
582 |
|
583 |
|
584 |
|
585 |
|
586 |
|
587 |
|
588 |
|
589 |
|
590 | if (!allowWebkitAcceleration)
|
591 | animation.playbackRate = 1.000001;
|
592 | }
|
593 | else if (valueIsTransform && keyframes.every(isNumber)) {
|
594 | if (keyframes.length === 1) {
|
595 | keyframes.unshift(style.get(element, name) || (definition === null || definition === void 0 ? void 0 : definition.initialValue) || 0);
|
596 | }
|
597 | |
598 |
|
599 |
|
600 |
|
601 |
|
602 | keyframes = keyframes.map((value) => typeof value === "string" ? parseFloat(value) : value);
|
603 | if (definition) {
|
604 | const applyStyle = render;
|
605 | render = (v) => applyStyle(definition.toDefaultUnit(v));
|
606 | }
|
607 | animation = animateNumber(render, keyframes, options);
|
608 | }
|
609 | else {
|
610 | const target = keyframes[keyframes.length - 1];
|
611 | render(definition && typeof target === "number"
|
612 | ? definition.toDefaultUnit(target)
|
613 | : target);
|
614 | }
|
615 | data.activeAnimations[name] = animation;
|
616 | return animation;
|
617 | }
|
618 | function stopCurrentAnimation(data, name) {
|
619 | if (data.activeAnimations[name]) {
|
620 | stopAnimation(data.activeAnimations[name]);
|
621 | data.activeAnimations[name] = undefined;
|
622 | }
|
623 | }
|
624 | const isNumber = (value) => typeof value === "number";
|
625 |
|
626 | const getOptions = (options, key) => options[key] ? Object.assign(Object.assign({}, options), options[key]) : Object.assign({}, options);
|
627 |
|
628 | function resolveElements(elements, selectorCache) {
|
629 | var _a;
|
630 | if (typeof elements === "string") {
|
631 | if (selectorCache) {
|
632 | (_a = selectorCache[elements]) !== null && _a !== void 0 ? _a : (selectorCache[elements] = document.querySelectorAll(elements));
|
633 | elements = selectorCache[elements];
|
634 | }
|
635 | else {
|
636 | elements = document.querySelectorAll(elements);
|
637 | }
|
638 | }
|
639 | else if (elements instanceof Element) {
|
640 | elements = [elements];
|
641 | }
|
642 | return Array.from(elements);
|
643 | }
|
644 |
|
645 | function createAnimationControls(animations) {
|
646 |
|
647 | const state = {
|
648 | animations,
|
649 | finished: Promise.all(animations.map((animation) => animation.finished)),
|
650 | };
|
651 | return new Proxy(state, controls);
|
652 | }
|
653 | const controls = {
|
654 | get: (target, key) => {
|
655 | var _a, _b;
|
656 | switch (key) {
|
657 | case "finished":
|
658 | return target.finished;
|
659 | case "currentTime":
|
660 |
|
661 | const duration = ((_a = target.animations[0]) === null || _a === void 0 ? void 0 : _a[key]) || 0;
|
662 | return duration ? duration / 1000 : 0;
|
663 | case "playbackRate":
|
664 |
|
665 | return (_b = target.animations[0]) === null || _b === void 0 ? void 0 : _b[key];
|
666 | case "stop":
|
667 | return () => target.animations.forEach(stopAnimation);
|
668 | default:
|
669 | return () => target.animations.forEach((animation) => animation[key]());
|
670 | }
|
671 | },
|
672 | set: (target, key, value) => {
|
673 | switch (key) {
|
674 | case "currentTime":
|
675 | value = ms(value);
|
676 | case "currentTime":
|
677 | case "playbackRate":
|
678 | for (let i = 0; i < target.animations.length; i++) {
|
679 | target.animations[i][key] = value;
|
680 | }
|
681 | return true;
|
682 | }
|
683 | return false;
|
684 | },
|
685 | };
|
686 |
|
687 | function stagger(duration = 0.1, { start = 0, from = 0, easing } = {}) {
|
688 | return (i, total) => {
|
689 | const fromIndex = typeof from === "number" ? from : getFromIndex(from, total);
|
690 | const distance = Math.abs(fromIndex - i);
|
691 | let delay = duration * distance;
|
692 | if (easing) {
|
693 | const maxDelay = total * i;
|
694 | const easingFunction = getEasingFunction(easing);
|
695 | delay = easingFunction(delay / maxDelay) * maxDelay;
|
696 | }
|
697 | return start + delay;
|
698 | };
|
699 | }
|
700 | function getFromIndex(from, total) {
|
701 | if (from === "first") {
|
702 | return 0;
|
703 | }
|
704 | else {
|
705 | const lastIndex = total - 1;
|
706 | return from === "last" ? lastIndex : lastIndex / 2;
|
707 | }
|
708 | }
|
709 | function resolveOption(option, i, total) {
|
710 | return typeof option === "function"
|
711 | ? option(i, total)
|
712 | : option;
|
713 | }
|
714 |
|
715 | function animate(elements, keyframes, options = {}) {
|
716 | elements = resolveElements(elements);
|
717 | const animations = [];
|
718 | const numElements = elements.length;
|
719 | for (let i = 0; i < numElements; i++) {
|
720 | const element = elements[i];
|
721 | for (const key in keyframes) {
|
722 | const valueOptions = getOptions(options, key);
|
723 | valueOptions.delay = resolveOption(valueOptions.delay, i, numElements);
|
724 | const animation = animateStyle(element, key, keyframes[key], valueOptions);
|
725 | animation && animations.push(animation);
|
726 | }
|
727 | }
|
728 | return createAnimationControls(animations);
|
729 | }
|
730 |
|
731 | function calcNextTime(current, next, prev, labels) {
|
732 | var _a;
|
733 | if (typeof next === "number") {
|
734 | return next;
|
735 | }
|
736 | else if (next.startsWith("-") || next.startsWith("+")) {
|
737 | return Math.max(0, current + parseFloat(next));
|
738 | }
|
739 | else if (next === "<") {
|
740 | return prev;
|
741 | }
|
742 | else {
|
743 | return (_a = labels.get(next)) !== null && _a !== void 0 ? _a : current;
|
744 | }
|
745 | }
|
746 |
|
747 | function eraseKeyframes(sequence, startTime, endTime) {
|
748 | for (let i = 0; i < sequence.length; i++) {
|
749 | const keyframe = sequence[i];
|
750 | if (keyframe.at > startTime && keyframe.at < endTime) {
|
751 | removeItem(sequence, keyframe);
|
752 |
|
753 | i--;
|
754 | }
|
755 | }
|
756 | }
|
757 | function addKeyframes(sequence, keyframes, easing, offset, startTime, endTime) {
|
758 | |
759 |
|
760 |
|
761 |
|
762 |
|
763 | eraseKeyframes(sequence, startTime, endTime);
|
764 | for (let i = 0; i < keyframes.length; i++) {
|
765 | sequence.push({
|
766 | value: keyframes[i],
|
767 | at: mix(startTime, endTime, offset[i]),
|
768 | easing: getEasingForSegment(easing, i),
|
769 | });
|
770 | }
|
771 | }
|
772 |
|
773 | function compareByTime(a, b) {
|
774 | if (a.at === b.at) {
|
775 | return a.value === null ? 1 : -1;
|
776 | }
|
777 | else {
|
778 | return a.at - b.at;
|
779 | }
|
780 | }
|
781 |
|
782 | function timeline(definition, options = {}) {
|
783 | const animations = [];
|
784 | const animationDefinitions = createAnimationsFromTimeline(definition, options);
|
785 | for (let i = 0; i < animationDefinitions.length; i++) {
|
786 | const animation = animateStyle(...animationDefinitions[i]);
|
787 | animation && animations.push(animation);
|
788 | }
|
789 | return createAnimationControls(animations);
|
790 | }
|
791 | function createAnimationsFromTimeline(definition, _a = {}) {
|
792 | var { defaultOptions = {} } = _a, timelineOptions = __rest(_a, ["defaultOptions"]);
|
793 | const animationDefinitions = [];
|
794 | const elementSequences = new Map();
|
795 | const elementCache = {};
|
796 | const timeLabels = new Map();
|
797 | let prevTime = 0;
|
798 | let currentTime = 0;
|
799 | let totalDuration = 0;
|
800 | |
801 |
|
802 |
|
803 |
|
804 |
|
805 | for (let i = 0; i < definition.length; i++) {
|
806 | const [elementDefinition, keyframes, options = {}] = definition[i];
|
807 | |
808 |
|
809 |
|
810 |
|
811 | if (options.at !== undefined) {
|
812 | currentTime = calcNextTime(currentTime, options.at, prevTime, timeLabels);
|
813 | }
|
814 | |
815 |
|
816 |
|
817 |
|
818 | let maxDuration = 0;
|
819 | |
820 |
|
821 |
|
822 |
|
823 | const elements = resolveElements(elementDefinition, elementCache);
|
824 | const numElements = elements.length;
|
825 | for (let elementIndex = 0; elementIndex < numElements; elementIndex++) {
|
826 | const element = elements[elementIndex];
|
827 | const elementSequence = getElementSequence(element, elementSequences);
|
828 | for (const key in keyframes) {
|
829 | const valueSequence = getValueSequence(key, elementSequence);
|
830 | const valueKeyframes = keyframesList(keyframes[key]);
|
831 | const valueOptions = getOptions(options, key);
|
832 | const { duration = defaultOptions.duration || defaults.duration, easing = defaultOptions.easing || defaults.easing, offset = defaultOffset(valueKeyframes.length), } = valueOptions;
|
833 | const delay = resolveOption(options.delay, elementIndex, numElements) || 0;
|
834 | const startTime = currentTime + delay;
|
835 | const targetTime = startTime + duration;
|
836 | if (offset.length === 1 && offset[0] === 0) {
|
837 | offset[1] = 1;
|
838 | }
|
839 | |
840 |
|
841 |
|
842 | const remainder = length - valueKeyframes.length;
|
843 | remainder > 0 && fillOffset(offset, remainder);
|
844 | |
845 |
|
846 |
|
847 |
|
848 |
|
849 | valueKeyframes.length === 1 && valueKeyframes.unshift(null);
|
850 | |
851 |
|
852 |
|
853 | addKeyframes(valueSequence, valueKeyframes, easing, offset, startTime, targetTime);
|
854 | maxDuration = Math.max(delay + duration, maxDuration);
|
855 | totalDuration = Math.max(targetTime, totalDuration);
|
856 | }
|
857 | }
|
858 | prevTime = currentTime;
|
859 | currentTime += maxDuration;
|
860 | }
|
861 | |
862 |
|
863 |
|
864 | elementSequences.forEach((valueSequences, element) => {
|
865 | for (const key in valueSequences) {
|
866 | const valueSequence = valueSequences[key];
|
867 | |
868 |
|
869 |
|
870 | valueSequence.sort(compareByTime);
|
871 | const keyframes = [];
|
872 | const valueOffset = [];
|
873 | const valueEasing = [];
|
874 | |
875 |
|
876 |
|
877 |
|
878 | for (let i = 0; i < valueSequence.length; i++) {
|
879 | const { at, value, easing } = valueSequence[i];
|
880 | keyframes.push(value);
|
881 | valueOffset.push(progress(0, totalDuration, at));
|
882 | valueEasing.push(easing || defaults.easing);
|
883 | }
|
884 | |
885 |
|
886 |
|
887 |
|
888 |
|
889 | if (valueOffset[valueOffset.length - 1] !== 1) {
|
890 | valueOffset.push(1);
|
891 | keyframes.push(null);
|
892 | }
|
893 | animationDefinitions.push([
|
894 | element,
|
895 | key,
|
896 | keyframes,
|
897 | Object.assign(Object.assign(Object.assign({}, defaultOptions), { duration: totalDuration, easing: valueEasing, offset: valueOffset }), timelineOptions),
|
898 | ]);
|
899 | }
|
900 | });
|
901 | return animationDefinitions;
|
902 | }
|
903 | function getElementSequence(element, sequences) {
|
904 | !sequences.has(element) && sequences.set(element, {});
|
905 | return sequences.get(element);
|
906 | }
|
907 | function getValueSequence(name, sequences) {
|
908 | if (!sequences[name])
|
909 | sequences[name] = [];
|
910 | return sequences[name];
|
911 | }
|
912 |
|
913 | exports.animate = animate;
|
914 | exports.animateStyle = animateStyle;
|
915 | exports.stagger = stagger;
|
916 | exports.timeline = timeline;
|
917 |
|
918 | Object.defineProperty(exports, '__esModule', { value: true });
|
919 |
|
920 | })));
|