select-animation 1.5.0 → 1.6.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/select-animation.js +38 -848
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "select-animation",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "High-performance JavaScript animation engine for organic & fluid motion",
5
5
  "main": "select-animation.js",
6
6
  "scripts": {
@@ -1,856 +1,46 @@
1
- /* -------------------------------------------------------------------------
2
- * Select-Animation: A High-Performance JavaScript Animation Engine
3
- * Designed for fluid motion and organic UI transitions.
4
- * Version: v1
5
- * Author: Housseyn Cheriet
6
- * Copyright: ©2026 Housseyn Cheriet
7
- * License: MIT
8
- * ------------------------------------------------------------------------- */
9
-
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
54
- };
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)"
96
- };
97
-
98
- // -----------------------------
1
+ // -----------------------------
99
2
  // select: simple DOM selector utility
100
3
  // Returns flat array of matched elements given one or more selectors
101
4
  // Usage: select('.class', '#id')
102
5
  // -----------------------------
103
- // --- Enhanced DOM Selection Utility with Explicit Error Reporting ---
104
- const selectDom = function (selector) {
105
- // 1. Check if the input is a DOM element directly
106
- if (isElement(selector)) return [selector];
107
-
108
- // 2. Handle string selectors (e.g., ".class", "#id")
109
- if (typeof selector === "string") {
110
- const nodes = document.querySelectorAll(selector);
111
- if (nodes.length === 0) {
112
- // Warning if the selector is valid string but matches nothing
113
- console.warn(`Select-Animation: No elements found matching the selector "${selector}".`);
114
- }
115
- return Array.from(nodes);
116
- }
117
-
118
- // 3. Handle arrays or collections
119
- if (Array.isArray(selector) || (selector && typeof selector.length === "number")) {
120
- return Array.from(selector).filter(isElement);
121
- }
122
-
123
- // 4. CRITICAL: Handle invalid types (like numbers, null, undefined)
124
- if (selector !== undefined && selector !== null) {
125
- // Throwing a console error to stop the developer and force a fix
126
- console.error(
127
- `Select-Animation ERROR: Invalid input passed to selectDom().\n` +
128
- `Expected: String (selector), HTMLElement, or Array.\n` +
129
- `Received: ${typeof selector} (${selector})`
130
- );
131
- }
132
-
133
- return [];
134
- };
135
-
136
- // -----------------------------
137
- // animate: animation factory
138
- // Accepts animation definitions and returns a runner function to start animations on targets.
139
- // -----------------------------
140
- const animate = function () {
141
- const definitions = arguments;
142
- const defsCopy = copyObj(definitions);
143
-
144
- return function () {
145
- let tmp, i, propIndex, fromItem, toItem, valFrom, valTo, t;
146
- let grouped = [];
147
- let expectNextGroup = false;
148
- let staging = { color: {}, transform: {}, from: {}, to: {} };
149
-
150
- // Process the definitions to map elements to their animation settings
151
- buildPlan();
152
-
153
- function buildPlan() {
154
- let secondPass = false;
155
-
156
- for (let c = 0, total = definitions.length; c < total; c++) {
157
- propIndex = 0;
158
- // If current item is an element or an array of elements
159
- if (expectNextGroup || Array.isArray(defsCopy[c]) || isElement(defsCopy[c])) {
160
- if (secondPass) {
161
- Array.isArray(defsCopy[c]) || (defsCopy[c] = [defsCopy[c]]);
162
- Array.prototype.push.apply(grouped, defsCopy[c]);
163
- }
164
- expectNextGroup = false;
165
- }
166
- // --- Handle Configuration Object with Validation ---
167
- else if (typeof defsCopy[c] === 'object' && defsCopy[c] !== null) {
168
- if (secondPass) {
169
- // Execute the animation runner for the current group
170
- runner(grouped, definitions, defsCopy, c)();
171
- } else {
172
- expectNextGroup = false;
173
-
174
- // 1. Validate Duration and Animation Type
175
- defsCopy[c].duration = (typeof defsCopy[c].duration === 'number' && defsCopy[c].duration > 0) ? defsCopy[c].duration : 1000;
176
-
177
- let requestedType = defsCopy[c].typeAnimation;
178
-
179
- if (requestedType === "vibration" && defsCopy[c].vibrationStep === undefined) {
180
- defsCopy[c].vibrationStep = 6;
181
- } else if (requestedType) {
182
- t = getNumber(requestedType);
183
- if (t && t.length === 4) {
184
- defsCopy[c].cubicbezier = t;
185
- defsCopy[c].typeAnimation = "cubicbezier";
186
- } else {
187
- // STOP EXECUTION: If easing is not found, do not fall back to linear
188
- if (requestedType !== "linear" && requestedType !== "vibration" && requestedType !== "cubicbezier" && (!Easing || !Easing[requestedType])) {
189
- // Use Error instead of warn to make it impossible to ignore
190
- throw new Error(`Select-Animation ERROR: The easing function "${requestedType}" does not exist. Please check your spelling or definitions.`);
191
- }
192
- }
193
- }
194
-
195
- // Double-check if the animation type is valid before processing
196
- if (!defsCopy[c].typeAnimation) return;
197
-
198
- // 2. Helper to sanitize input values (convert "100px" to 100)
199
- const parseVal = (v) => {
200
- if (typeof v === "number") return v;
201
- let p = parseFloat(v);
202
- return isNaN(p) ? 0 : p;
203
- };
204
-
205
- // Process properties and prepare "from" and "to" values
206
- if (!defsCopy[c].callback &&
207
- (Array.isArray(defsCopy[c].property) || (defsCopy[c].property !== undefined && (defsCopy[c].property = [defsCopy[c].property])))) {
208
-
209
- defsCopy[c].property.forEach(function (propItem) {
210
- const fromIsObject = typeof defsCopy[c].from === "object";
211
- const toIsObject = typeof defsCopy[c].to === "object";
212
-
213
- // Safely extract from/to values based on their types
214
- if (!fromIsObject) valFrom = parseVal(defsCopy[c].from);
215
- else fromItem = defsCopy[c]["from"][propIndex] || 0;
216
-
217
- if (!toIsObject) valTo = parseVal(defsCopy[c].to);
218
- else toItem = defsCopy[c]["to"][propIndex] || 0;
219
-
220
- if (typeof propItem === "object") {
221
- let propName = Object.keys(propItem)[0];
222
- if (!Array.isArray(propItem[propName])) propItem[propName] = [propItem[propName]];
223
-
224
- // Handle Colors and Transform objects
225
- if ((propName.toLowerCase().indexOf("color") !== -1 && (staging.color[propName] = COLOR_PROPERTIES[propName])) ||
226
- propName.toLowerCase().indexOf("transform") !== -1) {
227
-
228
- let inner = 0;
229
- staging["from"][propName] = {};
230
- staging["to"][propName] = {};
231
-
232
- propItem[propName].forEach(function (innerProp) {
233
- if (propName.toLowerCase() === "transform") staging[propName][innerProp] = 0;
234
- else staging.color[propName][innerProp] = 0;
235
-
236
- // Validate and assign nested properties
237
- if (fromIsObject) {
238
- let raw = (fromItem[propName] !== undefined) ? (Array.isArray(fromItem[propName]) ? fromItem[propName][inner] : fromItem[propName][innerProp]) : valFrom;
239
- staging["from"][propName][innerProp] = parseVal(raw);
240
- } else {
241
- staging["from"][propName][innerProp] = parseVal(defsCopy[c].from);
242
- }
243
-
244
- if (toIsObject) {
245
- let raw = (toItem[propName] !== undefined) ? (Array.isArray(toItem[propName]) ? toItem[propName][inner] : toItem[propName][innerProp]) : valTo;
246
- staging["to"][propName][innerProp] = parseVal(raw);
247
- } else {
248
- staging["to"][propName][innerProp] = parseVal(defsCopy[c].to);
249
- }
250
- inner++;
251
- });
252
- propIndex++;
253
- }
254
- } else {
255
- // Handle simple numeric CSS properties (width, height, etc.)
256
- if (fromIsObject) {
257
- let raw = fromItem[propItem] !== undefined ? fromItem[propItem] : (fromItem !== undefined ? fromItem : valFrom);
258
- staging["from"][propItem] = parseVal(raw);
259
- } else {
260
- staging["from"][propItem] = parseVal(defsCopy[c].from);
261
- }
262
-
263
- if (toIsObject) {
264
- let raw = toItem[propItem] !== undefined ? toItem[propItem] : (toItem !== undefined ? toItem : valTo);
265
- staging["to"][propItem] = parseVal(raw);
266
- } else {
267
- staging["to"][propItem] = parseVal(defsCopy[c].to);
268
- }
269
- propIndex++;
270
- }
271
- });
272
- }
273
-
274
- // 3. Callback Safety Validation
275
- // Ensure hooks are actual functions to prevent execution errors
276
- if (defsCopy[c].onStep && typeof defsCopy[c].onStep !== 'function') defsCopy[c].onStep = null;
277
- if (defsCopy[c].onComplete && typeof defsCopy[c].onComplete !== 'function') defsCopy[c].onComplete = null;
278
-
279
- // Finalize staging data and store it
280
- defsCopy[c].storeValueAnim = copyObj(staging);
281
- staging = { color: {}, transform: {}, from: {}, to: {} };
282
- }
283
-
284
- // Determine if the next item starts a new sequence group
285
- if (definitions[c + 1] !== undefined && (Array.isArray(definitions[c + 1]) || isElement(definitions[c + 1]))) {
286
- expectNextGroup = true;
287
- grouped = [];
288
- }
289
- }
290
-
291
- // Switch to second pass to execute the runners
292
- if (c === total - 1 && !secondPass) {
293
- expectNextGroup = false;
294
- secondPass = true;
295
- c = -1;
296
- }
297
- }
298
- }
299
-
300
- function runner(group, defs, defsCopyLocal, configIndex) {
301
- const conf = defs[configIndex];
302
- const declaredAnim = defsCopyLocal[configIndex].typeAnimation;
303
- let alternateAnim = declaredAnim;
304
-
305
- // Sanitize timing inputs
306
- conf.timeline = !isNaN(Number(conf.timeline)) ? Number(conf.timeline) : 0;
307
- conf.startafter = !isNaN(Number(conf.startafter)) ? Number(conf.startafter) : 0;
308
-
309
- // Prepare looping and easing alternates
310
- if (conf.boucle) {
311
- conf.delay = !isNaN(Number(conf.delay)) ? Number(conf.delay) : undefined;
312
- if (conf.boucleType === "returnRepeat" || conf.boucleType === "repeatReturn") {
313
- alternateAnim = Easing[declaredAnim][1];
314
- }
315
- }
316
-
317
- return function run(indexArg) {
318
- let pausedAccum = 0;
319
- let isPaused = false;
320
- let pauseStart;
321
-
322
- // Initialize event-based pause/resume logic if configured
323
- if (conf.pause && Array.isArray(conf.pause)) {
324
- const eventCfg = conf.pause[1] || "e:click|false";
325
- const parts = eventCfg.replace('e:', '').split('|');
326
- const eventName = parts[0];
327
- const useCapture = parts[1] === 'true';
328
-
329
- const togglePause = function (e) {
330
- if (e) {
331
- if (isPaused) {
332
- isPaused = false;
333
- pausedAccum += Date.now() - pauseStart;
334
- } else {
335
- isPaused = true;
336
- pauseStart = Date.now();
337
- }
338
- }
339
- };
340
-
341
- const targetEls = document.querySelectorAll(conf.pause[0]);
342
- targetEls.forEach(el => el.addEventListener(eventName, togglePause, useCapture));
343
- }
344
-
345
- const startedAt = Date.now();
346
-
347
- // Initialize state storage for each element in the group
348
- group.forEach(function (el, idx) {
349
- if (!el.storeTransform) el.storeTransform = copyObj(defsCopyLocal[configIndex].storeValueAnim.transform);
350
- if (!el.storeColor) {
351
- el.storeColor = copyObj(defsCopyLocal[configIndex].storeValueAnim.color);
352
- } else {
353
- Object.keys(defsCopyLocal[configIndex].storeValueAnim.color).forEach(key => {
354
- if (!el.storeColor[key]) el.storeColor[key] = defsCopyLocal[configIndex].storeValueAnim.color[key];
355
- });
356
- }
357
-
358
- // Start staggered animations if timeline offset exists
359
- if (conf.timeline !== 0) {
360
- frameRunner([el], idx, conf.timeline * idx + conf.startafter, conf.startafter);
361
- }
362
- });
363
-
364
- // Start simultaneous animations
365
- if (conf.timeline === 0) {
366
- frameRunner(group, 0, 0 + conf.startafter, conf.startafter);
367
- }
368
-
369
- function frameRunner(targetArray, idx, timeOffset, startAfter) {
370
- // Manage animation frame cycles
371
- if (conf.animFram) cancelAnimationFrame(conf.animFram[idx]);
372
- else conf.animFram = {};
373
-
374
- const iterConf = copyObj(defsCopyLocal[configIndex]);
375
- iterConf.changetypeAnim = iterConf.typeAnimation;
376
- iterConf.countSkip = 0;
377
- iterConf.countSkip2 = 0;
378
-
379
- let skipCounter;
380
- const sv = iterConf.storeValueAnim;
381
-
382
- // The main animation loop using requestAnimationFrame
383
- function loop() {
384
- if (isPaused) {
385
- conf.animFram[idx] = requestAnimationFrame(loop);
386
- return;
387
- }
388
-
389
- let delay = 0;
390
- let eased, tmpVal, css;
391
- const elapsed = Date.now() - (startedAt + timeOffset + pausedAccum);
392
-
393
- if (elapsed >= 0) {
394
- // Logic for handling loops, delays, and reversing (yoyo) animations
395
- if (iterConf.boucle) {
396
- if (iterConf.delay !== undefined) {
397
- delay = iterConf.delay;
398
- skipCounter = Math.floor((elapsed + delay) / (iterConf.duration + delay));
399
- if (skipCounter !== iterConf.countSkip) {
400
- iterConf.countSkip = skipCounter;
401
- iterConf.skip = iterConf.skipDelay = true;
402
- } else {
403
- iterConf.skip = false;
404
- if (elapsed % (iterConf.duration + delay) < iterConf.duration) {
405
- iterConf.skipDelay = false;
406
- if (iterConf.countSkip2 !== iterConf.countSkip) {
407
- iterConf.countSkip2 = iterConf.countSkip;
408
- iterConf.skip2 = true;
409
- } else iterConf.skip2 = false;
410
- }
411
- }
412
- } else {
413
- skipCounter = Math.floor((elapsed + delay) / (iterConf.duration + delay));
414
- if (skipCounter !== iterConf.countSkip) {
415
- iterConf.countSkip = iterConf.countSkip2 = skipCounter;
416
- iterConf.skip = iterConf.skip2 = true;
417
- } else {
418
- iterConf.skip = iterConf.skip2 = false;
419
- }
420
- }
421
-
422
- iterConf.timeEasing = elapsed % (iterConf.duration + delay);
423
- if (iterConf.skip) {
424
- iterConf.impair = !iterConf.impair;
425
- iterConf.changetypeAnim = iterConf.impair ? alternateAnim : declaredAnim;
426
- iterConf.timeEasing = (iterConf.impair || iterConf.boucleType.indexOf("repeat") === 0) ? iterConf.duration : 0;
427
- } else if (!iterConf.skipDelay) {
428
- if (iterConf.impair && iterConf.boucleType.indexOf("return") === 0) {
429
- iterConf.timeEasing = iterConf.duration - iterConf.timeEasing;
430
- }
431
- }
432
- } else {
433
- iterConf.timeEasing = elapsed < iterConf.duration ? elapsed : iterConf.duration;
434
- }
435
-
436
- // Update properties if not in delay phase
437
- if (!iterConf.skipDelay || iterConf.skip) {
438
- // Calculate ease factor (0 to 1)
439
- eased = Easing[iterConf.changetypeAnim][0](iterConf.timeEasing, 0, 1, iterConf.duration, iterConf, idx);
440
-
441
- if (iterConf.callback) {
442
- targetArray.forEach(function (el, index) {
443
- iterConf.callback(el, eased, iterConf, idx !== index ? idx : index);
444
- });
445
- } else {
446
- // Apply styles: Transform, Color, or standard Numeric properties
447
- iterConf.property.forEach(function (prop) {
448
- css = "";
449
- let key = typeof prop === "string" ? prop : Object.keys(prop)[0];
450
-
451
- if (key.toLowerCase() === "transform" && sv[key] != null) {
452
- prop.transform.forEach(function (tr) {
453
- tmpVal = sv["from"][key][tr] + eased * (sv["to"][key][tr] - sv["from"][key][tr]);
454
- targetArray.forEach(el => el.storeTransform[tr] = tmpVal);
455
- });
456
- targetArray.forEach(function (el) {
457
- Object.keys(el.storeTransform).forEach(k => {
458
- css += " " + PROPERTY_FORMAT_MAP[k].replace("*", el.storeTransform[k]);
459
- });
460
- el.style.transform = css;
461
- css = "";
462
- });
463
- } else if (key.toLowerCase().indexOf("color") !== -1 && sv.color != null) {
464
- targetArray.forEach(function (el) {
465
- prop[key].forEach(function (colProp) {
466
- tmpVal = sv["from"][key][colProp] + eased * (sv["to"][key][colProp] - sv["from"][key][colProp]);
467
- el.storeColor[key][colProp] = tmpVal;
468
- });
469
-
470
- let colorStr = PROPERTY_FORMAT_MAP.rgba;
471
- for (let colKey in COLOR_DEFAULTS) {
472
- colorStr = colorStr.replace(new RegExp(colKey, "g"), el.storeColor[key][colKey]);
473
- }
474
- el.style[key] = colorStr;
475
- });
476
- } else {
477
- css = (iterConf.px === "%" ? PROPERTY_FORMAT_MAP[key].replace("px", "%") : PROPERTY_FORMAT_MAP[key]).replace("*", sv["from"][key] + eased * (sv["to"][key] - sv["from"][key]));
478
- targetArray.forEach(el => el.style[key] = css);
479
- }
480
- });
481
- }
482
- }
483
- }
484
-
485
- // Continue the loop if animation is still active or looping
486
- if (iterConf.boucle || elapsed < iterConf.duration) {
487
- conf.animFram[idx] = requestAnimationFrame(loop);
488
- }
489
- }
490
-
491
- loop();
492
- }
493
- };
494
- }
495
- };
496
- };
497
-
498
- // -----------------------------
499
- // Easing functions
500
- // Standard easing definitions used by the animation engine.
501
- // -----------------------------
502
- const Easing = {
503
- linear: [function(e, n, t, a) {
504
- return t * e / a + n
505
- }, "linear"],
506
- quadin: [function(e, n, t, a) {
507
- return t * (e /= a) * e + n
508
- }, "quadout"],
509
- quadout: [function(e, n, t, a) {
510
- return -t * (e /= a) * (e - 2) + n
511
- }, "quadin"],
512
- quadinout: [function(e, n, t, a) {
513
- return (e /= a / 2) < 1 ? t / 2 * e * e + n : -t / 2 * (--e * (e - 2) - 1) + n
514
- }, "quadoutin"],
515
- quadoutin: [function(e, n, t, a) {
516
- var p = e / a,
517
- p0;
518
- if (p < 0.5) {
519
- p0 = 1 - 2 * p;
520
- return t * (0.5 * (1 - (p0 * p0))) + n;
521
- } else {
522
- p0 = p * 2 - 1;
523
- return t * (0.5 * (p0 * p0) + 0.5) + n;
524
- }
525
- }, "quadinout"],
526
- cubicin: [function(e, n, t, a) {
527
- return t * (e /= a) * e * e + n
528
- }, "cubicout"],
529
- cubicout: [function(e, n, t, a) {
530
- return t * ((e = e / a - 1) * e * e + 1) + n
531
- }, "cubicin"],
532
- cubicinout: [function(e, n, t, a) {
533
- return (e /= a / 2) < 1 ? t / 2 * e * e * e + n : t / 2 * ((e -= 2) * e * e + 2) + n
534
- }, "cubicoutin"],
535
- cubicoutin: [function(e, n, t, a) {
536
- var p = e / a,
537
- p0;
538
- if (p < 0.5) {
539
- p0 = 1 - 2 * p;
540
- return t * (0.5 * (1 - (p0 * p0 * p0))) + n;
541
- } else {
542
- p0 = p * 2 - 1;
543
- return t * (0.5 * (p0 * p0 * p0) + 0.5) + n;
544
- }
545
- }, "cubicinout"],
546
- quartin: [function(e, n, t, a) {
547
- return t * (e /= a) * e * e * e + n
548
- }, "quartout"],
549
- quartout: [function(e, n, t, a) {
550
- return -t * ((e = e / a - 1) * e * e * e - 1) + n
551
- }, "quartin"],
552
- quartinout: [function(e, n, t, a) {
553
- return (e /= a / 2) < 1 ? t / 2 * e * e * e * e + n : -t / 2 * ((e -= 2) * e * e * e - 2) + n
554
- }, "quartoutin"],
555
- quartoutin: [function(e, n, t, a) {
556
- var p = e / a,
557
- p0;
558
- if (p < 0.5) {
559
- p0 = 1 - 2 * p;
560
- return t * (0.5 * (1 - (p0 * p0 * p0 * p0))) + n;
561
- } else {
562
- p0 = p * 2 - 1;
563
- return t * (0.5 * (p0 * p0 * p0 * p0) + 0.5) + n;
564
- }
565
- }, "quartinout"],
566
- quintin: [function(e, n, t, a) {
567
- return t * (e /= a) * e * e * e * e + n
568
- }, "quintout"],
569
- quintout: [function(e, n, t, a) {
570
- return t * ((e = e / a - 1) * e * e * e * e + 1) + n
571
- }, "quintin"],
572
- quintinout: [function(e, n, t, a) {
573
- return (e /= a / 2) < 1 ? t / 2 * e * e * e * e * e + n : t / 2 * ((e -= 2) * e * e * e * e + 2) + n
574
- }, "quintoutin"],
575
- quintoutin: [function(e, n, t, a) {
576
- var p = e / a,
577
- p0;
578
- if (p < 0.5) {
579
- p0 = 1 - 2 * p;
580
- return t * (0.5 * (1 - (p0 * p0 * p0 * p0 * p0))) + n;
581
- } else {
582
- p0 = p * 2 - 1;
583
- return t * (0.5 * (p0 * p0 * p0 * p0 * p0) + 0.5) + n;
584
- }
585
- }, "quintinout"],
586
- sinein: [function(e, n, t, a) {
587
- return -t * Math.cos(e / a * (Math.PI / 2)) + t + n
588
- }, "sineout"],
589
- sineout: [function(e, n, t, a) {
590
- return t * Math.sin(e / a * (Math.PI / 2)) + n
591
- }, "sinein"],
592
- sineinout: [function(e, n, t, a) {
593
- return -t / 2 * (Math.cos(Math.PI * e / a) - 1) + n
594
- }, "sineoutin"],
595
- sineoutin: [function(e, n, t, a) {
596
- var p = e / a,
597
- p0;
598
- if (p < 0.5) {
599
- p0 = 1 - 2 * p;
600
- return t * (0.5 * (1 - (1 - Math.cos(p0 * Math.PI / 2)))) + n;
601
- } else {
602
- p0 = p * 2 - 1;
603
- return t * (0.5 * (1 - Math.cos(p0 * Math.PI / 2)) + 0.5) + n;
604
- }
605
- }, "sineinout"],
606
- expoin: [function(e, n, t, a) {
607
- return 0 == e ? n : t * Math.pow(2, 10 * (e / a - 1)) + n
608
- }, "expoout"],
609
- expoout: [function(e, n, t, a) {
610
- return e == a ? n + t : t * (1 - Math.pow(2, -10 * e / a)) + n
611
- }, "expoin"],
612
- expoinout: [function(e, n, t, a) {
613
- 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
614
- }, "expooutin"],
615
- expooutin: [function(e, n, t, a) {
616
- var p = e / a,
617
- p0;
618
- if (p == 0) {
619
- return n;
620
- } else if (p == 1) {
621
- return n + t;
622
- } else
623
- if (p < 0.5) {
624
- p0 = 1 - 2 * p;
625
- return t * (0.5 * (1 - (Math.pow(2, 10 * (p0 - 1))))) + n;
626
- } else {
627
- p0 = p * 2 - 1;
628
- return t * (0.5 * (Math.pow(2, 10 * (p0 - 1))) + 0.5) + n;
629
- }
630
- }, "expoinout"],
631
- circin: [function(e, n, t, a) {
632
- return -t * (Math.sqrt(1 - (e /= a) * e) - 1) + n
633
- }, "circout"],
634
- circout: [function(e, n, t, a) {
635
- return t * Math.sqrt(1 - (e = e / a - 1) * e) + n
636
- }, "circin"],
637
- circinout: [function(e, n, t, a) {
638
- return (e /= a / 2) < 1 ? -t / 2 * (Math.sqrt(1 - e * e) - 1) + n : t / 2 * (Math.sqrt(1 - (e -= 2) * e) + 1) + n
639
- }, "circoutin"],
640
- circoutin: [function(e, n, t, a) {
641
- var p = e / a,
642
- p0;
643
- if (p < 0.5) {
644
- p0 = 1 - 2 * p;
645
- return t * (0.5 * Math.sqrt(1 - p0 * p0)) + n;
646
- } else {
647
- p0 = p * 2 - 1;
648
- return t * (0.5 * (1 - Math.sqrt(1 - p0 * p0)) + 0.5) + n;
649
- }
650
- }, "circinout"],
651
- elasticin: [function(e, n, t, a) {
652
- var c = 1.70158,
653
- b = 0,
654
- r = t;
655
- 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)
656
- }, "elasticout"],
657
- elasticout: [function(e, n, t, a) {
658
- var c = 1.70158,
659
- b = 0,
660
- r = t;
661
- 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)
662
- }, "elasticin"],
663
- elasticinout: [function(e, n, t, a) {
664
- var c = 1.70158,
665
- b = 0,
666
- r = t;
667
- 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)
668
- }, "elasticoutin"],
669
- elasticoutin: [function(e, n, t, a) {
670
- var p = e / a,
671
- p0;
672
- if (p === 0) {
673
- return n;
674
- } else if (p === 1) {
675
- return t + n;
676
- }
677
- if (p < 0.5) {
678
- p0 = 1 - 2 * p;
679
- return t * (0.5 * (1 - (-Math.pow(2, 8 * (p0 - 1)) * Math.sin(((p0 - 1) * 80 - 7.5) * Math.PI / 15)))) + n;
680
- } else {
681
- p0 = p * 2 - 1;
682
- return t * (0.5 * (-Math.pow(2, 8 * (p0 - 1)) * Math.sin(((p0 - 1) * 80 - 7.5) * Math.PI / 15)) + 0.5) + n
683
- }
684
- }, "elasticinout"],
685
- backin: [function(e, n, t, a) {
686
- return t * (e /= a) * e * (2.70158 * e - 1.70158) + n
687
- }, "backout"],
688
- backout: [function(e, n, t, a) {
689
- return t * ((e = e / a - 1) * e * (2.70158 * e + 1.70158) + 1) + n
690
- }, "backin"],
691
- backinout: [function(e, n, t, a) {
692
- var c = 1.70158;
693
- 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
694
- }, "backoutin"],
695
- backoutin: [function(e, n, t, a) {
696
- var p = e / a,
697
- p0;
698
- if (p < 0.5) {
699
- p0 = 1 - 2 * p;
700
- return t * (0.5 * (1 - p0 * p0 * (3 * p0 - 2))) + n;
701
- } else {
702
- p0 = p * 2 - 1;
703
- return t * (0.5 * p0 * p0 * (3 * p0 - 2) + 0.5) + n;
704
- }
705
- }, "backinout"],
706
- bouncein: [function(e, n, t, a) {
707
- return t - Easing.bounceout[0](a - e, 0, t, a) + n
708
- }, "bounceout"],
709
- bounceout: [function(e, n, t, a) {
710
- 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
711
- }, "bouncein"],
712
- bounceinout: [function(e, n, t, a) {
713
- 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
714
- }, "bounceoutin"],
715
- bounceoutin: [function(e, n, t, a) {
716
- var p = e / a,
717
- p0, pow2, bounce = 4;
718
- if (p < 0.5) {
719
- p0 = 1 - 2 * p;
720
- while (p0 < ((pow2 = Math.pow(2, --bounce)) - 1) / 11) {}
721
- return t * (0.5 * (1 - (1 / Math.pow(4, 3 - bounce) - 7.5625 * Math.pow((pow2 * 3 - 2) / 22 - p0, 2)))) + n;
722
- } else {
723
- p0 = p * 2 - 1;
724
- while (p0 < ((pow2 = Math.pow(2, --bounce)) - 1) / 11) {}
725
- return t * (0.5 * (1 / Math.pow(4, 3 - bounce) - 7.5625 * Math.pow((pow2 * 3 - 2) / 22 - p0, 2)) + 0.5) + n;
726
- }
727
- }, "bounceinout"],
728
- vibration: [function(e, n, t, a, c) {
729
- return n + (t - n) / 2 + Math.sin(e * Math.PI / (a / c.vibrationStep) + 3 * Math.PI / 2) * (t - n) / 2
730
- }, "vibration"],
731
- cubicbezier: [function(e, n, t, a, c) {
732
- let q = 1, qq = 0, sol;
733
- if (c.impair && (c.boucleType === "returnRepeat" || c.boucleType === "repeatReturn")) {
734
- q = -1; qq = 1;
735
- }
736
- let b = e / a, r = 1 - b,
737
- l = Number(q * c.cubicbezier[0] + qq),
738
- o = Number(q * c.cubicbezier[2] + qq);
739
-
740
- if ((sol = solveCubic(3 * l - 3 * o + 1, 0 - 6 * l + 3 * o, 3 * l, 0 - b))) {
741
- b = sol;
742
- r = 1 - b;
743
- }
744
- let 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;
745
- return n + y * t;
746
- }, "cubicbezier"]
747
- };
748
-
749
- // The rest of easing functions identical to original (unchanged for correctness)
750
- // (For brevity in this file view we keep the full Easing object above in the same form as original.)
751
-
752
- // -----------------------------
753
- // Math helpers: cubic solver and cube root
754
- // -----------------------------
755
- function solveCubic(a, b, c, d) {
756
- let p = (3 * a * c - b * b) / (3 * a * a);
757
- let q = (2 * b * b * b - 9 * a * b * c + 27 * a * a * d) / (27 * a * a * a);
758
- let r;
6
+ // --- Enhanced DOM Selection Utility with Explicit Error Reporting (Supports Multiple Arguments) ---
7
+ const selectDom = function (...selectors) {
8
+ const allElements = [];
759
9
 
760
- if (Math.abs(p) < 1e-8) {
761
- if ((r = cubeRoot(-q) - b / (3 * a)) <= 1 && r >= 0) return r;
762
- } else if (Math.abs(q) < 1e-8) {
763
- if (((r = Math.sqrt(-p) - b / (3 * a)) <= 1 && r >= 0) || ((r = -Math.sqrt(-p) - b / (3 * a)) <= 1 && r >= 0)) return r;
764
- else return 0;
765
- } else {
766
- let D = q * q / 4 + p * p * p / 27;
767
- if (Math.abs(D) < 1e-8) {
768
- if (((r = -1.5 * q / p - b / (3 * a)) <= 1 && r >= 0) || ((r = 3 * q / p - b / (3 * a)) <= 1 && r >= 0)) return r;
769
- } else if (D > 0) {
770
- let u = cubeRoot(-q / 2 - Math.sqrt(D));
771
- if ((r = (u - p / (3 * u)) - b / (3 * a)) <= 1 && r >= 0) return r;
772
- } else {
773
- let u = 2 * Math.sqrt(-p / 3);
774
- let t = Math.acos(3 * q / p / u) / 3;
775
- let k = 2 * Math.PI / 3;
776
- 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;
777
- }
10
+ // If no arguments were passed at all
11
+ if (selectors.length === 0) {
12
+ console.warn("Select-Animation: selectDom() was called without any arguments.");
13
+ return [];
778
14
  }
779
- }
780
-
781
- function cubeRoot(v) {
782
- let n = Math.pow(Math.abs(v), 1 / 3);
783
- return v < 0 ? -n : n;
784
- }
785
15
 
786
- // -----------------------------
787
- // Utilities: getNumber, getStyle, isElement, copyObj
788
- // -----------------------------
789
- function getNumber(str) {
790
- return (str || '').match(/[+-]?\d+(\.\d+)?/g);
791
- }
792
-
793
- function getStyle(el, cssprop) {
794
- if (el.currentStyle) return el.currentStyle[cssprop];
795
- else if (document.defaultView && document.defaultView.getComputedStyle) return document.defaultView.getComputedStyle(el, "")[cssprop];
796
- else return el.style[cssprop];
797
- }
798
-
799
- // --- Robust DOM Element Validation ---
800
- function isElement(element) {
801
- try {
802
- // Check for standard DOM Element or HTMLDocument
803
- return element instanceof Element || element instanceof HTMLDocument;
804
- } catch (e) {
805
- // Fallback for environments where Element is not defined
806
- return (typeof element === "object") &&
807
- (element.nodeType === 1) &&
808
- (typeof element.nodeName === "string");
809
- }
810
- }
811
-
812
- const copyObj = function(obj) {
813
- let ret;
814
- const assign = function(o, key, target) {
815
- let sub = Object.prototype.toString.call(o[key]);
816
- if (sub === "[object Object]" || sub === "[object Array]") {
817
- target[key] = copyObj(o[key]);
818
- } else {
819
- target[key] = o[key];
820
- }
821
- };
822
-
823
- if (Object.prototype.toString.call(obj) === "[object Object]") {
824
- ret = {};
825
- for (let key in obj) {
826
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
827
- assign(obj, key, ret);
16
+ selectors.forEach((selector) => {
17
+ // 1. If the argument is already a DOM element
18
+ if (isElement(selector)) {
19
+ allElements.push(selector);
20
+ }
21
+ // 2. If the argument is a string (Selector)
22
+ else if (typeof selector === "string") {
23
+ const nodes = document.querySelectorAll(selector);
24
+ if (nodes.length === 0) {
25
+ console.warn(`Select-Animation: No elements found for selector "${selector}".`);
26
+ } else {
27
+ // Spread the NodeList into our results array
28
+ allElements.push(...Array.from(nodes));
828
29
  }
829
- }
830
- } else if (Object.prototype.toString.call(obj) === "[object Array]") {
831
- ret = [];
832
- for (let i = 0; i < obj.length; i++) {
833
- assign(obj, i, ret);
834
- }
835
- } else {
836
- ret = obj;
837
- }
838
- return ret;
839
- };
840
-
841
- // Expose both for browser and Node/npm consumers
842
- if (typeof module !== 'undefined' && module.exports) {
843
- module.exports = {
844
- animate,
845
- selectDom,
846
- copyObj
847
- };
848
- }
849
-
850
- if (typeof global !== 'undefined') {
851
- global.animate = animate;
852
- global.selectDom = selectDom;
853
- global.copyObj = copyObj;
854
- }
855
-
856
- })(typeof window !== 'undefined' ? window : this);
30
+ }
31
+ // 3. If the argument is an array or collection
32
+ else if (Array.isArray(selector) || (selector && typeof selector.length === "number")) {
33
+ const filtered = Array.from(selector).filter(isElement);
34
+ allElements.push(...filtered);
35
+ }
36
+ // 4. INVALID INPUT: Alert the developer if they passed a number/null/etc.
37
+ else if (selector !== undefined && selector !== null) {
38
+ console.error(
39
+ `Select-Animation ERROR: Invalid selector type "${typeof selector}". ` +
40
+ `Expected String, Element, or Array, but received:`, selector
41
+ );
42
+ }
43
+ });
44
+
45
+ return allElements;
46
+ };