@pixodesk/svg-animator-web 1.0.24 → 1.0.26

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 CHANGED
@@ -1018,8 +1018,10 @@ var PxNodeSchema = px.openObject(__spreadProps2(__spreadValues2({}, PxNodeBase._
1018
1018
  children: px.lazy(() => px.array(PxNodeSchema), []).optional()
1019
1019
  }), PxAttrValueSchema);
1020
1020
  var PxSvgNodeExtra = px.object({
1021
- width: px.number().optional(),
1022
- height: px.number().optional(),
1021
+ // `"100%"` and other SVG length strings are legal here — a number-only slot rejected
1022
+ // real documents (e.g. apple-store-look-14-main.json) at the root <svg>.
1023
+ width: px.union([px.number(), px.string()]).optional(),
1024
+ height: px.union([px.number(), px.string()]).optional(),
1023
1025
  viewBox: px.string().optional(),
1024
1026
  animator: PxAnimatorConfigSchema.optional()
1025
1027
  });
@@ -2052,7 +2054,7 @@ function walkAndMaterialise(node, opts) {
2052
2054
  if (newAnimate) cloned.animate = newAnimate;
2053
2055
  return cloned;
2054
2056
  }
2055
- var LOOP_JUMP_SHIFT_MS = 10;
2057
+ var LOOP_JUMP_SHIFT_MS = 1;
2056
2058
  function deepEqualValue(a, b) {
2057
2059
  if (a === b) return true;
2058
2060
  if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
@@ -2301,6 +2303,8 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2301
2303
  const looped = [];
2302
2304
  const separateBoundary = loop.extend !== PxLoopExtend.before;
2303
2305
  const originalTerminalKf = keyframes[keyframes.length - 1];
2306
+ let terminalEasingOverride;
2307
+ let hasTerminalEasingOverride = false;
2304
2308
  function appendRep(repStart, isReversed, partial) {
2305
2309
  var _a2;
2306
2310
  let entries;
@@ -2341,7 +2345,16 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2341
2345
  const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
2342
2346
  const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
2343
2347
  if (isBoundary) {
2344
- if (deepEqualValue(prevKf.v, entry.v)) continue;
2348
+ if (deepEqualValue(prevKf.v, entry.v)) {
2349
+ if (looped.length > 0) {
2350
+ prevKf.e = entry.e;
2351
+ prevKf.tangentOut = entry.tangentOut;
2352
+ } else {
2353
+ terminalEasingOverride = entry.e;
2354
+ hasTerminalEasingOverride = true;
2355
+ }
2356
+ continue;
2357
+ }
2345
2358
  if (looped.length > 0) {
2346
2359
  delete prevKf.tangentIn;
2347
2360
  delete prevKf.tangentOut;
@@ -2422,6 +2435,11 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2422
2435
  if (loop.extend === PxLoopExtend.before) {
2423
2436
  return [...looped, ...keyframes];
2424
2437
  } else {
2438
+ if (hasTerminalEasingOverride && keyframes.length > 0) {
2439
+ const head = keyframes.slice(0, -1);
2440
+ const tail = __spreadProps2(__spreadValues2({}, keyframes[keyframes.length - 1]), { e: terminalEasingOverride });
2441
+ return [...head, tail, ...looped];
2442
+ }
2425
2443
  return [...keyframes, ...looped];
2426
2444
  }
2427
2445
  }
@@ -2538,6 +2556,9 @@ function generateElementId() {
2538
2556
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2539
2557
  const normalized = {};
2540
2558
  for (const [propName, propAnim] of Object.entries(animDef)) {
2559
+ if (propName === "transform" && propAnim.alongPathMode === "offsetPath" && animDef["offsetDistance"] !== void 0) {
2560
+ continue;
2561
+ }
2541
2562
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2542
2563
  if (normalizedKfs.length > 0) {
2543
2564
  const out = { kfs: normalizedKfs };
@@ -5349,9 +5370,138 @@ function applyPlayerEffects_retime(node, ctx) {
5349
5370
  applyAllRetimeEffects(node, ctx);
5350
5371
  return node;
5351
5372
  }
5373
+ var kfTime = (kf) => {
5374
+ var _a, _b;
5375
+ return (_b = (_a = kf.t) != null ? _a : kf.time) != null ? _b : 0;
5376
+ };
5377
+ var kfValue = (kf) => {
5378
+ var _a;
5379
+ return (_a = kf.v) != null ? _a : kf.value;
5380
+ };
5381
+ var kfEasing = (kf) => {
5382
+ var _a;
5383
+ return (_a = kf.e) != null ? _a : kf.easing;
5384
+ };
5385
+ var kfTangentIn = (kf) => {
5386
+ var _a;
5387
+ return (_a = kf.tangentIn) != null ? _a : kf.ti;
5388
+ };
5389
+ var kfTangentOut = (kf) => {
5390
+ var _a;
5391
+ return (_a = kf.tangentOut) != null ? _a : kf.to;
5392
+ };
5393
+ function cubicAt(p0, c1, c2, p1, t) {
5394
+ const u = 1 - t;
5395
+ const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
5396
+ return [
5397
+ a * p0[0] + b * c1[0] + c * c2[0] + d * p1[0],
5398
+ a * p0[1] + b * c1[1] + c * c2[1] + d * p1[1]
5399
+ ];
5400
+ }
5401
+ function cubicLength(p0, c1, c2, p1, steps = 64) {
5402
+ let len = 0;
5403
+ let prev = p0;
5404
+ for (let i = 1; i <= steps; i++) {
5405
+ const pt = cubicAt(p0, c1, c2, p1, i / steps);
5406
+ len += Math.hypot(pt[0] - prev[0], pt[1] - prev[1]);
5407
+ prev = pt;
5408
+ }
5409
+ return len;
5410
+ }
5411
+ var fmt2 = (n) => {
5412
+ const r = Math.round(n * 1e4) / 1e4;
5413
+ return Object.is(r, -0) ? "0" : String(r);
5414
+ };
5415
+ function buildOffsetPath(propAnim) {
5416
+ var _a, _b, _c, _d;
5417
+ if (propAnim.alongPathMode !== "offsetPath") return void 0;
5418
+ const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
5419
+ if (!kfs || kfs.length < 2) return void 0;
5420
+ const first = kfValue(kfs[0]);
5421
+ const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
5422
+ const points = [];
5423
+ for (const kf of kfs) {
5424
+ const v = kfValue(kf);
5425
+ const tr = v == null ? void 0 : v.translate;
5426
+ if (!tr || tr.length < 2) return void 0;
5427
+ const parts = Object.keys(v);
5428
+ if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5429
+ const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
5430
+ if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5431
+ points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5432
+ }
5433
+ if (!kfs.some((kf) => kfTangentIn(kf) || kfTangentOut(kf))) return void 0;
5434
+ let d = "M" + fmt2(points[0][0]) + "," + fmt2(points[0][1]);
5435
+ const segLens = [];
5436
+ for (let i = 0; i < points.length - 1; i++) {
5437
+ const p0 = points[i], p1 = points[i + 1];
5438
+ const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5439
+ const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
5440
+ const c1 = [p0[0] + to[0], p0[1] + to[1]];
5441
+ const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5442
+ d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
5443
+ segLens.push(cubicLength(p0, c1, c2, p1));
5444
+ }
5445
+ const total = segLens.reduce((a, b) => a + b, 0);
5446
+ if (!(total > 0)) return void 0;
5447
+ const distanceKfs = [];
5448
+ let cum = 0;
5449
+ for (let i = 0; i < kfs.length; i++) {
5450
+ if (i > 0) cum += segLens[i - 1];
5451
+ const out = { t: kfTime(kfs[i]), v: cum / total };
5452
+ const e = kfEasing(kfs[i]);
5453
+ if (e !== void 0) out.e = e;
5454
+ distanceKfs.push(out);
5455
+ }
5456
+ return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5457
+ }
5458
+ function materialiseOffsetPathsInTree(root) {
5459
+ const walk = (node) => {
5460
+ var _a;
5461
+ let out = node;
5462
+ const anim = node.animate;
5463
+ const transform = anim == null ? void 0 : anim["transform"];
5464
+ if (transform) {
5465
+ const built = buildOffsetPath(transform);
5466
+ if (built) {
5467
+ const newAnimate = __spreadValues2({}, anim);
5468
+ delete newAnimate["transform"];
5469
+ const distance = { keyframes: built.distanceKfs };
5470
+ if (transform.loop !== void 0) distance.loop = transform.loop;
5471
+ newAnimate["offsetDistance"] = distance;
5472
+ const staticTr = node.transform;
5473
+ let newTransform = staticTr;
5474
+ if (staticTr && typeof staticTr === "object") {
5475
+ const t = __spreadValues2({}, staticTr);
5476
+ delete t["translate"];
5477
+ delete t["origin"];
5478
+ newTransform = Object.keys(t).length ? t : void 0;
5479
+ }
5480
+ out = __spreadProps2(__spreadValues2({}, node), {
5481
+ animate: newAnimate,
5482
+ style: __spreadProps2(__spreadValues2({}, node.style), {
5483
+ offsetPath: "path('" + built.pathStr + "')",
5484
+ offsetAnchor: fmt2(built.anchor[0]) + "px " + fmt2(built.anchor[1]) + "px",
5485
+ offsetRotate: built.autoOrient ? "auto" : "0deg",
5486
+ offsetDistance: "0%"
5487
+ })
5488
+ });
5489
+ if (newTransform !== void 0) out.transform = newTransform;
5490
+ else delete out.transform;
5491
+ }
5492
+ }
5493
+ if ((_a = out.children) == null ? void 0 : _a.length) {
5494
+ const children = out.children.map(walk);
5495
+ if (children.some((c, i) => c !== out.children[i])) out = __spreadProps2(__spreadValues2({}, out), { children });
5496
+ }
5497
+ return out;
5498
+ };
5499
+ return walk(root);
5500
+ }
5352
5501
  function materialiseAllInTree(doc, engine, opts) {
5353
5502
  var _a, _b;
5354
5503
  let root = applyPlayerEffects(doc).root;
5504
+ root = materialiseOffsetPathsInTree(root);
5355
5505
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
5356
5506
  root = materialiseInternalLoopsInTree(root, duration);
5357
5507
  if (engine === PxAnimatorEngine.waapi) {
@@ -6060,6 +6210,8 @@ function createCssKf(kf, t, propName, unsupportedSet) {
6060
6210
  } else if (propName === "d") {
6061
6211
  const paths = value && typeof value === "object" && Array.isArray(value.paths) ? value.paths : [];
6062
6212
  cssValue = 'path("' + paths.map((bz) => bezierToSvgPath(bz, true)).join("") + '")';
6213
+ } else if (PCT_BASED_ATTR_NAMES.has(propName) && typeof value === "number") {
6214
+ cssValue = value * 100 + "%";
6063
6215
  } else {
6064
6216
  cssValue = "" + value;
6065
6217
  }