select-animation 1.2.0 → 1.2.2

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.
@@ -7,741 +7,803 @@
7
7
  * License: MIT
8
8
  * ------------------------------------------------------------------------- */
9
9
 
10
- (function (global) {
11
- "use strict"; // Enable strict mode for safer JavaScript execution
12
-
13
- /* -------------------------------------------------
14
- RequestAnimationFrame Polyfill for cross-browser support
15
- ------------------------------------------------- */
16
- let lastFrameTime = 0;
17
- const vendorPrefixes = ["ms", "moz", "webkit", "o"];
18
-
19
- // Polyfill requestAnimationFrame
20
- for (let i = 0; i < vendorPrefixes.length && !window.requestAnimationFrame; ++i) {
21
- window.requestAnimationFrame = window[vendorPrefixes[i] + "RequestAnimationFrame"];
22
- window.cancelAnimationFrame =
23
- window[vendorPrefixes[i] + "CancelAnimationFrame"] ||
24
- window[vendorPrefixes[i] + "CancelRequestAnimationFrame"];
25
- }
26
- if (!window.requestAnimationFrame) {
27
- window.requestAnimationFrame = function (callback) {
28
- const currentTime = Date.now();
29
- const timeToCall = Math.max(0, 16 - (currentTime - lastFrameTime));
30
- const id = window.setTimeout(() => {
31
- callback(currentTime + timeToCall);
32
- }, timeToCall);
33
- lastFrameTime = currentTime + timeToCall;
34
- return id;
10
+
11
+ (function (global) {
12
+ "use strict";
13
+
14
+ // -----------------------------
15
+ // requestAnimationFrame polyfill
16
+ // Ensures consistent animation frame behavior across older browsers.
17
+ // -----------------------------
18
+ let _lastTime = 0;
19
+ const _vendors = ["ms", "moz", "webkit", "o"];
20
+ for (let i = 0; i < _vendors.length && !global.requestAnimationFrame; ++i) {
21
+ global.requestAnimationFrame = global[_vendors[i] + "RequestAnimationFrame"];
22
+ global.cancelAnimationFrame = global[_vendors[i] + "CancelAnimationFrame"] || global[_vendors[i] + "CancelRequestAnimationFrame"];
23
+ }
24
+
25
+ if (!global.requestAnimationFrame) {
26
+ global.requestAnimationFrame = function (callback) {
27
+ const currTime = new Date().getTime();
28
+ const timeToCall = Math.max(0, 16 - (currTime - _lastTime));
29
+ const id = global.setTimeout(function () {
30
+ callback(currTime + timeToCall);
31
+ }, timeToCall);
32
+ _lastTime = currTime + timeToCall;
33
+ return id;
34
+ };
35
+ }
36
+
37
+ if (!global.cancelAnimationFrame) {
38
+ global.cancelAnimationFrame = function (id) {
39
+ clearTimeout(id);
40
+ };
41
+ }
42
+
43
+ // -----------------------------
44
+ // Internal defaults and mappings
45
+ // Color defaults and map from logical property -> CSS format.
46
+ // -----------------------------
47
+ const COLOR_DEFAULTS = { rgbR: 255, rgbG: 255, rgbB: 255, rgbA: 1 };
48
+
49
+ const COLOR_PROPERTIES = {
50
+ color: COLOR_DEFAULTS,
51
+ background: COLOR_DEFAULTS,
52
+ backgroundColor: COLOR_DEFAULTS,
53
+ borderColor: COLOR_DEFAULTS
35
54
  };
36
- }
37
- if (!window.cancelAnimationFrame) {
38
- window.cancelAnimationFrame = function (id) {
39
- clearTimeout(id);
55
+
56
+ const PROPERTY_FORMAT_MAP = {
57
+ zIndex: "*",
58
+ left: "*px",
59
+ top: "*px",
60
+ bottom: "*px",
61
+ right: "*px",
62
+ width: "*px",
63
+ height: "*px",
64
+ minWidth: "*px",
65
+ minHeight: "*px",
66
+ maxWidth: "*px",
67
+ maxHeight: "*px",
68
+ padding: "*px",
69
+ margin: "*px",
70
+ borderRadius: "*%",
71
+ borderWidth: "*px",
72
+ borderTopWidth: "*px",
73
+ borderRightWidth: "*px",
74
+ borderBottomWidth: "*px",
75
+ borderLeftWidth: "*px",
76
+ borderImageWidth: "*px",
77
+ strokeWidth: "*px",
78
+ strokeHeight: "*px",
79
+ strokeOpacity: "*",
80
+ opacity: "*",
81
+ translateX: "translateX(*px)",
82
+ translateY: "translateY(*px)",
83
+ translateZ: "translateZ(*px)",
84
+ rotateX: "rotateX(*deg)",
85
+ rotateY: "rotateY(*deg)",
86
+ rotateZ: "rotateZ(*deg)",
87
+ scale: "scale(*)",
88
+ scaleX: "scaleX(*)",
89
+ scaleY: "scaleY(*)",
90
+ skewX: "skewX(*deg)",
91
+ skewY: "skewY(*deg)",
92
+ rgbR: "rgba(*,",
93
+ rgbG: "*,",
94
+ rgbB: "*,",
95
+ rgba: "rgba(rgbR,rgbG,rgbB,rgbA)"
40
96
  };
41
- }
42
-
43
- /* -------------------------------------------------
44
- Default color properties used for color transformations
45
- ------------------------------------------------- */
46
- const defaultColorProps = {
47
- red: 255,
48
- green: 255,
49
- blue: 255,
50
- alpha: 1
51
- };
52
-
53
- const colorProperties = {
54
- color: defaultColorProps,
55
- background: defaultColorProps,
56
- backgroundColor: defaultColorProps,
57
- borderColor: defaultColorProps
58
- };
59
-
60
- /* -------------------------------------------------
61
- Map of CSS property placeholders for transformations
62
- ------------------------------------------------- */
63
- const styleMap = {
64
- zIndex: "*",
65
- left: "*px",
66
- top: "*px",
67
- bottom: "*px",
68
- right: "*px",
69
- width: "*px",
70
- height: "*px",
71
- minWidth: "*px",
72
- minHeight: "*px",
73
- maxWidth: "*px",
74
- maxHeight: "*px",
75
- padding: "*px",
76
- margin: "*px",
77
- borderRadius: "*%",
78
- borderWidth: "*px",
79
- borderTopWidth: "*px",
80
- borderRightWidth: "*px",
81
- borderBottomWidth: "*px",
82
- borderLeftWidth: "*px",
83
- borderImageWidth: "*px",
84
- strokeWidth: "*px",
85
- strokeHeight: "*px",
86
- strokeOpacity: "*",
87
- opacity: "*",
88
- translateX: "translateX(*px)",
89
- translateY: "translateY(*px)",
90
- translateZ: "translateZ(*px)",
91
- rotateX: "rotateX(*deg)",
92
- rotateY: "rotateY(*deg)",
93
- rotateZ: "rotateZ(*deg)",
94
- scale: "scale(*)",
95
- scaleX: "scaleX(*)",
96
- scaleY: "scaleY(*)",
97
- skewX: "skewX(*deg)",
98
- skewY: "skewY(*deg)",
99
- rgbR: "rgba(*,",
100
- rgbG: "*,",
101
- rgbB: "*,",
102
- rgba: "rgba(rgbR,rgbG,rgbB,rgbA)" // Final RGBA string placeholder
103
- };
104
-
105
- /* -------------------------------------------------
106
- Utility function: Select DOM elements matching multiple selectors
107
- ------------------------------------------------- */
108
- global.selectDom = function (...selectors) {
109
- let elements = [];
110
- selectors.forEach((selector) => {
111
- const nodeList = document.querySelectorAll(selector);
112
- elements.push(...nodeList);
113
- });
114
- return elements;
115
- };
116
-
117
- /* -------------------------------------------------
118
- Core Animation Engine
119
- Accepts a flexible set of arguments defining animations
120
- Returns a function to initiate the animation
121
- ------------------------------------------------- */
122
- global.animate = function () {
123
- // Clone arguments for internal manipulation
124
- const args = Array.prototype.slice.call(arguments);
125
- const argsCopy = copyObject(args);
126
-
127
- // Return a function that executes the animation on given elements
128
- return function (elements, eventConfig, nextArgs) {
129
- let targetElements = [];
130
- let tempArgs = argsCopy;
131
-
132
- // Initialize variables for animation
133
- let currentTarget, fromValues, toValues, elementIndex, delay, animationDescriptor;
134
- let isNextGroup = false; // Flag for chaining groups of elements
135
- const animationData = {
136
- color: {},
137
- transform: {},
138
- from: {},
139
- to: {}
140
- };
141
-
142
- // Parse and prepare arguments
143
- parseArguments();
144
-
145
- /**
146
- * Parses the passed arguments to identify target elements,
147
- * animation descriptors, and setup necessary data structures.
148
- */
149
- function parseArguments() {
150
- if (elements !== undefined) {
151
- if (!Array.isArray(elements)) {
152
- elements = [elements];
153
- }
154
- targetElements = elements;
155
- }
156
97
 
157
- let secondLoopFlag = false;
158
- for (let index = 0, totalArgs = args.length; index < totalArgs; index++) {
159
- fromValues = 0;
160
- // Detect "next group" of elements for chaining
161
- if (isNextGroup || Array.isArray(argsCopy[index]) || isDOMElement(argsCopy[index])) {
162
- if (secondLoopFlag) {
163
- if (!Array.isArray(argsCopy[index])) {
164
- argsCopy[index] = [argsCopy[index]];
165
- }
166
- Array.prototype.push.apply(targetElements, argsCopy[index]);
167
- }
168
- isNextGroup = false;
169
- } else if (typeof argsCopy[index] === "object" && argsCopy[index] !== null) {
170
- if (secondLoopFlag) {
171
- // Handle second pass: resolve non-numeric values and callbacks
172
- if (index === 0) {
173
- for (let u = 0; u < elements.length; u++) {
174
- if (typeof elements[u] !== "number") targetElements.push(elements[u]);
98
+ // -----------------------------
99
+ // select: simple DOM selector utility
100
+ // Returns flat array of matched elements given one or more selectors
101
+ // Usage: select('.class', '#id')
102
+ // -----------------------------
103
+ const selectDom = function(...selectors) {
104
+ const all = [];
105
+ selectors.forEach(selector => {
106
+ const nodeList = document.querySelectorAll(selector);
107
+ all.push(...nodeList);
108
+ });
109
+ return all;
110
+ };
111
+
112
+ // -----------------------------
113
+ // animate: animation factory
114
+ // Accepts animation definitions and returns a runner function to start animations on targets.
115
+ // -----------------------------
116
+ const animate = function () {
117
+ const definitions = arguments;
118
+ const defsCopy = copyObj(definitions);
119
+
120
+ return function (targets, primaryParam, runtimeContext) {
121
+ let currentTargets, eventCheckResult, tmp, i, propIndex, fromItem, toItem, valFrom, valTo, t;
122
+ let grouped = [];
123
+ let runtimeGrouped = [];
124
+ let expectNextGroup = false;
125
+ let staging = { color: {}, transform: {}, from: {}, to: {} };
126
+
127
+ buildPlan();
128
+
129
+ function buildPlan() {
130
+ if (targets !== undefined) {
131
+ if (!Array.isArray(targets)) targets = [targets];
132
+ runtimeGrouped = targets;
175
133
  }
176
- }
177
- if (elements !== undefined) {
178
- for (let j = 0; j < targetElements.length; j++) {
179
- if (typeof targetElements[j] !== "number") {
180
- // Check for event-based callback
181
- let eventResult = checkEventValue(nextArgs, eventConfig, currentTarget, targetElements[j + 1]);
182
- if (eventResult[0]) eventConfig = eventResult[0];
183
- bindEvent(targetElements[j], getObjectAt(targetElements, args, argsCopy, index), eventResult[1]);
184
- }
134
+
135
+ let secondPass = false;
136
+
137
+ for (let c = 0, total = definitions.length; c < total; c++) {
138
+ propIndex = 0;
139
+ if (expectNextGroup || Array.isArray(defsCopy[c]) || isElement(defsCopy[c])) {
140
+ if (secondPass) {
141
+ Array.isArray(defsCopy[c]) || (defsCopy[c] = [defsCopy[c]]);
142
+ Array.prototype.push.apply(grouped, defsCopy[c]);
143
+ }
144
+ expectNextGroup = false;
145
+ } else if (typeof defsCopy[c] === 'object' && defsCopy[c] !== null) {
146
+ if (secondPass) {
147
+ if (c === 0) {
148
+ for (let u = 0; void 0 !== targets[u]; u++) {
149
+ if (typeof targets[u] !== "number") grouped.push(targets[u]);
150
+ }
151
+ }
152
+ if (targets !== undefined) {
153
+ for (let j = 0; void 0 !== runtimeGrouped[j]; j++) {
154
+ if (typeof runtimeGrouped[j] !== "number") {
155
+ eventCheckResult = checkValEvent(runtimeContext, primaryParam, currentTargets, runtimeGrouped[j + 1]);
156
+ if (eventCheckResult[0]) currentTargets = eventCheckResult[0];
157
+ bindEvent(runtimeGrouped[j], runner(grouped, definitions, defsCopy, c), eventCheckResult[1]);
158
+ }
159
+ }
160
+ } else {
161
+ runner(grouped, definitions, defsCopy, c)();
162
+ }
163
+ } else {
164
+ expectNextGroup = false;
165
+ const fromIsObject = typeof defsCopy[c].from === "object";
166
+ const toIsObject = typeof defsCopy[c].to === "object";
167
+
168
+ if (defsCopy[c].typeAnimation === "vibration" && defsCopy[c].vibrationStep === undefined) {
169
+ defsCopy[c].vibrationStep = 6;
170
+ } else {
171
+ t = getNumber(defsCopy[c].typeAnimation);
172
+ if (t && t.length === 4) {
173
+ defsCopy[c].cubicbezier = t;
174
+ defsCopy[c].typeAnimation = "cubicbezier";
175
+ }
176
+ }
177
+
178
+ if (defsCopy[c].boucle && defsCopy[c].boucleType === undefined) {
179
+ defsCopy[c].boucleType = "return";
180
+ }
181
+
182
+ if (!defsCopy[c].callback &&
183
+ (Array.isArray(defsCopy[c].property) || (defsCopy[c].property !== undefined && (defsCopy[c].property = [defsCopy[c].property])))) {
184
+
185
+ defsCopy[c].property.forEach(function (propItem) {
186
+ if (!fromIsObject) valFrom = defsCopy[c].from;
187
+ else fromItem = defsCopy[c]["from"][propIndex];
188
+
189
+ if (!toIsObject) valTo = defsCopy[c].to;
190
+ else toItem = defsCopy[c]["to"][propIndex];
191
+
192
+ if (typeof propItem === "object") {
193
+ let propName = Object.keys(propItem)[0];
194
+ if (!Array.isArray(propItem[propName])) propItem[propName] = [propItem[propName]];
195
+
196
+ if ((propName.toLowerCase().indexOf("color") !== -1 && (staging.color[propName] = COLOR_PROPERTIES[propName])) ||
197
+ propName.toLowerCase().indexOf("transform") !== -1) {
198
+
199
+ let inner = 0;
200
+ staging["from"][propName] = {};
201
+ staging["to"][propName] = {};
202
+
203
+ propItem[propName].forEach(function (innerProp) {
204
+ if (propName.toLowerCase() === "transform") staging[propName][innerProp] = 0;
205
+ else staging.color[propName][innerProp] = 0;
206
+
207
+ if (fromIsObject) {
208
+ if (fromItem[propName] !== undefined) {
209
+ if (typeof fromItem[propName] === "number") {
210
+ valFrom = staging["from"][propName][innerProp] = fromItem[propName];
211
+ } else if (Array.isArray(fromItem[propName])) {
212
+ valFrom = staging["from"][propName][innerProp] = fromItem[propName][inner] !== undefined ? fromItem[propName][inner] : valFrom;
213
+ } else if (fromItem[propName][innerProp] !== undefined) {
214
+ valFrom = staging["from"][propName][innerProp] = fromItem[propName][innerProp];
215
+ }
216
+ } else {
217
+ staging["from"][propName][innerProp] = valFrom;
218
+ }
219
+ } else {
220
+ staging["from"][propName][innerProp] = defsCopy[c].from;
221
+ }
222
+
223
+ if (toIsObject) {
224
+ if (toItem[propName] !== undefined) {
225
+ if (typeof toItem[propName] === "number") {
226
+ valTo = staging["to"][propName][innerProp] = toItem[propName];
227
+ } else if (Array.isArray(toItem[propName])) {
228
+ valTo = staging["to"][propName][innerProp] = toItem[propName][inner] !== undefined ? toItem[propName][inner] : valTo;
229
+ } else if (toItem[propName][innerProp] !== undefined) {
230
+ valTo = staging["to"][propName][innerProp] = toItem[propName][innerProp];
231
+ }
232
+ } else {
233
+ staging["to"][propName][innerProp] = valTo;
234
+ }
235
+ } else {
236
+ staging["to"][propName][innerProp] = defsCopy[c].to;
237
+ }
238
+ inner++;
239
+ });
240
+ propIndex++;
241
+ }
242
+ } else {
243
+ if (fromIsObject) {
244
+ valFrom = staging["from"][propItem] = fromItem[propItem] !== undefined ? fromItem[propItem] : (fromItem !== undefined ? fromItem : valFrom);
245
+ } else {
246
+ staging["from"][propItem] = defsCopy[c].from;
247
+ }
248
+
249
+ if (toIsObject) {
250
+ valTo = staging["to"][propItem] = toItem[propItem] !== undefined ? toItem[propItem] : (toItem !== undefined ? toItem : valTo);
251
+ } else {
252
+ staging["to"][propItem] = defsCopy[c].to;
253
+ }
254
+ propIndex++;
255
+ }
256
+ });
257
+ }
258
+ defsCopy[c].storeValueAnim = copyObj(staging);
259
+ staging = { color: {}, transform: {}, from: {}, to: {} };
260
+ }
261
+ if (definitions[c + 1] !== undefined && (Array.isArray(definitions[c + 1]) || isElement(definitions[c + 1]))) {
262
+ expectNextGroup = true;
263
+ grouped = [];
264
+ }
265
+ }
266
+ if (c === total - 1 && !secondPass) {
267
+ expectNextGroup = false;
268
+ secondPass = true;
269
+ c = -1;
270
+ }
185
271
  }
186
- } else {
187
- executeChain(targetElements, args, argsCopy, index)();
188
- }
189
- } else {
190
- isNextGroup = false;
191
- // Handle from/to objects for color and transform properties
192
- const isFromObject = typeof argsCopy[index].from === "object";
193
- const isToObject = typeof argsCopy[index].to === "object";
194
-
195
- // Handle special animation types
196
- if (argsCopy[index].typeAnimation === "vibration" && argsCopy[index].vibrationStep === undefined) {
197
- argsCopy[index].vibrationStep = 6;
198
- } else {
199
- const bezierParams = getNumberFromString(argsCopy[index].typeAnimation);
200
- if (bezierParams && bezierParams.length === 4) {
201
- argsCopy[index].cubicbezier = bezierParams;
202
- argsCopy[index].typeAnimation = "cubicbezier";
272
+ }
273
+
274
+ function runner(group, defs, defsCopyLocal, configIndex) {
275
+ const conf = defs[configIndex];
276
+ const declaredAnim = defsCopyLocal[configIndex].typeAnimation;
277
+ let alternateAnim = declaredAnim;
278
+
279
+ conf.timeline = !isNaN(Number(conf.timeline)) ? Number(conf.timeline) : 0;
280
+ conf.startafter = !isNaN(Number(conf.startafter)) ? Number(conf.startafter) : 0;
281
+
282
+ if (conf.boucle) {
283
+ conf.delay = !isNaN(Number(conf.delay)) ? Number(conf.delay) : undefined;
284
+ if (conf.boucleType === "returnRepeat" || conf.boucleType === "repeatReturn") {
285
+ alternateAnim = Easing[declaredAnim][1];
286
+ }
203
287
  }
204
- }
205
-
206
- // Default loop behavior
207
- if (argsCopy[index].loop && argsCopy[index].loopType === undefined) {
208
- argsCopy[index].loopType = "return";
209
- }
210
-
211
- // Normalize property list
212
- if (
213
- !argsCopy[index].callback &&
214
- (Array.isArray(argsCopy[index].property) ||
215
- (argsCopy[index].property !== undefined && (argsCopy[index].property = [argsCopy[index].property])))
216
- ) {
217
- argsCopy[index].property.forEach(function (propertyItem) {
218
- // Resolve from/to values per property
219
- if (!isFromObject) fromValues = argsCopy[index].from;
220
- else fromY = argsCopy[index]["from"][elementIndex];
221
-
222
- if (!isToObject) toValues = argsCopy[index].to;
223
- else toY = argsCopy[index]["to"][elementIndex];
224
-
225
- if (typeof propertyItem === "object") {
226
- // Handle property objects like { transform: ["scaleX", "rotateZ"] }
227
- const propertyKey = Object.keys(propertyItem)[0];
228
- if (!Array.isArray(propertyItem[propertyKey])) {
229
- propertyItem[propertyKey] = [propertyItem[propertyKey]];
288
+
289
+ return function run(indexArg) {
290
+ let pausedAccum = 0;
291
+ let isPaused = false;
292
+ let pauseStart;
293
+
294
+ if (conf.pause && Array.isArray(conf.pause)) {
295
+ const eventCfg = conf.pause[1] || "e:click|false";
296
+ const parts = eventCfg.replace('e:', '').split('|');
297
+ const eventName = parts[0];
298
+ const useCapture = parts[1] === 'true';
299
+
300
+ const togglePause = function (e) {
301
+ if (e) {
302
+ if (isPaused) {
303
+ isPaused = false;
304
+ pausedAccum += Date.now() - pauseStart;
305
+ } else {
306
+ isPaused = true;
307
+ pauseStart = Date.now();
308
+ }
309
+ }
310
+ };
311
+
312
+ const targetEls = document.querySelectorAll(conf.pause[0]);
313
+ targetEls.forEach(el => el.addEventListener(eventName, togglePause, useCapture));
230
314
  }
231
315
 
232
- if (
233
- propertyKey.toLowerCase().includes("color") &&
234
- (animationData.color[propertyKey] = colorProperties[propertyKey])
235
- ) {
236
- // Initialize color properties
237
- fromValues["from"][propertyKey] = {};
238
- toValues["to"][propertyKey] = {};
239
-
240
- propertyItem[propertyKey].forEach(function (subProp) {
241
- // Initialize sub-properties
242
- if (propertyKey.toLowerCase() === "transform") {
243
- animationData.transform[subProp] = 0;
316
+ const startedAt = Date.now();
317
+
318
+ group.forEach(function (el, idx) {
319
+ if (!el.storeTransform) el.storeTransform = copyObj(defsCopyLocal[configIndex].storeValueAnim.transform);
320
+ if (!el.storeColor) {
321
+ el.storeColor = copyObj(defsCopyLocal[configIndex].storeValueAnim.color);
244
322
  } else {
245
- animationData.color[propertyKey][subProp] = 0;
323
+ Object.keys(defsCopyLocal[configIndex].storeValueAnim.color).forEach(key => {
324
+ if (!el.storeColor[key]) el.storeColor[key] = defsCopyLocal[configIndex].storeValueAnim.color[key];
325
+ });
246
326
  }
247
327
 
248
- // Populate from-values
249
- if (isFromObject) {
250
- if (fromY[propertyKey] !== undefined) {
251
- if (typeof fromY[propertyKey] === "number") {
252
- fromValues["from"][propertyKey][subProp] = fromY[propertyKey];
253
- } else if (Array.isArray(fromY[propertyKey])) {
254
- fromValues["from"][propertyKey][subProp] = fromY[propertyKey][elementIndex] !== undefined ? fromY[propertyKey][elementIndex] : fromValues["from"][propertyKey][subProp];
255
- } else if (fromY[propertyKey][subProp] !== undefined) {
256
- fromValues["from"][propertyKey][subProp] = fromY[propertyKey][subProp];
257
- }
258
- } else {
259
- fromValues["from"][propertyKey][subProp] = argsCopy[index].from;
260
- }
261
- } else {
262
- fromValues["from"][propertyKey][subProp] = argsCopy[index].from;
328
+ if (conf.timeline !== 0) {
329
+ frameRunner([el], idx, conf.timeline * idx + conf.startafter, conf.startafter);
263
330
  }
331
+ });
332
+
333
+ if (conf.timeline === 0) {
334
+ frameRunner(group, 0, 0 + conf.startafter, conf.startafter);
335
+ }
336
+
337
+ function frameRunner(targetArray, idx, timeOffset, startAfter) {
338
+ if (conf.animFram) cancelAnimationFrame(conf.animFram[idx]);
339
+ else conf.animFram = {};
340
+
341
+ const iterConf = copyObj(defsCopyLocal[configIndex]);
342
+ iterConf.changetypeAnim = iterConf.typeAnimation;
343
+ iterConf.countSkip = 0;
344
+ iterConf.countSkip2 = 0;
345
+
346
+ let skipCounter;
347
+ const sv = iterConf.storeValueAnim;
264
348
 
265
- // Populate to-values
266
- if (isToObject) {
267
- if (toY[propertyKey] !== undefined) {
268
- if (typeof toY[propertyKey] === "number") {
269
- toValues["to"][propertyKey][subProp] = toY[propertyKey];
270
- } else if (Array.isArray(toY[propertyKey])) {
271
- toValues["to"][propertyKey][subProp] = toY[propertyKey][elementIndex] !== undefined ? toY[propertyKey][elementIndex] : toValues["to"][propertyKey][subProp];
272
- } else if (toY[propertyKey][subProp] !== undefined) {
273
- toValues["to"][propertyKey][subProp] = toY[propertyKey][subProp];
349
+ function loop() {
350
+ if (isPaused) {
351
+ conf.animFram[idx] = requestAnimationFrame(loop);
352
+ return;
353
+ }
354
+
355
+ let delay = 0;
356
+ let eased, tmpVal, css;
357
+ const elapsed = Date.now() - (startedAt + timeOffset + pausedAccum);
358
+
359
+ if (elapsed >= 0) {
360
+ if (iterConf.boucle) {
361
+ if (iterConf.delay !== undefined) {
362
+ delay = iterConf.delay;
363
+ skipCounter = Math.floor((elapsed + delay) / (iterConf.duration + delay));
364
+ if (skipCounter !== iterConf.countSkip) {
365
+ iterConf.countSkip = skipCounter;
366
+ iterConf.skip = iterConf.skipDelay = true;
367
+ } else {
368
+ iterConf.skip = false;
369
+ if (elapsed % (iterConf.duration + delay) < iterConf.duration) {
370
+ iterConf.skipDelay = false;
371
+ if (iterConf.countSkip2 !== iterConf.countSkip) {
372
+ iterConf.countSkip2 = iterConf.countSkip;
373
+ iterConf.skip2 = true;
374
+ } else iterConf.skip2 = false;
375
+ }
376
+ }
377
+ } else {
378
+ skipCounter = Math.floor((elapsed + delay) / (iterConf.duration + delay));
379
+ if (skipCounter !== iterConf.countSkip) {
380
+ iterConf.countSkip = iterConf.countSkip2 = skipCounter;
381
+ iterConf.skip = iterConf.skip2 = true;
382
+ } else {
383
+ iterConf.skip = iterConf.skip2 = false;
384
+ }
385
+ }
386
+
387
+ iterConf.timeEasing = elapsed % (iterConf.duration + delay);
388
+ if (iterConf.skip) {
389
+ iterConf.impair = !iterConf.impair;
390
+ iterConf.changetypeAnim = iterConf.impair ? alternateAnim : declaredAnim;
391
+ iterConf.timeEasing = (iterConf.impair || iterConf.boucleType.indexOf("repeat") === 0) ? iterConf.duration : 0;
392
+ } else if (!iterConf.skipDelay) {
393
+ if (iterConf.impair && iterConf.boucleType.indexOf("return") === 0) {
394
+ iterConf.timeEasing = iterConf.duration - iterConf.timeEasing;
395
+ }
396
+ }
397
+ } else {
398
+ iterConf.timeEasing = elapsed < iterConf.duration ? elapsed : iterConf.duration;
399
+ }
400
+
401
+ if (!iterConf.skipDelay || iterConf.skip) {
402
+ eased = Easing[iterConf.changetypeAnim][0](iterConf.timeEasing, 0, 1, iterConf.duration, iterConf, idx);
403
+
404
+ if (iterConf.callback) {
405
+ targetArray.forEach(function (el, index) {
406
+ iterConf.callback(el, eased, iterConf, idx !== index ? idx : index);
407
+ });
408
+ } else {
409
+ iterConf.property.forEach(function (prop) {
410
+ css = "";
411
+ let key = typeof prop === "string" ? prop : Object.keys(prop)[0];
412
+
413
+ if (key.toLowerCase() === "transform" && sv[key] != null) {
414
+ prop.transform.forEach(function (tr) {
415
+ tmpVal = sv["from"][key][tr] + eased * (sv["to"][key][tr] - sv["from"][key][tr]);
416
+ targetArray.forEach(el => el.storeTransform[tr] = tmpVal);
417
+ });
418
+ targetArray.forEach(function (el) {
419
+ Object.keys(el.storeTransform).forEach(k => {
420
+ css += " " + PROPERTY_FORMAT_MAP[k].replace("*", el.storeTransform[k]);
421
+ });
422
+ el.style.transform = css;
423
+ css = "";
424
+ });
425
+ } else if (key.toLowerCase().indexOf("color") !== -1 && sv.color != null) {
426
+ targetArray.forEach(function (el) {
427
+ prop[key].forEach(function (colProp) {
428
+ tmpVal = sv["from"][key][colProp] + eased * (sv["to"][key][colProp] - sv["from"][key][colProp]);
429
+ el.storeColor[key][colProp] = tmpVal;
430
+ });
431
+
432
+ let colorStr = PROPERTY_FORMAT_MAP.rgba;
433
+ for (let colKey in COLOR_DEFAULTS) {
434
+ colorStr = colorStr.replace(new RegExp(colKey, "g"), el.storeColor[key][colKey]);
435
+ }
436
+ el.style[key] = colorStr;
437
+ });
438
+ } else {
439
+ css = (iterConf.px === "%" ? PROPERTY_FORMAT_MAP[key].replace("px", "%") : PROPERTY_FORMAT_MAP[key]).replace("*", sv["from"][key] + eased * (sv["to"][key] - sv["from"][key]));
440
+ targetArray.forEach(el => el.style[key] = css);
441
+ }
442
+ });
443
+ }
444
+ }
445
+ }
446
+
447
+ if (iterConf.boucle || elapsed < iterConf.duration) {
448
+ conf.animFram[idx] = requestAnimationFrame(loop);
274
449
  }
275
- } else {
276
- toValues["to"][propertyKey][subProp] = argsCopy[index].to;
277
- }
278
- } else {
279
- toValues["to"][propertyKey][subProp] = argsCopy[index].to;
280
450
  }
281
- elementIndex++;
282
- });
283
- elementIndex++;
284
- y++;
285
- }
286
- } else {
287
- // Handle simple properties like "opacity"
288
- if (isFromObject) {
289
- fromValues["from"][propertyItem] = fromY[propertyItem] !== undefined ? fromY[propertyItem] : fromY !== undefined ? fromY : fromValues["from"][propertyItem];
290
- } else {
291
- fromValues["from"][propertyItem] = argsCopy[index].from;
292
- }
293
- if (isToObject) {
294
- toValues["to"][propertyItem] = toY[propertyItem] !== undefined ? toY[propertyItem] : toY !== undefined ? toY : toValues["to"][propertyItem];
295
- } else {
296
- toValues["to"][propertyItem] = argsCopy[index].to;
451
+
452
+ loop();
297
453
  }
298
- y++;
299
- }
300
- });
301
- }
302
-
303
- // Save deep copy of the animation values for future reference
304
- argsCopy[index].storedAnimationValues = copyObject(animationData);
305
- // Reset animation data for next iteration
306
- animationData.color = {};
307
- animationData.transform = {};
308
- animationData.from = {};
309
- animationData.to = {};
454
+ };
310
455
  }
456
+ };
457
+ };
311
458
 
312
- // Detect if next argument is a list of elements for chaining
313
- if (
314
- args[index + 1] !== undefined &&
315
- (Array.isArray(args[index + 1]) || isDOMElement(args[index + 1]))
316
- ) {
317
- isNextGroup = true;
318
- targetElements = [];
459
+ // -----------------------------
460
+ // Easing functions
461
+ // Standard easing definitions used by the animation engine.
462
+ // -----------------------------
463
+ const Easing = {
464
+ linear: [function(e, n, t, a) {
465
+ return t * e / a + n
466
+ }, "linear"],
467
+ quadin: [function(e, n, t, a) {
468
+ return t * (e /= a) * e + n
469
+ }, "quadout"],
470
+ quadout: [function(e, n, t, a) {
471
+ return -t * (e /= a) * (e - 2) + n
472
+ }, "quadin"],
473
+ quadinout: [function(e, n, t, a) {
474
+ return (e /= a / 2) < 1 ? t / 2 * e * e + n : -t / 2 * (--e * (e - 2) - 1) + n
475
+ }, "quadoutin"],
476
+ quadoutin: [function(e, n, t, a) {
477
+ var p = e / a,
478
+ p0;
479
+ if (p < 0.5) {
480
+ p0 = 1 - 2 * p;
481
+ return t * (0.5 * (1 - (p0 * p0))) + n;
482
+ } else {
483
+ p0 = p * 2 - 1;
484
+ return t * (0.5 * (p0 * p0) + 0.5) + n;
319
485
  }
320
- }
321
-
322
- // Restart loop for second pass if needed
323
- if (index === totalArgs - 1 && !secondLoopFlag) {
324
- isNextGroup = false;
325
- secondLoopFlag = true;
326
- index = -1; // restart loop
327
- }
328
- }
329
- }
330
-
331
- /**
332
- * Helper to execute a specific animation descriptor on a set of elements.
333
- * Returns a function that runs the animation.
334
- */
335
- function executeChain(targets, timelineSpecs, descriptorSpecs, descriptorIndex) {
336
- const descriptor = timelineSpecs[descriptorIndex];
337
- const animationType = descriptorSpecs[descriptorIndex].typeAnimation;
338
- let currentAnimationType = animationType;
339
-
340
- // Normalize timing properties
341
- descriptor.timeline = !isNaN(Number(descriptor.timeline)) ? Number(descriptor.timeline) : 0;
342
- descriptor.startafter = !isNaN(Number(descriptor.startafter)) ? Number(descriptor.startafter) : 0;
343
-
344
- // Handle looping specifics
345
- if (descriptor.boucle) {
346
- descriptor.delay = !isNaN(Number(descriptor.delay)) ? Number(descriptor.delay) : undefined;
347
- if (descriptor.boucleType === "returnRepeat" || descriptor.boucleType === "repeatReturn") {
348
- // Use reverse easing for looping
349
- currentAnimationType = Easing[animationType][1];
350
- }
351
- }
352
-
353
- // Return the animation runner function
354
- return function runAnimation() {
355
- let pauseStartTime = 0;
356
- let isPaused = false;
357
- let pauseTimestamp;
358
-
359
- // Setup pause/resume based on user events if specified
360
- if (descriptor.pause && Array.isArray(descriptor.pause)) {
361
- const [eventSelector, eventOptions] = descriptor.pause;
362
- const [eventName, useCaptureFlag] = (eventOptions || "e:click|false").split('|');
363
- const capture = useCaptureFlag === 'true';
364
-
365
- // Toggle pause/resume on specified event
366
- const togglePause = () => {
367
- if (isPaused) {
368
- isPaused = false;
369
- descriptor.pausedDuration += Date.now() - pauseTimestamp;
370
- } else {
371
- isPaused = true;
372
- pauseTimestamp = Date.now();
373
- }
374
- };
375
-
376
- // Attach event listeners to target elements
377
- document.querySelectorAll(eventSelector).forEach((el) => {
378
- el.addEventListener(eventName, togglePause, capture);
379
- });
380
- }
381
-
382
- const startTime = Date.now();
383
-
384
- // Initialize per-element stored states for transforms and colors
385
- targets.forEach((element, index) => {
386
- if (!element.storedTransform) element.storedTransform = copyObject(descriptorSpecs[descriptorIndex].storedAnimationValues.transform);
387
- if (!element.storedColor) {
388
- element.storedColor = copyObject(descriptorSpecs[descriptorIndex].storedAnimationValues.color);
486
+ }, "quadinout"],
487
+ cubicin: [function(e, n, t, a) {
488
+ return t * (e /= a) * e * e + n
489
+ }, "cubicout"],
490
+ cubicout: [function(e, n, t, a) {
491
+ return t * ((e = e / a - 1) * e * e + 1) + n
492
+ }, "cubicin"],
493
+ cubicinout: [function(e, n, t, a) {
494
+ return (e /= a / 2) < 1 ? t / 2 * e * e * e + n : t / 2 * ((e -= 2) * e * e + 2) + n
495
+ }, "cubicoutin"],
496
+ cubicoutin: [function(e, n, t, a) {
497
+ var p = e / a,
498
+ p0;
499
+ if (p < 0.5) {
500
+ p0 = 1 - 2 * p;
501
+ return t * (0.5 * (1 - (p0 * p0 * p0))) + n;
502
+ } else {
503
+ p0 = p * 2 - 1;
504
+ return t * (0.5 * (p0 * p0 * p0) + 0.5) + n;
505
+ }
506
+ }, "cubicinout"],
507
+ quartin: [function(e, n, t, a) {
508
+ return t * (e /= a) * e * e * e + n
509
+ }, "quartout"],
510
+ quartout: [function(e, n, t, a) {
511
+ return -t * ((e = e / a - 1) * e * e * e - 1) + n
512
+ }, "quartin"],
513
+ quartinout: [function(e, n, t, a) {
514
+ return (e /= a / 2) < 1 ? t / 2 * e * e * e * e + n : -t / 2 * ((e -= 2) * e * e * e - 2) + n
515
+ }, "quartoutin"],
516
+ quartoutin: [function(e, n, t, a) {
517
+ var p = e / a,
518
+ p0;
519
+ if (p < 0.5) {
520
+ p0 = 1 - 2 * p;
521
+ return t * (0.5 * (1 - (p0 * p0 * p0 * p0))) + n;
522
+ } else {
523
+ p0 = p * 2 - 1;
524
+ return t * (0.5 * (p0 * p0 * p0 * p0) + 0.5) + n;
525
+ }
526
+ }, "quartinout"],
527
+ quintin: [function(e, n, t, a) {
528
+ return t * (e /= a) * e * e * e * e + n
529
+ }, "quintout"],
530
+ quintout: [function(e, n, t, a) {
531
+ return t * ((e = e / a - 1) * e * e * e * e + 1) + n
532
+ }, "quintin"],
533
+ quintinout: [function(e, n, t, a) {
534
+ return (e /= a / 2) < 1 ? t / 2 * e * e * e * e * e + n : t / 2 * ((e -= 2) * e * e * e * e + 2) + n
535
+ }, "quintoutin"],
536
+ quintoutin: [function(e, n, t, a) {
537
+ var p = e / a,
538
+ p0;
539
+ if (p < 0.5) {
540
+ p0 = 1 - 2 * p;
541
+ return t * (0.5 * (1 - (p0 * p0 * p0 * p0 * p0))) + n;
389
542
  } else {
390
- // Preserve previously stored color properties
391
- Object.keys(descriptorSpecs[descriptorIndex].storedAnimationValues.color).forEach((key) => {
392
- if (!element.storedColor[key]) element.storedColor[key] = descriptorSpecs[descriptorIndex].storedAnimationValues.color[key];
393
- });
543
+ p0 = p * 2 - 1;
544
+ return t * (0.5 * (p0 * p0 * p0 * p0 * p0) + 0.5) + n;
545
+ }
546
+ }, "quintinout"],
547
+ sinein: [function(e, n, t, a) {
548
+ return -t * Math.cos(e / a * (Math.PI / 2)) + t + n
549
+ }, "sineout"],
550
+ sineout: [function(e, n, t, a) {
551
+ return t * Math.sin(e / a * (Math.PI / 2)) + n
552
+ }, "sinein"],
553
+ sineinout: [function(e, n, t, a) {
554
+ return -t / 2 * (Math.cos(Math.PI * e / a) - 1) + n
555
+ }, "sineoutin"],
556
+ sineoutin: [function(e, n, t, a) {
557
+ var p = e / a,
558
+ p0;
559
+ if (p < 0.5) {
560
+ p0 = 1 - 2 * p;
561
+ return t * (0.5 * (1 - (1 - Math.cos(p0 * Math.PI / 2)))) + n;
562
+ } else {
563
+ p0 = p * 2 - 1;
564
+ return t * (0.5 * (1 - Math.cos(p0 * Math.PI / 2)) + 0.5) + n;
565
+ }
566
+ }, "sineinout"],
567
+ expoin: [function(e, n, t, a) {
568
+ return 0 == e ? n : t * Math.pow(2, 10 * (e / a - 1)) + n
569
+ }, "expoout"],
570
+ expoout: [function(e, n, t, a) {
571
+ return e == a ? n + t : t * (1 - Math.pow(2, -10 * e / a)) + n
572
+ }, "expoin"],
573
+ expoinout: [function(e, n, t, a) {
574
+ return 0 == e ? n : e == a ? n + t : (e /= a / 2) < 1 ? t / 2 * Math.pow(2, 10 * (e - 1)) + n : t / 2 * (2 - Math.pow(2, -10 * --e)) + n
575
+ }, "expooutin"],
576
+ expooutin: [function(e, n, t, a) {
577
+ var p = e / a,
578
+ p0;
579
+ if (p == 0) {
580
+ return n;
581
+ } else if (p == 1) {
582
+ return n + t;
583
+ } else
584
+ if (p < 0.5) {
585
+ p0 = 1 - 2 * p;
586
+ return t * (0.5 * (1 - (Math.pow(2, 10 * (p0 - 1))))) + n;
587
+ } else {
588
+ p0 = p * 2 - 1;
589
+ return t * (0.5 * (Math.pow(2, 10 * (p0 - 1))) + 0.5) + n;
590
+ }
591
+ }, "expoinout"],
592
+ circin: [function(e, n, t, a) {
593
+ return -t * (Math.sqrt(1 - (e /= a) * e) - 1) + n
594
+ }, "circout"],
595
+ circout: [function(e, n, t, a) {
596
+ return t * Math.sqrt(1 - (e = e / a - 1) * e) + n
597
+ }, "circin"],
598
+ circinout: [function(e, n, t, a) {
599
+ return (e /= a / 2) < 1 ? -t / 2 * (Math.sqrt(1 - e * e) - 1) + n : t / 2 * (Math.sqrt(1 - (e -= 2) * e) + 1) + n
600
+ }, "circoutin"],
601
+ circoutin: [function(e, n, t, a) {
602
+ var p = e / a,
603
+ p0;
604
+ if (p < 0.5) {
605
+ p0 = 1 - 2 * p;
606
+ return t * (0.5 * Math.sqrt(1 - p0 * p0)) + n;
607
+ } else {
608
+ p0 = p * 2 - 1;
609
+ return t * (0.5 * (1 - Math.sqrt(1 - p0 * p0)) + 0.5) + n;
610
+ }
611
+ }, "circinout"],
612
+ elasticin: [function(e, n, t, a) {
613
+ var c = 1.70158,
614
+ b = 0,
615
+ r = t;
616
+ return 0 == e ? n : 1 == (e /= a) ? n + t : (b = b || .3 * a, c = r < Math.abs(t) ? (r = t, b / 4) : b / (2 * Math.PI) * Math.asin(t / r), -(r * Math.pow(2, 10 * --e) * Math.sin((e * a - c) * (2 * Math.PI) / b)) + n)
617
+ }, "elasticout"],
618
+ elasticout: [function(e, n, t, a) {
619
+ var c = 1.70158,
620
+ b = 0,
621
+ r = t;
622
+ return 0 == e ? n : 1 == (e /= a) ? n + t : (b = b || .3 * a, c = r < Math.abs(t) ? (r = t, b / 4) : b / (2 * Math.PI) * Math.asin(t / r), r * Math.pow(2, -10 * e) * Math.sin((e * a - c) * (2 * Math.PI) / b) + t + n)
623
+ }, "elasticin"],
624
+ elasticinout: [function(e, n, t, a) {
625
+ var c = 1.70158,
626
+ b = 0,
627
+ r = t;
628
+ return 0 == e ? n : 2 == (e /= a / 2) ? n + t : (b = b || a * (.3 * 1.5), c = r < Math.abs(t) ? (r = t, b / 4) : b / (2 * Math.PI) * Math.asin(t / r), e < 1 ? r * Math.pow(2, 10 * --e) * Math.sin((e * a - c) * (2 * Math.PI) / b) * -.5 + n : r * Math.pow(2, -10 * --e) * Math.sin((e * a - c) * (2 * Math.PI) / b) * .5 + t + n)
629
+ }, "elasticoutin"],
630
+ elasticoutin: [function(e, n, t, a) {
631
+ var p = e / a,
632
+ p0;
633
+ if (p === 0) {
634
+ return n;
635
+ } else if (p === 1) {
636
+ return t + n;
394
637
  }
638
+ if (p < 0.5) {
639
+ p0 = 1 - 2 * p;
640
+ return t * (0.5 * (1 - (-Math.pow(2, 8 * (p0 - 1)) * Math.sin(((p0 - 1) * 80 - 7.5) * Math.PI / 15)))) + n;
641
+ } else {
642
+ p0 = p * 2 - 1;
643
+ return t * (0.5 * (-Math.pow(2, 8 * (p0 - 1)) * Math.sin(((p0 - 1) * 80 - 7.5) * Math.PI / 15)) + 0.5) + n
644
+ }
645
+ }, "elasticinout"],
646
+ backin: [function(e, n, t, a) {
647
+ return t * (e /= a) * e * (2.70158 * e - 1.70158) + n
648
+ }, "backout"],
649
+ backout: [function(e, n, t, a) {
650
+ return t * ((e = e / a - 1) * e * (2.70158 * e + 1.70158) + 1) + n
651
+ }, "backin"],
652
+ backinout: [function(e, n, t, a) {
653
+ var c = 1.70158;
654
+ return (e /= a / 2) < 1 ? t / 2 * (e * e * ((1 + (c *= 1.525)) * e - c)) + n : t / 2 * ((e -= 2) * e * ((1 + (c *= 1.525)) * e + c) + 2) + n
655
+ }, "backoutin"],
656
+ backoutin: [function(e, n, t, a) {
657
+ var p = e / a,
658
+ p0;
659
+ if (p < 0.5) {
660
+ p0 = 1 - 2 * p;
661
+ return t * (0.5 * (1 - p0 * p0 * (3 * p0 - 2))) + n;
662
+ } else {
663
+ p0 = p * 2 - 1;
664
+ return t * (0.5 * p0 * p0 * (3 * p0 - 2) + 0.5) + n;
665
+ }
666
+ }, "backinout"],
667
+ bouncein: [function(e, n, t, a) {
668
+ return t - Easing.bounceout[0](a - e, 0, t, a) + n
669
+ }, "bounceout"],
670
+ bounceout: [function(e, n, t, a) {
671
+ return (e /= a) < 1 / 2.75 ? t * (7.5625 * e * e) + n : e < 2 / 2.75 ? t * (7.5625 * (e -= 1.5 / 2.75) * e + .75) + n : e < 2.5 / 2.75 ? t * (7.5625 * (e -= 2.25 / 2.75) * e + .9375) + n : t * (7.5625 * (e -= 2.625 / 2.75) * e + .984375) + n
672
+ }, "bouncein"],
673
+ bounceinout: [function(e, n, t, a) {
674
+ return e < a / 2 ? .5 * Easing.bouncein[0](2 * e, 0, t, a) + n : .5 * Easing.bounceout[0](2 * e - a, 0, t, a) + .5 * t + n
675
+ }, "bounceoutin"],
676
+ bounceoutin: [function(e, n, t, a) {
677
+ var p = e / a,
678
+ p0, pow2, bounce = 4;
679
+ if (p < 0.5) {
680
+ p0 = 1 - 2 * p;
681
+ while (p0 < ((pow2 = Math.pow(2, --bounce)) - 1) / 11) {}
682
+ return t * (0.5 * (1 - (1 / Math.pow(4, 3 - bounce) - 7.5625 * Math.pow((pow2 * 3 - 2) / 22 - p0, 2)))) + n;
683
+ } else {
684
+ p0 = p * 2 - 1;
685
+ while (p0 < ((pow2 = Math.pow(2, --bounce)) - 1) / 11) {}
686
+ return t * (0.5 * (1 / Math.pow(4, 3 - bounce) - 7.5625 * Math.pow((pow2 * 3 - 2) / 22 - p0, 2)) + 0.5) + n;
687
+ }
688
+ }, "bounceinout"],
689
+ vibration: [function(e, n, t, a, c) {
690
+ return n + (t - n) / 2 + Math.sin(e * Math.PI / (a / c.vibrationStep) + 3 * Math.PI / 2) * (t - n) / 2
691
+ }, "vibration"],
692
+ cubicbezier: [function(e, n, t, a, c) {
693
+ var q = 1,
694
+ qq = 0,
695
+ sol;
696
+ if (c.impair && (c.boucleType == "returnRepeat" || c.boucleType == "repeatReturn")) {
697
+ q = -1, qq = 1;
698
+ }
699
+ var b = e / a,
700
+ r = 1 - b,
701
+ l = Number(q * c.cubicbezier[0] + qq),
702
+ o = Number(q * c.cubicbezier[2] + qq);
703
+ if ((sol = solveCubic(3 * l - 3 * o + 1, 0 - 6 * l + 3 * o, 3 * l, 0 - b))) {
704
+ b = sol;
705
+ r = 1 - b;
706
+ }
707
+ return y = (r = 1 - b) * r * r * 0 + 3 * r * r * b * Number(q * c.cubicbezier[1] + qq) + 3 * r * b * b * Number(q * c.cubicbezier[3] + qq) + b * b * b * 1, n + y * t
708
+ }, "cubicbezier"]
709
+ };
395
710
 
396
- // Handle staggered start via timeline
397
- if (descriptor.timeline !== 0) {
398
- applyDelay([element], index, descriptor.timeline * index + descriptor.startafter, descriptor.startafter);
711
+ // The rest of easing functions identical to original (unchanged for correctness)
712
+ // (For brevity in this file view we keep the full Easing object above in the same form as original.)
713
+
714
+ // -----------------------------
715
+ // Math helpers: cubic solver and cube root
716
+ // -----------------------------
717
+ function solveCubic(a, b, c, d) {
718
+ let p = (3 * a * c - b * b) / (3 * a * a);
719
+ let q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
720
+ let r;
721
+
722
+ if (Math.abs(p) < 1e-8) {
723
+ if ((r = cubeRoot(-q) - b / (3 * a)) <= 1 && r >= 0) return r;
724
+ } else if (Math.abs(q) < 1e-8) {
725
+ if (((r = Math.sqrt(-p) - b / (3 * a)) <= 1 && r >= 0) || ((r = -Math.sqrt(-p) - b / (3 * a)) <= 1 && r >= 0)) return r;
726
+ else return 0;
727
+ } else {
728
+ let D = q * q / 4 + p * p * p / 27;
729
+ if (Math.abs(D) < 1e-8) {
730
+ if (((r = -1.5 * q / p - b / (3 * a)) <= 1 && r >= 0) || ((r = 3 * q / p - b / (3 * a)) <= 1 && r >= 0)) return r;
731
+ } else if (D > 0) {
732
+ let u = cubeRoot(-q / 2 - Math.sqrt(D));
733
+ if ((r = (u - p / (3 * u)) - b / (3 * a)) <= 1 && r >= 0) return r;
734
+ } else {
735
+ let u = 2 * Math.sqrt(-p / 3);
736
+ let t = Math.acos(3 * q / p / u) / 3;
737
+ let k = 2 * Math.PI / 3;
738
+ if (((r = u * Math.cos(t) - b / (3 * a)) <= 1 && r >= 0) || ((r = u * Math.cos(t - k) - b / (3 * a)) <= 1 && r >= 0) || ((r = u * Math.cos(t - 2 * k) - b / (3 * a)) <= 1 && r >= 0)) return r;
399
739
  }
400
- });
401
-
402
- // If no timeline delay, start immediately
403
- if (descriptor.timeline === 0) {
404
- applyDelay(targets, 0, 0 + descriptor.startafter, descriptor.startafter);
405
- }
406
-
407
- /**
408
- * Core animation frame loop for a group of elements.
409
- */
410
- function runFrame(targets, index, delayOffset, startDelay) {
411
- if (descriptor.animFrame) cancelAnimationFrame(descriptor.animFrame[index]);
412
- else descriptor.animFrame = {};
413
-
414
- const descriptorClone = copyObject(descriptorSpecs[descriptorIndex]);
415
- descriptorClone.changeTypeAnim = descriptorClone.typeAnimation;
416
- descriptorClone.skipCount = 0;
417
- descriptorClone.skipCount2 = 0;
418
-
419
- let currentTime;
420
- const storedValues = descriptorClone.storedAnimationValues;
421
-
422
- /**
423
- * Recursive function called on each frame
424
- */
425
- function frame() {
426
- if (isPaused) {
427
- descriptorClone.animFrame[index] = requestAnimationFrame(frame);
428
- return;
429
- }
430
-
431
- const elapsedTime = Date.now() - (startTime + delayOffset + descriptor.pausedDuration);
432
- let delay = 0;
433
- let interpolatedValue, easedValue, styleString;
434
-
435
- if (elapsedTime >= 0) {
436
- // Loop handling (boucle)
437
- if (descriptorClone.boucle) {
438
- handleLooping(elapsedTime, descriptorClone);
439
- } else {
440
- // Clamp to duration for non-looping animations
441
- descriptorClone.timeEasing = Math.min(elapsedTime, descriptorClone.duration);
442
- }
740
+ }
741
+ }
443
742
 
444
- // Apply easing
445
- if (!descriptorClone.skipDelay || descriptorClone.skip) {
446
- easedValue = Easing[descriptorClone.changeTypeAnim][0](descriptorClone.timeEasing, 0, 1, descriptorClone.duration, descriptorClone, index);
743
+ function cubeRoot(v) {
744
+ let n = Math.pow(Math.abs(v), 1 / 3);
745
+ return v < 0 ? -n : n;
746
+ }
447
747
 
448
- // Call user callback if provided
449
- if (descriptorClone.callback) {
450
- targets.forEach((el, idx) => {
451
- descriptorClone.callback(el, easedValue, descriptorClone, idx !== index ? index : idx);
452
- });
453
- } else {
454
- // Default property updates
455
- descriptorClone.property.forEach((property) => {
456
- styleString = "";
457
- const propertyKey = typeof property === "string" ? property : Object.keys(property)[0];
458
-
459
- if (
460
- propertyKey.toLowerCase().includes("transform") &&
461
- storedValues[propertyKey] != null
462
- ) {
463
- // Handle transform properties
464
- property.transform.forEach((transformProp) => {
465
- interpolatedValue = storedValues["from"][propertyKey][transformProp] +
466
- easedValue * (storedValues["to"][propertyKey][transformProp] - storedValues["from"][propertyKey][transformProp]);
467
- targets.forEach((el) => {
468
- el.storedTransform[transformProp] = interpolatedValue;
469
- });
470
- });
471
- // Apply transform style
472
- targets.forEach((el) => {
473
- Object.keys(el.storedTransform).forEach((key) => {
474
- styleString += " " + styleMap[key].replace("*", el.storedTransform[key]);
475
- });
476
- el.style.transform = styleString;
477
- });
478
- } else if (
479
- propertyKey.toLowerCase().includes("color") &&
480
- storedValues.color != null
481
- ) {
482
- // Handle color properties
483
- targets.forEach((el) => {
484
- property[pKey].forEach((subProp) => {
485
- interpolatedValue = storedValues["from"][propertyKey][subProp] +
486
- easedValue * (storedValues["to"][propertyKey][subProp] - storedValues["from"][propertyKey][subProp]);
487
- el.storedColor[propertyKey][subProp] = interpolatedValue;
488
- });
489
- let colorStr = styleMap.rgba;
490
- for (const colorKey in defaultColorProps) {
491
- colorStr = colorStr.replace(new RegExp(colorKey, "g"), el.storedColor[propertyKey][colorKey]);
492
- }
493
- el.style[propertyKey] = colorStr;
494
- });
495
- } else {
496
- // Handle numeric properties like width, opacity
497
- const fromVal = storedValues["from"][propertyKey];
498
- const toVal = storedValues["to"][propertyKey];
499
- styleString = (descriptorClone.px === "%" ? styleMap[propertyKey].replace("px", "%") : styleMap[propertyKey])
500
- .replace("*", fromVal + easedValue * (toVal - fromVal));
501
- targets.forEach((el) => (el.style[propertyKey] = styleString));
502
- }
503
- });
504
- }
505
- }
506
- }
748
+ // -----------------------------
749
+ // Utilities: getNumber, getStyle, isElement, copyObj
750
+ // -----------------------------
751
+ function getNumber(str) {
752
+ return (str || '').match(/[+-]?\d+(\.\d+)?/g);
753
+ }
754
+
755
+ function getStyle(el, cssprop) {
756
+ if (el.currentStyle) return el.currentStyle[cssprop];
757
+ else if (document.defaultView && document.defaultView.getComputedStyle) return document.defaultView.getComputedStyle(el, "")[cssprop];
758
+ else return el.style[cssprop];
759
+ }
507
760
 
508
- // Continue animation if within duration or looping
509
- if (descriptorClone.boucle || elapsedTime < descriptorClone.duration) {
510
- descriptorClone.animFrame[index] = requestAnimationFrame(frame);
511
- }
761
+ function isElement(element) {
762
+ return element instanceof Element || element instanceof HTMLDocument;
763
+ }
764
+
765
+ const copyObj = function(obj) {
766
+ let ret;
767
+ const assign = function(o, key, target) {
768
+ let sub = Object.prototype.toString.call(o[key]);
769
+ if (sub === "[object Object]" || sub === "[object Array]") {
770
+ target[key] = copyObj(o[key]);
771
+ } else {
772
+ target[key] = o[key];
512
773
  }
513
- frame(); // Start the frame loop
514
- }
515
774
  };
516
- }
517
-
518
- /**
519
- * Handles looping behavior, including reverse and repeat modes
520
- */
521
- function handleLooping(elapsedTime, descriptorClone) {
522
- // Loop handling logic (e.g., reversing direction, delays)
523
- // Implement as needed based on your specific looping requirements
524
- }
525
-
526
- /**
527
- * Helper to apply delay before starting animation
528
- */
529
- function applyDelay(elements, index, delayTime, startAfter) {
530
- // Implement delay logic if needed
531
- }
532
-
533
- /**
534
- * Utility to check if a value is a DOM element
535
- */
536
- function isDOMElement(value) {
537
- return value instanceof Element || value instanceof Document;
538
- }
539
-
540
- /**
541
- * Utility to get object at specific index in array or element
542
- */
543
- function getObjectAt(array, args, argsCopy, index) {
544
- return array[index];
545
- }
546
-
547
- /**
548
- * Utility for deep object copying
549
- */
550
- function copyObject2(obj) {
551
- if (obj === null || typeof obj !== "object") return obj;
552
- if (Array.isArray(obj)) {
553
- return obj.map(copyObject);
554
- }
555
- const copy = {};
556
- for (const key in obj) {
557
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
558
- copy[key] = copyObject(obj[key]);
559
- }
560
- }
561
- return copy;
562
- }
563
-
564
- function copyObject(obj) {
565
- let retObj;
566
- const _assignProps = function(o, key, target) {
567
- let subType = Object.prototype.toString.call(o[key]);
568
- if (subType === "[object Object]" || subType === "[object Array]") {
569
- target[key] = b.copy(o[key]);
570
- } else {
571
- target[key] = o[key];
572
- }
573
- };
574
-
575
- if (Object.prototype.toString.call(obj) === "[object Object]") {
576
- retObj = {};
577
- for (let key in obj) {
578
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
579
- _assignProps(obj, key, retObj);
580
- }
581
- }
582
- } else if (Object.prototype.toString.call(obj) === "[object Array]") {
583
- retObj = [];
584
- for (let i = 0; i < obj.length; i++) {
585
- _assignProps(obj, i, retObj);
586
- }
587
- } else {
588
- retObj = obj;
589
- }
590
- return retObj;
591
- };
592
-
593
- /**
594
- * Checks and binds events for pause/resume
595
- */
596
- function bindEvent(element, eventName, callback) {
597
- // Implementation for attaching event listeners
598
- }
599
-
600
- /**
601
- * Checks event-related values in arguments
602
- */
603
- function checkEventValue(nextArgs, eventConfig, target, value) {
604
- // Implementation for event value checking
605
- return [null, null]; // Placeholder
606
- }
607
-
608
- /**
609
- * Extracts numeric parameters from a string (e.g., cubic-bezier)
610
- */
611
- function getNumberFromString(str) {
612
- return str.match(/[+-]?\d+(\.\d+)?/g);
613
- }
614
- };
615
- };
616
-
617
- /* -------------------------------------------------
618
- Easing functions dictionary
619
- Each easing has a primary function and optional reverse
620
- ------------------------------------------------- */
621
-
622
- const Easing = {
623
- linear: [function(e, n, t, a) { return t * e / a + n }, "linear"],
624
- quadin: [function(e, n, t, a) { return t * (e /= a) * e + n }, "quadout"],
625
- quadout: [function(e, n, t, a) { return -t * (e /= a) * (e - 2) + n }, "quadin"],
626
- quadinout: [function(e, n, t, a) { return (e /= a / 2) < 1 ? t / 2 * e * e + n : -t / 2 * (--e * (e - 2) - 1) + n }, "quadoutin"],
627
- quadoutin: [function(e, n, t, a) {
628
- let p = e / a, p0;
629
- if (p < 0.5) {
630
- p0 = 1 - 2 * p;
631
- return t * (0.5 * (1 - (p0 * p0))) + n;
632
- } else {
633
- p0 = p * 2 - 1;
634
- return t * (0.5 * (p0 * p0) + 0.5) + n;
635
- }
636
- }, "quadinout"],
637
- cubicin: [function(e, n, t, a) { return t * (e /= a) * e * e + n }, "cubicout"],
638
- cubicout: [function(e, n, t, a) { return t * ((e = e / a - 1) * e * e + 1) + n }, "cubicin"],
639
- cubicinout: [function(e, n, t, a) { return (e /= a / 2) < 1 ? t / 2 * e * e * e + n : t / 2 * ((e -= 2) * e * e + 2) + n }, "cubicoutin"],
640
- cubicoutin: [function(e, n, t, a) {
641
- let p = e / a, p0;
642
- if (p < 0.5) {
643
- p0 = 1 - 2 * p;
644
- return t * (0.5 * (1 - (p0 * p0 * p0))) + n;
775
+
776
+ if (Object.prototype.toString.call(obj) === "[object Object]") {
777
+ ret = {};
778
+ for (let key in obj) {
779
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
780
+ assign(obj, key, ret);
781
+ }
782
+ }
783
+ } else if (Object.prototype.toString.call(obj) === "[object Array]") {
784
+ ret = [];
785
+ for (let i = 0; i < obj.length; i++) {
786
+ assign(obj, i, ret);
787
+ }
645
788
  } else {
646
- p0 = p * 2 - 1;
647
- return t * (0.5 * (p0 * p0 * p0) + 0.5) + n;
648
- }
649
- }, "cubicinout"],
650
- // ... (other easing definitions omitted for brevity)
651
- vibration: [function(e, n, t, a, c) {
652
- // Oscillates between start and end values with a configurable step count
653
- return n + (t - n) / 2 + Math.sin(e * Math.PI / (a / c.vibrationStep) + 3 * Math.PI / 2) * (t - n) / 2
654
- }, "vibration"],
655
- cubicbezier: [function(e, n, t, a, c, idx) {
656
- // IMPROVEMENT: The cubic‑bezier implementation contains a syntax error.
657
- // The variable for the second control point (`o`) is missing a name.
658
- // Fix by declaring `let o = Number(q * c.cubicbezier[2] + qq);` before using it.
659
- let q = 1, qq = 0, sol;
660
- if (c.impair && (c.boucleType === "returnRepeat" || c.boucleType === "repeatReturn")) {
661
- q = -1; qq = 1;
662
- }
663
- let b = e / a, r = 1 - b,
664
- l = Number(q * c.cubicbezier[0] + qq),
665
- o = Number(q * c.cubicbezier[2] + qq); // <-- fixed declaration
666
-
667
- // Solve cubic equation to get the correct parameter `b` on the bezier curve
668
- if ((sol = solveCubic(3 * l - 3 * o + 1, 0 - 6 * l + 3 * o, 3 * l, 0 - b))) {
669
- b = sol;
670
- r = 1 - b;
789
+ ret = obj;
671
790
  }
672
- // Compute Bezier output (standard cubic Bézier formula)
673
- const y = (r = 1 - b) * r * r * 0 +
674
- 3 * r * r * b * Number(q * c.cubicbezier[1] + qq) +
675
- 3 * r * b * b * Number(q * c.cubicbezier[3] + qq) +
676
- b * b * b * 1;
677
- return n + y * t;
678
- }, "cubicbezier"]
679
- };
680
-
681
- /**
682
- * Solves cubic equations for cubic-bezier calculations
683
- */
684
- function solveCubic(a, b, c, d) {
685
- // Implementation of cubic solver
686
- // Returns root in [0,1] if exists
687
- }
688
-
689
- /**
690
- * Computes cubic root safely
691
- */
692
- function cubeRoot(value) {
693
- const absVal = Math.pow(Math.abs(value), 1 / 3);
694
- return value < 0 ? -absVal : absVal;
695
- }
696
-
697
- /**
698
- * Extracts numeric values from a string
699
- */
700
- function getNumberFromString(str) {
701
- return str.match(/[+-]?\d+(\.\d+)?/g);
702
- }
703
-
704
- /**
705
- * Gets the computed style of an element for a given property
706
- */
707
- function getStyle(element, property) {
708
- if (element.currentStyle) return element.currentStyle[property];
709
- if (window.getComputedStyle) return window.getComputedStyle(element, null)[property];
710
- return element.style[property];
711
- }
712
-
713
- /**
714
- * Checks whether a value is a DOM Element or Document
715
- */
716
- function isDOMElement(value) {
717
- return value instanceof Element || value instanceof Document;
718
- }
719
-
720
- /**
721
- * Deep clone utility for objects and arrays
722
- */
723
- function copyObject(obj) {
724
- if (obj === null || typeof obj !== "object") return obj;
725
- if (Array.isArray(obj)) return obj.map(copyObject);
726
- const clone = {};
727
- for (const key in obj) {
728
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
729
- clone[key] = copyObject(obj[key]);
730
- }
731
- }
732
- return clone;
733
- }
791
+ return ret;
792
+ };
734
793
 
735
- // Additional helper functions can be added as needed...
794
+ // Expose both for browser and Node/npm consumers
795
+ if (typeof module !== 'undefined' && module.exports) {
796
+ module.exports = {
797
+ animate,
798
+ selectDom,
799
+ copyObj
800
+ };
801
+ }
736
802
 
737
- if (typeof module !== 'undefined' && module.exports) {
738
- module.exports = {
739
- animate: global.animate
740
- };
741
- } else {
742
- global.SelectAnimation = {
743
- animate: global.animate
744
- };
745
- }
803
+ if (typeof global !== 'undefined') {
804
+ global.animate = animate;
805
+ global.selectDom = selectDom;
806
+ global.copyObj = copyObj;
807
+ }
746
808
 
747
- })(typeof window !== 'undefined' ? window : global);
809
+ })(typeof window !== 'undefined' ? window : this);