select-animation 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/select-animation.js +99 -61
package/package.json
CHANGED
package/select-animation.js
CHANGED
|
@@ -100,13 +100,37 @@
|
|
|
100
100
|
// Returns flat array of matched elements given one or more selectors
|
|
101
101
|
// Usage: select('.class', '#id')
|
|
102
102
|
// -----------------------------
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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 [];
|
|
110
134
|
};
|
|
111
135
|
|
|
112
136
|
// -----------------------------
|
|
@@ -139,49 +163,65 @@
|
|
|
139
163
|
}
|
|
140
164
|
expectNextGroup = false;
|
|
141
165
|
}
|
|
142
|
-
//
|
|
166
|
+
// --- Handle Configuration Object with Validation ---
|
|
143
167
|
else if (typeof defsCopy[c] === 'object' && defsCopy[c] !== null) {
|
|
144
168
|
if (secondPass) {
|
|
145
|
-
// Execute the runner for the current group
|
|
169
|
+
// Execute the animation runner for the current group
|
|
146
170
|
runner(grouped, definitions, defsCopy, c)();
|
|
147
171
|
} else {
|
|
148
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;
|
|
149
176
|
|
|
150
|
-
|
|
151
|
-
|
|
177
|
+
let requestedType = defsCopy[c].typeAnimation;
|
|
178
|
+
|
|
179
|
+
if (requestedType === "vibration" && defsCopy[c].vibrationStep === undefined) {
|
|
152
180
|
defsCopy[c].vibrationStep = 6;
|
|
153
|
-
} else {
|
|
154
|
-
t = getNumber(
|
|
181
|
+
} else if (requestedType) {
|
|
182
|
+
t = getNumber(requestedType);
|
|
155
183
|
if (t && t.length === 4) {
|
|
156
184
|
defsCopy[c].cubicbezier = t;
|
|
157
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
|
+
}
|
|
158
192
|
}
|
|
159
193
|
}
|
|
160
|
-
|
|
161
|
-
//
|
|
162
|
-
if (defsCopy[c].
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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 &&
|
|
168
207
|
(Array.isArray(defsCopy[c].property) || (defsCopy[c].property !== undefined && (defsCopy[c].property = [defsCopy[c].property])))) {
|
|
169
208
|
|
|
170
209
|
defsCopy[c].property.forEach(function (propItem) {
|
|
171
210
|
const fromIsObject = typeof defsCopy[c].from === "object";
|
|
172
211
|
const toIsObject = typeof defsCopy[c].to === "object";
|
|
173
212
|
|
|
174
|
-
|
|
175
|
-
|
|
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;
|
|
176
216
|
|
|
177
|
-
if (!toIsObject) valTo = defsCopy[c].to;
|
|
178
|
-
else toItem = defsCopy[c]["to"][propIndex];
|
|
217
|
+
if (!toIsObject) valTo = parseVal(defsCopy[c].to);
|
|
218
|
+
else toItem = defsCopy[c]["to"][propIndex] || 0;
|
|
179
219
|
|
|
180
|
-
// Handle complex properties (Colors and Transforms)
|
|
181
220
|
if (typeof propItem === "object") {
|
|
182
221
|
let propName = Object.keys(propItem)[0];
|
|
183
222
|
if (!Array.isArray(propItem[propName])) propItem[propName] = [propItem[propName]];
|
|
184
223
|
|
|
224
|
+
// Handle Colors and Transform objects
|
|
185
225
|
if ((propName.toLowerCase().indexOf("color") !== -1 && (staging.color[propName] = COLOR_PROPERTIES[propName])) ||
|
|
186
226
|
propName.toLowerCase().indexOf("transform") !== -1) {
|
|
187
227
|
|
|
@@ -193,66 +233,55 @@
|
|
|
193
233
|
if (propName.toLowerCase() === "transform") staging[propName][innerProp] = 0;
|
|
194
234
|
else staging.color[propName][innerProp] = 0;
|
|
195
235
|
|
|
196
|
-
//
|
|
236
|
+
// Validate and assign nested properties
|
|
197
237
|
if (fromIsObject) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
valFrom = staging["from"][propName][innerProp] = fromItem[propName];
|
|
201
|
-
} else if (Array.isArray(fromItem[propName])) {
|
|
202
|
-
valFrom = staging["from"][propName][innerProp] = fromItem[propName][inner] !== undefined ? fromItem[propName][inner] : valFrom;
|
|
203
|
-
} else if (fromItem[propName][innerProp] !== undefined) {
|
|
204
|
-
valFrom = staging["from"][propName][innerProp] = fromItem[propName][innerProp];
|
|
205
|
-
}
|
|
206
|
-
} else {
|
|
207
|
-
staging["from"][propName][innerProp] = valFrom;
|
|
208
|
-
}
|
|
238
|
+
let raw = (fromItem[propName] !== undefined) ? (Array.isArray(fromItem[propName]) ? fromItem[propName][inner] : fromItem[propName][innerProp]) : valFrom;
|
|
239
|
+
staging["from"][propName][innerProp] = parseVal(raw);
|
|
209
240
|
} else {
|
|
210
|
-
staging["from"][propName][innerProp] = defsCopy[c].from;
|
|
241
|
+
staging["from"][propName][innerProp] = parseVal(defsCopy[c].from);
|
|
211
242
|
}
|
|
212
243
|
|
|
213
|
-
// Repeat logic for "to" values
|
|
214
244
|
if (toIsObject) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
valTo = staging["to"][propName][innerProp] = toItem[propName];
|
|
218
|
-
} else if (Array.isArray(toItem[propName])) {
|
|
219
|
-
valTo = staging["to"][propName][innerProp] = toItem[propName][inner] !== undefined ? toItem[propName][inner] : valTo;
|
|
220
|
-
} else if (toItem[propName][innerProp] !== undefined) {
|
|
221
|
-
valTo = staging["to"][propName][innerProp] = toItem[propName][innerProp];
|
|
222
|
-
}
|
|
223
|
-
} else {
|
|
224
|
-
staging["to"][propName][innerProp] = valTo;
|
|
225
|
-
}
|
|
245
|
+
let raw = (toItem[propName] !== undefined) ? (Array.isArray(toItem[propName]) ? toItem[propName][inner] : toItem[propName][innerProp]) : valTo;
|
|
246
|
+
staging["to"][propName][innerProp] = parseVal(raw);
|
|
226
247
|
} else {
|
|
227
|
-
staging["to"][propName][innerProp] = defsCopy[c].to;
|
|
248
|
+
staging["to"][propName][innerProp] = parseVal(defsCopy[c].to);
|
|
228
249
|
}
|
|
229
250
|
inner++;
|
|
230
251
|
});
|
|
231
252
|
propIndex++;
|
|
232
253
|
}
|
|
233
254
|
} else {
|
|
234
|
-
// Handle simple numeric CSS properties (
|
|
255
|
+
// Handle simple numeric CSS properties (width, height, etc.)
|
|
235
256
|
if (fromIsObject) {
|
|
236
|
-
|
|
257
|
+
let raw = fromItem[propItem] !== undefined ? fromItem[propItem] : (fromItem !== undefined ? fromItem : valFrom);
|
|
258
|
+
staging["from"][propItem] = parseVal(raw);
|
|
237
259
|
} else {
|
|
238
|
-
staging["from"][propItem] = defsCopy[c].from;
|
|
260
|
+
staging["from"][propItem] = parseVal(defsCopy[c].from);
|
|
239
261
|
}
|
|
240
262
|
|
|
241
263
|
if (toIsObject) {
|
|
242
|
-
|
|
264
|
+
let raw = toItem[propItem] !== undefined ? toItem[propItem] : (toItem !== undefined ? toItem : valTo);
|
|
265
|
+
staging["to"][propItem] = parseVal(raw);
|
|
243
266
|
} else {
|
|
244
|
-
staging["to"][propItem] = defsCopy[c].to;
|
|
267
|
+
staging["to"][propItem] = parseVal(defsCopy[c].to);
|
|
245
268
|
}
|
|
246
269
|
propIndex++;
|
|
247
270
|
}
|
|
248
271
|
});
|
|
249
272
|
}
|
|
250
|
-
|
|
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
|
|
251
280
|
defsCopy[c].storeValueAnim = copyObj(staging);
|
|
252
281
|
staging = { color: {}, transform: {}, from: {}, to: {} };
|
|
253
282
|
}
|
|
254
|
-
|
|
255
|
-
//
|
|
283
|
+
|
|
284
|
+
// Determine if the next item starts a new sequence group
|
|
256
285
|
if (definitions[c + 1] !== undefined && (Array.isArray(definitions[c + 1]) || isElement(definitions[c + 1]))) {
|
|
257
286
|
expectNextGroup = true;
|
|
258
287
|
grouped = [];
|
|
@@ -767,8 +796,17 @@
|
|
|
767
796
|
else return el.style[cssprop];
|
|
768
797
|
}
|
|
769
798
|
|
|
799
|
+
// --- Robust DOM Element Validation ---
|
|
770
800
|
function isElement(element) {
|
|
771
|
-
|
|
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
|
+
}
|
|
772
810
|
}
|
|
773
811
|
|
|
774
812
|
const copyObj = function(obj) {
|