@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.js
CHANGED
|
@@ -30,671 +30,874 @@ var __objRest = (source, exclude) => {
|
|
|
30
30
|
return target;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
// src/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
33
|
+
// src/PxAnimatorTypes.ts
|
|
34
|
+
var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
|
|
35
|
+
var PX_ANIM_ATTR_NAME = "_px_animator";
|
|
36
|
+
var ANIMATE_ATTR = "animate";
|
|
37
|
+
var TEXT_ATTR = "text";
|
|
38
|
+
var TEXT_CONTENT_ATTR = "textContent";
|
|
39
|
+
var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
|
|
40
|
+
"type",
|
|
41
|
+
"children",
|
|
42
|
+
ANIMATE_ATTR,
|
|
43
|
+
"animator",
|
|
44
|
+
"meta",
|
|
45
|
+
"defs",
|
|
46
|
+
"bindings",
|
|
47
|
+
TEXT_ATTR,
|
|
48
|
+
TEXT_CONTENT_ATTR
|
|
49
|
+
]);
|
|
50
|
+
function isPxElementFileFormat(fileJson) {
|
|
51
|
+
if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
|
|
55
|
+
}
|
|
56
|
+
function isObject(v) {
|
|
57
|
+
return v && typeof v === "object" && !Array.isArray(v);
|
|
58
|
+
}
|
|
59
|
+
function validateFillMode(v, path, errors) {
|
|
60
|
+
if (v === "forwards" || v === "backwards" || v === "both" || v === "none") return true;
|
|
61
|
+
errors.push(path + ': invalid FillMode "' + v + `", expected 'forwards'|'backwards'|'both'|'none'`);
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
function validatePlaybackDirection(v, path, errors) {
|
|
65
|
+
if (v === "normal" || v === "reverse" || v === "alternate" || v === "alternate-reverse") return true;
|
|
66
|
+
errors.push(path + ': invalid PlaybackDirection "' + v + `", expected 'normal'|'reverse'|'alternate'|'alternate-reverse'`);
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
function validatePxEasingOrRef(v, path, errors) {
|
|
70
|
+
if (typeof v === "string") return true;
|
|
71
|
+
if (Array.isArray(v) && v.length === 4 && v.every((n) => typeof n === "number")) return true;
|
|
72
|
+
errors.push(path + ": invalid easing, expected string or [number, number, number, number]");
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
function validatePxKeyframe(v, path, errors) {
|
|
76
|
+
if (!isObject(v)) {
|
|
77
|
+
errors.push(path + ": expected object");
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
let valid = true;
|
|
81
|
+
if (v.time !== void 0 && typeof v.time !== "number") {
|
|
82
|
+
errors.push(path + ".time: expected number, got " + typeof v.time);
|
|
83
|
+
valid = false;
|
|
84
|
+
}
|
|
85
|
+
if (v.t !== void 0 && typeof v.t !== "number") {
|
|
86
|
+
errors.push(path + ".t: expected number, got " + typeof v.t);
|
|
87
|
+
valid = false;
|
|
88
|
+
}
|
|
89
|
+
if (v.easing !== void 0 && !validatePxEasingOrRef(v.easing, path + ".easing", errors)) valid = false;
|
|
90
|
+
if (v.e !== void 0 && !validatePxEasingOrRef(v.e, path + ".e", errors)) valid = false;
|
|
91
|
+
return valid;
|
|
92
|
+
}
|
|
93
|
+
function validatePxPropertyAnimation(v, path, errors) {
|
|
94
|
+
if (!isObject(v)) {
|
|
95
|
+
errors.push(path + ": expected object");
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
let valid = true;
|
|
99
|
+
if (v.keyframes !== void 0) {
|
|
100
|
+
if (!Array.isArray(v.keyframes)) {
|
|
101
|
+
errors.push(path + ".keyframes: expected array");
|
|
102
|
+
valid = false;
|
|
52
103
|
} else {
|
|
53
|
-
|
|
104
|
+
v.keyframes.forEach((kf, i) => {
|
|
105
|
+
if (!validatePxKeyframe(kf, path + ".keyframes[" + i + "]", errors)) valid = false;
|
|
106
|
+
});
|
|
54
107
|
}
|
|
55
108
|
}
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
109
|
+
if (v.kfs !== void 0) {
|
|
110
|
+
if (!Array.isArray(v.kfs)) {
|
|
111
|
+
errors.push(path + ".kfs: expected array");
|
|
112
|
+
valid = false;
|
|
113
|
+
} else {
|
|
114
|
+
v.kfs.forEach((kf, i) => {
|
|
115
|
+
if (!validatePxKeyframe(kf, path + ".kfs[" + i + "]", errors)) valid = false;
|
|
116
|
+
});
|
|
64
117
|
}
|
|
65
|
-
d.push("z");
|
|
66
118
|
}
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
function interpolateNum(a, b, t) {
|
|
70
|
-
return a + (b - a) * t;
|
|
119
|
+
return valid;
|
|
71
120
|
}
|
|
72
|
-
function
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
|
|
121
|
+
function validatePxAnimationDefinition(v, path, errors) {
|
|
122
|
+
if (!isObject(v)) {
|
|
123
|
+
errors.push(path + ": expected object");
|
|
124
|
+
return false;
|
|
77
125
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return [
|
|
82
|
-
interpolateNum(a[0] || 0, b[0] || 0, t),
|
|
83
|
-
interpolateNum(a[1] || 0, b[1] || 0, t),
|
|
84
|
-
interpolateNum(a[2] || 0, b[2] || 0, t),
|
|
85
|
-
interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
|
|
86
|
-
];
|
|
87
|
-
}
|
|
88
|
-
function interpolateBeziers(paths1, paths2, progress) {
|
|
89
|
-
const count = Math.max(paths1.length, paths2.length);
|
|
90
|
-
const res = [];
|
|
91
|
-
for (let i = 0; i < count; i++) {
|
|
92
|
-
res.push(interpolateBezier(paths1[i], paths2[i], progress));
|
|
126
|
+
let valid = true;
|
|
127
|
+
for (const key of Object.keys(v)) {
|
|
128
|
+
if (!validatePxPropertyAnimation(v[key], path + "." + key, errors)) valid = false;
|
|
93
129
|
}
|
|
94
|
-
return
|
|
130
|
+
return valid;
|
|
95
131
|
}
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const v2 = path2.v[idx];
|
|
107
|
-
v.push(interpolateVec(v1, v2, t));
|
|
108
|
-
const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
|
|
109
|
-
const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
|
|
110
|
-
i.push(interpolateVec(i1, i2, t));
|
|
111
|
-
const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
|
|
112
|
-
const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
|
|
113
|
-
o.push(interpolateVec(o1, o2, t));
|
|
132
|
+
function validatePxElementAnimation(v, path, errors) {
|
|
133
|
+
if (typeof v === "string") return true;
|
|
134
|
+
if (Array.isArray(v)) {
|
|
135
|
+
let valid = true;
|
|
136
|
+
v.forEach((item, i) => {
|
|
137
|
+
if (typeof item !== "string" && !validatePxAnimationDefinition(item, path + "[" + i + "]", errors)) {
|
|
138
|
+
valid = false;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return valid;
|
|
114
142
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (inMax === inMin) return outMin;
|
|
119
|
-
const t = (value - inMin) / (inMax - inMin);
|
|
120
|
-
return outMin + t * (outMax - outMin);
|
|
143
|
+
if (isObject(v)) return validatePxAnimationDefinition(v, path, errors);
|
|
144
|
+
errors.push(path + ": expected string, array, or PxAnimationDefinition object");
|
|
145
|
+
return false;
|
|
121
146
|
}
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const ax = 1 - cx - bx;
|
|
127
|
-
const cy = 3 * p1y;
|
|
128
|
-
const by = 3 * (p2y - p1y) - cy;
|
|
129
|
-
const ay = 1 - cy - by;
|
|
130
|
-
function sampleCurveX(t) {
|
|
131
|
-
return ((ax * t + bx) * t + cx) * t;
|
|
147
|
+
function validatePxTrigger(v, path, errors) {
|
|
148
|
+
if (!isObject(v)) {
|
|
149
|
+
errors.push(path + ": expected object");
|
|
150
|
+
return false;
|
|
132
151
|
}
|
|
133
|
-
|
|
134
|
-
|
|
152
|
+
let valid = true;
|
|
153
|
+
const validStartOn = ["load", "mouseOver", "click", "scrollIntoView", "programmatic"];
|
|
154
|
+
if (!validStartOn.includes(v.startOn)) {
|
|
155
|
+
errors.push(path + '.startOn: invalid value "' + v.startOn + '", expected ' + validStartOn.join("|"));
|
|
156
|
+
valid = false;
|
|
135
157
|
}
|
|
136
|
-
|
|
137
|
-
|
|
158
|
+
if (v.outAction !== void 0) {
|
|
159
|
+
const validOutAction = ["continue", "pause", "reset", "reverse"];
|
|
160
|
+
if (!validOutAction.includes(v.outAction)) {
|
|
161
|
+
errors.push(path + '.outAction: invalid value "' + v.outAction + '", expected ' + validOutAction.join("|"));
|
|
162
|
+
valid = false;
|
|
163
|
+
}
|
|
138
164
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
let t2 = x;
|
|
143
|
-
let t0 = 0;
|
|
144
|
-
let t1 = 1;
|
|
145
|
-
for (let i = 0; i < 8; i++) {
|
|
146
|
-
const x2 = sampleCurveX(t2) - x;
|
|
147
|
-
if (Math.abs(x2) < 1e-6) return t2;
|
|
148
|
-
const d2 = sampleCurveDerivativeX(t2);
|
|
149
|
-
if (Math.abs(d2) < 1e-6) break;
|
|
150
|
-
t2 -= x2 / d2;
|
|
151
|
-
}
|
|
152
|
-
t2 = x;
|
|
153
|
-
while (t0 < t1) {
|
|
154
|
-
const x2 = sampleCurveX(t2);
|
|
155
|
-
if (Math.abs(x2 - x) < 1e-6) return t2;
|
|
156
|
-
if (x > x2) t0 = t2;
|
|
157
|
-
else t1 = t2;
|
|
158
|
-
t2 = (t1 + t0) / 2;
|
|
159
|
-
}
|
|
160
|
-
return t2;
|
|
165
|
+
if (v.scrollIntoViewThreshold !== void 0 && typeof v.scrollIntoViewThreshold !== "number") {
|
|
166
|
+
errors.push(path + ".scrollIntoViewThreshold: expected number, got " + typeof v.scrollIntoViewThreshold);
|
|
167
|
+
valid = false;
|
|
161
168
|
}
|
|
162
|
-
return
|
|
163
|
-
return sampleCurveY(solveCurveX(x));
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
function toRGBA(color) {
|
|
167
|
-
const r = Math.round(color[0] * 255);
|
|
168
|
-
const g = Math.round(color[1] * 255);
|
|
169
|
-
const b = Math.round(color[2] * 255);
|
|
170
|
-
return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
|
|
171
|
-
}
|
|
172
|
-
function parseRgba(s) {
|
|
173
|
-
var _a;
|
|
174
|
-
const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
|
|
175
|
-
if (!inner) throw new Error("Invalid rgb/rgba format");
|
|
176
|
-
const parts = inner.split(",").map((v) => +v.trim());
|
|
177
|
-
return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
|
|
169
|
+
return valid;
|
|
178
170
|
}
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
|
|
184
|
-
const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
|
|
185
|
-
const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
|
|
186
|
-
const result = [
|
|
187
|
-
parseInt(r, 16) / 255,
|
|
188
|
-
parseInt(g, 16) / 255,
|
|
189
|
-
parseInt(b, 16) / 255
|
|
190
|
-
];
|
|
191
|
-
if (a !== null) {
|
|
192
|
-
result.push(parseInt(a, 16) / 255);
|
|
171
|
+
function validatePxAnimatorConfig(v, path, errors) {
|
|
172
|
+
if (!isObject(v)) {
|
|
173
|
+
errors.push(path + ": expected object");
|
|
174
|
+
return false;
|
|
193
175
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (Array.isArray(s)) return s;
|
|
199
|
-
if (typeof s !== "string") return void 0;
|
|
200
|
-
if (s.startsWith("#")) {
|
|
201
|
-
return parseHex(s);
|
|
202
|
-
} else if (s.startsWith("rgb")) {
|
|
203
|
-
return parseRgba(s);
|
|
204
|
-
} else {
|
|
205
|
-
console.warn("Unsupported color format: " + s);
|
|
176
|
+
let valid = true;
|
|
177
|
+
if (v.mode !== void 0 && !["auto", "webapi", "frames"].includes(v.mode)) {
|
|
178
|
+
errors.push(path + '.mode: invalid value "' + v.mode + `", expected 'auto'|'webapi'|'frames'`);
|
|
179
|
+
valid = false;
|
|
206
180
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
|
|
211
|
-
var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
212
|
-
var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
213
|
-
var DEFAULT_DURATION_MS = 1e3;
|
|
214
|
-
function kebabToCamelCaseWord(kebab) {
|
|
215
|
-
return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
|
|
216
|
-
}
|
|
217
|
-
function isCamelCaseWord(word) {
|
|
218
|
-
return !word.includes("-") && /[a-z][A-Z]/.test(word);
|
|
219
|
-
}
|
|
220
|
-
var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
|
|
221
|
-
// Transform/positioning
|
|
222
|
-
"viewBox",
|
|
223
|
-
"preserveAspectRatio",
|
|
224
|
-
// Gradient
|
|
225
|
-
"gradientUnits",
|
|
226
|
-
"gradientTransform",
|
|
227
|
-
"spreadMethod",
|
|
228
|
-
// Pattern
|
|
229
|
-
"patternUnits",
|
|
230
|
-
"patternContentUnits",
|
|
231
|
-
"patternTransform",
|
|
232
|
-
// Clipping/masking
|
|
233
|
-
"clipPathUnits",
|
|
234
|
-
"maskUnits",
|
|
235
|
-
"maskContentUnits",
|
|
236
|
-
// Text
|
|
237
|
-
"textLength",
|
|
238
|
-
"lengthAdjust",
|
|
239
|
-
"startOffset",
|
|
240
|
-
// Filter
|
|
241
|
-
"filterUnits",
|
|
242
|
-
"primitiveUnits",
|
|
243
|
-
"stdDeviation",
|
|
244
|
-
"baseFrequency",
|
|
245
|
-
"numOctaves",
|
|
246
|
-
"surfaceScale",
|
|
247
|
-
"diffuseConstant",
|
|
248
|
-
"specularConstant",
|
|
249
|
-
"specularExponent",
|
|
250
|
-
"kernelMatrix",
|
|
251
|
-
"kernelUnitLength",
|
|
252
|
-
"edgeMode",
|
|
253
|
-
"preserveAlpha",
|
|
254
|
-
"targetX",
|
|
255
|
-
"targetY"
|
|
256
|
-
// // Animation
|
|
257
|
-
// 'attributeName',
|
|
258
|
-
// 'attributeType',
|
|
259
|
-
// 'calcMode',
|
|
260
|
-
// 'keyTimes',
|
|
261
|
-
// 'keySplines',
|
|
262
|
-
// 'repeatCount',
|
|
263
|
-
// 'repeatDur'
|
|
264
|
-
]);
|
|
265
|
-
function camelCaseToKebabWordIfNeeded(camel) {
|
|
266
|
-
return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
267
|
-
}
|
|
268
|
-
function clamp(value, min, max) {
|
|
269
|
-
return Math.max(min, Math.min(value, max));
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// src/PxAnimatorDOM.ts
|
|
273
|
-
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
274
|
-
var INTERNAL_ATTRS = /* @__PURE__ */ new Set(["type", "children", "animate", "style", "animator", "defs", "bindings"]);
|
|
275
|
-
function createElement(tagName, props, style, children) {
|
|
276
|
-
const element = document.createElementNS(SVG_NS, tagName);
|
|
277
|
-
for (const propName in props) {
|
|
278
|
-
element.setAttribute(camelCaseToKebabWordIfNeeded(propName), props[propName]);
|
|
181
|
+
if (v.duration !== void 0 && typeof v.duration !== "number") {
|
|
182
|
+
errors.push(path + ".duration: expected number, got " + typeof v.duration);
|
|
183
|
+
valid = false;
|
|
279
184
|
}
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
185
|
+
if (v.delay !== void 0 && typeof v.delay !== "number") {
|
|
186
|
+
errors.push(path + ".delay: expected number, got " + typeof v.delay);
|
|
187
|
+
valid = false;
|
|
284
188
|
}
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
189
|
+
if (v.iterations !== void 0 && typeof v.iterations !== "number" && v.iterations !== "infinite") {
|
|
190
|
+
errors.push(path + ".iterations: expected number or 'infinite', got " + typeof v.iterations);
|
|
191
|
+
valid = false;
|
|
289
192
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (typeof style === "string") {
|
|
296
|
-
return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
|
|
193
|
+
if (v.fill !== void 0 && !validateFillMode(v.fill, path + ".fill", errors)) valid = false;
|
|
194
|
+
if (v.direction !== void 0 && !validatePlaybackDirection(v.direction, path + ".direction", errors)) valid = false;
|
|
195
|
+
if (v.frameRate !== void 0 && typeof v.frameRate !== "number") {
|
|
196
|
+
errors.push(path + ".frameRate: expected number, got " + typeof v.frameRate);
|
|
197
|
+
valid = false;
|
|
297
198
|
}
|
|
298
|
-
|
|
199
|
+
if (v.trigger !== void 0 && !validatePxTrigger(v.trigger, path + ".trigger", errors)) valid = false;
|
|
200
|
+
return valid;
|
|
299
201
|
}
|
|
300
|
-
function
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
let value = props[key];
|
|
305
|
-
if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
|
|
306
|
-
propsCopy[key] = toRGBA(value);
|
|
307
|
-
} else if (TRANSFORM_FN_NAMES.has(key)) {
|
|
308
|
-
if (Array.isArray(value)) {
|
|
309
|
-
if (key === "translate") value = value.map((v) => v + "px");
|
|
310
|
-
value = value.join(",");
|
|
311
|
-
}
|
|
312
|
-
if (key === "rotate") value = value + "deg";
|
|
313
|
-
propsCopy["transform"] = key + "(" + value + ")";
|
|
314
|
-
} else if (value !== void 0 && value !== null) {
|
|
315
|
-
propsCopy[key] = String(value);
|
|
316
|
-
}
|
|
202
|
+
function validatePxDefs(v, path, errors) {
|
|
203
|
+
if (!isObject(v)) {
|
|
204
|
+
errors.push(path + ": expected object");
|
|
205
|
+
return false;
|
|
317
206
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (children) {
|
|
327
|
-
for (const ch of children) {
|
|
328
|
-
const child = renderNode(ch, nodeDefs);
|
|
329
|
-
if (child) {
|
|
330
|
-
if (!childElements) childElements = [];
|
|
331
|
-
childElements.push(child);
|
|
207
|
+
let valid = true;
|
|
208
|
+
if (v.easings !== void 0) {
|
|
209
|
+
if (!isObject(v.easings)) {
|
|
210
|
+
errors.push(path + ".easings: expected object");
|
|
211
|
+
valid = false;
|
|
212
|
+
} else {
|
|
213
|
+
for (const key of Object.keys(v.easings)) {
|
|
214
|
+
if (!validatePxEasingOrRef(v.easings[key], path + ".easings." + key, errors)) valid = false;
|
|
332
215
|
}
|
|
333
216
|
}
|
|
334
217
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
// src/PxAnimatorTriggers.ts
|
|
344
|
-
function setupAnimationTriggers(api, config) {
|
|
345
|
-
const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
|
|
346
|
-
const root = api.getRootElement();
|
|
347
|
-
if (!root) {
|
|
348
|
-
console.warn("setupAnimationTriggers: No root element found for animation.");
|
|
349
|
-
return api;
|
|
350
|
-
}
|
|
351
|
-
const start = () => {
|
|
352
|
-
api.play();
|
|
353
|
-
};
|
|
354
|
-
const handleEndAction = () => {
|
|
355
|
-
switch (outAction) {
|
|
356
|
-
case "pause":
|
|
357
|
-
api.pause();
|
|
358
|
-
break;
|
|
359
|
-
case "reset":
|
|
360
|
-
api.cancel();
|
|
361
|
-
break;
|
|
362
|
-
case "reverse":
|
|
363
|
-
api.play();
|
|
364
|
-
break;
|
|
365
|
-
case "continue":
|
|
366
|
-
default:
|
|
367
|
-
break;
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
switch (startOn) {
|
|
371
|
-
case "load": {
|
|
372
|
-
const startHandler = () => start();
|
|
373
|
-
if (document.readyState === "complete") {
|
|
374
|
-
startHandler();
|
|
375
|
-
} else {
|
|
376
|
-
window.addEventListener("load", startHandler, { once: true });
|
|
218
|
+
if (v.animations !== void 0) {
|
|
219
|
+
if (!isObject(v.animations)) {
|
|
220
|
+
errors.push(path + ".animations: expected object");
|
|
221
|
+
valid = false;
|
|
222
|
+
} else {
|
|
223
|
+
for (const key of Object.keys(v.animations)) {
|
|
224
|
+
if (!validatePxAnimationDefinition(v.animations[key], path + ".animations." + key, errors)) valid = false;
|
|
377
225
|
}
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
380
|
-
case "mouseOver": {
|
|
381
|
-
const mouseOverHandler = () => start();
|
|
382
|
-
const mouseOutHandler = () => handleEndAction();
|
|
383
|
-
root.addEventListener("mouseenter", mouseOverHandler);
|
|
384
|
-
root.addEventListener("mouseleave", mouseOutHandler);
|
|
385
|
-
break;
|
|
386
|
-
}
|
|
387
|
-
case "click": {
|
|
388
|
-
const clickHandler = () => {
|
|
389
|
-
if (api.isPlaying()) {
|
|
390
|
-
handleEndAction();
|
|
391
|
-
} else {
|
|
392
|
-
start();
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
root.addEventListener("click", clickHandler);
|
|
396
|
-
break;
|
|
397
|
-
}
|
|
398
|
-
case "scrollIntoView": {
|
|
399
|
-
const observer = new IntersectionObserver(
|
|
400
|
-
(entries) => {
|
|
401
|
-
entries.forEach((entry) => {
|
|
402
|
-
if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
|
|
403
|
-
start();
|
|
404
|
-
} else {
|
|
405
|
-
handleEndAction();
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
},
|
|
409
|
-
{ threshold: scrollIntoViewThreshold }
|
|
410
|
-
);
|
|
411
|
-
observer.observe(root);
|
|
412
|
-
break;
|
|
413
226
|
}
|
|
414
|
-
case "programmatic":
|
|
415
|
-
break;
|
|
416
227
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
// src/PxAnimatorTypes.ts
|
|
421
|
-
var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
|
|
422
|
-
var PX_ANIM_ATTR_NAME = "_px_animator";
|
|
423
|
-
function isPxElementFileFormat(fileJson) {
|
|
424
|
-
if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
|
|
425
|
-
return false;
|
|
228
|
+
if (v.styles !== void 0 && !isObject(v.styles)) {
|
|
229
|
+
errors.push(path + ".styles: expected object");
|
|
230
|
+
valid = false;
|
|
426
231
|
}
|
|
427
|
-
return
|
|
428
|
-
}
|
|
429
|
-
function isObject(v) {
|
|
430
|
-
return v && typeof v === "object" && !Array.isArray(v);
|
|
431
|
-
}
|
|
432
|
-
function validateFillMode(v, path, errors) {
|
|
433
|
-
if (v === "forwards" || v === "backwards" || v === "both" || v === "none") return true;
|
|
434
|
-
errors.push(path + ': invalid FillMode "' + v + `", expected 'forwards'|'backwards'|'both'|'none'`);
|
|
435
|
-
return false;
|
|
436
|
-
}
|
|
437
|
-
function validatePlaybackDirection(v, path, errors) {
|
|
438
|
-
if (v === "normal" || v === "reverse" || v === "alternate" || v === "alternate-reverse") return true;
|
|
439
|
-
errors.push(path + ': invalid PlaybackDirection "' + v + `", expected 'normal'|'reverse'|'alternate'|'alternate-reverse'`);
|
|
440
|
-
return false;
|
|
441
|
-
}
|
|
442
|
-
function validatePxEasingOrRef(v, path, errors) {
|
|
443
|
-
if (typeof v === "string") return true;
|
|
444
|
-
if (Array.isArray(v) && v.length === 4 && v.every((n) => typeof n === "number")) return true;
|
|
445
|
-
errors.push(path + ": invalid easing, expected string or [number, number, number, number]");
|
|
446
|
-
return false;
|
|
232
|
+
return valid;
|
|
447
233
|
}
|
|
448
|
-
function
|
|
234
|
+
function validatePxBinding(v, path, errors) {
|
|
449
235
|
if (!isObject(v)) {
|
|
450
236
|
errors.push(path + ": expected object");
|
|
451
237
|
return false;
|
|
452
238
|
}
|
|
453
239
|
let valid = true;
|
|
454
|
-
if (
|
|
455
|
-
errors.push(path + ".
|
|
456
|
-
valid = false;
|
|
457
|
-
}
|
|
458
|
-
if (v.t !== void 0 && typeof v.t !== "number") {
|
|
459
|
-
errors.push(path + ".t: expected number, got " + typeof v.t);
|
|
240
|
+
if (typeof v.id !== "string") {
|
|
241
|
+
errors.push(path + ".id: expected string, got " + typeof v.id);
|
|
460
242
|
valid = false;
|
|
461
243
|
}
|
|
462
|
-
if (
|
|
463
|
-
if (v.e !== void 0 && !validatePxEasingOrRef(v.e, path + ".e", errors)) valid = false;
|
|
244
|
+
if (!validatePxElementAnimation(v.animate, path + ".animate", errors)) valid = false;
|
|
464
245
|
return valid;
|
|
465
246
|
}
|
|
466
|
-
function
|
|
247
|
+
function validatePxNode(v, path, errors) {
|
|
467
248
|
if (!isObject(v)) {
|
|
468
249
|
errors.push(path + ": expected object");
|
|
469
250
|
return false;
|
|
470
251
|
}
|
|
471
252
|
let valid = true;
|
|
472
|
-
if (v.
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
valid = false;
|
|
476
|
-
} else {
|
|
477
|
-
v.keyframes.forEach((kf, i) => {
|
|
478
|
-
if (!validatePxKeyframe(kf, path + ".keyframes[" + i + "]", errors)) valid = false;
|
|
479
|
-
});
|
|
480
|
-
}
|
|
253
|
+
if (typeof v.type !== "string") {
|
|
254
|
+
errors.push(path + ".type: expected string, got " + typeof v.type);
|
|
255
|
+
valid = false;
|
|
481
256
|
}
|
|
482
|
-
if (v.
|
|
483
|
-
if (!Array.isArray(v.
|
|
484
|
-
errors.push(path + ".
|
|
257
|
+
if (v.children !== void 0) {
|
|
258
|
+
if (!Array.isArray(v.children)) {
|
|
259
|
+
errors.push(path + ".children: expected array");
|
|
485
260
|
valid = false;
|
|
486
261
|
} else {
|
|
487
|
-
v.
|
|
488
|
-
if (!
|
|
262
|
+
v.children.forEach((child, i) => {
|
|
263
|
+
if (!validatePxNode(child, path + ".children[" + i + "]", errors)) valid = false;
|
|
489
264
|
});
|
|
490
265
|
}
|
|
491
266
|
}
|
|
267
|
+
if (v.animate !== void 0 && !validatePxElementAnimation(v.animate, path + ".animate", errors)) valid = false;
|
|
492
268
|
return valid;
|
|
493
269
|
}
|
|
494
|
-
function
|
|
495
|
-
if (!
|
|
496
|
-
errors.push(path + ": expected object");
|
|
497
|
-
return false;
|
|
498
|
-
}
|
|
270
|
+
function validatePxSvgNode(v, path, errors) {
|
|
271
|
+
if (!validatePxNode(v, path, errors)) return false;
|
|
499
272
|
let valid = true;
|
|
500
|
-
|
|
501
|
-
|
|
273
|
+
if (v.type !== "svg") {
|
|
274
|
+
errors.push(path + ".type: expected 'svg', got '" + v.type + "'");
|
|
275
|
+
valid = false;
|
|
502
276
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (typeof v === "string") return true;
|
|
507
|
-
if (Array.isArray(v)) {
|
|
508
|
-
let valid = true;
|
|
509
|
-
v.forEach((item, i) => {
|
|
510
|
-
if (typeof item !== "string" && !validatePxAnimationDefinition(item, path + "[" + i + "]", errors)) {
|
|
511
|
-
valid = false;
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
return valid;
|
|
277
|
+
if (v.width !== void 0 && typeof v.width !== "number") {
|
|
278
|
+
errors.push(path + ".width: expected number, got " + typeof v.width);
|
|
279
|
+
valid = false;
|
|
515
280
|
}
|
|
516
|
-
if (
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
function validatePxTrigger(v, path, errors) {
|
|
521
|
-
if (!isObject(v)) {
|
|
522
|
-
errors.push(path + ": expected object");
|
|
523
|
-
return false;
|
|
281
|
+
if (v.height !== void 0 && typeof v.height !== "number") {
|
|
282
|
+
errors.push(path + ".height: expected number, got " + typeof v.height);
|
|
283
|
+
valid = false;
|
|
524
284
|
}
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
if (!validStartOn.includes(v.startOn)) {
|
|
528
|
-
errors.push(path + '.startOn: invalid value "' + v.startOn + '", expected ' + validStartOn.join("|"));
|
|
285
|
+
if (v.viewBox !== void 0 && typeof v.viewBox !== "string") {
|
|
286
|
+
errors.push(path + ".viewBox: expected string, got " + typeof v.viewBox);
|
|
529
287
|
valid = false;
|
|
530
288
|
}
|
|
531
|
-
if (v.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
289
|
+
if (v.animator !== void 0 && !validatePxAnimatorConfig(v.animator, path + ".animator", errors)) valid = false;
|
|
290
|
+
if (v.defs !== void 0 && !validatePxDefs(v.defs, path + ".defs", errors)) valid = false;
|
|
291
|
+
if (v.bindings !== void 0) {
|
|
292
|
+
if (!Array.isArray(v.bindings)) {
|
|
293
|
+
errors.push(path + ".bindings: expected array");
|
|
535
294
|
valid = false;
|
|
295
|
+
} else {
|
|
296
|
+
v.bindings.forEach((binding, i) => {
|
|
297
|
+
if (!validatePxBinding(binding, path + ".bindings[" + i + "]", errors)) valid = false;
|
|
298
|
+
});
|
|
536
299
|
}
|
|
537
300
|
}
|
|
538
|
-
if (v.
|
|
539
|
-
errors.push(path + ".scrollIntoViewThreshold: expected number, got " + typeof v.scrollIntoViewThreshold);
|
|
540
|
-
valid = false;
|
|
541
|
-
}
|
|
301
|
+
if (v.design !== void 0 && !validatePxNode(v.design, path + ".design", errors)) valid = false;
|
|
542
302
|
return valid;
|
|
543
303
|
}
|
|
544
|
-
function
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
304
|
+
function isPxElementFileFormatDeep(fileJson) {
|
|
305
|
+
const errors = [];
|
|
306
|
+
const valid = validatePxSvgNode(fileJson, "root", errors);
|
|
307
|
+
return { valid, errors };
|
|
308
|
+
}
|
|
309
|
+
function getAnimatorConfig(doc) {
|
|
310
|
+
var _a, _b;
|
|
311
|
+
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);
|
|
312
|
+
}
|
|
313
|
+
function getDefs(doc) {
|
|
314
|
+
var _a;
|
|
315
|
+
if (!doc) return void 0;
|
|
316
|
+
return doc.defs || ((_a = doc.meta) == null ? void 0 : _a.defs);
|
|
317
|
+
}
|
|
318
|
+
function getBindings(doc) {
|
|
319
|
+
var _a;
|
|
320
|
+
if (!doc) return void 0;
|
|
321
|
+
return doc.bindings || ((_a = doc.meta) == null ? void 0 : _a.bindings);
|
|
322
|
+
}
|
|
323
|
+
function getChildren(doc) {
|
|
324
|
+
return doc == null ? void 0 : doc.children;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/PxAnimatorUtil.ts
|
|
328
|
+
function bezierToSvgPath(path) {
|
|
329
|
+
var _a, _b, _c, _d;
|
|
330
|
+
const v = path.v;
|
|
331
|
+
const i = path.i;
|
|
332
|
+
const o = path.o;
|
|
333
|
+
const c = path.c;
|
|
334
|
+
if (!v.length) return "";
|
|
335
|
+
const d = [];
|
|
336
|
+
const len = v.length;
|
|
337
|
+
d.push("M" + v[0][0] + "," + v[0][1]);
|
|
338
|
+
for (let idx = 1; idx < len; idx++) {
|
|
339
|
+
const prevV = v[idx - 1];
|
|
340
|
+
const prevO = (_a = o == null ? void 0 : o[idx - 1]) != null ? _a : prevV;
|
|
341
|
+
const currI = (_b = i == null ? void 0 : i[idx]) != null ? _b : v[idx];
|
|
342
|
+
const currV = v[idx];
|
|
343
|
+
const isLine = prevO[0] === prevV[0] && prevO[1] === prevV[1] && (currI[0] === currV[0] && currI[1] === currV[1]);
|
|
344
|
+
if (isLine) {
|
|
345
|
+
d.push("L" + currV[0] + "," + currV[1]);
|
|
346
|
+
} else {
|
|
347
|
+
d.push("C" + prevO[0] + "," + prevO[1] + "," + currI[0] + "," + currI[1] + "," + currV[0] + "," + currV[1]);
|
|
348
|
+
}
|
|
553
349
|
}
|
|
554
|
-
if (
|
|
555
|
-
|
|
556
|
-
|
|
350
|
+
if (c && len > 0) {
|
|
351
|
+
const lastV = v[len - 1];
|
|
352
|
+
const lastO = (_c = o == null ? void 0 : o[len - 1]) != null ? _c : lastV;
|
|
353
|
+
const firstI = (_d = i == null ? void 0 : i[0]) != null ? _d : v[0];
|
|
354
|
+
const firstV = v[0];
|
|
355
|
+
const isLine = lastO[0] === lastV[0] && lastO[1] === lastV[1] && (firstI[0] === firstV[0] && firstI[1] === firstV[1]);
|
|
356
|
+
if (!isLine) {
|
|
357
|
+
d.push("C" + lastO[0] + "," + lastO[1] + "," + firstI[0] + "," + firstI[1] + "," + firstV[0] + "," + firstV[1]);
|
|
358
|
+
}
|
|
359
|
+
d.push("z");
|
|
557
360
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
361
|
+
return d.join("");
|
|
362
|
+
}
|
|
363
|
+
function interpolateNum(a, b, t) {
|
|
364
|
+
return a + (b - a) * t;
|
|
365
|
+
}
|
|
366
|
+
function interpolateVec(a, b, t) {
|
|
367
|
+
const res = [];
|
|
368
|
+
const count = Math.max(a.length, b.length);
|
|
369
|
+
for (let i = 0; i < count; i++) {
|
|
370
|
+
res[i] = interpolateNum(a[i] || 0, b[i] || 0, t);
|
|
561
371
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
372
|
+
return res;
|
|
373
|
+
}
|
|
374
|
+
function interpolateColor(a, b, t) {
|
|
375
|
+
return [
|
|
376
|
+
interpolateNum(a[0] || 0, b[0] || 0, t),
|
|
377
|
+
interpolateNum(a[1] || 0, b[1] || 0, t),
|
|
378
|
+
interpolateNum(a[2] || 0, b[2] || 0, t),
|
|
379
|
+
interpolateNum(a[3] === void 0 ? 1 : a[3], b[3] === void 0 ? 1 : b[3], t)
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
function interpolateBeziers(paths1, paths2, progress) {
|
|
383
|
+
const count = Math.max(paths1.length, paths2.length);
|
|
384
|
+
const res = [];
|
|
385
|
+
for (let i = 0; i < count; i++) {
|
|
386
|
+
res.push(interpolateBezier(paths1[i], paths2[i], progress));
|
|
565
387
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
388
|
+
return res;
|
|
389
|
+
}
|
|
390
|
+
function interpolateBezier(path1, path2, progress) {
|
|
391
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
392
|
+
if (!path1 || !path2) return path1 || path2 || { v: [] };
|
|
393
|
+
const t = Math.min(Math.max(progress, 0), 1);
|
|
394
|
+
const len = Math.min(path1.v.length, path2.v.length);
|
|
395
|
+
const v = [];
|
|
396
|
+
const i = [];
|
|
397
|
+
const o = [];
|
|
398
|
+
for (let idx = 0; idx < len; idx++) {
|
|
399
|
+
const v1 = path1.v[idx];
|
|
400
|
+
const v2 = path2.v[idx];
|
|
401
|
+
v.push(interpolateVec(v1, v2, t));
|
|
402
|
+
const i1 = (_b = (_a = path1.i) == null ? void 0 : _a[idx]) != null ? _b : v1;
|
|
403
|
+
const i2 = (_d = (_c = path2.i) == null ? void 0 : _c[idx]) != null ? _d : v2;
|
|
404
|
+
i.push(interpolateVec(i1, i2, t));
|
|
405
|
+
const o1 = (_f = (_e = path1.o) == null ? void 0 : _e[idx]) != null ? _f : v1;
|
|
406
|
+
const o2 = (_h = (_g = path2.o) == null ? void 0 : _g[idx]) != null ? _h : v2;
|
|
407
|
+
o.push(interpolateVec(o1, o2, t));
|
|
571
408
|
}
|
|
572
|
-
|
|
573
|
-
return valid;
|
|
409
|
+
return { v, i: i.length ? i : void 0, o: o.length ? o : void 0, c: (_i = path1.c) != null ? _i : path2.c };
|
|
574
410
|
}
|
|
575
|
-
function
|
|
576
|
-
if (
|
|
577
|
-
|
|
578
|
-
|
|
411
|
+
function remap(value, inMin, inMax, outMin, outMax) {
|
|
412
|
+
if (inMax === inMin) return outMin;
|
|
413
|
+
const t = (value - inMin) / (inMax - inMin);
|
|
414
|
+
return outMin + t * (outMax - outMin);
|
|
415
|
+
}
|
|
416
|
+
function solveCubicBezierX(p1x, p2x, x) {
|
|
417
|
+
if (x <= 0) return 0;
|
|
418
|
+
if (x >= 1) return 1;
|
|
419
|
+
const cx = 3 * p1x;
|
|
420
|
+
const bx = 3 * (p2x - p1x) - cx;
|
|
421
|
+
const ax = 1 - cx - bx;
|
|
422
|
+
function sampleX(t) {
|
|
423
|
+
return ((ax * t + bx) * t + cx) * t;
|
|
579
424
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (!isObject(v.easings)) {
|
|
583
|
-
errors.push(path + ".easings: expected object");
|
|
584
|
-
valid = false;
|
|
585
|
-
} else {
|
|
586
|
-
for (const key of Object.keys(v.easings)) {
|
|
587
|
-
if (!validatePxEasingOrRef(v.easings[key], path + ".easings." + key, errors)) valid = false;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
425
|
+
function sampleDX(t) {
|
|
426
|
+
return (3 * ax * t + 2 * bx) * t + cx;
|
|
590
427
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
428
|
+
let t2 = x;
|
|
429
|
+
let t0 = 0;
|
|
430
|
+
let t1 = 1;
|
|
431
|
+
for (let i = 0; i < 8; i++) {
|
|
432
|
+
const x2 = sampleX(t2) - x;
|
|
433
|
+
if (Math.abs(x2) < 1e-6) return t2;
|
|
434
|
+
const d2 = sampleDX(t2);
|
|
435
|
+
if (Math.abs(d2) < 1e-6) break;
|
|
436
|
+
t2 -= x2 / d2;
|
|
437
|
+
}
|
|
438
|
+
t2 = x;
|
|
439
|
+
while (t0 < t1) {
|
|
440
|
+
const x2 = sampleX(t2);
|
|
441
|
+
if (Math.abs(x2 - x) < 1e-6) return t2;
|
|
442
|
+
if (x > x2) t0 = t2;
|
|
443
|
+
else t1 = t2;
|
|
444
|
+
t2 = (t1 + t0) / 2;
|
|
445
|
+
}
|
|
446
|
+
return t2;
|
|
447
|
+
}
|
|
448
|
+
function cubicBezier(easing) {
|
|
449
|
+
const [p1x, p1y, p2x, p2y] = easing;
|
|
450
|
+
const cy = 3 * p1y;
|
|
451
|
+
const by = 3 * (p2y - p1y) - cy;
|
|
452
|
+
const ay = 1 - cy - by;
|
|
453
|
+
function sampleCurveY(t) {
|
|
454
|
+
return ((ay * t + by) * t + cy) * t;
|
|
600
455
|
}
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
456
|
+
return function(x) {
|
|
457
|
+
return sampleCurveY(solveCubicBezierX(p1x, p2x, x));
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function lerp2(a, b, t) {
|
|
461
|
+
return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
|
|
462
|
+
}
|
|
463
|
+
function subdivideCubicBezier(p0, p1, p2, p3, t) {
|
|
464
|
+
const q0 = lerp2(p0, p1, t);
|
|
465
|
+
const q1 = lerp2(p1, p2, t);
|
|
466
|
+
const q2 = lerp2(p2, p3, t);
|
|
467
|
+
const r0 = lerp2(q0, q1, t);
|
|
468
|
+
const r1 = lerp2(q1, q2, t);
|
|
469
|
+
const s = lerp2(r0, r1, t);
|
|
470
|
+
return {
|
|
471
|
+
left: [p0, q0, r0, s],
|
|
472
|
+
right: [s, r1, q2, p3]
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
function splitEasing(easing, xFraction) {
|
|
476
|
+
if (!easing) return { left: void 0, right: void 0 };
|
|
477
|
+
if (xFraction <= 0) return { left: void 0, right: easing };
|
|
478
|
+
if (xFraction >= 1) return { left: easing, right: void 0 };
|
|
479
|
+
const [x1, y1, x2, y2] = easing;
|
|
480
|
+
const t = solveCubicBezierX(x1, x2, xFraction);
|
|
481
|
+
const p0 = [0, 0];
|
|
482
|
+
const p1 = [x1, y1];
|
|
483
|
+
const p2 = [x2, y2];
|
|
484
|
+
const p3 = [1, 1];
|
|
485
|
+
const { left, right } = subdivideCubicBezier(p0, p1, p2, p3, t);
|
|
486
|
+
const sx = left[3][0];
|
|
487
|
+
const sy = left[3][1];
|
|
488
|
+
let leftEasing;
|
|
489
|
+
if (sx > 1e-9 && Math.abs(sy) > 1e-9) {
|
|
490
|
+
leftEasing = [
|
|
491
|
+
left[1][0] / sx,
|
|
492
|
+
left[1][1] / sy,
|
|
493
|
+
left[2][0] / sx,
|
|
494
|
+
left[2][1] / sy
|
|
495
|
+
];
|
|
496
|
+
}
|
|
497
|
+
let rightEasing;
|
|
498
|
+
const rx = 1 - sx;
|
|
499
|
+
const ry = 1 - sy;
|
|
500
|
+
if (rx > 1e-9 && Math.abs(ry) > 1e-9) {
|
|
501
|
+
rightEasing = [
|
|
502
|
+
(right[1][0] - sx) / rx,
|
|
503
|
+
(right[1][1] - sy) / ry,
|
|
504
|
+
(right[2][0] - sx) / rx,
|
|
505
|
+
(right[2][1] - sy) / ry
|
|
506
|
+
];
|
|
507
|
+
}
|
|
508
|
+
return { left: leftEasing, right: rightEasing };
|
|
509
|
+
}
|
|
510
|
+
function reverseEasing(easing) {
|
|
511
|
+
if (!easing) return void 0;
|
|
512
|
+
return [1 - easing[2], 1 - easing[3], 1 - easing[0], 1 - easing[1]];
|
|
513
|
+
}
|
|
514
|
+
function toRGBA(color) {
|
|
515
|
+
const r = Math.round(color[0] * 255);
|
|
516
|
+
const g = Math.round(color[1] * 255);
|
|
517
|
+
const b = Math.round(color[2] * 255);
|
|
518
|
+
return color.length === 4 ? "rgba(" + r + "," + g + "," + b + "," + color[3] + ")" : "rgb(" + r + "," + g + "," + b + ")";
|
|
519
|
+
}
|
|
520
|
+
function parseRgba(s) {
|
|
521
|
+
var _a;
|
|
522
|
+
const inner = (_a = s.match(/rgba?\((.*)\)/)) == null ? void 0 : _a[1];
|
|
523
|
+
if (!inner) throw new Error("Invalid rgb/rgba format");
|
|
524
|
+
const parts = inner.split(",").map((v) => +v.trim());
|
|
525
|
+
return [parts[0] / 255, parts[1] / 255, parts[2] / 255, ...parts[3] !== void 0 ? [parts[3]] : []];
|
|
526
|
+
}
|
|
527
|
+
function parseHex(s) {
|
|
528
|
+
const hex = s.slice(1);
|
|
529
|
+
const isShort = hex.length <= 4;
|
|
530
|
+
const r = isShort ? hex[0] + hex[0] : hex.slice(0, 2);
|
|
531
|
+
const g = isShort ? hex[1] + hex[1] : hex.slice(2, 4);
|
|
532
|
+
const b = isShort ? hex[2] + hex[2] : hex.slice(4, 6);
|
|
533
|
+
const a = hex.length === 4 ? hex[3] + hex[3] : hex.length === 8 ? hex.slice(6, 8) : null;
|
|
534
|
+
const result = [
|
|
535
|
+
parseInt(r, 16) / 255,
|
|
536
|
+
parseInt(g, 16) / 255,
|
|
537
|
+
parseInt(b, 16) / 255
|
|
538
|
+
];
|
|
539
|
+
if (a !== null) {
|
|
540
|
+
result.push(parseInt(a, 16) / 255);
|
|
604
541
|
}
|
|
605
|
-
return
|
|
542
|
+
return result;
|
|
606
543
|
}
|
|
607
|
-
function
|
|
608
|
-
if (!
|
|
609
|
-
|
|
610
|
-
|
|
544
|
+
function parseColor(s) {
|
|
545
|
+
if (!s) return void 0;
|
|
546
|
+
if (Array.isArray(s)) return s;
|
|
547
|
+
if (typeof s !== "string") return void 0;
|
|
548
|
+
if (s.startsWith("#")) {
|
|
549
|
+
return parseHex(s);
|
|
550
|
+
} else if (s.startsWith("rgb")) {
|
|
551
|
+
return parseRgba(s);
|
|
552
|
+
} else {
|
|
553
|
+
console.warn("Unsupported color format: " + s);
|
|
554
|
+
}
|
|
555
|
+
return void 0;
|
|
556
|
+
}
|
|
557
|
+
var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
|
|
558
|
+
var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
|
|
559
|
+
var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
560
|
+
var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
|
|
561
|
+
var DEFAULT_DURATION_MS = 1e3;
|
|
562
|
+
function kebabToCamelCaseWord(kebab) {
|
|
563
|
+
return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
|
|
564
|
+
}
|
|
565
|
+
function isCamelCaseWord(word) {
|
|
566
|
+
return !word.includes("-") && /[a-z][A-Z]/.test(word);
|
|
567
|
+
}
|
|
568
|
+
var SVG_CAMEL_CASE_ATTRS = /* @__PURE__ */ new Set([
|
|
569
|
+
// Transform/positioning
|
|
570
|
+
"viewBox",
|
|
571
|
+
"preserveAspectRatio",
|
|
572
|
+
// Gradient
|
|
573
|
+
"gradientUnits",
|
|
574
|
+
"gradientTransform",
|
|
575
|
+
"spreadMethod",
|
|
576
|
+
// Pattern
|
|
577
|
+
"patternUnits",
|
|
578
|
+
"patternContentUnits",
|
|
579
|
+
"patternTransform",
|
|
580
|
+
// Clipping/masking
|
|
581
|
+
"clipPathUnits",
|
|
582
|
+
"maskUnits",
|
|
583
|
+
"maskContentUnits",
|
|
584
|
+
// Text
|
|
585
|
+
"textLength",
|
|
586
|
+
"lengthAdjust",
|
|
587
|
+
"startOffset",
|
|
588
|
+
// Filter
|
|
589
|
+
"filterUnits",
|
|
590
|
+
"primitiveUnits",
|
|
591
|
+
"stdDeviation",
|
|
592
|
+
"baseFrequency",
|
|
593
|
+
"numOctaves",
|
|
594
|
+
"surfaceScale",
|
|
595
|
+
"diffuseConstant",
|
|
596
|
+
"specularConstant",
|
|
597
|
+
"specularExponent",
|
|
598
|
+
"kernelMatrix",
|
|
599
|
+
"kernelUnitLength",
|
|
600
|
+
"edgeMode",
|
|
601
|
+
"preserveAlpha",
|
|
602
|
+
"targetX",
|
|
603
|
+
"targetY"
|
|
604
|
+
// // Animation
|
|
605
|
+
// 'attributeName',
|
|
606
|
+
// 'attributeType',
|
|
607
|
+
// 'calcMode',
|
|
608
|
+
// 'keyTimes',
|
|
609
|
+
// 'keySplines',
|
|
610
|
+
// 'repeatCount',
|
|
611
|
+
// 'repeatDur'
|
|
612
|
+
]);
|
|
613
|
+
function camelCaseToKebabWordIfNeeded(camel) {
|
|
614
|
+
return SVG_CAMEL_CASE_ATTRS.has(camel) ? camel : camel.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
615
|
+
}
|
|
616
|
+
function clamp(value, min, max) {
|
|
617
|
+
return Math.max(min, Math.min(value, max));
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/PxAnimatorDOM.ts
|
|
621
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
622
|
+
var ALLOWED_SVG_TAGS_LOWER_CASE = new Set([
|
|
623
|
+
"svg",
|
|
624
|
+
"g",
|
|
625
|
+
"path",
|
|
626
|
+
"circle",
|
|
627
|
+
"ellipse",
|
|
628
|
+
"rect",
|
|
629
|
+
"line",
|
|
630
|
+
"polyline",
|
|
631
|
+
"polygon",
|
|
632
|
+
"text",
|
|
633
|
+
"tspan",
|
|
634
|
+
"defs",
|
|
635
|
+
"clipPath",
|
|
636
|
+
"mask",
|
|
637
|
+
"pattern",
|
|
638
|
+
"linearGradient",
|
|
639
|
+
"radialGradient",
|
|
640
|
+
"stop",
|
|
641
|
+
"use",
|
|
642
|
+
"symbol",
|
|
643
|
+
"marker",
|
|
644
|
+
"filter",
|
|
645
|
+
"feGaussianBlur",
|
|
646
|
+
"feOffset",
|
|
647
|
+
"feBlend",
|
|
648
|
+
"feColorMatrix",
|
|
649
|
+
"feMerge",
|
|
650
|
+
"feMergeNode"
|
|
651
|
+
].map((tagName) => tagName.toLowerCase()));
|
|
652
|
+
var ALLOWED_RESOURCE_ATTRIBUTES = [
|
|
653
|
+
"href",
|
|
654
|
+
// <use>
|
|
655
|
+
"src",
|
|
656
|
+
// <image>
|
|
657
|
+
"filter",
|
|
658
|
+
// url(#filterId)
|
|
659
|
+
"clipPath",
|
|
660
|
+
// clip-path="url(#clipPathId)"
|
|
661
|
+
"mask",
|
|
662
|
+
// url(#maskId)
|
|
663
|
+
"markerStart",
|
|
664
|
+
// marker-start="url(#markerId)"
|
|
665
|
+
"markerMid",
|
|
666
|
+
// marker-mid="url(#markerId)"
|
|
667
|
+
"markerEnd"
|
|
668
|
+
// marker-end="url(#markerId)"
|
|
669
|
+
// 'fill', // url(#gradientId) or url(#patternId)
|
|
670
|
+
// 'stroke', // url(#gradientId) or url(#patternId)
|
|
671
|
+
// Don't allow 'cursor', can use external SVG, // url(cursor.svg)
|
|
672
|
+
];
|
|
673
|
+
var ALLOWED_RESOURCE_ATTRIBUTES_SET = new Set(ALLOWED_RESOURCE_ATTRIBUTES);
|
|
674
|
+
var ALLOWED_ATTRIBUTES_SET = /* @__PURE__ */ new Set([
|
|
675
|
+
"href",
|
|
676
|
+
"src",
|
|
677
|
+
// Presentation
|
|
678
|
+
"fill",
|
|
679
|
+
"stroke",
|
|
680
|
+
"strokeWidth",
|
|
681
|
+
"opacity",
|
|
682
|
+
"transform",
|
|
683
|
+
// Geometry
|
|
684
|
+
"x",
|
|
685
|
+
"y",
|
|
686
|
+
"cx",
|
|
687
|
+
"cy",
|
|
688
|
+
"r",
|
|
689
|
+
"rx",
|
|
690
|
+
"ry",
|
|
691
|
+
"width",
|
|
692
|
+
"height",
|
|
693
|
+
"d",
|
|
694
|
+
"x1",
|
|
695
|
+
"y1",
|
|
696
|
+
"x2",
|
|
697
|
+
"y2",
|
|
698
|
+
"points",
|
|
699
|
+
// Text
|
|
700
|
+
"fontSize",
|
|
701
|
+
"fontFamily",
|
|
702
|
+
"textAnchor",
|
|
703
|
+
// Structure
|
|
704
|
+
"id",
|
|
705
|
+
"class",
|
|
706
|
+
"viewBox",
|
|
707
|
+
"preserveAspectRatio",
|
|
708
|
+
// Gradient/Pattern
|
|
709
|
+
"offset",
|
|
710
|
+
"stopColor",
|
|
711
|
+
"stopOpacity",
|
|
712
|
+
"gradientTransform",
|
|
713
|
+
// Clippath/Mask
|
|
714
|
+
"clipPath",
|
|
715
|
+
"mask",
|
|
716
|
+
// Filter
|
|
717
|
+
"filter",
|
|
718
|
+
"stdDeviation",
|
|
719
|
+
"in",
|
|
720
|
+
"in2",
|
|
721
|
+
"result",
|
|
722
|
+
"mode",
|
|
723
|
+
...ALLOWED_RESOURCE_ATTRIBUTES
|
|
724
|
+
]);
|
|
725
|
+
function sanitiseAttributeValue(name, value) {
|
|
726
|
+
const nameLower = name.toLowerCase();
|
|
727
|
+
if (!ALLOWED_ATTRIBUTES_SET.has(nameLower)) {
|
|
728
|
+
console.warn("Attribute not in whitelist: ", nameLower);
|
|
729
|
+
return void 0;
|
|
730
|
+
}
|
|
731
|
+
if (nameLower === "fill" || nameLower === "stroke" || nameLower === "stopColor") {
|
|
732
|
+
const str = String(value);
|
|
733
|
+
if (str.includes("url(") && !/^url\(#[^)]+\)$/.test(str)) {
|
|
734
|
+
console.warn('Attribute "' + nameLower + '" blocked: url() references must be internal url(#id), got:', value);
|
|
735
|
+
return void 0;
|
|
736
|
+
}
|
|
737
|
+
return value;
|
|
611
738
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
739
|
+
if (ALLOWED_RESOURCE_ATTRIBUTES_SET.has(nameLower)) {
|
|
740
|
+
const str = String(value);
|
|
741
|
+
if (str.startsWith("#")) {
|
|
742
|
+
return value;
|
|
743
|
+
}
|
|
744
|
+
if (/^url\(#[^)]+\)$/.test(str)) {
|
|
745
|
+
return value;
|
|
746
|
+
}
|
|
747
|
+
return void 0;
|
|
616
748
|
}
|
|
617
|
-
|
|
618
|
-
return valid;
|
|
749
|
+
return value;
|
|
619
750
|
}
|
|
620
|
-
function
|
|
621
|
-
if (!
|
|
622
|
-
|
|
623
|
-
|
|
751
|
+
function createElement(tagName, normalisedProps, style, children, textContent) {
|
|
752
|
+
if (!ALLOWED_SVG_TAGS_LOWER_CASE.has(tagName.toLowerCase())) return null;
|
|
753
|
+
const element = document.createElementNS(SVG_NS, tagName);
|
|
754
|
+
for (const propName in normalisedProps) {
|
|
755
|
+
element.setAttribute(
|
|
756
|
+
camelCaseToKebabWordIfNeeded(propName),
|
|
757
|
+
sanitiseAttributeValue(propName, normalisedProps[propName])
|
|
758
|
+
);
|
|
624
759
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
760
|
+
if (style) {
|
|
761
|
+
for (const styleProp in style) {
|
|
762
|
+
element.style[styleProp] = String(style[styleProp]);
|
|
763
|
+
}
|
|
629
764
|
}
|
|
630
|
-
if (
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
valid = false;
|
|
634
|
-
} else {
|
|
635
|
-
v.children.forEach((child, i) => {
|
|
636
|
-
if (!validatePxNode(child, path + ".children[" + i + "]", errors)) valid = false;
|
|
637
|
-
});
|
|
765
|
+
if (children) {
|
|
766
|
+
for (const child of children) {
|
|
767
|
+
element.appendChild(child);
|
|
638
768
|
}
|
|
639
769
|
}
|
|
640
|
-
if (
|
|
641
|
-
return
|
|
770
|
+
if (textContent) element.textContent = textContent;
|
|
771
|
+
return element;
|
|
642
772
|
}
|
|
643
|
-
function
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
if (
|
|
647
|
-
|
|
648
|
-
valid = false;
|
|
773
|
+
function resolveStyle(style, defs) {
|
|
774
|
+
var _a;
|
|
775
|
+
if (!style) return void 0;
|
|
776
|
+
if (typeof style === "string") {
|
|
777
|
+
return (_a = defs == null ? void 0 : defs.styles) == null ? void 0 : _a[style];
|
|
649
778
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
779
|
+
return style;
|
|
780
|
+
}
|
|
781
|
+
function getNormalizedProps(props) {
|
|
782
|
+
const propsCopy = {};
|
|
783
|
+
for (const key of Object.keys(props)) {
|
|
784
|
+
if (INTERNAL_ATTRS.has(key)) continue;
|
|
785
|
+
if (key === "style") continue;
|
|
786
|
+
let value = props[key];
|
|
787
|
+
if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
|
|
788
|
+
propsCopy[key] = toRGBA(value);
|
|
789
|
+
} else if (TRANSFORM_FN_NAMES.has(key)) {
|
|
790
|
+
if (Array.isArray(value)) {
|
|
791
|
+
if (key === "translate") value = value.map((v) => v + "px");
|
|
792
|
+
value = value.join(",");
|
|
793
|
+
}
|
|
794
|
+
if (key === "rotate") value = value + "deg";
|
|
795
|
+
propsCopy["transform"] = key + "(" + value + ")";
|
|
796
|
+
} else if (value !== void 0 && value !== null) {
|
|
797
|
+
propsCopy[key] = String(value);
|
|
798
|
+
}
|
|
653
799
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
800
|
+
return propsCopy;
|
|
801
|
+
}
|
|
802
|
+
function renderNode(node, defs) {
|
|
803
|
+
if (!node) return null;
|
|
804
|
+
const _a = node, { type, children, animate, style } = _a, props = __objRest(_a, ["type", "children", "animate", "style"]);
|
|
805
|
+
const nodeDefs = node.defs || defs;
|
|
806
|
+
const resolvedStyle = resolveStyle(style, nodeDefs);
|
|
807
|
+
let childElements;
|
|
808
|
+
if (children) {
|
|
809
|
+
for (const ch of children) {
|
|
810
|
+
const child = renderNode(ch, nodeDefs);
|
|
811
|
+
if (child) {
|
|
812
|
+
if (!childElements) childElements = [];
|
|
813
|
+
childElements.push(child);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
657
816
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
817
|
+
return createElement(
|
|
818
|
+
type || "g",
|
|
819
|
+
getNormalizedProps(props),
|
|
820
|
+
resolvedStyle,
|
|
821
|
+
childElements,
|
|
822
|
+
props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// src/PxAnimatorTriggers.ts
|
|
827
|
+
function setupAnimationTriggers(api, config) {
|
|
828
|
+
const { startOn, outAction = "continue", scrollIntoViewThreshold = 0.5 } = config;
|
|
829
|
+
const root = api.getRootElement();
|
|
830
|
+
if (!root) {
|
|
831
|
+
console.warn("setupAnimationTriggers: No root element found for animation.");
|
|
832
|
+
return api;
|
|
661
833
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
834
|
+
const start = () => {
|
|
835
|
+
api.play();
|
|
836
|
+
};
|
|
837
|
+
const handleEndAction = () => {
|
|
838
|
+
switch (outAction) {
|
|
839
|
+
case "pause":
|
|
840
|
+
api.pause();
|
|
841
|
+
break;
|
|
842
|
+
case "reset":
|
|
843
|
+
api.cancel();
|
|
844
|
+
break;
|
|
845
|
+
case "reverse":
|
|
846
|
+
api.play();
|
|
847
|
+
break;
|
|
848
|
+
case "continue":
|
|
849
|
+
default:
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
};
|
|
853
|
+
switch (startOn) {
|
|
854
|
+
case "load": {
|
|
855
|
+
const startHandler = () => start();
|
|
856
|
+
if (document.readyState === "complete") {
|
|
857
|
+
startHandler();
|
|
858
|
+
} else {
|
|
859
|
+
window.addEventListener("load", startHandler, { once: true });
|
|
860
|
+
}
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
case "mouseOver": {
|
|
864
|
+
const mouseOverHandler = () => start();
|
|
865
|
+
const mouseOutHandler = () => handleEndAction();
|
|
866
|
+
root.addEventListener("mouseenter", mouseOverHandler);
|
|
867
|
+
root.addEventListener("mouseleave", mouseOutHandler);
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
case "click": {
|
|
871
|
+
const clickHandler = () => {
|
|
872
|
+
if (api.isPlaying()) {
|
|
873
|
+
handleEndAction();
|
|
874
|
+
} else {
|
|
875
|
+
start();
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
root.addEventListener("click", clickHandler);
|
|
879
|
+
break;
|
|
880
|
+
}
|
|
881
|
+
case "scrollIntoView": {
|
|
882
|
+
const observer = new IntersectionObserver(
|
|
883
|
+
(entries) => {
|
|
884
|
+
entries.forEach((entry) => {
|
|
885
|
+
if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
|
|
886
|
+
start();
|
|
887
|
+
} else {
|
|
888
|
+
handleEndAction();
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
},
|
|
892
|
+
{ threshold: scrollIntoViewThreshold }
|
|
893
|
+
);
|
|
894
|
+
observer.observe(root);
|
|
895
|
+
break;
|
|
672
896
|
}
|
|
897
|
+
case "programmatic":
|
|
898
|
+
break;
|
|
673
899
|
}
|
|
674
|
-
|
|
675
|
-
return valid;
|
|
676
|
-
}
|
|
677
|
-
function isPxElementFileFormatDeep(fileJson) {
|
|
678
|
-
const errors = [];
|
|
679
|
-
const valid = validatePxSvgNode(fileJson, "root", errors);
|
|
680
|
-
return { valid, errors };
|
|
681
|
-
}
|
|
682
|
-
function getAnimatorConfig(doc) {
|
|
683
|
-
var _a, _b;
|
|
684
|
-
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);
|
|
685
|
-
}
|
|
686
|
-
function getDefs(doc) {
|
|
687
|
-
var _a;
|
|
688
|
-
if (!doc) return void 0;
|
|
689
|
-
return doc.defs || ((_a = doc.meta) == null ? void 0 : _a.defs);
|
|
690
|
-
}
|
|
691
|
-
function getBindings(doc) {
|
|
692
|
-
var _a;
|
|
693
|
-
if (!doc) return void 0;
|
|
694
|
-
return doc.bindings || ((_a = doc.meta) == null ? void 0 : _a.bindings);
|
|
695
|
-
}
|
|
696
|
-
function getChildren(doc) {
|
|
697
|
-
return doc == null ? void 0 : doc.children;
|
|
900
|
+
return api;
|
|
698
901
|
}
|
|
699
902
|
|
|
700
903
|
// src/PxDefinitions.ts
|
|
@@ -851,6 +1054,111 @@ function resolveElementAnimation(animate, defs) {
|
|
|
851
1054
|
}
|
|
852
1055
|
return results;
|
|
853
1056
|
}
|
|
1057
|
+
function interpolateValue(propName, a, b, t) {
|
|
1058
|
+
var _a, _b;
|
|
1059
|
+
if (propName === "d") {
|
|
1060
|
+
const aPaths = (_a = a == null ? void 0 : a.paths) != null ? _a : Array.isArray(a) ? a : [];
|
|
1061
|
+
const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
|
|
1062
|
+
return { paths: interpolateBeziers(aPaths, bPaths, t) };
|
|
1063
|
+
}
|
|
1064
|
+
if (COLOUR_ATTR_NAMES.has(propName)) {
|
|
1065
|
+
return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
|
|
1066
|
+
}
|
|
1067
|
+
if (TRANSFORM_FN_NAMES.has(propName) || propName === "stroke-dasharray" || propName === "strokeDasharray") {
|
|
1068
|
+
return interpolateVec(a || [], b || [], t);
|
|
1069
|
+
}
|
|
1070
|
+
return interpolateNum(+(a || 0), +(b || 0), t);
|
|
1071
|
+
}
|
|
1072
|
+
function expandLoopKeyframes(propName, keyframes, loop, duration) {
|
|
1073
|
+
var _a, _b, _c, _d, _e;
|
|
1074
|
+
const totalIntervals = keyframes.length - 1;
|
|
1075
|
+
const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
|
|
1076
|
+
let segKfs;
|
|
1077
|
+
if (loop.before) {
|
|
1078
|
+
segKfs = keyframes.slice(0, segCount + 1);
|
|
1079
|
+
} else {
|
|
1080
|
+
segKfs = keyframes.slice(totalIntervals - segCount);
|
|
1081
|
+
}
|
|
1082
|
+
const firstT = (_b = keyframes[0].t) != null ? _b : 0;
|
|
1083
|
+
const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
|
|
1084
|
+
let fillStart, fillEnd;
|
|
1085
|
+
if (loop.before) {
|
|
1086
|
+
fillStart = 0;
|
|
1087
|
+
fillEnd = firstT;
|
|
1088
|
+
} else {
|
|
1089
|
+
fillStart = lastT;
|
|
1090
|
+
fillEnd = duration;
|
|
1091
|
+
}
|
|
1092
|
+
const fillDuration = fillEnd - fillStart;
|
|
1093
|
+
if (fillDuration <= 0) return keyframes;
|
|
1094
|
+
const segStartT = (_d = segKfs[0].t) != null ? _d : 0;
|
|
1095
|
+
const segEndT = (_e = segKfs[segKfs.length - 1].t) != null ? _e : 0;
|
|
1096
|
+
const segDuration = segEndT - segStartT;
|
|
1097
|
+
if (segDuration <= 0) return keyframes;
|
|
1098
|
+
const template = segKfs.map((kf) => ({
|
|
1099
|
+
relT: (kf.t - segStartT) / segDuration,
|
|
1100
|
+
v: kf.v,
|
|
1101
|
+
e: kf.e
|
|
1102
|
+
}));
|
|
1103
|
+
const fullReps = Math.floor(fillDuration / segDuration);
|
|
1104
|
+
const remainder = fillDuration - fullReps * segDuration;
|
|
1105
|
+
const partialFraction = remainder / segDuration;
|
|
1106
|
+
const looped = [];
|
|
1107
|
+
function appendRep(repStart, isReversed, partial) {
|
|
1108
|
+
let entries;
|
|
1109
|
+
if (isReversed) {
|
|
1110
|
+
entries = [];
|
|
1111
|
+
for (let i = template.length - 1; i >= 0; i--) {
|
|
1112
|
+
entries.push({
|
|
1113
|
+
relT: 1 - template[i].relT,
|
|
1114
|
+
v: template[i].v,
|
|
1115
|
+
// Easing for reversed transition: use reversed easing from the forward "from" keyframe
|
|
1116
|
+
e: i > 0 ? reverseEasing(template[i - 1].e) : void 0
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
} else {
|
|
1120
|
+
entries = template;
|
|
1121
|
+
}
|
|
1122
|
+
const cutRelT = partial !== void 0 ? partial : 1;
|
|
1123
|
+
for (let i = 0; i < entries.length; i++) {
|
|
1124
|
+
const entry = entries[i];
|
|
1125
|
+
if (entry.relT > cutRelT + 1e-9) {
|
|
1126
|
+
const prev = entries[i - 1];
|
|
1127
|
+
const intervalSpan = entry.relT - prev.relT;
|
|
1128
|
+
const localFrac = (cutRelT - prev.relT) / intervalSpan;
|
|
1129
|
+
const easedFrac = prev.e ? cubicBezier(prev.e)(localFrac) : localFrac;
|
|
1130
|
+
const cutValue = interpolateValue(propName, prev.v, entry.v, easedFrac);
|
|
1131
|
+
const { left: leftEasing } = splitEasing(prev.e, localFrac);
|
|
1132
|
+
if (looped.length > 0 && prev.relT <= cutRelT) {
|
|
1133
|
+
looped[looped.length - 1].e = leftEasing;
|
|
1134
|
+
}
|
|
1135
|
+
looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
looped.push({
|
|
1139
|
+
t: repStart + entry.relT * segDuration,
|
|
1140
|
+
v: entry.v,
|
|
1141
|
+
e: i < entries.length - 1 ? entry.e : void 0
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
for (let rep = 0; rep < fullReps; rep++) {
|
|
1146
|
+
const distFromBoundary = loop.before ? fullReps - 1 - rep : rep;
|
|
1147
|
+
const isReversed = !!loop.alternate && distFromBoundary % 2 === 0;
|
|
1148
|
+
const repStart = fillStart + rep * segDuration;
|
|
1149
|
+
appendRep(repStart, isReversed);
|
|
1150
|
+
}
|
|
1151
|
+
if (partialFraction > 1e-9) {
|
|
1152
|
+
const isReversed = !!loop.alternate && fullReps % 2 === 0;
|
|
1153
|
+
const repStart = fillStart + fullReps * segDuration;
|
|
1154
|
+
appendRep(repStart, isReversed, partialFraction);
|
|
1155
|
+
}
|
|
1156
|
+
if (loop.before) {
|
|
1157
|
+
return [...looped, ...keyframes];
|
|
1158
|
+
} else {
|
|
1159
|
+
return [...keyframes, ...looped];
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
854
1162
|
function normalizeKeyframes(propName, propAnim, duration, defs) {
|
|
855
1163
|
var _a, _b, _c, _d, _e;
|
|
856
1164
|
const keyframes = propAnim.keyframes || propAnim.kfs || [];
|
|
@@ -875,6 +1183,11 @@ function normalizeKeyframes(propName, propAnim, duration, defs) {
|
|
|
875
1183
|
var _a2, _b2;
|
|
876
1184
|
return ((_a2 = a.t) != null ? _a2 : 0) - ((_b2 = b.t) != null ? _b2 : 0);
|
|
877
1185
|
});
|
|
1186
|
+
const loopRaw = propAnim.loop;
|
|
1187
|
+
const loop = loopRaw === true ? {} : loopRaw || void 0;
|
|
1188
|
+
if (loop && normalized.length >= 2) {
|
|
1189
|
+
return expandLoopKeyframes(propName, normalized, loop, duration);
|
|
1190
|
+
}
|
|
878
1191
|
return normalized;
|
|
879
1192
|
}
|
|
880
1193
|
function mergeAnimationDefinitions(animations) {
|
|
@@ -1309,40 +1622,56 @@ function createDomAdapter(rootElement) {
|
|
|
1309
1622
|
}
|
|
1310
1623
|
|
|
1311
1624
|
// src/PxAnimatorWebApi.ts
|
|
1625
|
+
function createCssKf(kf, t, propName, unsupportedSet) {
|
|
1626
|
+
var _a, _b;
|
|
1627
|
+
let value = (_a = kf.v) != null ? _a : kf.value;
|
|
1628
|
+
const e = (_b = kf.e) != null ? _b : kf.easing;
|
|
1629
|
+
const cssKf = {
|
|
1630
|
+
offset: t,
|
|
1631
|
+
easing: e && Array.isArray(e) ? "cubic-bezier(" + e.join(",") + ")" : void 0
|
|
1632
|
+
};
|
|
1633
|
+
let cssValue;
|
|
1634
|
+
let cssKey = propName;
|
|
1635
|
+
if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
|
|
1636
|
+
cssValue = toRGBA(value);
|
|
1637
|
+
} else if (TRANSFORM_FN_NAMES.has(propName)) {
|
|
1638
|
+
if (Array.isArray(value)) {
|
|
1639
|
+
if (propName === "translate") value = value.map((v) => v + "px");
|
|
1640
|
+
value = value.join(",");
|
|
1641
|
+
}
|
|
1642
|
+
if (propName === "rotate") value = value + "deg";
|
|
1643
|
+
cssValue = propName + "(" + value + ")";
|
|
1644
|
+
cssKey = "transform";
|
|
1645
|
+
} else {
|
|
1646
|
+
cssValue = "" + value;
|
|
1647
|
+
}
|
|
1648
|
+
if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
|
|
1649
|
+
cssKey = kebabToCamelCaseWord(cssKey);
|
|
1650
|
+
cssKf[cssKey] = cssValue;
|
|
1651
|
+
return cssKf;
|
|
1652
|
+
}
|
|
1312
1653
|
function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
|
|
1313
|
-
var _a, _b
|
|
1654
|
+
var _a, _b;
|
|
1314
1655
|
const result = /* @__PURE__ */ new Map();
|
|
1315
1656
|
for (const [propName, propAnim] of Object.entries(animDef)) {
|
|
1316
1657
|
const keyframes = propAnim.kfs || propAnim.keyframes || [];
|
|
1317
1658
|
const cssKeyframes = [];
|
|
1318
|
-
for (
|
|
1659
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
1660
|
+
const kf = keyframes[i];
|
|
1319
1661
|
let t = (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
|
|
1320
1662
|
t = clamp(t / (config.duration || 1), 0, 1);
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
};
|
|
1327
|
-
let cssValue;
|
|
1328
|
-
let cssKey = propName;
|
|
1329
|
-
if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
|
|
1330
|
-
cssValue = toRGBA(value);
|
|
1331
|
-
} else if (TRANSFORM_FN_NAMES.has(propName)) {
|
|
1332
|
-
if (Array.isArray(value)) {
|
|
1333
|
-
if (propName === "translate") value = value.map((v) => v + "px");
|
|
1334
|
-
value = value.join(",");
|
|
1335
|
-
}
|
|
1336
|
-
if (propName === "rotate") value = value + "deg";
|
|
1337
|
-
cssValue = propName + "(" + value + ")";
|
|
1338
|
-
cssKey = "transform";
|
|
1339
|
-
} else {
|
|
1340
|
-
cssValue = "" + value;
|
|
1663
|
+
const cssKf = createCssKf(kf, t, propName, unsupportedSet);
|
|
1664
|
+
if (i === 0 && (cssKf.offset || 0) > 0) {
|
|
1665
|
+
cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
|
|
1666
|
+
offset: 0
|
|
1667
|
+
}));
|
|
1341
1668
|
}
|
|
1342
|
-
if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
|
|
1343
|
-
cssKey = kebabToCamelCaseWord(cssKey);
|
|
1344
|
-
cssKf[cssKey] = cssValue;
|
|
1345
1669
|
cssKeyframes.push(cssKf);
|
|
1670
|
+
if (i === keyframes.length - 1 && (cssKf.offset || 0) < 1) {
|
|
1671
|
+
cssKeyframes.push(__spreadProps(__spreadValues({}, cssKf), {
|
|
1672
|
+
offset: 1
|
|
1673
|
+
}));
|
|
1674
|
+
}
|
|
1346
1675
|
}
|
|
1347
1676
|
if (cssKeyframes.length > 0) {
|
|
1348
1677
|
result.set(propName, cssKeyframes);
|
|
@@ -1383,17 +1712,17 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
1383
1712
|
console.warn('createWebApiAnimator: No elements found for selector "' + selector + '"');
|
|
1384
1713
|
}
|
|
1385
1714
|
const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
|
|
1715
|
+
const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
|
|
1716
|
+
const seekPosition = config.delay && config.delay < 0 && config.duration ? -config.delay % config.duration : void 0;
|
|
1717
|
+
const effectOptions = {
|
|
1718
|
+
duration: config.duration,
|
|
1719
|
+
delay: positiveDelay,
|
|
1720
|
+
fill: config.fill,
|
|
1721
|
+
direction: config.direction,
|
|
1722
|
+
iterations
|
|
1723
|
+
};
|
|
1386
1724
|
for (let i = 0; i < elements.length; i++) {
|
|
1387
1725
|
const element = elements[i];
|
|
1388
|
-
const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
|
|
1389
|
-
const seekPosition = config.delay && config.delay < 0 && config.duration ? -config.delay % config.duration : void 0;
|
|
1390
|
-
const effectOptions = {
|
|
1391
|
-
duration: config.duration,
|
|
1392
|
-
delay: positiveDelay,
|
|
1393
|
-
fill: config.fill,
|
|
1394
|
-
direction: config.direction,
|
|
1395
|
-
iterations
|
|
1396
|
-
};
|
|
1397
1726
|
for (const [, keyframes] of keyframesMap) {
|
|
1398
1727
|
if (keyframes.length > 0) {
|
|
1399
1728
|
try {
|
|
@@ -1445,7 +1774,20 @@ function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsuppo
|
|
|
1445
1774
|
(_a = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a.call(callbacks);
|
|
1446
1775
|
},
|
|
1447
1776
|
"finish": () => {
|
|
1448
|
-
|
|
1777
|
+
var _a;
|
|
1778
|
+
for (const a of animations) {
|
|
1779
|
+
try {
|
|
1780
|
+
if (((_a = a.effect) == null ? void 0 : _a.getTiming().iterations) === Infinity) {
|
|
1781
|
+
a.effect.updateTiming({ iterations: 1 });
|
|
1782
|
+
a.finish();
|
|
1783
|
+
a.effect.updateTiming({ iterations: Infinity });
|
|
1784
|
+
} else {
|
|
1785
|
+
a.finish();
|
|
1786
|
+
}
|
|
1787
|
+
} catch (e) {
|
|
1788
|
+
a.cancel();
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1449
1791
|
},
|
|
1450
1792
|
"setPlaybackRate": (rate) => {
|
|
1451
1793
|
animations.forEach((a) => a.playbackRate = rate);
|
|
@@ -1576,7 +1918,7 @@ function generateNewIds(doc) {
|
|
|
1576
1918
|
value[styleProp] = replaceUrlRefs(styleValue, idMap);
|
|
1577
1919
|
}
|
|
1578
1920
|
}
|
|
1579
|
-
} else if (typeof value === "object" && value !== null && key !==
|
|
1921
|
+
} else if (typeof value === "object" && value !== null && key !== ANIMATE_ATTR) {
|
|
1580
1922
|
updateRefs(value);
|
|
1581
1923
|
}
|
|
1582
1924
|
}
|