@pixodesk/svg-animator-web 1.0.8 → 1.0.10
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/dist/index.cjs +953 -611
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -3
- package/dist/index.d.ts +50 -3
- package/dist/index.js +953 -611
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.umd.js +953 -611
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -77,671 +77,874 @@ __export(index_exports, {
|
|
|
77
77
|
});
|
|
78
78
|
module.exports = __toCommonJS(index_exports);
|
|
79
79
|
|
|
80
|
-
// src/
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
80
|
+
// src/PxAnimatorTypes.ts
|
|
81
|
+
var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
|
|
82
|
+
var PX_ANIM_ATTR_NAME = "_px_animator";
|
|
83
|
+
var ANIMATE_ATTR = "animate";
|
|
84
|
+
var TEXT_ATTR = "text";
|
|
85
|
+
var TEXT_CONTENT_ATTR = "textContent";
|
|
86
|
+
var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
|
|
87
|
+
"type",
|
|
88
|
+
"children",
|
|
89
|
+
ANIMATE_ATTR,
|
|
90
|
+
"animator",
|
|
91
|
+
"meta",
|
|
92
|
+
"defs",
|
|
93
|
+
"bindings",
|
|
94
|
+
TEXT_ATTR,
|
|
95
|
+
TEXT_CONTENT_ATTR
|
|
96
|
+
]);
|
|
97
|
+
function isPxElementFileFormat(fileJson) {
|
|
98
|
+
if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
|
|
102
|
+
}
|
|
103
|
+
function isObject(v) {
|
|
104
|
+
return v && typeof v === "object" && !Array.isArray(v);
|
|
105
|
+
}
|
|
106
|
+
function validateFillMode(v, path, errors) {
|
|
107
|
+
if (v === "forwards" || v === "backwards" || v === "both" || v === "none") return true;
|
|
108
|
+
errors.push(path + ': invalid FillMode "' + v + `", expected 'forwards'|'backwards'|'both'|'none'`);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function validatePlaybackDirection(v, path, errors) {
|
|
112
|
+
if (v === "normal" || v === "reverse" || v === "alternate" || v === "alternate-reverse") return true;
|
|
113
|
+
errors.push(path + ': invalid PlaybackDirection "' + v + `", expected 'normal'|'reverse'|'alternate'|'alternate-reverse'`);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
function validatePxEasingOrRef(v, path, errors) {
|
|
117
|
+
if (typeof v === "string") return true;
|
|
118
|
+
if (Array.isArray(v) && v.length === 4 && v.every((n) => typeof n === "number")) return true;
|
|
119
|
+
errors.push(path + ": invalid easing, expected string or [number, number, number, number]");
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
function validatePxKeyframe(v, path, errors) {
|
|
123
|
+
if (!isObject(v)) {
|
|
124
|
+
errors.push(path + ": expected object");
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
let valid = true;
|
|
128
|
+
if (v.time !== void 0 && typeof v.time !== "number") {
|
|
129
|
+
errors.push(path + ".time: expected number, got " + typeof v.time);
|
|
130
|
+
valid = false;
|
|
131
|
+
}
|
|
132
|
+
if (v.t !== void 0 && typeof v.t !== "number") {
|
|
133
|
+
errors.push(path + ".t: expected number, got " + typeof v.t);
|
|
134
|
+
valid = false;
|
|
135
|
+
}
|
|
136
|
+
if (v.easing !== void 0 && !validatePxEasingOrRef(v.easing, path + ".easing", errors)) valid = false;
|
|
137
|
+
if (v.e !== void 0 && !validatePxEasingOrRef(v.e, path + ".e", errors)) valid = false;
|
|
138
|
+
return valid;
|
|
139
|
+
}
|
|
140
|
+
function validatePxPropertyAnimation(v, path, errors) {
|
|
141
|
+
if (!isObject(v)) {
|
|
142
|
+
errors.push(path + ": expected object");
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
let valid = true;
|
|
146
|
+
if (v.keyframes !== void 0) {
|
|
147
|
+
if (!Array.isArray(v.keyframes)) {
|
|
148
|
+
errors.push(path + ".keyframes: expected array");
|
|
149
|
+
valid = false;
|
|
99
150
|
} else {
|
|
100
|
-
|
|
151
|
+
v.keyframes.forEach((kf, i) => {
|
|
152
|
+
if (!validatePxKeyframe(kf, path + ".keyframes[" + i + "]", errors)) valid = false;
|
|
153
|
+
});
|
|
101
154
|
}
|
|
102
155
|
}
|
|
103
|
-
if (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
156
|
+
if (v.kfs !== void 0) {
|
|
157
|
+
if (!Array.isArray(v.kfs)) {
|
|
158
|
+
errors.push(path + ".kfs: expected array");
|
|
159
|
+
valid = false;
|
|
160
|
+
} else {
|
|
161
|
+
v.kfs.forEach((kf, i) => {
|
|
162
|
+
if (!validatePxKeyframe(kf, path + ".kfs[" + i + "]", errors)) valid = false;
|
|
163
|
+
});
|
|
111
164
|
}
|
|
112
|
-
d.push("z");
|
|
113
165
|
}
|
|
114
|
-
return
|
|
115
|
-
}
|
|
116
|
-
function interpolateNum(a, b, t) {
|
|
117
|
-
return a + (b - a) * t;
|
|
166
|
+
return valid;
|
|
118
167
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
|
|
168
|
+
function validatePxAnimationDefinition(v, path, errors) {
|
|
169
|
+
if (!isObject(v)) {
|
|
170
|
+
errors.push(path + ": expected object");
|
|
171
|
+
return false;
|
|
124
172
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return [
|
|
129
|
-
interpolateNum(a[0] || 0, b[0] || 0, t),
|
|
130
|
-
interpolateNum(a[1] || 0, b[1] || 0, t),
|
|
131
|
-
interpolateNum(a[2] || 0, b[2] || 0, t),
|
|
132
|
-
interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
|
|
133
|
-
];
|
|
134
|
-
}
|
|
135
|
-
function interpolateBeziers(paths1, paths2, progress) {
|
|
136
|
-
const count = Math.max(paths1.length, paths2.length);
|
|
137
|
-
const res = [];
|
|
138
|
-
for (let i = 0; i < count; i++) {
|
|
139
|
-
res.push(interpolateBezier(paths1[i], paths2[i], progress));
|
|
173
|
+
let valid = true;
|
|
174
|
+
for (const key of Object.keys(v)) {
|
|
175
|
+
if (!validatePxPropertyAnimation(v[key], path + "." + key, errors)) valid = false;
|
|
140
176
|
}
|
|
141
|
-
return
|
|
177
|
+
return valid;
|
|
142
178
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
if (
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const v2 = path2.v[idx];
|
|
154
|
-
v.push(interpolateVec(v1, v2, t));
|
|
155
|
-
const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
|
|
156
|
-
const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
|
|
157
|
-
i.push(interpolateVec(i1, i2, t));
|
|
158
|
-
const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
|
|
159
|
-
const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
|
|
160
|
-
o.push(interpolateVec(o1, o2, t));
|
|
179
|
+
function validatePxElementAnimation(v, path, errors) {
|
|
180
|
+
if (typeof v === "string") return true;
|
|
181
|
+
if (Array.isArray(v)) {
|
|
182
|
+
let valid = true;
|
|
183
|
+
v.forEach((item, i) => {
|
|
184
|
+
if (typeof item !== "string" && !validatePxAnimationDefinition(item, path + "[" + i + "]", errors)) {
|
|
185
|
+
valid = false;
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
return valid;
|
|
161
189
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
if (inMax === inMin) return outMin;
|
|
166
|
-
const t = (value - inMin) / (inMax - inMin);
|
|
167
|
-
return outMin + t * (outMax - outMin);
|
|
190
|
+
if (isObject(v)) return validatePxAnimationDefinition(v, path, errors);
|
|
191
|
+
errors.push(path + ": expected string, array, or PxAnimationDefinition object");
|
|
192
|
+
return false;
|
|
168
193
|
}
|
|
169
|
-
function
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const ax = 1 - cx - bx;
|
|
174
|
-
const cy = 3 * p1y;
|
|
175
|
-
const by = 3 * (p2y - p1y) - cy;
|
|
176
|
-
const ay = 1 - cy - by;
|
|
177
|
-
function sampleCurveX(t) {
|
|
178
|
-
return ((ax * t + bx) * t + cx) * t;
|
|
194
|
+
function validatePxTrigger(v, path, errors) {
|
|
195
|
+
if (!isObject(v)) {
|
|
196
|
+
errors.push(path + ": expected object");
|
|
197
|
+
return false;
|
|
179
198
|
}
|
|
180
|
-
|
|
181
|
-
|
|
199
|
+
let valid = true;
|
|
200
|
+
const validStartOn = ["load", "mouseOver", "click", "scrollIntoView", "programmatic"];
|
|
201
|
+
if (!validStartOn.includes(v.startOn)) {
|
|
202
|
+
errors.push(path + '.startOn: invalid value "' + v.startOn + '", expected ' + validStartOn.join("|"));
|
|
203
|
+
valid = false;
|
|
182
204
|
}
|
|
183
|
-
|
|
184
|
-
|
|
205
|
+
if (v.outAction !== void 0) {
|
|
206
|
+
const validOutAction = ["continue", "pause", "reset", "reverse"];
|
|
207
|
+
if (!validOutAction.includes(v.outAction)) {
|
|
208
|
+
errors.push(path + '.outAction: invalid value "' + v.outAction + '", expected ' + validOutAction.join("|"));
|
|
209
|
+
valid = false;
|
|
210
|
+
}
|
|
185
211
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
let t2 = x;
|
|
190
|
-
let t0 = 0;
|
|
191
|
-
let t1 = 1;
|
|
192
|
-
for (let i = 0; i < 8; i++) {
|
|
193
|
-
const x2 = sampleCurveX(t2) - x;
|
|
194
|
-
if (Math.abs(x2) < 1e-6) return t2;
|
|
195
|
-
const d2 = sampleCurveDerivativeX(t2);
|
|
196
|
-
if (Math.abs(d2) < 1e-6) break;
|
|
197
|
-
t2 -= x2 / d2;
|
|
198
|
-
}
|
|
199
|
-
t2 = x;
|
|
200
|
-
while (t0 < t1) {
|
|
201
|
-
const x2 = sampleCurveX(t2);
|
|
202
|
-
if (Math.abs(x2 - x) < 1e-6) return t2;
|
|
203
|
-
if (x > x2) t0 = t2;
|
|
204
|
-
else t1 = t2;
|
|
205
|
-
t2 = (t1 + t0) / 2;
|
|
206
|
-
}
|
|
207
|
-
return t2;
|
|
212
|
+
if (v.scrollIntoViewThreshold !== void 0 && typeof v.scrollIntoViewThreshold !== "number") {
|
|
213
|
+
errors.push(path + ".scrollIntoViewThreshold: expected number, got " + typeof v.scrollIntoViewThreshold);
|
|
214
|
+
valid = false;
|
|
208
215
|
}
|
|
209
|
-
return
|
|
210
|
-
return sampleCurveY(solveCurveX(x));
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
function toRGBA(color) {
|
|
214
|
-
const r = Math.round(color[0] * 255);
|
|
215
|
-
const g = Math.round(color[1] * 255);
|
|
216
|
-
const b = Math.round(color[2] * 255);
|
|
217
|
-
return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
|
|
218
|
-
}
|
|
219
|
-
function parseRgba(s) {
|
|
220
|
-
var _a;
|
|
221
|
-
const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
|
|
222
|
-
if (!inner) throw new Error("Invalid rgb/rgba format");
|
|
223
|
-
const parts = inner.split(",").map((v) => +v.trim());
|
|
224
|
-
return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
|
|
216
|
+
return valid;
|
|
225
217
|
}
|
|
226
|
-
function
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
|
|
231
|
-
const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
|
|
232
|
-
const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
|
|
233
|
-
const result = [
|
|
234
|
-
parseInt(r, 16) / 255,
|
|
235
|
-
parseInt(g, 16) / 255,
|
|
236
|
-
parseInt(b, 16) / 255
|
|
237
|
-
];
|
|
238
|
-
if (a !== null) {
|
|
239
|
-
result.push(parseInt(a, 16) / 255);
|
|
218
|
+
function validatePxAnimatorConfig(v, path, errors) {
|
|
219
|
+
if (!isObject(v)) {
|
|
220
|
+
errors.push(path + ": expected object");
|
|
221
|
+
return false;
|
|
240
222
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
if (Array.isArray(s)) return s;
|
|
246
|
-
if (typeof s !== "string") return void 0;
|
|
247
|
-
if (s.startsWith("#")) {
|
|
248
|
-
return parseHex(s);
|
|
249
|
-
} else if (s.startsWith("rgb")) {
|
|
250
|
-
return parseRgba(s);
|
|
251
|
-
} else {
|
|
252
|
-
console.warn("Unsupported color format: " + s);
|
|
223
|
+
let valid = true;
|
|
224
|
+
if (v.mode !== void 0 && !["auto", "webapi", "frames"].includes(v.mode)) {
|
|
225
|
+
errors.push(path + '.mode: invalid value "' + v.mode + `", expected 'auto'|'webapi'|'frames'`);
|
|
226
|
+
valid = false;
|
|
253
227
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
|
|
258
|
-
var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
259
|
-
var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
260
|
-
var DEFAULT_DURATION_MS = 1e3;
|
|
261
|
-
function kebabToCamelCaseWord(kebab) {
|
|
262
|
-
return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
|
|
263
|
-
}
|
|
264
|
-
function isCamelCaseWord(word) {
|
|
265
|
-
return !word.includes("-") && /[a-z][A-Z]/.test(word);
|
|
266
|
-
}
|
|
267
|
-
var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
|
|
268
|
-
// Transform/positioning
|
|
269
|
-
"viewBox",
|
|
270
|
-
"preserveAspectRatio",
|
|
271
|
-
// Gradient
|
|
272
|
-
"gradientUnits",
|
|
273
|
-
"gradientTransform",
|
|
274
|
-
"spreadMethod",
|
|
275
|
-
// Pattern
|
|
276
|
-
"patternUnits",
|
|
277
|
-
"patternContentUnits",
|
|
278
|
-
"patternTransform",
|
|
279
|
-
// Clipping/masking
|
|
280
|
-
"clipPathUnits",
|
|
281
|
-
"maskUnits",
|
|
282
|
-
"maskContentUnits",
|
|
283
|
-
// Text
|
|
284
|
-
"textLength",
|
|
285
|
-
"lengthAdjust",
|
|
286
|
-
"startOffset",
|
|
287
|
-
// Filter
|
|
288
|
-
"filterUnits",
|
|
289
|
-
"primitiveUnits",
|
|
290
|
-
"stdDeviation",
|
|
291
|
-
"baseFrequency",
|
|
292
|
-
"numOctaves",
|
|
293
|
-
"surfaceScale",
|
|
294
|
-
"diffuseConstant",
|
|
295
|
-
"specularConstant",
|
|
296
|
-
"specularExponent",
|
|
297
|
-
"kernelMatrix",
|
|
298
|
-
"kernelUnitLength",
|
|
299
|
-
"edgeMode",
|
|
300
|
-
"preserveAlpha",
|
|
301
|
-
"targetX",
|
|
302
|
-
"targetY"
|
|
303
|
-
// // Animation
|
|
304
|
-
// 'attributeName',
|
|
305
|
-
// 'attributeType',
|
|
306
|
-
// 'calcMode',
|
|
307
|
-
// 'keyTimes',
|
|
308
|
-
// 'keySplines',
|
|
309
|
-
// 'repeatCount',
|
|
310
|
-
// 'repeatDur'
|
|
311
|
-
]);
|
|
312
|
-
function camelCaseToKebabWordIfNeeded(camel) {
|
|
313
|
-
return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
314
|
-
}
|
|
315
|
-
function clamp(value, min, max) {
|
|
316
|
-
return Math.max(min, Math.min(value, max));
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// src/PxAnimatorDOM.ts
|
|
320
|
-
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
321
|
-
var INTERNAL_ATTRS = /* @__PURE__ */ new Set(["type", "children", "animate", "style", "animator", "defs", "bindings"]);
|
|
322
|
-
function createElement(tagName, props, style, children) {
|
|
323
|
-
const element = document.createElementNS(SVG_NS, tagName);
|
|
324
|
-
for (const propName in props) {
|
|
325
|
-
element.setAttribute(camelCaseToKebabWordIfNeeded(propName), props[propName]);
|
|
228
|
+
if (v.duration !== void 0 && typeof v.duration !== "number") {
|
|
229
|
+
errors.push(path + ".duration: expected number, got " + typeof v.duration);
|
|
230
|
+
valid = false;
|
|
326
231
|
}
|
|
327
|
-
if (
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
232
|
+
if (v.delay !== void 0 && typeof v.delay !== "number") {
|
|
233
|
+
errors.push(path + ".delay: expected number, got " + typeof v.delay);
|
|
234
|
+
valid = false;
|
|
331
235
|
}
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
236
|
+
if (v.iterations !== void 0 && typeof v.iterations !== "number" && v.iterations !== "infinite") {
|
|
237
|
+
errors.push(path + ".iterations: expected number or 'infinite', got " + typeof v.iterations);
|
|
238
|
+
valid = false;
|
|
336
239
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (typeof style === "string") {
|
|
343
|
-
return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
|
|
240
|
+
if (v.fill !== void 0 && !validateFillMode(v.fill, path + ".fill", errors)) valid = false;
|
|
241
|
+
if (v.direction !== void 0 && !validatePlaybackDirection(v.direction, path + ".direction", errors)) valid = false;
|
|
242
|
+
if (v.frameRate !== void 0 && typeof v.frameRate !== "number") {
|
|
243
|
+
errors.push(path + ".frameRate: expected number, got " + typeof v.frameRate);
|
|
244
|
+
valid = false;
|
|
344
245
|
}
|
|
345
|
-
|
|
246
|
+
if (v.trigger !== void 0 && !validatePxTrigger(v.trigger, path + ".trigger", errors)) valid = false;
|
|
247
|
+
return valid;
|
|
346
248
|
}
|
|
347
|
-
function
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
let value = props[key];
|
|
352
|
-
if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
|
|
353
|
-
propsCopy[key] = toRGBA(value);
|
|
354
|
-
} else if (TRANSFORM_FN_NAMES.has(key)) {
|
|
355
|
-
if (Array.isArray(value)) {
|
|
356
|
-
if (key === "translate") value = value.map((v) => v + "px");
|
|
357
|
-
value = value.join(",");
|
|
358
|
-
}
|
|
359
|
-
if (key === "rotate") value = value + "deg";
|
|
360
|
-
propsCopy["transform"] = key + "(" + value + ")";
|
|
361
|
-
} else if (value !== void 0 && value !== null) {
|
|
362
|
-
propsCopy[key] = String(value);
|
|
363
|
-
}
|
|
249
|
+
function validatePxDefs(v, path, errors) {
|
|
250
|
+
if (!isObject(v)) {
|
|
251
|
+
errors.push(path + ": expected object");
|
|
252
|
+
return false;
|
|
364
253
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
if (children) {
|
|
374
|
-
for (const ch of children) {
|
|
375
|
-
const child = renderNode(ch, nodeDefs);
|
|
376
|
-
if (child) {
|
|
377
|
-
if (!childElements) childElements = [];
|
|
378
|
-
childElements.push(child);
|
|
254
|
+
let valid = true;
|
|
255
|
+
if (v.easings !== void 0) {
|
|
256
|
+
if (!isObject(v.easings)) {
|
|
257
|
+
errors.push(path + ".easings: expected object");
|
|
258
|
+
valid = false;
|
|
259
|
+
} else {
|
|
260
|
+
for (const key of Object.keys(v.easings)) {
|
|
261
|
+
if (!validatePxEasingOrRef(v.easings[key], path + ".easings." + key, errors)) valid = false;
|
|
379
262
|
}
|
|
380
263
|
}
|
|
381
264
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// src/PxAnimatorTriggers.ts
|
|
391
|
-
function setupAnimationTriggers(api, config) {
|
|
392
|
-
const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
|
|
393
|
-
const root = api.getRootElement();
|
|
394
|
-
if (!root) {
|
|
395
|
-
console.warn("setupAnimationTriggers: No root element found for animation.");
|
|
396
|
-
return api;
|
|
397
|
-
}
|
|
398
|
-
const start = () => {
|
|
399
|
-
api.play();
|
|
400
|
-
};
|
|
401
|
-
const handleEndAction = () => {
|
|
402
|
-
switch (outAction) {
|
|
403
|
-
case "pause":
|
|
404
|
-
api.pause();
|
|
405
|
-
break;
|
|
406
|
-
case "reset":
|
|
407
|
-
api.cancel();
|
|
408
|
-
break;
|
|
409
|
-
case "reverse":
|
|
410
|
-
api.play();
|
|
411
|
-
break;
|
|
412
|
-
case "continue":
|
|
413
|
-
default:
|
|
414
|
-
break;
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
switch (startOn) {
|
|
418
|
-
case "load": {
|
|
419
|
-
const startHandler = () => start();
|
|
420
|
-
if (document.readyState === "complete") {
|
|
421
|
-
startHandler();
|
|
422
|
-
} else {
|
|
423
|
-
window.addEventListener("load", startHandler, { once: true });
|
|
265
|
+
if (v.animations !== void 0) {
|
|
266
|
+
if (!isObject(v.animations)) {
|
|
267
|
+
errors.push(path + ".animations: expected object");
|
|
268
|
+
valid = false;
|
|
269
|
+
} else {
|
|
270
|
+
for (const key of Object.keys(v.animations)) {
|
|
271
|
+
if (!validatePxAnimationDefinition(v.animations[key], path + ".animations." + key, errors)) valid = false;
|
|
424
272
|
}
|
|
425
|
-
break;
|
|
426
|
-
}
|
|
427
|
-
case "mouseOver": {
|
|
428
|
-
const mouseOverHandler = () => start();
|
|
429
|
-
const mouseOutHandler = () => handleEndAction();
|
|
430
|
-
root.addEventListener("mouseenter", mouseOverHandler);
|
|
431
|
-
root.addEventListener("mouseleave", mouseOutHandler);
|
|
432
|
-
break;
|
|
433
|
-
}
|
|
434
|
-
case "click": {
|
|
435
|
-
const clickHandler = () => {
|
|
436
|
-
if (api.isPlaying()) {
|
|
437
|
-
handleEndAction();
|
|
438
|
-
} else {
|
|
439
|
-
start();
|
|
440
|
-
}
|
|
441
|
-
};
|
|
442
|
-
root.addEventListener("click", clickHandler);
|
|
443
|
-
break;
|
|
444
|
-
}
|
|
445
|
-
case "scrollIntoView": {
|
|
446
|
-
const observer = new IntersectionObserver(
|
|
447
|
-
(entries) => {
|
|
448
|
-
entries.forEach((entry) => {
|
|
449
|
-
if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
|
|
450
|
-
start();
|
|
451
|
-
} else {
|
|
452
|
-
handleEndAction();
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
},
|
|
456
|
-
{ threshold: scrollIntoViewThreshold }
|
|
457
|
-
);
|
|
458
|
-
observer.observe(root);
|
|
459
|
-
break;
|
|
460
273
|
}
|
|
461
|
-
case "programmatic":
|
|
462
|
-
break;
|
|
463
274
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
// src/PxAnimatorTypes.ts
|
|
468
|
-
var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
|
|
469
|
-
var PX_ANIM_ATTR_NAME = "_px_animator";
|
|
470
|
-
function isPxElementFileFormat(fileJson) {
|
|
471
|
-
if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
|
|
472
|
-
return false;
|
|
275
|
+
if (v.styles !== void 0 && !isObject(v.styles)) {
|
|
276
|
+
errors.push(path + ".styles: expected object");
|
|
277
|
+
valid = false;
|
|
473
278
|
}
|
|
474
|
-
return
|
|
475
|
-
}
|
|
476
|
-
function isObject(v) {
|
|
477
|
-
return v && typeof v === "object" && !Array.isArray(v);
|
|
478
|
-
}
|
|
479
|
-
function validateFillMode(v, path, errors) {
|
|
480
|
-
if (v === "forwards" || v === "backwards" || v === "both" || v === "none") return true;
|
|
481
|
-
errors.push(path + ': invalid FillMode "' + v + `", expected 'forwards'|'backwards'|'both'|'none'`);
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
484
|
-
function validatePlaybackDirection(v, path, errors) {
|
|
485
|
-
if (v === "normal" || v === "reverse" || v === "alternate" || v === "alternate-reverse") return true;
|
|
486
|
-
errors.push(path + ': invalid PlaybackDirection "' + v + `", expected 'normal'|'reverse'|'alternate'|'alternate-reverse'`);
|
|
487
|
-
return false;
|
|
488
|
-
}
|
|
489
|
-
function validatePxEasingOrRef(v, path, errors) {
|
|
490
|
-
if (typeof v === "string") return true;
|
|
491
|
-
if (Array.isArray(v) && v.length === 4 && v.every((n) => typeof n === "number")) return true;
|
|
492
|
-
errors.push(path + ": invalid easing, expected string or [number, number, number, number]");
|
|
493
|
-
return false;
|
|
279
|
+
return valid;
|
|
494
280
|
}
|
|
495
|
-
function
|
|
281
|
+
function validatePxBinding(v, path, errors) {
|
|
496
282
|
if (!isObject(v)) {
|
|
497
283
|
errors.push(path + ": expected object");
|
|
498
284
|
return false;
|
|
499
285
|
}
|
|
500
286
|
let valid = true;
|
|
501
|
-
if (
|
|
502
|
-
errors.push(path + ".
|
|
503
|
-
valid = false;
|
|
504
|
-
}
|
|
505
|
-
if (v.t !== void 0 && typeof v.t !== "number") {
|
|
506
|
-
errors.push(path + ".t: expected number, got " + typeof v.t);
|
|
287
|
+
if (typeof v.id !== "string") {
|
|
288
|
+
errors.push(path + ".id: expected string, got " + typeof v.id);
|
|
507
289
|
valid = false;
|
|
508
290
|
}
|
|
509
|
-
if (
|
|
510
|
-
if (v.e !== void 0 && !validatePxEasingOrRef(v.e, path + ".e", errors)) valid = false;
|
|
291
|
+
if (!validatePxElementAnimation(v.animate, path + ".animate", errors)) valid = false;
|
|
511
292
|
return valid;
|
|
512
293
|
}
|
|
513
|
-
function
|
|
294
|
+
function validatePxNode(v, path, errors) {
|
|
514
295
|
if (!isObject(v)) {
|
|
515
296
|
errors.push(path + ": expected object");
|
|
516
297
|
return false;
|
|
517
298
|
}
|
|
518
299
|
let valid = true;
|
|
519
|
-
if (v.
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
valid = false;
|
|
523
|
-
} else {
|
|
524
|
-
v.keyframes.forEach((kf, i) => {
|
|
525
|
-
if (!validatePxKeyframe(kf, path + ".keyframes[" + i + "]", errors)) valid = false;
|
|
526
|
-
});
|
|
527
|
-
}
|
|
300
|
+
if (typeof v.type !== "string") {
|
|
301
|
+
errors.push(path + ".type: expected string, got " + typeof v.type);
|
|
302
|
+
valid = false;
|
|
528
303
|
}
|
|
529
|
-
if (v.
|
|
530
|
-
if (!Array.isArray(v.
|
|
531
|
-
errors.push(path + ".
|
|
304
|
+
if (v.children !== void 0) {
|
|
305
|
+
if (!Array.isArray(v.children)) {
|
|
306
|
+
errors.push(path + ".children: expected array");
|
|
532
307
|
valid = false;
|
|
533
308
|
} else {
|
|
534
|
-
v.
|
|
535
|
-
if (!
|
|
309
|
+
v.children.forEach((child, i) => {
|
|
310
|
+
if (!validatePxNode(child, path + ".children[" + i + "]", errors)) valid = false;
|
|
536
311
|
});
|
|
537
312
|
}
|
|
538
313
|
}
|
|
314
|
+
if (v.animate !== void 0 && !validatePxElementAnimation(v.animate, path + ".animate", errors)) valid = false;
|
|
539
315
|
return valid;
|
|
540
316
|
}
|
|
541
|
-
function
|
|
542
|
-
if (!
|
|
543
|
-
errors.push(path + ": expected object");
|
|
544
|
-
return false;
|
|
545
|
-
}
|
|
317
|
+
function validatePxSvgNode(v, path, errors) {
|
|
318
|
+
if (!validatePxNode(v, path, errors)) return false;
|
|
546
319
|
let valid = true;
|
|
547
|
-
|
|
548
|
-
|
|
320
|
+
if (v.type !== "svg") {
|
|
321
|
+
errors.push(path + ".type: expected 'svg', got '" + v.type + "'");
|
|
322
|
+
valid = false;
|
|
549
323
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
if (typeof v === "string") return true;
|
|
554
|
-
if (Array.isArray(v)) {
|
|
555
|
-
let valid = true;
|
|
556
|
-
v.forEach((item, i) => {
|
|
557
|
-
if (typeof item !== "string" && !validatePxAnimationDefinition(item, path + "[" + i + "]", errors)) {
|
|
558
|
-
valid = false;
|
|
559
|
-
}
|
|
560
|
-
});
|
|
561
|
-
return valid;
|
|
324
|
+
if (v.width !== void 0 && typeof v.width !== "number") {
|
|
325
|
+
errors.push(path + ".width: expected number, got " + typeof v.width);
|
|
326
|
+
valid = false;
|
|
562
327
|
}
|
|
563
|
-
if (
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
function validatePxTrigger(v, path, errors) {
|
|
568
|
-
if (!isObject(v)) {
|
|
569
|
-
errors.push(path + ": expected object");
|
|
570
|
-
return false;
|
|
328
|
+
if (v.height !== void 0 && typeof v.height !== "number") {
|
|
329
|
+
errors.push(path + ".height: expected number, got " + typeof v.height);
|
|
330
|
+
valid = false;
|
|
571
331
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if (!validStartOn.includes(v.startOn)) {
|
|
575
|
-
errors.push(path + '.startOn: invalid value "' + v.startOn + '", expected ' + validStartOn.join("|"));
|
|
332
|
+
if (v.viewBox !== void 0 && typeof v.viewBox !== "string") {
|
|
333
|
+
errors.push(path + ".viewBox: expected string, got " + typeof v.viewBox);
|
|
576
334
|
valid = false;
|
|
577
335
|
}
|
|
578
|
-
if (v.
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
336
|
+
if (v.animator !== void 0 && !validatePxAnimatorConfig(v.animator, path + ".animator", errors)) valid = false;
|
|
337
|
+
if (v.defs !== void 0 && !validatePxDefs(v.defs, path + ".defs", errors)) valid = false;
|
|
338
|
+
if (v.bindings !== void 0) {
|
|
339
|
+
if (!Array.isArray(v.bindings)) {
|
|
340
|
+
errors.push(path + ".bindings: expected array");
|
|
582
341
|
valid = false;
|
|
342
|
+
} else {
|
|
343
|
+
v.bindings.forEach((binding, i) => {
|
|
344
|
+
if (!validatePxBinding(binding, path + ".bindings[" + i + "]", errors)) valid = false;
|
|
345
|
+
});
|
|
583
346
|
}
|
|
584
347
|
}
|
|
585
|
-
if (v.
|
|
586
|
-
errors.push(path + ".scrollIntoViewThreshold: expected number, got " + typeof v.scrollIntoViewThreshold);
|
|
587
|
-
valid = false;
|
|
588
|
-
}
|
|
348
|
+
if (v.design !== void 0 && !validatePxNode(v.design, path + ".design", errors)) valid = false;
|
|
589
349
|
return valid;
|
|
590
350
|
}
|
|
591
|
-
function
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
351
|
+
function isPxElementFileFormatDeep(fileJson) {
|
|
352
|
+
const errors = [];
|
|
353
|
+
const valid = validatePxSvgNode(fileJson, "root", errors);
|
|
354
|
+
return { valid, errors };
|
|
355
|
+
}
|
|
356
|
+
function getAnimatorConfig(doc) {
|
|
357
|
+
var _a, _b;
|
|
358
|
+
return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator) || (doc == null ? void 0 : doc.animation) || ((_b = doc == null ? void 0 : doc.meta) == null ? void 0 : _b.animation);
|
|
359
|
+
}
|
|
360
|
+
function getDefs(doc) {
|
|
361
|
+
var _a;
|
|
362
|
+
if (!doc) return void 0;
|
|
363
|
+
return doc.defs || ((_a = doc.meta) == null ? void 0 : _a.defs);
|
|
364
|
+
}
|
|
365
|
+
function getBindings(doc) {
|
|
366
|
+
var _a;
|
|
367
|
+
if (!doc) return void 0;
|
|
368
|
+
return doc.bindings || ((_a = doc.meta) == null ? void 0 : _a.bindings);
|
|
369
|
+
}
|
|
370
|
+
function getChildren(doc) {
|
|
371
|
+
return doc == null ? void 0 : doc.children;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/PxAnimatorUtil.ts
|
|
375
|
+
function bezierToSvgPath(path) {
|
|
376
|
+
var _a, _b, _c, _d;
|
|
377
|
+
const v = path.v;
|
|
378
|
+
const i = path.i;
|
|
379
|
+
const o = path.o;
|
|
380
|
+
const c = path.c;
|
|
381
|
+
if (!v.length) return "";
|
|
382
|
+
const d = [];
|
|
383
|
+
const len = v.length;
|
|
384
|
+
d.push("M" + v[0][0] + "," + v[0][1]);
|
|
385
|
+
for (let idx = 1; idx < len; idx++) {
|
|
386
|
+
const prevV = v[idx - 1];
|
|
387
|
+
const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
|
|
388
|
+
const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
|
|
389
|
+
const currV = v[idx];
|
|
390
|
+
const isLine = prevO[0] === prevV[0] && prevO[1] === prevV[1] && (currI[0] === currV[0] && currI[1] === currV[1]);
|
|
391
|
+
if (isLine) {
|
|
392
|
+
d.push("L" + currV[0] + "," + currV[1]);
|
|
393
|
+
} else {
|
|
394
|
+
d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
|
|
395
|
+
}
|
|
600
396
|
}
|
|
601
|
-
if (
|
|
602
|
-
|
|
603
|
-
|
|
397
|
+
if (c && len > 0) {
|
|
398
|
+
const lastV = v[len - 1];
|
|
399
|
+
const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
|
|
400
|
+
const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
|
|
401
|
+
const firstV = v[0];
|
|
402
|
+
const isLine = lastO[0] === lastV[0] && lastO[1] === lastV[1] && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
|
|
403
|
+
if (!isLine) {
|
|
404
|
+
d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
|
|
405
|
+
}
|
|
406
|
+
d.push("z");
|
|
604
407
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
408
|
+
return d.join("");
|
|
409
|
+
}
|
|
410
|
+
function interpolateNum(a, b, t) {
|
|
411
|
+
return a + (b - a) * t;
|
|
412
|
+
}
|
|
413
|
+
function interpolateVec(a, b, t) {
|
|
414
|
+
const res = [];
|
|
415
|
+
const count = Math.max(a.length, b.length);
|
|
416
|
+
for (let i = 0; i < count; i++) {
|
|
417
|
+
res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
|
|
608
418
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
419
|
+
return res;
|
|
420
|
+
}
|
|
421
|
+
function interpolateColor(a, b, t) {
|
|
422
|
+
return [
|
|
423
|
+
interpolateNum(a[0] || 0, b[0] || 0, t),
|
|
424
|
+
interpolateNum(a[1] || 0, b[1] || 0, t),
|
|
425
|
+
interpolateNum(a[2] || 0, b[2] || 0, t),
|
|
426
|
+
interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
|
|
427
|
+
];
|
|
428
|
+
}
|
|
429
|
+
function interpolateBeziers(paths1, paths2, progress) {
|
|
430
|
+
const count = Math.max(paths1.length, paths2.length);
|
|
431
|
+
const res = [];
|
|
432
|
+
for (let i = 0; i < count; i++) {
|
|
433
|
+
res.push(interpolateBezier(paths1[i], paths2[i], progress));
|
|
612
434
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
435
|
+
return res;
|
|
436
|
+
}
|
|
437
|
+
function interpolateBezier(path1, path2, progress) {
|
|
438
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
439
|
+
if (!path1 || !path2) return path1 || path2 || { v: [] };
|
|
440
|
+
const t = Math.min(Math.max(progress, 0), 1);
|
|
441
|
+
const len = Math.min(path1.v.length, path2.v.length);
|
|
442
|
+
const v = [];
|
|
443
|
+
const i = [];
|
|
444
|
+
const o = [];
|
|
445
|
+
for (let idx = 0; idx < len; idx++) {
|
|
446
|
+
const v1 = path1.v[idx];
|
|
447
|
+
const v2 = path2.v[idx];
|
|
448
|
+
v.push(interpolateVec(v1, v2, t));
|
|
449
|
+
const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
|
|
450
|
+
const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
|
|
451
|
+
i.push(interpolateVec(i1, i2, t));
|
|
452
|
+
const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
|
|
453
|
+
const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
|
|
454
|
+
o.push(interpolateVec(o1, o2, t));
|
|
618
455
|
}
|
|
619
|
-
|
|
620
|
-
return valid;
|
|
456
|
+
return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
|
|
621
457
|
}
|
|
622
|
-
function
|
|
623
|
-
if (
|
|
624
|
-
|
|
625
|
-
|
|
458
|
+
function remap(value, inMin, inMax, outMin, outMax) {
|
|
459
|
+
if (inMax === inMin) return outMin;
|
|
460
|
+
const t = (value - inMin) / (inMax - inMin);
|
|
461
|
+
return outMin + t * (outMax - outMin);
|
|
462
|
+
}
|
|
463
|
+
function solveCubicBezierX(p1x, p2x, x) {
|
|
464
|
+
if (x <= 0) return 0;
|
|
465
|
+
if (x >= 1) return 1;
|
|
466
|
+
const cx = 3 * p1x;
|
|
467
|
+
const bx = 3 * (p2x - p1x) - cx;
|
|
468
|
+
const ax = 1 - cx - bx;
|
|
469
|
+
function sampleX(t) {
|
|
470
|
+
return ((ax * t + bx) * t + cx) * t;
|
|
626
471
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
if (!isObject(v.easings)) {
|
|
630
|
-
errors.push(path + ".easings: expected object");
|
|
631
|
-
valid = false;
|
|
632
|
-
} else {
|
|
633
|
-
for (const key of Object.keys(v.easings)) {
|
|
634
|
-
if (!validatePxEasingOrRef(v.easings[key], path + ".easings." + key, errors)) valid = false;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
472
|
+
function sampleDX(t) {
|
|
473
|
+
return (3 * ax * t + 2 * bx) * t + cx;
|
|
637
474
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
475
|
+
let t2 = x;
|
|
476
|
+
let t0 = 0;
|
|
477
|
+
let t1 = 1;
|
|
478
|
+
for (let i = 0; i < 8; i++) {
|
|
479
|
+
const x2 = sampleX(t2) - x;
|
|
480
|
+
if (Math.abs(x2) < 1e-6) return t2;
|
|
481
|
+
const d2 = sampleDX(t2);
|
|
482
|
+
if (Math.abs(d2) < 1e-6) break;
|
|
483
|
+
t2 -= x2 / d2;
|
|
484
|
+
}
|
|
485
|
+
t2 = x;
|
|
486
|
+
while (t0 < t1) {
|
|
487
|
+
const x2 = sampleX(t2);
|
|
488
|
+
if (Math.abs(x2 - x) < 1e-6) return t2;
|
|
489
|
+
if (x > x2) t0 = t2;
|
|
490
|
+
else t1 = t2;
|
|
491
|
+
t2 = (t1 + t0) / 2;
|
|
492
|
+
}
|
|
493
|
+
return t2;
|
|
494
|
+
}
|
|
495
|
+
function cubicBezier(easing) {
|
|
496
|
+
const [p1x, p1y, p2x, p2y] = easing;
|
|
497
|
+
const cy = 3 * p1y;
|
|
498
|
+
const by = 3 * (p2y - p1y) - cy;
|
|
499
|
+
const ay = 1 - cy - by;
|
|
500
|
+
function sampleCurveY(t) {
|
|
501
|
+
return ((ay * t + by) * t + cy) * t;
|
|
647
502
|
}
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
503
|
+
return function(x) {
|
|
504
|
+
return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
function lerp2(a, b, t) {
|
|
508
|
+
return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
|
|
509
|
+
}
|
|
510
|
+
function subdivideCubicBezier(p0, p1, p2, p3, t) {
|
|
511
|
+
const q0 = lerp2(p0, p1, t);
|
|
512
|
+
const q1 = lerp2(p1, p2, t);
|
|
513
|
+
const q2 = lerp2(p2, p3, t);
|
|
514
|
+
const r0 = lerp2(q0, q1, t);
|
|
515
|
+
const r1 = lerp2(q1, q2, t);
|
|
516
|
+
const s = lerp2(r0, r1, t);
|
|
517
|
+
return {
|
|
518
|
+
left: [p0, q0, r0, s],
|
|
519
|
+
right: [s, r1, q2, p3]
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
function splitEasing(easing, xFraction) {
|
|
523
|
+
if (!easing) return { left: void 0, right: void 0 };
|
|
524
|
+
if (xFraction <= 0) return { left: void 0, right: easing };
|
|
525
|
+
if (xFraction >= 1) return { left: easing, right: void 0 };
|
|
526
|
+
const [x1, y1, x2, y2] = easing;
|
|
527
|
+
const t = solveCubicBezierX(x1, x2, xFraction);
|
|
528
|
+
const p0 = [0, 0];
|
|
529
|
+
const p1 = [x1, y1];
|
|
530
|
+
const p2 = [x2, y2];
|
|
531
|
+
const p3 = [1, 1];
|
|
532
|
+
const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
|
|
533
|
+
const sx = left[3][0];
|
|
534
|
+
const sy = left[3][1];
|
|
535
|
+
let leftEasing;
|
|
536
|
+
if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
|
|
537
|
+
leftEasing = [
|
|
538
|
+
left[1][0] / sx,
|
|
539
|
+
left[1][1] / sy,
|
|
540
|
+
left[2][0] / sx,
|
|
541
|
+
left[2][1] / sy
|
|
542
|
+
];
|
|
543
|
+
}
|
|
544
|
+
let rightEasing;
|
|
545
|
+
const rx = 1 - sx;
|
|
546
|
+
const ry = 1 - sy;
|
|
547
|
+
if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
|
|
548
|
+
rightEasing = [
|
|
549
|
+
(right[1][0] - sx) / rx,
|
|
550
|
+
(right[1][1] - sy) / ry,
|
|
551
|
+
(right[2][0] - sx) / rx,
|
|
552
|
+
(right[2][1] - sy) / ry
|
|
553
|
+
];
|
|
554
|
+
}
|
|
555
|
+
return { left: leftEasing, right: rightEasing };
|
|
556
|
+
}
|
|
557
|
+
function reverseEasing(easing) {
|
|
558
|
+
if (!easing) return void 0;
|
|
559
|
+
return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
|
|
560
|
+
}
|
|
561
|
+
function toRGBA(color) {
|
|
562
|
+
const r = Math.round(color[0] * 255);
|
|
563
|
+
const g = Math.round(color[1] * 255);
|
|
564
|
+
const b = Math.round(color[2] * 255);
|
|
565
|
+
return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
|
|
566
|
+
}
|
|
567
|
+
function parseRgba(s) {
|
|
568
|
+
var _a;
|
|
569
|
+
const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
|
|
570
|
+
if (!inner) throw new Error("Invalid rgb/rgba format");
|
|
571
|
+
const parts = inner.split(",").map((v) => +v.trim());
|
|
572
|
+
return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
|
|
573
|
+
}
|
|
574
|
+
function parseHex(s) {
|
|
575
|
+
const hex = s.slice(1);
|
|
576
|
+
const isShort = hex.length <= 4;
|
|
577
|
+
const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
|
|
578
|
+
const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
|
|
579
|
+
const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
|
|
580
|
+
const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
|
|
581
|
+
const result = [
|
|
582
|
+
parseInt(r, 16) / 255,
|
|
583
|
+
parseInt(g, 16) / 255,
|
|
584
|
+
parseInt(b, 16) / 255
|
|
585
|
+
];
|
|
586
|
+
if (a !== null) {
|
|
587
|
+
result.push(parseInt(a, 16) / 255);
|
|
651
588
|
}
|
|
652
|
-
return
|
|
589
|
+
return result;
|
|
653
590
|
}
|
|
654
|
-
function
|
|
655
|
-
if (!
|
|
656
|
-
|
|
657
|
-
|
|
591
|
+
function parseColor(s) {
|
|
592
|
+
if (!s) return void 0;
|
|
593
|
+
if (Array.isArray(s)) return s;
|
|
594
|
+
if (typeof s !== "string") return void 0;
|
|
595
|
+
if (s.startsWith("#")) {
|
|
596
|
+
return parseHex(s);
|
|
597
|
+
} else if (s.startsWith("rgb")) {
|
|
598
|
+
return parseRgba(s);
|
|
599
|
+
} else {
|
|
600
|
+
console.warn("Unsupported color format: " + s);
|
|
601
|
+
}
|
|
602
|
+
return void 0;
|
|
603
|
+
}
|
|
604
|
+
var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
|
|
605
|
+
var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
|
|
606
|
+
var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
607
|
+
var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
608
|
+
var DEFAULT_DURATION_MS = 1e3;
|
|
609
|
+
function kebabToCamelCaseWord(kebab) {
|
|
610
|
+
return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
|
|
611
|
+
}
|
|
612
|
+
function isCamelCaseWord(word) {
|
|
613
|
+
return !word.includes("-") && /[a-z][A-Z]/.test(word);
|
|
614
|
+
}
|
|
615
|
+
var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
|
|
616
|
+
// Transform/positioning
|
|
617
|
+
"viewBox",
|
|
618
|
+
"preserveAspectRatio",
|
|
619
|
+
// Gradient
|
|
620
|
+
"gradientUnits",
|
|
621
|
+
"gradientTransform",
|
|
622
|
+
"spreadMethod",
|
|
623
|
+
// Pattern
|
|
624
|
+
"patternUnits",
|
|
625
|
+
"patternContentUnits",
|
|
626
|
+
"patternTransform",
|
|
627
|
+
// Clipping/masking
|
|
628
|
+
"clipPathUnits",
|
|
629
|
+
"maskUnits",
|
|
630
|
+
"maskContentUnits",
|
|
631
|
+
// Text
|
|
632
|
+
"textLength",
|
|
633
|
+
"lengthAdjust",
|
|
634
|
+
"startOffset",
|
|
635
|
+
// Filter
|
|
636
|
+
"filterUnits",
|
|
637
|
+
"primitiveUnits",
|
|
638
|
+
"stdDeviation",
|
|
639
|
+
"baseFrequency",
|
|
640
|
+
"numOctaves",
|
|
641
|
+
"surfaceScale",
|
|
642
|
+
"diffuseConstant",
|
|
643
|
+
"specularConstant",
|
|
644
|
+
"specularExponent",
|
|
645
|
+
"kernelMatrix",
|
|
646
|
+
"kernelUnitLength",
|
|
647
|
+
"edgeMode",
|
|
648
|
+
"preserveAlpha",
|
|
649
|
+
"targetX",
|
|
650
|
+
"targetY"
|
|
651
|
+
// // Animation
|
|
652
|
+
// 'attributeName',
|
|
653
|
+
// 'attributeType',
|
|
654
|
+
// 'calcMode',
|
|
655
|
+
// 'keyTimes',
|
|
656
|
+
// 'keySplines',
|
|
657
|
+
// 'repeatCount',
|
|
658
|
+
// 'repeatDur'
|
|
659
|
+
]);
|
|
660
|
+
function camelCaseToKebabWordIfNeeded(camel) {
|
|
661
|
+
return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
662
|
+
}
|
|
663
|
+
function clamp(value, min, max) {
|
|
664
|
+
return Math.max(min, Math.min(value, max));
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// src/PxAnimatorDOM.ts
|
|
668
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
669
|
+
var ALLOWED_SVG_TAGS_LOWER_CASE = new Set([
|
|
670
|
+
"svg",
|
|
671
|
+
"g",
|
|
672
|
+
"path",
|
|
673
|
+
"circle",
|
|
674
|
+
"ellipse",
|
|
675
|
+
"rect",
|
|
676
|
+
"line",
|
|
677
|
+
"polyline",
|
|
678
|
+
"polygon",
|
|
679
|
+
"text",
|
|
680
|
+
"tspan",
|
|
681
|
+
"defs",
|
|
682
|
+
"clipPath",
|
|
683
|
+
"mask",
|
|
684
|
+
"pattern",
|
|
685
|
+
"linearGradient",
|
|
686
|
+
"radialGradient",
|
|
687
|
+
"stop",
|
|
688
|
+
"use",
|
|
689
|
+
"symbol",
|
|
690
|
+
"marker",
|
|
691
|
+
"filter",
|
|
692
|
+
"feGaussianBlur",
|
|
693
|
+
"feOffset",
|
|
694
|
+
"feBlend",
|
|
695
|
+
"feColorMatrix",
|
|
696
|
+
"feMerge",
|
|
697
|
+
"feMergeNode"
|
|
698
|
+
].map((tagName) => tagName.toLowerCase()));
|
|
699
|
+
var ALLOWED_RESOURCE_ATTRIBUTES = [
|
|
700
|
+
"href",
|
|
701
|
+
// <use>
|
|
702
|
+
"src",
|
|
703
|
+
// <image>
|
|
704
|
+
"filter",
|
|
705
|
+
// url(#filterId)
|
|
706
|
+
"clipPath",
|
|
707
|
+
// clip-path="url(#clipPathId)"
|
|
708
|
+
"mask",
|
|
709
|
+
// url(#maskId)
|
|
710
|
+
"markerStart",
|
|
711
|
+
// marker-start="url(#markerId)"
|
|
712
|
+
"markerMid",
|
|
713
|
+
// marker-mid="url(#markerId)"
|
|
714
|
+
"markerEnd"
|
|
715
|
+
// marker-end="url(#markerId)"
|
|
716
|
+
// 'fill', // url(#gradientId) or url(#patternId)
|
|
717
|
+
// 'stroke', // url(#gradientId) or url(#patternId)
|
|
718
|
+
// Don't allow 'cursor', can use external SVG, // url(cursor.svg)
|
|
719
|
+
];
|
|
720
|
+
var ALLOWED_RESOURCE_ATTRIBUTES_SET = new Set(ALLOWED_RESOURCE_ATTRIBUTES);
|
|
721
|
+
var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
|
|
722
|
+
"href",
|
|
723
|
+
"src",
|
|
724
|
+
// Presentation
|
|
725
|
+
"fill",
|
|
726
|
+
"stroke",
|
|
727
|
+
"strokeWidth",
|
|
728
|
+
"opacity",
|
|
729
|
+
"transform",
|
|
730
|
+
// Geometry
|
|
731
|
+
"x",
|
|
732
|
+
"y",
|
|
733
|
+
"cx",
|
|
734
|
+
"cy",
|
|
735
|
+
"r",
|
|
736
|
+
"rx",
|
|
737
|
+
"ry",
|
|
738
|
+
"width",
|
|
739
|
+
"height",
|
|
740
|
+
"d",
|
|
741
|
+
"x1",
|
|
742
|
+
"y1",
|
|
743
|
+
"x2",
|
|
744
|
+
"y2",
|
|
745
|
+
"points",
|
|
746
|
+
// Text
|
|
747
|
+
"fontSize",
|
|
748
|
+
"fontFamily",
|
|
749
|
+
"textAnchor",
|
|
750
|
+
// Structure
|
|
751
|
+
"id",
|
|
752
|
+
"class",
|
|
753
|
+
"viewBox",
|
|
754
|
+
"preserveAspectRatio",
|
|
755
|
+
// Gradient/Pattern
|
|
756
|
+
"offset",
|
|
757
|
+
"stopColor",
|
|
758
|
+
"stopOpacity",
|
|
759
|
+
"gradientTransform",
|
|
760
|
+
// Clippath/Mask
|
|
761
|
+
"clipPath",
|
|
762
|
+
"mask",
|
|
763
|
+
// Filter
|
|
764
|
+
"filter",
|
|
765
|
+
"stdDeviation",
|
|
766
|
+
"in",
|
|
767
|
+
"in2",
|
|
768
|
+
"result",
|
|
769
|
+
"mode",
|
|
770
|
+
...ALLOWED_RESOURCE_ATTRIBUTES
|
|
771
|
+
]);
|
|
772
|
+
function sanitiseAttributeValue(name, value) {
|
|
773
|
+
const nameLower = name.toLowerCase();
|
|
774
|
+
if (!ALLOWED_ATTRIBUTES_SET.has(nameLower)) {
|
|
775
|
+
console.warn("Attribute not in whitelist: ", nameLower);
|
|
776
|
+
return void 0;
|
|
777
|
+
}
|
|
778
|
+
if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopColor") {
|
|
779
|
+
const str = String(value);
|
|
780
|
+
if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
|
|
781
|
+
console.warn('Attribute "' + nameLower + '" blocked: url() references must be internal url(#id), got:', value);
|
|
782
|
+
return void 0;
|
|
783
|
+
}
|
|
784
|
+
return value;
|
|
658
785
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
786
|
+
if (ALLOWED_RESOURCE_ATTRIBUTES_SET.has(nameLower)) {
|
|
787
|
+
const str = String(value);
|
|
788
|
+
if (str.startsWith("#")) {
|
|
789
|
+
return value;
|
|
790
|
+
}
|
|
791
|
+
if (/^url\(#[^)]+\)$/.test(str)) {
|
|
792
|
+
return value;
|
|
793
|
+
}
|
|
794
|
+
return void 0;
|
|
663
795
|
}
|
|
664
|
-
|
|
665
|
-
return valid;
|
|
796
|
+
return value;
|
|
666
797
|
}
|
|
667
|
-
function
|
|
668
|
-
if (!
|
|
669
|
-
|
|
670
|
-
|
|
798
|
+
function createElement(tagName, normalisedProps, style, children, textContent) {
|
|
799
|
+
if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) return null;
|
|
800
|
+
const element = document.createElementNS(SVG_NS, tagName);
|
|
801
|
+
for (const propName in normalisedProps) {
|
|
802
|
+
element.setAttribute(
|
|
803
|
+
camelCaseToKebabWordIfNeeded(propName),
|
|
804
|
+
sanitiseAttributeValue(propName, normalisedProps[propName])
|
|
805
|
+
);
|
|
671
806
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
807
|
+
if (style) {
|
|
808
|
+
for (const styleProp in style) {
|
|
809
|
+
element.style[styleProp] = String(style[styleProp]);
|
|
810
|
+
}
|
|
676
811
|
}
|
|
677
|
-
if (
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
valid = false;
|
|
681
|
-
} else {
|
|
682
|
-
v.children.forEach((child, i) => {
|
|
683
|
-
if (!validatePxNode(child, path + ".children[" + i + "]", errors)) valid = false;
|
|
684
|
-
});
|
|
812
|
+
if (children) {
|
|
813
|
+
for (const child of children) {
|
|
814
|
+
element.appendChild(child);
|
|
685
815
|
}
|
|
686
816
|
}
|
|
687
|
-
if (
|
|
688
|
-
return
|
|
817
|
+
if (textContent) element.textContent = textContent;
|
|
818
|
+
return element;
|
|
689
819
|
}
|
|
690
|
-
function
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
if (
|
|
694
|
-
|
|
695
|
-
valid = false;
|
|
820
|
+
function resolveStyle(style, defs) {
|
|
821
|
+
var _a;
|
|
822
|
+
if (!style) return void 0;
|
|
823
|
+
if (typeof style === "string") {
|
|
824
|
+
return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
|
|
696
825
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
826
|
+
return style;
|
|
827
|
+
}
|
|
828
|
+
function getNormalizedProps(props) {
|
|
829
|
+
const propsCopy = {};
|
|
830
|
+
for (const key of Object.keys(props)) {
|
|
831
|
+
if (INTERNAL_ATTRS.has(key)) continue;
|
|
832
|
+
if (key === "style") continue;
|
|
833
|
+
let value = props[key];
|
|
834
|
+
if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
|
|
835
|
+
propsCopy[key] = toRGBA(value);
|
|
836
|
+
} else if (TRANSFORM_FN_NAMES.has(key)) {
|
|
837
|
+
if (Array.isArray(value)) {
|
|
838
|
+
if (key === "translate") value = value.map((v) => v + "px");
|
|
839
|
+
value = value.join(",");
|
|
840
|
+
}
|
|
841
|
+
if (key === "rotate") value = value + "deg";
|
|
842
|
+
propsCopy["transform"] = key + "(" + value + ")";
|
|
843
|
+
} else if (value !== void 0 && value !== null) {
|
|
844
|
+
propsCopy[key] = String(value);
|
|
845
|
+
}
|
|
700
846
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
847
|
+
return propsCopy;
|
|
848
|
+
}
|
|
849
|
+
function renderNode(node, defs) {
|
|
850
|
+
if (!node) return null;
|
|
851
|
+
const _a = node, { type, children, animate, style } = _a, props = __objRest(_a, ["type", "children", "animate", "style"]);
|
|
852
|
+
const nodeDefs = node.defs || defs;
|
|
853
|
+
const resolvedStyle = resolveStyle(style, nodeDefs);
|
|
854
|
+
let childElements;
|
|
855
|
+
if (children) {
|
|
856
|
+
for (const ch of children) {
|
|
857
|
+
const child = renderNode(ch, nodeDefs);
|
|
858
|
+
if (child) {
|
|
859
|
+
if (!childElements) childElements = [];
|
|
860
|
+
childElements.push(child);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
704
863
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
864
|
+
return createElement(
|
|
865
|
+
type || "g",
|
|
866
|
+
getNormalizedProps(props),
|
|
867
|
+
resolvedStyle,
|
|
868
|
+
childElements,
|
|
869
|
+
props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// src/PxAnimatorTriggers.ts
|
|
874
|
+
function setupAnimationTriggers(api, config) {
|
|
875
|
+
const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
|
|
876
|
+
const root = api.getRootElement();
|
|
877
|
+
if (!root) {
|
|
878
|
+
console.warn("setupAnimationTriggers: No root element found for animation.");
|
|
879
|
+
return api;
|
|
708
880
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
881
|
+
const start = () => {
|
|
882
|
+
api.play();
|
|
883
|
+
};
|
|
884
|
+
const handleEndAction = () => {
|
|
885
|
+
switch (outAction) {
|
|
886
|
+
case "pause":
|
|
887
|
+
api.pause();
|
|
888
|
+
break;
|
|
889
|
+
case "reset":
|
|
890
|
+
api.cancel();
|
|
891
|
+
break;
|
|
892
|
+
case "reverse":
|
|
893
|
+
api.play();
|
|
894
|
+
break;
|
|
895
|
+
case "continue":
|
|
896
|
+
default:
|
|
897
|
+
break;
|
|
898
|
+
}
|
|
899
|
+
};
|
|
900
|
+
switch (startOn) {
|
|
901
|
+
case "load": {
|
|
902
|
+
const startHandler = () => start();
|
|
903
|
+
if (document.readyState === "complete") {
|
|
904
|
+
startHandler();
|
|
905
|
+
} else {
|
|
906
|
+
window.addEventListener("load", startHandler, { once: true });
|
|
907
|
+
}
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
case "mouseOver": {
|
|
911
|
+
const mouseOverHandler = () => start();
|
|
912
|
+
const mouseOutHandler = () => handleEndAction();
|
|
913
|
+
root.addEventListener("mouseenter", mouseOverHandler);
|
|
914
|
+
root.addEventListener("mouseleave", mouseOutHandler);
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
case "click": {
|
|
918
|
+
const clickHandler = () => {
|
|
919
|
+
if (api.isPlaying()) {
|
|
920
|
+
handleEndAction();
|
|
921
|
+
} else {
|
|
922
|
+
start();
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
root.addEventListener("click", clickHandler);
|
|
926
|
+
break;
|
|
927
|
+
}
|
|
928
|
+
case "scrollIntoView": {
|
|
929
|
+
const observer = new IntersectionObserver(
|
|
930
|
+
(entries) => {
|
|
931
|
+
entries.forEach((entry) => {
|
|
932
|
+
if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
|
|
933
|
+
start();
|
|
934
|
+
} else {
|
|
935
|
+
handleEndAction();
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
},
|
|
939
|
+
{ threshold: scrollIntoViewThreshold }
|
|
940
|
+
);
|
|
941
|
+
observer.observe(root);
|
|
942
|
+
break;
|
|
719
943
|
}
|
|
944
|
+
case "programmatic":
|
|
945
|
+
break;
|
|
720
946
|
}
|
|
721
|
-
|
|
722
|
-
return valid;
|
|
723
|
-
}
|
|
724
|
-
function isPxElementFileFormatDeep(fileJson) {
|
|
725
|
-
const errors = [];
|
|
726
|
-
const valid = validatePxSvgNode(fileJson, "root", errors);
|
|
727
|
-
return { valid, errors };
|
|
728
|
-
}
|
|
729
|
-
function getAnimatorConfig(doc) {
|
|
730
|
-
var _a, _b;
|
|
731
|
-
return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator) || (doc == null ? void 0 : doc.animation) || ((_b = doc == null ? void 0 : doc.meta) == null ? void 0 : _b.animation);
|
|
732
|
-
}
|
|
733
|
-
function getDefs(doc) {
|
|
734
|
-
var _a;
|
|
735
|
-
if (!doc) return void 0;
|
|
736
|
-
return doc.defs || ((_a = doc.meta) == null ? void 0 : _a.defs);
|
|
737
|
-
}
|
|
738
|
-
function getBindings(doc) {
|
|
739
|
-
var _a;
|
|
740
|
-
if (!doc) return void 0;
|
|
741
|
-
return doc.bindings || ((_a = doc.meta) == null ? void 0 : _a.bindings);
|
|
742
|
-
}
|
|
743
|
-
function getChildren(doc) {
|
|
744
|
-
return doc == null ? void 0 : doc.children;
|
|
947
|
+
return api;
|
|
745
948
|
}
|
|
746
949
|
|
|
747
950
|
// src/PxDefinitions.ts
|
|
@@ -898,6 +1101,111 @@ function resolveElementAnimation(animate, defs) {
|
|
|
898
1101
|
}
|
|
899
1102
|
return results;
|
|
900
1103
|
}
|
|
1104
|
+
function interpolateValue(propName, a, b, t) {
|
|
1105
|
+
var _a, _b;
|
|
1106
|
+
if (propName === "d") {
|
|
1107
|
+
const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
|
|
1108
|
+
const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
|
|
1109
|
+
return { paths: interpolateBeziers(aPaths, bPaths, t) };
|
|
1110
|
+
}
|
|
1111
|
+
if (COLOUR_ATTR_NAMES.has(propName)) {
|
|
1112
|
+
return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
|
|
1113
|
+
}
|
|
1114
|
+
if (TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
|
|
1115
|
+
return interpolateVec(a || [], b || [], t);
|
|
1116
|
+
}
|
|
1117
|
+
return interpolateNum(+(a || 0), +(b || 0), t);
|
|
1118
|
+
}
|
|
1119
|
+
function expandLoopKeyframes(propName, keyframes, loop, duration) {
|
|
1120
|
+
var _a, _b, _c, _d, _e;
|
|
1121
|
+
const totalIntervals = keyframes.length - 1;
|
|
1122
|
+
const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
|
|
1123
|
+
let segKfs;
|
|
1124
|
+
if (loop.before) {
|
|
1125
|
+
segKfs = keyframes.slice(0, segCount + 1);
|
|
1126
|
+
} else {
|
|
1127
|
+
segKfs = keyframes.slice(totalIntervals - segCount);
|
|
1128
|
+
}
|
|
1129
|
+
const firstT = (_b = keyframes[0].t) != null ? _b : 0;
|
|
1130
|
+
const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
|
|
1131
|
+
let fillStart, fillEnd;
|
|
1132
|
+
if (loop.before) {
|
|
1133
|
+
fillStart = 0;
|
|
1134
|
+
fillEnd = firstT;
|
|
1135
|
+
} else {
|
|
1136
|
+
fillStart = lastT;
|
|
1137
|
+
fillEnd = duration;
|
|
1138
|
+
}
|
|
1139
|
+
const fillDuration = fillEnd - fillStart;
|
|
1140
|
+
if (fillDuration <= 0) return keyframes;
|
|
1141
|
+
const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
|
|
1142
|
+
const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
|
|
1143
|
+
const segDuration = segEndT - segStartT;
|
|
1144
|
+
if (segDuration <= 0) return keyframes;
|
|
1145
|
+
const template = segKfs.map((kf) => ({
|
|
1146
|
+
relT: (kf.t - segStartT) / segDuration,
|
|
1147
|
+
v: kf.v,
|
|
1148
|
+
e: kf.e
|
|
1149
|
+
}));
|
|
1150
|
+
const fullReps = Math.floor(fillDuration / segDuration);
|
|
1151
|
+
const remainder = fillDuration - fullReps * segDuration;
|
|
1152
|
+
const partialFraction = remainder / segDuration;
|
|
1153
|
+
const looped = [];
|
|
1154
|
+
function appendRep(repStart, isReversed, partial) {
|
|
1155
|
+
let entries;
|
|
1156
|
+
if (isReversed) {
|
|
1157
|
+
entries = [];
|
|
1158
|
+
for (let i = template.length - 1; i >= 0; i--) {
|
|
1159
|
+
entries.push({
|
|
1160
|
+
relT: 1 - template[i].relT,
|
|
1161
|
+
v: template[i].v,
|
|
1162
|
+
// Easing for reversed transition: use reversed easing from the forward "from" keyframe
|
|
1163
|
+
e: i > 0 ? reverseEasing(template[i - 1].e) : void 0
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
} else {
|
|
1167
|
+
entries = template;
|
|
1168
|
+
}
|
|
1169
|
+
const cutRelT = partial !== void 0 ? partial : 1;
|
|
1170
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1171
|
+
const entry = entries[i];
|
|
1172
|
+
if (entry.relT > cutRelT + 1e-9) {
|
|
1173
|
+
const prev = entries[i - 1];
|
|
1174
|
+
const intervalSpan = entry.relT - prev.relT;
|
|
1175
|
+
const localFrac = (cutRelT - prev.relT) / intervalSpan;
|
|
1176
|
+
const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
|
|
1177
|
+
const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
|
|
1178
|
+
const { left: leftEasing } = splitEasing(prev.e, localFrac);
|
|
1179
|
+
if (looped.length > 0 && prev.relT <= cutRelT) {
|
|
1180
|
+
looped[looped.length - 1].e = leftEasing;
|
|
1181
|
+
}
|
|
1182
|
+
looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
looped.push({
|
|
1186
|
+
t: repStart + entry.relT * segDuration,
|
|
1187
|
+
v: entry.v,
|
|
1188
|
+
e: i < entries.length - 1 ? entry.e : void 0
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
for (let rep = 0; rep < fullReps; rep++) {
|
|
1193
|
+
const distFromBoundary = loop.before ? fullReps - 1 - rep : rep;
|
|
1194
|
+
const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
|
|
1195
|
+
const repStart = fillStart + rep * segDuration;
|
|
1196
|
+
appendRep(repStart, isReversed);
|
|
1197
|
+
}
|
|
1198
|
+
if (partialFraction > 1e-9) {
|
|
1199
|
+
const isReversed = !!loop.alternate && fullReps % 2 === 0;
|
|
1200
|
+
const repStart = fillStart + fullReps * segDuration;
|
|
1201
|
+
appendRep(repStart, isReversed, partialFraction);
|
|
1202
|
+
}
|
|
1203
|
+
if (loop.before) {
|
|
1204
|
+
return [...looped, ...keyframes];
|
|
1205
|
+
} else {
|
|
1206
|
+
return [...keyframes, ...looped];
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
901
1209
|
function normalizeKeyframes(propName, propAnim, duration, defs) {
|
|
902
1210
|
var _a, _b, _c, _d, _e;
|
|
903
1211
|
const keyframes = propAnim.keyframes || propAnim.kfs || [];
|
|
@@ -922,6 +1230,11 @@ function normalizeKeyframes(propName, propAnim, duration, defs) {
|
|
|
922
1230
|
var _a2, _b2;
|
|
923
1231
|
return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
|
|
924
1232
|
});
|
|
1233
|
+
const loopRaw = propAnim.loop;
|
|
1234
|
+
const loop = loopRaw === true ? {} : loopRaw || void 0;
|
|
1235
|
+
if (loop && normalized.length >= 2) {
|
|
1236
|
+
return expandLoopKeyframes(propName, normalized, loop, duration);
|
|
1237
|
+
}
|
|
925
1238
|
return normalized;
|
|
926
1239
|
}
|
|
927
1240
|
function mergeAnimationDefinitions(animations) {
|
|
@@ -1356,40 +1669,56 @@ function createDomAdapter(rootElement) {
|
|
|
1356
1669
|
}
|
|
1357
1670
|
|
|
1358
1671
|
// src/PxAnimatorWebApi.ts
|
|
1672
|
+
function createCssKf(kf, t, propName, unsupportedSet) {
|
|
1673
|
+
var _a, _b;
|
|
1674
|
+
let value = (_a = kf.v) != null ? _a : kf.value;
|
|
1675
|
+
const e = (_b = kf.e) != null ? _b : kf.easing;
|
|
1676
|
+
const cssKf = {
|
|
1677
|
+
offset: t,
|
|
1678
|
+
easing: e && Array.isArray(e) ? "cubic-bezier(" + e.join(",") + ")" : void 0
|
|
1679
|
+
};
|
|
1680
|
+
let cssValue;
|
|
1681
|
+
let cssKey = propName;
|
|
1682
|
+
if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
|
|
1683
|
+
cssValue = toRGBA(value);
|
|
1684
|
+
} else if (TRANSFORM_FN_NAMES.has(propName)) {
|
|
1685
|
+
if (Array.isArray(value)) {
|
|
1686
|
+
if (propName === "translate") value = value.map((v) => v + "px");
|
|
1687
|
+
value = value.join(",");
|
|
1688
|
+
}
|
|
1689
|
+
if (propName === "rotate") value = value + "deg";
|
|
1690
|
+
cssValue = propName + "(" + value + ")";
|
|
1691
|
+
cssKey = "transform";
|
|
1692
|
+
} else {
|
|
1693
|
+
cssValue = "" + value;
|
|
1694
|
+
}
|
|
1695
|
+
if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
|
|
1696
|
+
cssKey = kebabToCamelCaseWord(cssKey);
|
|
1697
|
+
cssKf[cssKey] = cssValue;
|
|
1698
|
+
return cssKf;
|
|
1699
|
+
}
|
|
1359
1700
|
function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
|
|
1360
|
-
var _a, _b
|
|
1701
|
+
var _a, _b;
|
|
1361
1702
|
const result = /* @__PURE__ */ new Map();
|
|
1362
1703
|
for (const [propName, propAnim] of Object.entries(animDef)) {
|
|
1363
1704
|
const keyframes = propAnim.kfs || propAnim.keyframes || [];
|
|
1364
1705
|
const cssKeyframes = [];
|
|
1365
|
-
for (
|
|
1706
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
1707
|
+
const kf = keyframes[i];
|
|
1366
1708
|
let t = (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
|
|
1367
1709
|
t = clamp(t / (config.duration || 1), 0, 1);
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
};
|
|
1374
|
-
let cssValue;
|
|
1375
|
-
let cssKey = propName;
|
|
1376
|
-
if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
|
|
1377
|
-
cssValue = toRGBA(value);
|
|
1378
|
-
} else if (TRANSFORM_FN_NAMES.has(propName)) {
|
|
1379
|
-
if (Array.isArray(value)) {
|
|
1380
|
-
if (propName === "translate") value = value.map((v) => v + "px");
|
|
1381
|
-
value = value.join(",");
|
|
1382
|
-
}
|
|
1383
|
-
if (propName === "rotate") value = value + "deg";
|
|
1384
|
-
cssValue = propName + "(" + value + ")";
|
|
1385
|
-
cssKey = "transform";
|
|
1386
|
-
} else {
|
|
1387
|
-
cssValue = "" + value;
|
|
1710
|
+
const cssKf = createCssKf(kf, t, propName, unsupportedSet);
|
|
1711
|
+
if (i === 0 && (cssKf.offset || 0) > 0) {
|
|
1712
|
+
cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
|
|
1713
|
+
offset: 0
|
|
1714
|
+
}));
|
|
1388
1715
|
}
|
|
1389
|
-
if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
|
|
1390
|
-
cssKey = kebabToCamelCaseWord(cssKey);
|
|
1391
|
-
cssKf[cssKey] = cssValue;
|
|
1392
1716
|
cssKeyframes.push(cssKf);
|
|
1717
|
+
if (i === keyframes.length - 1 && (cssKf.offset || 0) < 1) {
|
|
1718
|
+
cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
|
|
1719
|
+
offset: 1
|
|
1720
|
+
}));
|
|
1721
|
+
}
|
|
1393
1722
|
}
|
|
1394
1723
|
if (cssKeyframes.length > 0) {
|
|
1395
1724
|
result.set(propName, cssKeyframes);
|
|
@@ -1430,17 +1759,17 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
1430
1759
|
console.warn('createWebApiAnimator: No elements found for selector "' + selector + '"');
|
|
1431
1760
|
}
|
|
1432
1761
|
const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
|
|
1762
|
+
const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
|
|
1763
|
+
const seekPosition = config.delay && config.delay < 0 && config.duration ? -config.delay % config.duration : void 0;
|
|
1764
|
+
const effectOptions = {
|
|
1765
|
+
duration: config.duration,
|
|
1766
|
+
delay: positiveDelay,
|
|
1767
|
+
fill: config.fill,
|
|
1768
|
+
direction: config.direction,
|
|
1769
|
+
iterations
|
|
1770
|
+
};
|
|
1433
1771
|
for (let i = 0; i < elements.length; i++) {
|
|
1434
1772
|
const element = elements[i];
|
|
1435
|
-
const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
|
|
1436
|
-
const seekPosition = config.delay && config.delay < 0 && config.duration ? -config.delay % config.duration : void 0;
|
|
1437
|
-
const effectOptions = {
|
|
1438
|
-
duration: config.duration,
|
|
1439
|
-
delay: positiveDelay,
|
|
1440
|
-
fill: config.fill,
|
|
1441
|
-
direction: config.direction,
|
|
1442
|
-
iterations
|
|
1443
|
-
};
|
|
1444
1773
|
for (const [, keyframes] of keyframesMap) {
|
|
1445
1774
|
if (keyframes.length > 0) {
|
|
1446
1775
|
try {
|
|
@@ -1492,7 +1821,20 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
1492
1821
|
(_a = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a.call(callbacks);
|
|
1493
1822
|
},
|
|
1494
1823
|
"finish": () => {
|
|
1495
|
-
|
|
1824
|
+
var _a;
|
|
1825
|
+
for (const a of animations) {
|
|
1826
|
+
try {
|
|
1827
|
+
if (((_a = a.effect) == null ? void 0 : _a.getTiming().iterations) === Infinity) {
|
|
1828
|
+
a.effect.updateTiming({ iterations: 1 });
|
|
1829
|
+
a.finish();
|
|
1830
|
+
a.effect.updateTiming({ iterations: Infinity });
|
|
1831
|
+
} else {
|
|
1832
|
+
a.finish();
|
|
1833
|
+
}
|
|
1834
|
+
} catch (e) {
|
|
1835
|
+
a.cancel();
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1496
1838
|
},
|
|
1497
1839
|
"setPlaybackRate": (rate) => {
|
|
1498
1840
|
animations.forEach((a) => a.playbackRate = rate);
|
|
@@ -1623,7 +1965,7 @@ function generateNewIds(doc) {
|
|
|
1623
1965
|
value[styleProp] = replaceUrlRefs(styleValue, idMap);
|
|
1624
1966
|
}
|
|
1625
1967
|
}
|
|
1626
|
-
} else if (typeof value === "object" && value !== null && key !==
|
|
1968
|
+
} else if (typeof value === "object" && value !== null && key !== ANIMATE_ATTR) {
|
|
1627
1969
|
updateRefs(value);
|
|
1628
1970
|
}
|
|
1629
1971
|
}
|