@pixodesk/svg-animator-react 1.0.21 → 1.0.24

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.umd.js CHANGED
@@ -1936,8 +1936,9 @@ var PixodeskAnimatorReact = (() => {
1936
1936
  }
1937
1937
  isValid(raw, ctx, path) {
1938
1938
  var _a;
1939
- if (this.schemas.some((s) => s.isValid(raw))) return true;
1940
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a = JSON.stringify(raw)) != null ? _a : "").slice(0, 60));
1939
+ const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
1940
+ if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
1941
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a = JSON.stringify(raw)) != null ? _a : "").slice(0, 240));
1941
1942
  return false;
1942
1943
  }
1943
1944
  _canSanitize(raw) {
@@ -2013,6 +2014,7 @@ var PixodeskAnimatorReact = (() => {
2013
2014
  if (ctx == null ? void 0 : ctx.strict) {
2014
2015
  for (const key of Object.keys(obj)) {
2015
2016
  if (key in this._shape) continue;
2017
+ if (obj[key] === void 0) continue;
2016
2018
  p.push(key);
2017
2019
  ctx.errors.push(pathStr(p) + ": unexpected extra key");
2018
2020
  p.pop();
@@ -2153,6 +2155,23 @@ var PixodeskAnimatorReact = (() => {
2153
2155
  return true;
2154
2156
  }
2155
2157
  };
2158
+ var Defined = class extends Base {
2159
+ constructor() {
2160
+ super(...arguments);
2161
+ this._default = void 0;
2162
+ }
2163
+ sanitize(raw) {
2164
+ return raw;
2165
+ }
2166
+ isValid(raw, ctx, path) {
2167
+ if (raw !== void 0) return true;
2168
+ ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": required value is missing");
2169
+ return false;
2170
+ }
2171
+ _canSanitize(raw) {
2172
+ return raw !== void 0;
2173
+ }
2174
+ };
2156
2175
  var Lazy = class extends Base {
2157
2176
  constructor(fn, _default) {
2158
2177
  super();
@@ -2250,6 +2269,8 @@ var PixodeskAnimatorReact = (() => {
2250
2269
  record: (value) => new Rec(value),
2251
2270
  /** Passes anything through unchanged — always valid. */
2252
2271
  any: () => new Any(),
2272
+ /** Anything EXCEPT `undefined` — an open type whose presence is required (V6). */
2273
+ defined: () => new Defined(),
2253
2274
  /** Fixed-length tuple — validates element count and each position individually. */
2254
2275
  tuple: (schemas) => new Tuple(schemas),
2255
2276
  /** Defers schema creation — required for recursive types. Must supply a default value. */
@@ -2259,13 +2280,52 @@ var PixodeskAnimatorReact = (() => {
2259
2280
  var PX_ANIM_ATTR_NAME = "_px_animator";
2260
2281
  var PxAnimatorMode = {
2261
2282
  auto: "auto",
2262
- webapi: "webapi",
2283
+ waapi: "waapi",
2263
2284
  frames: "frames"
2264
2285
  };
2265
2286
  var PxAnimatorEngine = {
2266
- webapi: PxAnimatorMode.webapi,
2287
+ waapi: PxAnimatorMode.waapi,
2267
2288
  frames: PxAnimatorMode.frames
2268
2289
  };
2290
+ var PxLoopExtend = {
2291
+ /** Segment from the START; the animation is extended BEFORE the first keyframe
2292
+ * (intro loops that run before the main timeline begins). */
2293
+ before: "before",
2294
+ /** DEFAULT — segment from the END; extended AFTER the last keyframe (idle/outro
2295
+ * loops that continue once the main timeline has finished). */
2296
+ after: "after"
2297
+ };
2298
+ var PxMaskType = {
2299
+ luminance: "luminance",
2300
+ alpha: "alpha"
2301
+ };
2302
+ var PxUnits = {
2303
+ userSpaceOnUse: "userSpaceOnUse",
2304
+ objectBoundingBox: "objectBoundingBox"
2305
+ };
2306
+ var PxCloneType = {
2307
+ content: "content"
2308
+ };
2309
+ var PxPathOverflow = {
2310
+ clip: "clip",
2311
+ extend: "extend"
2312
+ };
2313
+ var PxLengthAdjust = {
2314
+ spacing: "spacing",
2315
+ spacingAndGlyphs: "spacingAndGlyphs"
2316
+ };
2317
+ var PxTextPathMethod = {
2318
+ align: "align",
2319
+ stretch: "stretch"
2320
+ };
2321
+ var PxTextPathSpacing = {
2322
+ auto: "auto",
2323
+ exact: "exact"
2324
+ };
2325
+ var PxTrimSubPaths = {
2326
+ separate: "separate",
2327
+ combined: "combined"
2328
+ };
2269
2329
  var TEXT_ATTR = "text";
2270
2330
  var TEXT_CONTENT_ATTR = "textContent";
2271
2331
  var INTERNAL_ATTRS = /* @__PURE__ */ new Set([
@@ -2274,9 +2334,45 @@ var PixodeskAnimatorReact = (() => {
2274
2334
  "animator",
2275
2335
  "meta",
2276
2336
  "animate",
2337
+ "effects",
2277
2338
  TEXT_ATTR,
2278
2339
  TEXT_CONTENT_ATTR
2279
2340
  ]);
2341
+ var PxGradientUnits = {
2342
+ userSpaceOnUse: "userSpaceOnUse",
2343
+ objectBoundingBox: "objectBoundingBox"
2344
+ };
2345
+ var PxGradientSpreadMethod = {
2346
+ pad: "pad",
2347
+ reflect: "reflect",
2348
+ repeat: "repeat"
2349
+ };
2350
+ var PxGradientType = {
2351
+ linear: "linear",
2352
+ radial: "radial"
2353
+ };
2354
+ function isPxElementFileFormat(fileJson) {
2355
+ if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
2356
+ return false;
2357
+ }
2358
+ return fileJson["type"] === "svg";
2359
+ }
2360
+ function getAnimatorConfig(doc) {
2361
+ var _a;
2362
+ return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
2363
+ }
2364
+ function getDefs(doc) {
2365
+ var _a;
2366
+ if (!doc) return void 0;
2367
+ return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
2368
+ }
2369
+ function getBindings(doc) {
2370
+ var _a;
2371
+ if (!doc) return void 0;
2372
+ const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
2373
+ if (!animateById) return void 0;
2374
+ return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
2375
+ }
2280
2376
  var PxEasingOrRefSchema = px.union([
2281
2377
  px.string(),
2282
2378
  px.tuple([px.number(), px.number(), px.number(), px.number()])
@@ -2288,13 +2384,15 @@ var PixodeskAnimatorReact = (() => {
2288
2384
  px.array(px.number()),
2289
2385
  px.lazy(() => PxTransformPartsSchema, {}),
2290
2386
  px.object({ path: px.string() }),
2291
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] })
2387
+ px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
2388
+ // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
2389
+ px.lazy(() => px.array(PxGradientStopSchema), [])
2292
2390
  ]));
2293
2391
  var PxKeyframeSchema = implementsInterface()(px.object({
2294
2392
  time: px.number().optional(),
2295
2393
  t: px.number().optional(),
2296
- value: px.any().optional(),
2297
- v: px.any().optional(),
2394
+ value: PxKeyframeValueSchema.optional(),
2395
+ v: PxKeyframeValueSchema.optional(),
2298
2396
  easing: PxEasingOrRefSchema.optional(),
2299
2397
  e: PxEasingOrRefSchema.optional(),
2300
2398
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
@@ -2308,10 +2406,11 @@ var PixodeskAnimatorReact = (() => {
2308
2406
  }));
2309
2407
  var PxLoopSchema = implementsInterface()(px.object({
2310
2408
  segmentCount: px.number().optional(),
2311
- before: px.boolean().optional(),
2409
+ extend: px.enum([PxLoopExtend.before, PxLoopExtend.after]).optional(),
2312
2410
  alternate: px.boolean().optional()
2313
2411
  }));
2314
2412
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
2413
+ value: PxKeyframeValueSchema.optional(),
2315
2414
  keyframes: px.array(PxKeyframeSchema).optional(),
2316
2415
  kfs: px.array(PxKeyframeSchema).optional(),
2317
2416
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
@@ -2326,6 +2425,7 @@ var PixodeskAnimatorReact = (() => {
2326
2425
  }));
2327
2426
  var PxTransformValueSchema = px.union([
2328
2427
  px.string(),
2428
+ PxTransformPartsSchema,
2329
2429
  px.object({ value: PxTransformPartsSchema }),
2330
2430
  PxPropertyAnimationSchema
2331
2431
  ]);
@@ -2360,9 +2460,11 @@ var PixodeskAnimatorReact = (() => {
2360
2460
  glyphs: px.record(PxGlyphFontSchema).optional()
2361
2461
  }));
2362
2462
  var PxAnimatorConfigSchema = implementsInterface()(px.object({
2363
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.webapi, PxAnimatorMode.frames]).optional(),
2463
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
2364
2464
  duration: px.number().optional(),
2365
2465
  delay: px.number().optional(),
2466
+ // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
2467
+ // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
2366
2468
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
2367
2469
  fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
2368
2470
  direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
@@ -2370,8 +2472,8 @@ var PixodeskAnimatorReact = (() => {
2370
2472
  trigger: PxTriggerSchema.optional(),
2371
2473
  resetOnFinish: px.boolean().optional(),
2372
2474
  definitions: PxDefsSchema.optional(),
2373
- animate: px.record(PxElementAnimationSchema).optional(),
2374
- debug: px.boolean().optional(),
2475
+ animateById: px.record(PxElementAnimationSchema).optional(),
2476
+ timelineSource: px.string().optional(),
2375
2477
  debugInstName: px.string().optional()
2376
2478
  }));
2377
2479
  var PxBindingSchema = implementsInterface()(px.object({
@@ -2381,26 +2483,29 @@ var PixodeskAnimatorReact = (() => {
2381
2483
  var PxAttrValueSchema = px.union([
2382
2484
  px.string(),
2383
2485
  px.number(),
2384
- px.object({ value: px.any() }),
2385
- PxPropertyAnimationSchema
2486
+ px.array(px.number()),
2487
+ // Structured static — `{value: …}` (read-accepted transitional spelling, S1).
2488
+ // `defined`, not `any`: the KEY's presence is what identifies this branch (V6).
2489
+ px.object({ value: px.defined() }),
2490
+ // Bare transform parts record — the canonical static `transform` on the wire (T2).
2491
+ PxTransformPartsSchema
2386
2492
  ]);
2387
2493
  var PxAnimatableNumberSchema = px.union([
2388
2494
  px.number(),
2389
2495
  px.object({ value: px.number() }),
2390
- px.object({
2391
- keyframes: px.array(PxKeyframeSchema),
2392
- autoOrient: px.boolean().optional()
2393
- })
2496
+ PxPropertyAnimationSchema
2394
2497
  ]);
2395
2498
  var PxAnimatableVec2Schema = px.union([
2396
2499
  px.tuple([px.number(), px.number()]),
2397
2500
  px.object({ value: px.tuple([px.number(), px.number()]) }),
2398
- px.object({
2399
- keyframes: px.array(PxKeyframeSchema),
2400
- autoOrient: px.boolean().optional()
2401
- })
2501
+ PxPropertyAnimationSchema
2402
2502
  ]);
2403
- var PxTransformationEffectSchema = implementsInterface()(px.object({
2503
+ var PxAnimatableStringSchema = px.union([
2504
+ px.string(),
2505
+ px.object({ value: px.string() }),
2506
+ PxPropertyAnimationSchema
2507
+ ]);
2508
+ var PxTransformByEffectSchema = implementsInterface()(px.object({
2404
2509
  translate: PxAnimatableVec2Schema.optional(),
2405
2510
  rotate: PxAnimatableNumberSchema.optional(),
2406
2511
  scale: PxAnimatableVec2Schema.optional(),
@@ -2408,42 +2513,46 @@ var PixodeskAnimatorReact = (() => {
2408
2513
  origin: PxAnimatableVec2Schema.optional()
2409
2514
  }));
2410
2515
  var PxRepeaterEffectSchema = implementsInterface()(px.object({
2516
+ // STATIC config, not a channel (V2/SCHEMA-DESIGN R5): the copy COUNT is read
2517
+ // once at expansion time and never sampled — plain number, no `keyframes`.
2411
2518
  copies: px.number().optional(),
2412
2519
  translate: PxAnimatableVec2Schema.optional(),
2413
2520
  rotate: PxAnimatableNumberSchema.optional(),
2521
+ skew: PxAnimatableNumberSchema.optional(),
2414
2522
  scale: PxAnimatableVec2Schema.optional(),
2415
2523
  origin: PxAnimatableVec2Schema.optional()
2416
2524
  }));
2417
2525
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
2418
- href: px.string().optional(),
2419
- maskType: px.string().optional(),
2420
- maskUnits: px.string().optional(),
2421
- maskContentUnits: px.string().optional()
2526
+ sourceId: px.string().optional(),
2527
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
2528
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
2529
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
2530
+ x: px.number().optional(),
2531
+ y: px.number().optional(),
2532
+ width: px.number().optional(),
2533
+ height: px.number().optional()
2422
2534
  }));
2423
2535
  var PxClipPathEffectSchema = implementsInterface()(px.object({
2424
- d: px.string().optional(),
2536
+ d: PxAnimatableStringSchema.optional(),
2425
2537
  animate: PxPropertyAnimationSchema.optional()
2426
2538
  }));
2427
2539
  var PxTrimPathEffectSchema = implementsInterface()(px.object({
2428
2540
  offset: PxAnimatableNumberSchema.optional(),
2429
2541
  range: PxAnimatableVec2Schema.optional(),
2430
- trimAllAsOne: px.boolean().optional()
2542
+ subPaths: px.enum([PxTrimSubPaths.separate, PxTrimSubPaths.combined]).optional()
2431
2543
  }));
2432
2544
  var PxRetimeEffectSchema = implementsInterface()(px.object({
2433
- baseId: px.string().optional(),
2545
+ sourceId: px.string().optional(),
2434
2546
  start: px.number().optional(),
2435
2547
  stretch: px.number().optional(),
2436
2548
  timeCrop: px.tuple([px.number(), px.number()]).optional()
2437
2549
  }));
2438
2550
  var PxCloneEffectSchema = implementsInterface()(px.object({
2439
- type: px.string().optional(),
2440
- baseId: px.string().optional(),
2551
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
2552
+ type: px.enum([PxCloneType.content]).optional(),
2553
+ sourceId: px.string().optional(),
2441
2554
  retime: PxRetimeEffectSchema.optional()
2442
2555
  }));
2443
- var PxGradientType = {
2444
- linear: "linear",
2445
- radial: "radial"
2446
- };
2447
2556
  var PxGradientStopSchema = implementsInterface()(px.object({
2448
2557
  offset: px.number(),
2449
2558
  color: px.string()
@@ -2451,27 +2560,28 @@ var PixodeskAnimatorReact = (() => {
2451
2560
  var PxAnimatableGradientStopsSchema = px.union([
2452
2561
  px.array(PxGradientStopSchema),
2453
2562
  px.object({ value: px.array(PxGradientStopSchema) }),
2454
- px.object({ keyframes: px.array(PxKeyframeSchema) })
2563
+ PxPropertyAnimationSchema
2455
2564
  ]);
2456
2565
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
2566
+ // Contextual kind — the `type` convention, see `PxNodeBase.type`.
2457
2567
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
2458
- p1: px.tuple([px.number(), px.number()]).optional(),
2459
- p2: px.tuple([px.number(), px.number()]).optional(),
2460
- c: px.tuple([px.number(), px.number()]).optional(),
2461
- r: px.number().optional(),
2462
- fp: px.tuple([px.number(), px.number()]).optional(),
2568
+ p1: PxAnimatableVec2Schema.optional(),
2569
+ p2: PxAnimatableVec2Schema.optional(),
2570
+ c: PxAnimatableVec2Schema.optional(),
2571
+ r: PxAnimatableNumberSchema.optional(),
2572
+ fp: PxAnimatableVec2Schema.optional(),
2463
2573
  stops: PxAnimatableGradientStopsSchema.optional(),
2464
- gradientUnits: px.string().optional(),
2465
- spreadMethod: px.string().optional(),
2574
+ gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
2575
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
2466
2576
  gradientTransform: px.string().optional()
2467
2577
  }));
2468
2578
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
2469
2579
  var PxTextPathEffectSchema = implementsInterface()(px.object({
2470
2580
  path: px.string(),
2471
- pathOverflow: px.string().optional(),
2472
- lengthAdjust: px.string().optional(),
2473
- method: px.string().optional(),
2474
- spacing: px.string().optional(),
2581
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
2582
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
2583
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
2584
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
2475
2585
  startOffset: PxAnimatableNumberSchema.optional(),
2476
2586
  textLength: PxAnimatableNumberSchema.optional()
2477
2587
  }));
@@ -2479,13 +2589,12 @@ var PixodeskAnimatorReact = (() => {
2479
2589
  useGlyphs: px.boolean().optional()
2480
2590
  }));
2481
2591
  var PxEffectsSchema = implementsInterface()(px.object({
2482
- transformation: PxTransformationEffectSchema.optional(),
2592
+ transformBy: PxTransformByEffectSchema.optional(),
2483
2593
  repeater: PxRepeaterEffectSchema.optional(),
2484
2594
  maskedBy: PxMaskedByEffectSchema.optional(),
2485
2595
  clipPath: PxClipPathEffectSchema.optional(),
2486
2596
  trimPath: PxTrimPathEffectSchema.optional(),
2487
2597
  clone: PxCloneEffectSchema.optional(),
2488
- isCombinedShape: px.boolean().optional(),
2489
2598
  fillGradient: PxFillGradientEffectSchema.optional(),
2490
2599
  strokeGradient: PxStrokeGradientEffectSchema.optional(),
2491
2600
  textPath: PxTextPathEffectSchema.optional(),
@@ -2509,6 +2618,14 @@ var PixodeskAnimatorReact = (() => {
2509
2618
  return warnings;
2510
2619
  }
2511
2620
  var PxNodeBase = px.openObject({
2621
+ // CONVENTION (SCHEMA-DESIGN R1 / issues N4): `type` is the ONE word for "what
2622
+ // kind of thing is this", discriminated by its CARRIER — here the node TAG
2623
+ // (`rect`, `text`), and inside a sub-object that object's kind (`clone.type`,
2624
+ // `fillGradient.type`, editor `preset.type`). Each sits in its own object, so
2625
+ // the carrier disambiguates completely; synonyms (`cloneKind`, `presetShape`)
2626
+ // would add words that all mean "type" and still need the carrier to read.
2627
+ // Guarding a `type` SLOT against a wrong VALUE is the job of strict enums
2628
+ // (issues V3), never of distinct key names.
2512
2629
  type: px.string(),
2513
2630
  id: px.string().optional(),
2514
2631
  meta: px.any().optional(),
@@ -2518,7 +2635,7 @@ var PixodeskAnimatorReact = (() => {
2518
2635
  effects: PxEffectsSchema.optional(),
2519
2636
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
2520
2637
  // string ref / array of refs / inline definition / mixed array; mirrors
2521
- // `animator.animate` map values and what `processNode` resolves at runtime.
2638
+ // `animator.animateById` map values and what `processNode` resolves at runtime.
2522
2639
  animate: PxElementAnimationSchema.optional(),
2523
2640
  style: px.union([px.string(), px.record(px.union([px.string(), px.number()]))]).optional()
2524
2641
  }, PxAttrValueSchema);
@@ -2542,28 +2659,6 @@ var PixodeskAnimatorReact = (() => {
2542
2659
  o: px.array(px.array(px.number())).optional(),
2543
2660
  c: px.boolean().optional()
2544
2661
  }));
2545
- function isPxElementFileFormat(fileJson) {
2546
- if (!(fileJson && typeof fileJson === "object" && !Array.isArray(fileJson))) {
2547
- return false;
2548
- }
2549
- return fileJson["type"] === "svg" || fileJson["tagName"] === "svg";
2550
- }
2551
- function getAnimatorConfig(doc) {
2552
- var _a, _b;
2553
- 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);
2554
- }
2555
- function getDefs(doc) {
2556
- var _a;
2557
- if (!doc) return void 0;
2558
- return (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.definitions;
2559
- }
2560
- function getBindings(doc) {
2561
- var _a;
2562
- if (!doc) return void 0;
2563
- const animate = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animate;
2564
- if (!animate) return void 0;
2565
- return Object.entries(animate).map(([id, anim]) => ({ id, animate: anim }));
2566
- }
2567
2662
  function bezierToSvgPath(path, forceCurves = false) {
2568
2663
  var _a, _b, _c, _d;
2569
2664
  const v = path.v;
@@ -3014,7 +3109,7 @@ var PixodeskAnimatorReact = (() => {
3014
3109
  "flood-color",
3015
3110
  "lighting-color"
3016
3111
  ]);
3017
- const directIdRefAttrs = /* @__PURE__ */ new Set(["baseId", "targetId", "boundElementId"]);
3112
+ const directIdRefAttrs = /* @__PURE__ */ new Set(["sourceId", "targetId", "boundElementId"]);
3018
3113
  function collectIds(node) {
3019
3114
  if (!node || typeof node !== "object") return;
3020
3115
  if (node.id && typeof node.id === "string") {
@@ -3052,9 +3147,10 @@ var PixodeskAnimatorReact = (() => {
3052
3147
  } else if (urlRefAttrs.has(key)) {
3053
3148
  node[key] = replaceUrlRefs(value, idMap);
3054
3149
  } else if (directIdRefAttrs.has(key)) {
3055
- const newId = idMap.get(value);
3150
+ const hasHash = value.startsWith("#");
3151
+ const newId = idMap.get(hasHash ? value.slice(1) : value);
3056
3152
  if (newId) {
3057
- node[key] = newId;
3153
+ node[key] = hasHash ? "#" + newId : newId;
3058
3154
  }
3059
3155
  } else if (value.includes("url(#")) {
3060
3156
  node[key] = replaceUrlRefs(value, idMap);
@@ -3072,14 +3168,14 @@ var PixodeskAnimatorReact = (() => {
3072
3168
  }
3073
3169
  collectIds(cloned);
3074
3170
  updateRefs(cloned);
3075
- const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animate;
3171
+ const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
3076
3172
  if (docAnimate && typeof docAnimate === "object") {
3077
3173
  const updatedAnimate = {};
3078
3174
  for (const [id, anim] of Object.entries(docAnimate)) {
3079
3175
  const newId = (_b = idMap.get(id)) != null ? _b : id;
3080
3176
  updatedAnimate[newId] = anim;
3081
3177
  }
3082
- cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animate: updatedAnimate });
3178
+ cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animateById: updatedAnimate });
3083
3179
  }
3084
3180
  return cloned;
3085
3181
  }
@@ -3168,8 +3264,9 @@ var PixodeskAnimatorReact = (() => {
3168
3264
  let value = props[rawKey];
3169
3265
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
3170
3266
  propsCopy[key] = toRGBA(value);
3171
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && value.value && typeof value.value === "object") {
3172
- propsCopy["transform"] = composeTransformParts(value.value, { withUnits: false });
3267
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
3268
+ const parts = value.value && typeof value.value === "object" ? value.value : value;
3269
+ propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
3173
3270
  } else if (TRANSFORM_FN_NAMES.has(key)) {
3174
3271
  if (Array.isArray(value)) {
3175
3272
  if (key === "translate") value = value.map((v) => v + "px");
@@ -3177,6 +3274,8 @@ var PixodeskAnimatorReact = (() => {
3177
3274
  }
3178
3275
  if (key === "rotate") value = value + "deg";
3179
3276
  propsCopy["transform"] = key + "(" + value + ")";
3277
+ } else if (Array.isArray(value)) {
3278
+ propsCopy[key] = value.join(",");
3180
3279
  } else if (value !== void 0 && value !== null) {
3181
3280
  propsCopy[key] = String(value);
3182
3281
  }
@@ -3574,6 +3673,16 @@ var PixodeskAnimatorReact = (() => {
3574
3673
  if (newAnimate) cloned.animate = newAnimate;
3575
3674
  return cloned;
3576
3675
  }
3676
+ var LOOP_JUMP_SHIFT_MS = 10;
3677
+ function deepEqualValue(a, b) {
3678
+ if (a === b) return true;
3679
+ if (typeof a !== typeof b || a === null || b === null || typeof a !== "object") return false;
3680
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
3681
+ const ka = Object.keys(a);
3682
+ const kb = Object.keys(b);
3683
+ if (ka.length !== kb.length) return false;
3684
+ return ka.every((k) => deepEqualValue(a[k], b[k]));
3685
+ }
3577
3686
  function parsePathCommands(d) {
3578
3687
  const tokens = d.split(/([MLCZmlcz]|[\s,]+)/).map((t) => t.trim()).filter((t) => t && t !== ",");
3579
3688
  const commands = [];
@@ -3776,7 +3885,7 @@ var PixodeskAnimatorReact = (() => {
3776
3885
  const totalIntervals = keyframes.length - 1;
3777
3886
  const segCount = clamp((_a = loop.segmentCount) != null ? _a : totalIntervals, 1, totalIntervals);
3778
3887
  let segKfs;
3779
- if (loop.before) {
3888
+ if (loop.extend === PxLoopExtend.before) {
3780
3889
  segKfs = keyframes.slice(0, segCount + 1);
3781
3890
  } else {
3782
3891
  segKfs = keyframes.slice(totalIntervals - segCount);
@@ -3784,7 +3893,7 @@ var PixodeskAnimatorReact = (() => {
3784
3893
  const firstT = (_b = keyframes[0].t) != null ? _b : 0;
3785
3894
  const lastT = (_c = keyframes[keyframes.length - 1].t) != null ? _c : 0;
3786
3895
  let fillStart, fillEnd;
3787
- if (loop.before) {
3896
+ if (loop.extend === PxLoopExtend.before) {
3788
3897
  fillStart = 0;
3789
3898
  fillEnd = firstT;
3790
3899
  } else {
@@ -3811,7 +3920,10 @@ var PixodeskAnimatorReact = (() => {
3811
3920
  const remainder = fillDuration - fullReps * segDuration;
3812
3921
  const partialFraction = remainder / segDuration;
3813
3922
  const looped = [];
3923
+ const separateBoundary = loop.extend !== PxLoopExtend.before;
3924
+ const originalTerminalKf = keyframes[keyframes.length - 1];
3814
3925
  function appendRep(repStart, isReversed, partial) {
3926
+ var _a2;
3815
3927
  let entries;
3816
3928
  if (isReversed) {
3817
3929
  entries = [];
@@ -3847,8 +3959,17 @@ var PixodeskAnimatorReact = (() => {
3847
3959
  looped.push({ t: repStart + cutRelT * segDuration, v: cutValue, e: void 0 });
3848
3960
  return;
3849
3961
  }
3962
+ const prevKf = looped.length > 0 ? looped[looped.length - 1] : originalTerminalKf;
3963
+ const isBoundary = separateBoundary && i === 0 && prevKf !== void 0 && Math.abs(((_a2 = prevKf.t) != null ? _a2 : 0) - (repStart + entry.relT * segDuration)) < 1e-9;
3964
+ if (isBoundary) {
3965
+ if (deepEqualValue(prevKf.v, entry.v)) continue;
3966
+ if (looped.length > 0) {
3967
+ delete prevKf.tangentIn;
3968
+ delete prevKf.tangentOut;
3969
+ }
3970
+ }
3850
3971
  const pushed = {
3851
- t: repStart + entry.relT * segDuration,
3972
+ t: repStart + entry.relT * segDuration + (isBoundary ? LOOP_JUMP_SHIFT_MS : 0),
3852
3973
  v: entry.v,
3853
3974
  e: i < entries.length - 1 ? entry.e : void 0
3854
3975
  };
@@ -3896,7 +4017,7 @@ var PixodeskAnimatorReact = (() => {
3896
4017
  looped.push(pushed);
3897
4018
  }
3898
4019
  }
3899
- if (loop.before) {
4020
+ if (loop.extend === PxLoopExtend.before) {
3900
4021
  if (partialFraction > 1e-9) {
3901
4022
  const isReversed = !!loop.alternate && fullReps % 2 === 0;
3902
4023
  appendRepTail(fillStart, isReversed, partialFraction);
@@ -3919,7 +4040,7 @@ var PixodeskAnimatorReact = (() => {
3919
4040
  appendRep(repStart, isReversed, partialFraction);
3920
4041
  }
3921
4042
  }
3922
- if (loop.before) {
4043
+ if (loop.extend === PxLoopExtend.before) {
3923
4044
  return [...looped, ...keyframes];
3924
4045
  } else {
3925
4046
  return [...keyframes, ...looped];
@@ -4035,7 +4156,7 @@ var PixodeskAnimatorReact = (() => {
4035
4156
  function generateElementId() {
4036
4157
  return "_px_el_" + ++_elementIdCounter;
4037
4158
  }
4038
- function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.webapi) {
4159
+ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
4039
4160
  const normalized = {};
4040
4161
  for (const [propName, propAnim] of Object.entries(animDef)) {
4041
4162
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
@@ -4043,12 +4164,12 @@ var PixodeskAnimatorReact = (() => {
4043
4164
  const out = { kfs: normalizedKfs };
4044
4165
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
4045
4166
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
4046
- normalized[propName] = engine === PxAnimatorEngine.webapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
4167
+ normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
4047
4168
  }
4048
4169
  }
4049
4170
  return normalized;
4050
4171
  }
4051
- function getNormalisedBindings(doc, engine = PxAnimatorEngine.webapi) {
4172
+ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
4052
4173
  const animatorConfig = getAnimatorConfig(doc) || {};
4053
4174
  const defs = getDefs(doc);
4054
4175
  const duration = animatorConfig.duration || 1e3;
@@ -4453,6 +4574,7 @@ var PixodeskAnimatorReact = (() => {
4453
4574
  return rec;
4454
4575
  }
4455
4576
  function readAnimatable(raw) {
4577
+ var _a, _b, _c;
4456
4578
  if (raw === void 0) return {
4457
4579
  kind: "absent"
4458
4580
  /* Absent */
@@ -4460,19 +4582,56 @@ var PixodeskAnimatorReact = (() => {
4460
4582
  if (Array.isArray(raw)) return { kind: "static", value: raw };
4461
4583
  if (typeof raw === "object") {
4462
4584
  const obj = raw;
4463
- if (obj.keyframes) {
4464
- return { kind: "animated", keyframes: obj.keyframes, autoOrient: obj.autoOrient, loop: obj.loop };
4585
+ const kfs = (_a = obj.keyframes) != null ? _a : obj.kfs;
4586
+ if (kfs) {
4587
+ const out = { kind: "animated", keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
4588
+ const base = (_b = obj.value) != null ? _b : obj.v;
4589
+ if (base !== void 0 && out.kind === "animated") out.base = base;
4590
+ return out;
4465
4591
  }
4466
- if (obj.value !== void 0) return { kind: "static", value: obj.value };
4592
+ const staticValue = (_c = obj.value) != null ? _c : obj.v;
4593
+ if (staticValue !== void 0) return { kind: "static", value: staticValue };
4467
4594
  }
4468
4595
  return { kind: "static", value: raw };
4469
4596
  }
4597
+ function writeAnimatableChannel(node, attrName, read, opts) {
4598
+ var _a, _b, _c, _d;
4599
+ const toOut = (v) => (opts == null ? void 0 : opts.asString) && v !== void 0 && v !== null ? String(v) : v;
4600
+ if (read.kind === "absent") return;
4601
+ if (read.kind === "static") {
4602
+ node[attrName] = toOut(read.value);
4603
+ return;
4604
+ }
4605
+ const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
4606
+ const animate = __spreadValues2({}, prevAnimate || {});
4607
+ const block = { keyframes: read.keyframes };
4608
+ if (read.loop !== void 0) block.loop = read.loop;
4609
+ if (read.autoOrient !== void 0) block.autoOrient = read.autoOrient;
4610
+ animate[attrName] = block;
4611
+ node.animate = animate;
4612
+ const baseline = (_d = (_b = read.base) != null ? _b : (_a = read.keyframes[0]) == null ? void 0 : _a.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
4613
+ if (baseline !== void 0) node[attrName] = toOut(baseline);
4614
+ }
4615
+ function normaliseKeyframe(kf) {
4616
+ if (!kf || typeof kf !== "object") return kf;
4617
+ const k = kf;
4618
+ if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
4619
+ return kf;
4620
+ }
4621
+ const out = __spreadValues2({}, k);
4622
+ if (out.time === void 0 && k.t !== void 0) out.time = k.t;
4623
+ if (out.value === void 0 && k.v !== void 0) out.value = k.v;
4624
+ if (out.easing === void 0 && k.e !== void 0) out.easing = k.e;
4625
+ if (out.tangentOut === void 0 && k.to !== void 0) out.tangentOut = k.to;
4626
+ if (out.tangentIn === void 0 && k.ti !== void 0) out.tangentIn = k.ti;
4627
+ return out;
4628
+ }
4470
4629
  function readStaticOrigin(raw, ctx) {
4471
4630
  var _a;
4472
4631
  const o = readAnimatable(raw);
4473
4632
  if (o.kind === "absent") return void 0;
4474
4633
  if (o.kind === "static") return o.value;
4475
- ctx.warnings.push("transformation.origin: animated origin approximated by its first keyframe");
4634
+ ctx.warnings.push("transformBy.origin: animated origin approximated by its first keyframe");
4476
4635
  return (_a = o.keyframes[0]) == null ? void 0 : _a.value;
4477
4636
  }
4478
4637
  function keyframeWith(kf, value) {
@@ -4483,7 +4642,7 @@ var PixodeskAnimatorReact = (() => {
4483
4642
  if (kf.tangentIn !== void 0) out.tangentIn = kf.tangentIn;
4484
4643
  return out;
4485
4644
  }
4486
- function applyTransformationEffect(node, fx, ctx) {
4645
+ function applyTransformByEffect(node, fx, ctx) {
4487
4646
  if (!fx) return node;
4488
4647
  delete node.transform;
4489
4648
  let n = node;
@@ -4519,6 +4678,10 @@ var PixodeskAnimatorReact = (() => {
4519
4678
  } else {
4520
4679
  n = wrapTransformPart(n, "translate", fx.translate, ctx);
4521
4680
  }
4681
+ if (n !== node && node.id) {
4682
+ n.id = node.id;
4683
+ delete node.id;
4684
+ }
4522
4685
  return n;
4523
4686
  }
4524
4687
  function translateHasAutoOrient(translate) {
@@ -4528,8 +4691,6 @@ var PixodeskAnimatorReact = (() => {
4528
4691
  return Array.isArray(obj.keyframes) && obj.keyframes.some((kf) => kf.tangentOut || kf.tangentIn);
4529
4692
  }
4530
4693
  function normalizeScale(raw) {
4531
- if (raw === void 0) return void 0;
4532
- if (Array.isArray(raw)) return [raw[0] / 100, raw[1] / 100];
4533
4694
  return raw;
4534
4695
  }
4535
4696
  function wrapTransformPart(inner, part, raw, ctx) {
@@ -4570,34 +4731,54 @@ var PixodeskAnimatorReact = (() => {
4570
4731
  }
4571
4732
  return inner;
4572
4733
  }
4734
+ function genId(ctx, prefix) {
4735
+ return "_lw_" + prefix + "_" + ctx.nextId++;
4736
+ }
4737
+ function stripHash2(href) {
4738
+ return typeof href === "string" ? href.replace(/^#/, "") : void 0;
4739
+ }
4740
+ function indexById(node, map) {
4741
+ var _a;
4742
+ if (typeof node.id === "string") map.set(node.id, node);
4743
+ (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
4744
+ }
4745
+ function spliceDefs(root, defs) {
4746
+ if (!defs.length) return;
4747
+ const existing = root.children || (root.children = []);
4748
+ existing.unshift({ type: "defs", children: defs });
4749
+ }
4750
+ var clone = deepClonePxNode;
4751
+ function regenerateIdsInClone(root, ctx) {
4752
+ return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
4753
+ }
4573
4754
  function identifyContentRefTargets(node, ctx, allocator) {
4574
4755
  var _a, _b, _c;
4575
4756
  if (node.type === "use" && ((_b = (_a = node.effects) == null ? void 0 : _a.clone) == null ? void 0 : _b.type) === "content") {
4576
- const baseId = node.effects.clone.baseId;
4577
- if (typeof baseId === "string" && baseId && !ctx.contentRefInnerIds.has(baseId)) {
4578
- ctx.contentRefInnerIds.set(baseId, allocator(baseId));
4757
+ const sourceId = stripHash2(node.effects.clone.sourceId);
4758
+ if (typeof sourceId === "string" && sourceId && !ctx.contentRefInnerIds.has(sourceId)) {
4759
+ ctx.contentRefInnerIds.set(sourceId, allocator(sourceId));
4579
4760
  }
4580
4761
  }
4581
4762
  (_c = node.children) == null ? void 0 : _c.forEach((c) => identifyContentRefTargets(c, ctx, allocator));
4582
4763
  }
4583
- function splitForContentRef(node, transformation, originalId, innerId, ctx) {
4584
- const outerBody = liftBodyTranslate(node, transformation);
4764
+ function splitForContentRef(node, transformBy, originalId, innerId, ctx) {
4765
+ const outerBody = liftBodyTranslate(node, transformBy);
4585
4766
  if (typeof node.id === "string") delete node.id;
4586
- const { outer: outerTr, inner: innerTr } = splitTransformationEffect(transformation);
4767
+ const { outer: outerTr, inner: innerTr } = splitTransformByEffect(transformBy);
4587
4768
  let innerNode = node;
4588
- innerNode = applyTransformationEffect(innerNode, innerTr, ctx);
4769
+ innerNode = applyTransformByEffect(innerNode, innerTr, ctx);
4589
4770
  const innerWrapper = { type: "g", id: innerId, children: [innerNode] };
4590
4771
  let outerWrapper = { type: "g", id: originalId, children: [innerWrapper] };
4591
4772
  if (outerBody.transform !== void 0) outerWrapper.transform = outerBody.transform;
4592
4773
  if (outerBody.animate !== void 0) outerWrapper.animate = outerBody.animate;
4593
4774
  if (outerTr) {
4594
4775
  delete outerWrapper.id;
4595
- outerWrapper = applyTransformationEffect(outerWrapper, outerTr, ctx);
4776
+ outerWrapper = applyTransformByEffect(outerWrapper, outerTr, ctx);
4596
4777
  outerWrapper.id = originalId;
4597
4778
  }
4598
4779
  return outerWrapper;
4599
4780
  }
4600
- function liftBodyTranslate(node, transformation) {
4781
+ function liftBodyTranslate(node, transformBy) {
4601
4782
  var _a, _b, _c;
4602
4783
  const out = {};
4603
4784
  let didLiftAnimate = false;
@@ -4651,7 +4832,7 @@ var PixodeskAnimatorReact = (() => {
4651
4832
  didLiftAnimate = true;
4652
4833
  }
4653
4834
  }
4654
- const transformationHasTranslate = (transformation == null ? void 0 : transformation.translate) !== void 0;
4835
+ const transformationHasTranslate = (transformBy == null ? void 0 : transformBy.translate) !== void 0;
4655
4836
  const stripBodyTranslateOnly = didLiftAnimate || transformationHasTranslate;
4656
4837
  const liftedAnimateIsAutoOriented = didLiftAnimate && needsOriginOnOuter(((_b = node.animate) == null ? void 0 : _b.transform) || void 0) || didLiftAnimate && needsOriginOnOuter(((_c = out.animate) == null ? void 0 : _c.transform) || void 0);
4657
4838
  if (typeof node.transform === "string") {
@@ -4670,6 +4851,24 @@ var PixodeskAnimatorReact = (() => {
4670
4851
  if (split.rest) node.transform = split.rest;
4671
4852
  else delete node.transform;
4672
4853
  }
4854
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
4855
+ const wrapped = node.transform.value;
4856
+ const isWrapped = !!(wrapped && typeof wrapped === "object");
4857
+ const value = isWrapped ? wrapped : node.transform;
4858
+ const rewrap = (rec) => isWrapped ? { value: rec } : rec;
4859
+ if (Array.isArray(value.translate)) {
4860
+ const rest = __spreadValues2({}, value);
4861
+ delete rest.translate;
4862
+ const hasRest = Object.keys(rest).length > 0;
4863
+ if (stripBodyTranslateOnly) {
4864
+ if (hasRest) node.transform = rewrap(rest);
4865
+ else delete node.transform;
4866
+ } else {
4867
+ out.transform = rewrap({ translate: value.translate });
4868
+ if (hasRest) node.transform = rewrap(rest);
4869
+ else delete node.transform;
4870
+ }
4871
+ }
4673
4872
  }
4674
4873
  return out;
4675
4874
  }
@@ -4739,7 +4938,7 @@ var PixodeskAnimatorReact = (() => {
4739
4938
  const nums = m[1].split(/[\s,]+/).filter(Boolean).map(Number);
4740
4939
  return [nums[0] || 0, nums[1] || 0];
4741
4940
  }
4742
- function splitTransformationEffect(fx) {
4941
+ function splitTransformByEffect(fx) {
4743
4942
  if (!fx) return {};
4744
4943
  const originOnOuter = needsOriginOnOuter(fx.translate);
4745
4944
  const innerHasPivotedPart = fx.rotate !== void 0 || fx.scale !== void 0;
@@ -4765,26 +4964,6 @@ var PixodeskAnimatorReact = (() => {
4765
4964
  }
4766
4965
  return false;
4767
4966
  }
4768
- function genId(ctx, prefix) {
4769
- return "_lw_" + prefix + "_" + ctx.nextId++;
4770
- }
4771
- function stripHash2(href) {
4772
- return typeof href === "string" ? href.replace(/^#/, "") : void 0;
4773
- }
4774
- function indexById(node, map) {
4775
- var _a;
4776
- if (typeof node.id === "string") map.set(node.id, node);
4777
- (_a = node.children) == null ? void 0 : _a.forEach((child) => indexById(child, map));
4778
- }
4779
- function spliceDefs(root, defs) {
4780
- if (!defs.length) return;
4781
- const existing = root.children || (root.children = []);
4782
- existing.unshift({ type: "defs", children: defs });
4783
- }
4784
- var clone = deepClonePxNode;
4785
- function regenerateIdsInClone(root, ctx) {
4786
- return regenerateIdsAndRewriteRefs(root, () => genId(ctx, "retimed"));
4787
- }
4788
4967
  function applyFillGradientEffect(node, fx, ctx) {
4789
4968
  return applyGradient(node, fx, ctx, "fill");
4790
4969
  }
@@ -4805,62 +4984,63 @@ var PixodeskAnimatorReact = (() => {
4805
4984
  id
4806
4985
  };
4807
4986
  if (fx.type === PxGradientType.linear) {
4808
- if (fx.p1) {
4809
- out.x1 = String(fx.p1[0]);
4810
- out.y1 = String(fx.p1[1]);
4811
- }
4812
- if (fx.p2) {
4813
- out.x2 = String(fx.p2[0]);
4814
- out.y2 = String(fx.p2[1]);
4815
- }
4987
+ applyGeomVec(out, "x1", "y1", fx.p1);
4988
+ applyGeomVec(out, "x2", "y2", fx.p2);
4816
4989
  } else {
4817
- if (fx.c) {
4818
- out.cx = String(fx.c[0]);
4819
- out.cy = String(fx.c[1]);
4820
- }
4821
- if (fx.r !== void 0) out.r = String(fx.r);
4822
- if (fx.fp) {
4823
- out.fx = String(fx.fp[0]);
4824
- out.fy = String(fx.fp[1]);
4825
- }
4990
+ applyGeomVec(out, "cx", "cy", fx.c);
4991
+ applyGeomNumber(out, "r", fx.r);
4992
+ applyGeomVec(out, "fx", "fy", fx.fp);
4826
4993
  }
4827
4994
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
4828
4995
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
4829
4996
  if (fx.gradientTransform) out.gradientTransform = fx.gradientTransform;
4830
- const animate = fx.animate;
4831
- if (animate) {
4832
- const mapped = {};
4833
- for (const wireKey of Object.keys(animate)) {
4834
- const attr = GRADIENT_ANIM_CHANNEL_TO_ATTR[wireKey];
4835
- if (attr) mapped[attr] = animate[wireKey];
4836
- }
4837
- if (Object.keys(mapped).length) out.animate = mapped;
4838
- }
4839
4997
  out.children = buildStopChildren(fx.stops, ctx);
4840
4998
  return out;
4841
4999
  }
4842
- var GRADIENT_ANIM_CHANNEL_TO_ATTR = {
4843
- gradientX1: "x1",
4844
- gradientY1: "y1",
4845
- gradientX2: "x2",
4846
- gradientY2: "y2",
4847
- gradientCx: "cx",
4848
- gradientCy: "cy",
4849
- gradientFx: "fx",
4850
- gradientFy: "fy",
4851
- gradientR: "r"
4852
- };
5000
+ function applyGeomVec(out, xAttr, yAttr, raw) {
5001
+ var _a, _b, _c;
5002
+ const read = readAnimatable(raw);
5003
+ if (read.kind === "absent") return;
5004
+ if (read.kind === "static") {
5005
+ out[xAttr] = String(read.value[0]);
5006
+ out[yAttr] = String(read.value[1]);
5007
+ return;
5008
+ }
5009
+ const axisChannel = (idx) => {
5010
+ const block = {
5011
+ keyframes: read.keyframes.map((kf) => {
5012
+ const axisKf = { time: kf.time, value: Array.isArray(kf.value) ? kf.value[idx] : void 0 };
5013
+ if (kf.easing !== void 0) axisKf.easing = kf.easing;
5014
+ return axisKf;
5015
+ })
5016
+ };
5017
+ if (read.loop !== void 0) block.loop = read.loop;
5018
+ return block;
5019
+ };
5020
+ const animate = (_a = out.animate) != null ? _a : {};
5021
+ animate[xAttr] = axisChannel(0);
5022
+ animate[yAttr] = axisChannel(1);
5023
+ out.animate = animate;
5024
+ const baseline = (_c = read.base) != null ? _c : (_b = read.keyframes[0]) == null ? void 0 : _b.value;
5025
+ if (Array.isArray(baseline)) {
5026
+ out[xAttr] = String(baseline[0]);
5027
+ out[yAttr] = String(baseline[1]);
5028
+ }
5029
+ }
5030
+ function applyGeomNumber(out, attrName, raw) {
5031
+ const read = readAnimatable(raw);
5032
+ if (read.kind === "absent") return;
5033
+ writeAnimatableChannel(out, attrName, read, { asString: true });
5034
+ }
4853
5035
  function buildStopChildren(stops, ctx) {
4854
5036
  var _a, _b, _c, _d;
4855
5037
  if (!stops) return [];
4856
- if (Array.isArray(stops)) return stops.map(staticStopNode);
4857
- if (typeof stops === "object" && Array.isArray(stops.value)) {
4858
- return stops.value.map(staticStopNode);
4859
- }
4860
- const animBlock = stops;
4861
- const kfs = animBlock.keyframes;
4862
- if (!Array.isArray(kfs) || !kfs.length) return [];
4863
- const loopFromSource = animBlock.loop;
5038
+ const read = readAnimatable(stops);
5039
+ if (read.kind === "absent") return [];
5040
+ if (read.kind === "static") return Array.isArray(read.value) ? read.value.map(staticStopNode) : [];
5041
+ const kfs = read.keyframes;
5042
+ if (!kfs.length) return [];
5043
+ const loopFromSource = read.loop;
4864
5044
  let stopCount = 0;
4865
5045
  for (const kf of kfs) {
4866
5046
  const v = (_a = kf.value) != null ? _a : kf.v;
@@ -4935,36 +5115,60 @@ var PixodeskAnimatorReact = (() => {
4935
5115
  return pct + "%";
4936
5116
  }
4937
5117
  function applyClipPathEffect(node, fx, ctx) {
5118
+ var _a, _b;
4938
5119
  if (!fx || !fx.d && !fx.animate) return node;
4939
5120
  const clipId = genId(ctx, "clip");
4940
- const pathChild = { type: "path", d: fx.d };
4941
- if (fx.animate) pathChild.animate = { d: fx.animate };
5121
+ const pathChild = { type: "path" };
5122
+ const read = readAnimatable(fx.d);
5123
+ if (read.kind !== "absent") {
5124
+ if (read.kind === "static") {
5125
+ pathChild.d = pathString(read.value);
5126
+ } else {
5127
+ writeAnimatableChannel(pathChild, "d", read);
5128
+ if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
5129
+ }
5130
+ }
5131
+ if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
5132
+ const animate = (_b = pathChild.animate) != null ? _b : {};
5133
+ animate.d = fx.animate;
5134
+ pathChild.animate = animate;
5135
+ }
4942
5136
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
4943
5137
  node.clipPath = "url(#" + clipId + ")";
4944
5138
  return node;
4945
5139
  }
4946
- function applyMaskedByEffect(node, fx, transformation, ctx) {
5140
+ function pathString(v) {
5141
+ if (typeof v === "string") return v;
5142
+ if (v && typeof v === "object" && typeof v.path === "string") return v.path;
5143
+ return void 0;
5144
+ }
5145
+ function applyMaskedByEffect(node, fx, transformBy, ctx) {
4947
5146
  if (!fx) return node;
4948
- if (!fx.href) {
4949
- ctx.errors.push("maskedBy.href missing \u2014 cannot build mask");
5147
+ const sourceId = stripHash2(fx.sourceId);
5148
+ if (!sourceId) {
5149
+ ctx.errors.push("maskedBy.sourceId missing \u2014 cannot build mask");
4950
5150
  return node;
4951
5151
  }
4952
5152
  const maskId = genId(ctx, "mask");
4953
- let content = { type: "use", href: "#" + fx.href };
4954
- if (transformation) {
4955
- content = wrapInverseTransform(content, transformation, ctx);
5153
+ let content = { type: "use", href: "#" + sourceId };
5154
+ if (transformBy) {
5155
+ content = wrapInverseTransform(content, transformBy, ctx);
4956
5156
  } else if (hasAnimateTransform(node)) {
4957
5157
  content = wrapInverseAnimatedBodyTransform(content, node, ctx);
4958
5158
  } else {
4959
5159
  const bodyStatic = readTransformationFromBody(node);
4960
5160
  if (bodyStatic) content = wrapInverseTransform(content, bodyStatic, ctx);
4961
5161
  }
4962
- const includeTargetOwn = transformation === void 0 && !nodeHasBodyTransform(node);
4963
- content = wrapAncestorChainCompensation(content, node, fx.href, ctx, includeTargetOwn);
5162
+ const includeTargetOwn = transformBy === void 0 && !nodeHasBodyTransform(node);
5163
+ content = wrapAncestorChainCompensation(content, node, sourceId, ctx, includeTargetOwn);
4964
5164
  const mask = { type: "mask", id: maskId, children: [content] };
4965
5165
  if (fx.maskType) mask.maskType = fx.maskType;
4966
5166
  if (fx.maskUnits) mask.maskUnits = fx.maskUnits;
4967
5167
  if (fx.maskContentUnits) mask.maskContentUnits = fx.maskContentUnits;
5168
+ if (fx.x !== void 0) mask.x = String(fx.x);
5169
+ if (fx.y !== void 0) mask.y = String(fx.y);
5170
+ if (fx.width !== void 0) mask.width = String(fx.width);
5171
+ if (fx.height !== void 0) mask.height = String(fx.height);
4968
5172
  ctx.defs.push(mask);
4969
5173
  node.mask = "url(#" + maskId + ")";
4970
5174
  return node;
@@ -5071,6 +5275,19 @@ var PixodeskAnimatorReact = (() => {
5071
5275
  if (parts.origin) out.origin = parts.origin;
5072
5276
  return Object.keys(out).length ? out : void 0;
5073
5277
  }
5278
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
5279
+ const wrapped = node.transform.value;
5280
+ const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
5281
+ if (value && typeof value === "object") {
5282
+ const out = {};
5283
+ if (Array.isArray(value.translate)) out.translate = value.translate;
5284
+ if (typeof value.rotate === "number") out.rotate = value.rotate;
5285
+ if (typeof value.skew === "number") out.skew = value.skew;
5286
+ if (Array.isArray(value.scale)) out.scale = { value: value.scale };
5287
+ if (Array.isArray(value.origin)) out.origin = value.origin;
5288
+ return Object.keys(out).length ? out : void 0;
5289
+ }
5290
+ }
5074
5291
  return void 0;
5075
5292
  }
5076
5293
  function parseTransformStringToParts(s) {
@@ -5204,10 +5421,10 @@ var PixodeskAnimatorReact = (() => {
5204
5421
  const interestingNodes = /* @__PURE__ */ new Set();
5205
5422
  const collectInterestingNodes = (n) => {
5206
5423
  var _a, _b;
5207
- const href = (_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.href;
5208
- if (typeof href === "string") {
5424
+ const maskSourceId = stripHash2((_b = (_a = n.effects) == null ? void 0 : _a.maskedBy) == null ? void 0 : _b.sourceId);
5425
+ if (typeof maskSourceId === "string") {
5209
5426
  interestingNodes.add(n);
5210
- const sourceNode = ctx.idMap.get(href);
5427
+ const sourceNode = ctx.idMap.get(maskSourceId);
5211
5428
  if (sourceNode) interestingNodes.add(sourceNode);
5212
5429
  }
5213
5430
  if (Array.isArray(n.children)) for (const ch of n.children) collectInterestingNodes(ch);
@@ -5233,8 +5450,9 @@ var PixodeskAnimatorReact = (() => {
5233
5450
  if (typeof tr === "string") {
5234
5451
  const parts = parseTranslateOnlyFromString(tr, ctx);
5235
5452
  if (parts) out.translate = parts;
5236
- } else if (tr && typeof tr === "object") {
5237
- const value = tr.value;
5453
+ } else if (tr && typeof tr === "object" && !tr.keyframes && !tr.kfs) {
5454
+ const wrapped = tr.value;
5455
+ const value = wrapped && typeof wrapped === "object" ? wrapped : tr;
5238
5456
  if (value && typeof value === "object" && Array.isArray(value.translate)) {
5239
5457
  out.translate = [value.translate[0] || 0, value.translate[1] || 0];
5240
5458
  }
@@ -5282,17 +5500,17 @@ var PixodeskAnimatorReact = (() => {
5282
5500
  var CONTENT_SUBREF = "content";
5283
5501
  function applyRefHref(node, clone2, ctx) {
5284
5502
  if (!clone2) return;
5285
- const baseId = clone2.baseId;
5286
- if (!baseId) {
5287
- if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing baseId");
5503
+ const sourceId = stripHash2(clone2.sourceId);
5504
+ if (!sourceId) {
5505
+ if (clone2.type === CONTENT_SUBREF) ctx.errors.push("clone: content ref missing sourceId");
5288
5506
  return;
5289
5507
  }
5290
- const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(baseId) || baseId : baseId;
5508
+ const targetId = clone2.type === CONTENT_SUBREF ? ctx.contentRefInnerIds.get(sourceId) || sourceId : sourceId;
5291
5509
  node.href = "#" + targetId;
5292
5510
  }
5293
- function applyRefAndTransformationEffect(node, clone2, transformation, ctx) {
5511
+ function applyRefAndTransformationEffect(node, clone2, transformBy, ctx) {
5294
5512
  applyRefHref(node, clone2, ctx);
5295
- return applyTransformationEffect(node, transformation, ctx);
5513
+ return applyTransformByEffect(node, transformBy, ctx);
5296
5514
  }
5297
5515
  function applyRepeaterEffect(node, fx, ctx) {
5298
5516
  var _a, _b;
@@ -5315,7 +5533,7 @@ var PixodeskAnimatorReact = (() => {
5315
5533
  for (let i = 1; i < copies; i++) {
5316
5534
  const baseClone = clone(base);
5317
5535
  const synthFx = synthesisePerCopyFx(fx, i);
5318
- const wrapped = synthFx ? applyTransformationEffect(baseClone, synthFx, ctx) : baseClone;
5536
+ const wrapped = synthFx ? applyTransformByEffect(baseClone, synthFx, ctx) : baseClone;
5319
5537
  children.push(wrapped);
5320
5538
  }
5321
5539
  const wrapper = { type: "g", children };
@@ -5327,10 +5545,13 @@ var PixodeskAnimatorReact = (() => {
5327
5545
  function synthesisePerCopyFx(fx, i) {
5328
5546
  const out = {};
5329
5547
  if (fx.translate !== void 0) {
5330
- out.translate = mapAnimatableVec2(fx.translate, (v) => [v[0] * i, v[1] * i]);
5548
+ out.translate = mapAnimatable(fx.translate, (v) => [v[0] * i, v[1] * i]);
5331
5549
  }
5332
5550
  if (fx.rotate !== void 0) {
5333
- out.rotate = mapAnimatableNumber(fx.rotate, (v) => v * i);
5551
+ out.rotate = mapAnimatable(fx.rotate, (v) => v * i);
5552
+ }
5553
+ if (fx.skew !== void 0) {
5554
+ out.skew = mapAnimatable(fx.skew, (v) => v * i);
5334
5555
  }
5335
5556
  if (fx.scale !== void 0) {
5336
5557
  out.scale = synthesiseScale(fx.scale, i);
@@ -5340,63 +5561,50 @@ var PixodeskAnimatorReact = (() => {
5340
5561
  }
5341
5562
  return Object.keys(out).length ? out : void 0;
5342
5563
  }
5343
- function mapAnimatableVec2(raw, fn) {
5344
- if (Array.isArray(raw)) return fn(raw);
5345
- if (raw && typeof raw === "object") {
5346
- const obj = raw;
5347
- if (Array.isArray(obj.keyframes)) {
5348
- return __spreadProps2(__spreadValues2({}, obj), {
5349
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
5350
- });
5351
- }
5352
- if (obj.value !== void 0) {
5353
- return __spreadProps2(__spreadValues2({}, obj), { value: fn(obj.value) });
5354
- }
5355
- }
5356
- return raw;
5357
- }
5358
- function mapAnimatableNumber(raw, fn) {
5359
- if (typeof raw === "number") return fn(raw);
5360
- if (raw && typeof raw === "object") {
5361
- const obj = raw;
5362
- if (Array.isArray(obj.keyframes)) {
5363
- return __spreadProps2(__spreadValues2({}, obj), {
5364
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
5365
- });
5366
- }
5367
- if (obj.value !== void 0) {
5368
- return __spreadProps2(__spreadValues2({}, obj), { value: fn(obj.value) });
5369
- }
5564
+ function mapAnimatable(raw, fn, wrapStatic = false) {
5565
+ const read = readAnimatable(raw);
5566
+ if (read.kind === "absent") return raw;
5567
+ if (read.kind === "static") {
5568
+ const mapped = fn(read.value);
5569
+ const wasRawStatic = typeof raw === "number" || Array.isArray(raw);
5570
+ return wasRawStatic && !wrapStatic ? mapped : { value: mapped };
5370
5571
  }
5371
- return raw;
5572
+ const out = {
5573
+ keyframes: read.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: fn(kf.value) }) : kf)
5574
+ };
5575
+ if (read.loop !== void 0) out.loop = read.loop;
5576
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
5577
+ if (read.base !== void 0) out.value = fn(read.base);
5578
+ return out;
5372
5579
  }
5373
5580
  function synthesiseScale(raw, i) {
5374
- const scalePowerFromPercent = (v) => [Math.pow(v[0] / 100, i), Math.pow(v[1] / 100, i)];
5375
- const scalePowerFromUnits = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
5376
- if (Array.isArray(raw)) {
5377
- return { value: scalePowerFromPercent(raw) };
5378
- }
5379
- if (raw && typeof raw === "object") {
5380
- const obj = raw;
5381
- if (Array.isArray(obj.keyframes)) {
5382
- return __spreadProps2(__spreadValues2({}, obj), {
5383
- keyframes: obj.keyframes.map((kf) => kf && kf.value !== void 0 ? __spreadProps2(__spreadValues2({}, kf), { value: scalePowerFromUnits(kf.value) }) : kf)
5384
- });
5385
- }
5386
- if (obj.value !== void 0) {
5387
- return __spreadProps2(__spreadValues2({}, obj), { value: scalePowerFromPercent(obj.value) });
5388
- }
5389
- }
5390
- return raw;
5581
+ const scalePower = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
5582
+ return mapAnimatable(raw, scalePower, true);
5391
5583
  }
5392
5584
  var RETIME_MATERIALISATION_MODE_INLINE_G = false;
5393
5585
  function asRetime(r) {
5394
5586
  var _a, _b;
5395
- if (r.timeCrop) {
5396
- console.warn("retime: `timeCrop` is not supported yet and will be ignored");
5397
- }
5398
5587
  return { start: (_a = r.start) != null ? _a : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
5399
5588
  }
5589
+ var CROP_EDGE_MS = 1;
5590
+ function applyTimeCrop(useNode, crop, ctx) {
5591
+ const [start, end] = crop;
5592
+ if (!Number.isFinite(start) || !Number.isFinite(end)) {
5593
+ ctx.warnings.push("retime: timeCrop is not a pair of finite numbers \u2014 ignored");
5594
+ return;
5595
+ }
5596
+ const keyframes = end <= start ? [{ time: 0, value: 0 }] : [
5597
+ ...start > 0 ? [{ time: Math.max(0, start - CROP_EDGE_MS), value: 0 }] : [],
5598
+ { time: Math.max(0, start), value: 1 },
5599
+ { time: end, value: 1 },
5600
+ { time: end + CROP_EDGE_MS, value: 0 }
5601
+ ];
5602
+ const inner = __spreadValues2({}, useNode);
5603
+ for (const k of Object.keys(useNode)) delete useNode[k];
5604
+ useNode.type = "g";
5605
+ useNode.children = [inner];
5606
+ useNode.animate = { opacity: { keyframes } };
5607
+ }
5400
5608
  function concatRetime(child, parent) {
5401
5609
  return {
5402
5610
  start: parent.start + parent.stretch * child.start,
@@ -5456,8 +5664,10 @@ var PixodeskAnimatorReact = (() => {
5456
5664
  for (const useNode of sites) {
5457
5665
  const retime = readCloneRetime(useNode);
5458
5666
  if (!retime) continue;
5667
+ const crop = retime.timeCrop;
5459
5668
  clearCloneRetime(useNode);
5460
5669
  materialiseRetime(useNode, asRetime(retime), ctx);
5670
+ if (crop) applyTimeCrop(useNode, crop, ctx);
5461
5671
  }
5462
5672
  }
5463
5673
  function materialiseRetime(useNode, retime, ctx) {
@@ -5700,14 +5910,11 @@ var PixodeskAnimatorReact = (() => {
5700
5910
  }
5701
5911
  var EXTEND_MARGIN_FRAC = 0.15;
5702
5912
  function numRange(v) {
5703
- if (typeof v === "number") return { min: v, max: v };
5704
- if (v && typeof v === "object") {
5705
- const o = v;
5706
- if (typeof o.value === "number") return { min: o.value, max: o.value };
5707
- if (Array.isArray(o.keyframes) && o.keyframes.length) {
5708
- const vals = o.keyframes.map((k) => Number(k.value) || 0);
5709
- return { min: Math.min(...vals), max: Math.max(...vals) };
5710
- }
5913
+ const read = readAnimatable(v);
5914
+ if (read.kind === "static" && typeof read.value === "number") return { min: read.value, max: read.value };
5915
+ if (read.kind === "animated" && read.keyframes.length) {
5916
+ const vals = read.keyframes.map((k) => Number(k.value) || 0);
5917
+ return { min: Math.min(...vals), max: Math.max(...vals) };
5711
5918
  }
5712
5919
  return { min: 0, max: 0 };
5713
5920
  }
@@ -5727,11 +5934,16 @@ var PixodeskAnimatorReact = (() => {
5727
5934
  var r3 = (n) => Math.round(n * 1e3) / 1e3;
5728
5935
  function shiftAnimatable(v, by) {
5729
5936
  if (!by || v === void 0 || v === null) return v;
5730
- if (typeof v === "number") return v + by;
5731
- const o = v;
5732
- if (typeof o.value === "number") return __spreadProps2(__spreadValues2({}, o), { value: o.value + by });
5733
- if (Array.isArray(o.keyframes)) return __spreadProps2(__spreadValues2({}, o), { keyframes: o.keyframes.map((k) => __spreadProps2(__spreadValues2({}, k), { value: (Number(k.value) || 0) + by })) });
5734
- return v;
5937
+ const read = readAnimatable(v);
5938
+ if (read.kind === "absent") return v;
5939
+ if (read.kind === "static") return typeof v === "number" ? read.value + by : { value: read.value + by };
5940
+ const out = {
5941
+ keyframes: read.keyframes.map((k) => __spreadProps2(__spreadValues2({}, k), { value: (Number(k.value) || 0) + by }))
5942
+ };
5943
+ if (read.loop !== void 0) out.loop = read.loop;
5944
+ if (read.autoOrient !== void 0) out.autoOrient = read.autoOrient;
5945
+ if (read.base !== void 0) out.value = read.base + by;
5946
+ return out;
5735
5947
  }
5736
5948
  function extendedPathForBrowser(pathD, opts) {
5737
5949
  var _a;
@@ -5787,26 +5999,7 @@ var PixodeskAnimatorReact = (() => {
5787
5999
  }
5788
6000
  function applyAnimatableNumber(node, attrName, raw) {
5789
6001
  if (raw === void 0 || raw === null) return;
5790
- if (typeof raw === "number") {
5791
- node[attrName] = String(raw);
5792
- return;
5793
- }
5794
- if (typeof raw === "object" && raw !== null) {
5795
- const obj = raw;
5796
- if (Array.isArray(obj.keyframes)) {
5797
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
5798
- const animate = __spreadValues2({}, prevAnimate || {});
5799
- const block = { keyframes: obj.keyframes };
5800
- if (obj.loop !== void 0) block.loop = obj.loop;
5801
- animate[attrName] = block;
5802
- node.animate = animate;
5803
- return;
5804
- }
5805
- if (typeof obj.value === "number") {
5806
- node[attrName] = String(obj.value);
5807
- return;
5808
- }
5809
- }
6002
+ writeAnimatableChannel(node, attrName, readAnimatable(raw), { asString: true });
5810
6003
  }
5811
6004
  var jsonElementFactory = (type, props, children) => {
5812
6005
  const node = { type };
@@ -5994,13 +6187,13 @@ var PixodeskAnimatorReact = (() => {
5994
6187
  if (y !== void 0) pen.y = y;
5995
6188
  pen.x += (_a2 = parseLen(el.dx)) != null ? _a2 : 0;
5996
6189
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
5997
- const content = (_c2 = str(el[TEXT_ATTR])) != null ? _c2 : str(el[TEXT_CONTENT_ATTR]);
6190
+ const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
5998
6191
  if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
5999
6192
  if (el.children) for (const ch of el.children) walk(ch, s);
6000
6193
  };
6001
6194
  const rootStyle = rootStyleOf(node);
6002
6195
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
6003
- const rootContent = (_c = str(node[TEXT_ATTR])) != null ? _c : str(node[TEXT_CONTENT_ATTR]);
6196
+ const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
6004
6197
  if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
6005
6198
  const anchor = str(node.textAnchor);
6006
6199
  if (anchor === "middle" || anchor === "end") {
@@ -6018,7 +6211,7 @@ var PixodeskAnimatorReact = (() => {
6018
6211
  const walk = (el, parentStyle) => {
6019
6212
  var _a, _b, _c;
6020
6213
  const s = resolveStyle2(el, parentStyle);
6021
- const content = (_a = str(el[TEXT_ATTR])) != null ? _a : str(el[TEXT_CONTENT_ATTR]);
6214
+ const content = (_a = str(el[TEXT_CONTENT_ATTR])) != null ? _a : str(el[TEXT_ATTR]);
6022
6215
  if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
6023
6216
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
6024
6217
  if (gf) {
@@ -6242,9 +6435,9 @@ var PixodeskAnimatorReact = (() => {
6242
6435
  }
6243
6436
  return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
6244
6437
  }
6245
- function applyTrimPathEffect(node, trimPath, isCombinedShape, ctx) {
6438
+ function applyTrimPathEffect(node, trimPath, ctx) {
6246
6439
  if (!trimPath) return node;
6247
- const trimAllAsOne = !!trimPath.trimAllAsOne;
6440
+ const combined = trimPath.subPaths === PxTrimSubPaths.combined;
6248
6441
  const leafEntries = [];
6249
6442
  const measure = (n) => {
6250
6443
  if (Array.isArray(n.children) && n.children.length > 0) {
@@ -6265,16 +6458,16 @@ var PixodeskAnimatorReact = (() => {
6265
6458
  measure(node);
6266
6459
  if (!leafEntries.length) return node;
6267
6460
  let acc = 0;
6268
- const iterOrder = trimAllAsOne ? [...leafEntries].reverse() : leafEntries;
6461
+ const iterOrder = combined ? [...leafEntries].reverse() : leafEntries;
6269
6462
  for (const entry of iterOrder) {
6270
6463
  for (const sp of entry.subpaths) {
6271
- if (!trimAllAsOne) acc = 0;
6464
+ if (!combined) acc = 0;
6272
6465
  sp.startOffsetPx = acc;
6273
6466
  acc += sp.lengthPx;
6274
6467
  }
6275
6468
  }
6276
6469
  const chainLengthPx = acc;
6277
- if (trimAllAsOne && chainLengthPx < 1e-3) return node;
6470
+ if (combined && chainLengthPx < 1e-3) return node;
6278
6471
  const offsetReadRaw = readAnimatable(trimPath.offset);
6279
6472
  const offsetRead = offsetReadRaw.kind === "absent" ? { kind: "static", value: 0 } : offsetReadRaw;
6280
6473
  const rangeReadRaw = readRangeWithCrossings(trimPath.range);
@@ -6286,18 +6479,18 @@ var PixodeskAnimatorReact = (() => {
6286
6479
  if (leafEntries.length === 1 && leafEntries[0].leaf === node && leafEntries[0].subpaths.length === 1) {
6287
6480
  const entry = leafEntries[0];
6288
6481
  const sp = entry.subpaths[0];
6289
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
6482
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
6290
6483
  if (pathLengthPx < 1e-3) return node;
6291
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
6484
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
6292
6485
  return collapseLeafWithTrim(entry.leaf, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead);
6293
6486
  }
6294
6487
  const replacements = /* @__PURE__ */ new Map();
6295
6488
  for (const entry of leafEntries) {
6296
6489
  const newChildren = [];
6297
6490
  for (const sp of entry.subpaths) {
6298
- const pathLengthPx = trimAllAsOne ? chainLengthPx : sp.lengthPx;
6491
+ const pathLengthPx = combined ? chainLengthPx : sp.lengthPx;
6299
6492
  if (pathLengthPx < 1e-3) continue;
6300
- const startOffsetPct = trimAllAsOne ? sp.startOffsetPx / pathLengthPx : 0;
6493
+ const startOffsetPct = combined ? sp.startOffsetPx / pathLengthPx : 0;
6301
6494
  newChildren.push(...buildSubpathNodes(entry.leaf, sp.subpath, pathLengthPx, startOffsetPct, minMaxOffset, offsetRead, rangeRead, ctx));
6302
6495
  }
6303
6496
  replacements.set(entry.leaf, wrapLeafAsGroup(entry.leaf, newChildren));
@@ -6404,22 +6597,8 @@ var PixodeskAnimatorReact = (() => {
6404
6597
  };
6405
6598
  }
6406
6599
  function applyAttr(node, attrName, attr) {
6407
- var _a, _b;
6408
6600
  if (!attr) return;
6409
- if (attr.kind === "static") {
6410
- node[attrName] = attr.value;
6411
- return;
6412
- }
6413
- const prevAnimate = node.animate && typeof node.animate === "object" && !Array.isArray(node.animate) ? node.animate : void 0;
6414
- const animate = __spreadValues2({}, prevAnimate || {});
6415
- const block = { keyframes: attr.keyframes };
6416
- if (attr.loop !== void 0) block.loop = attr.loop;
6417
- animate[attrName] = block;
6418
- node.animate = animate;
6419
- const firstKf = attr.keyframes[0];
6420
- if (firstKf && ((_a = firstKf.value) != null ? _a : firstKf.v) !== void 0) {
6421
- node[attrName] = (_b = firstKf.value) != null ? _b : firstKf.v;
6422
- }
6601
+ writeAnimatableChannel(node, attrName, attr);
6423
6602
  }
6424
6603
  var OPACITY_STEP_MS = 10;
6425
6604
  function computeOpacityFromRange(rangeRead) {
@@ -6601,9 +6780,9 @@ var PixodeskAnimatorReact = (() => {
6601
6780
  nextId: 0,
6602
6781
  contentRefInnerIds: /* @__PURE__ */ new Map(),
6603
6782
  maskAncestorChains: /* @__PURE__ */ new Map(),
6604
- // Resolved engine: `frames` ONLY when explicitly set; auto/webapi/unset →
6605
- // webapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
6606
- engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi,
6783
+ // Resolved engine: `frames` ONLY when explicitly set; auto/waapi/unset →
6784
+ // waapi (we're not 100% sure it's frames, and CSS/WAAPI need the inline form).
6785
+ engine: ((_a = getAnimatorConfig(root)) == null ? void 0 : _a.mode) === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi,
6607
6786
  glyphs: (_b = getDefs(root)) == null ? void 0 : _b.glyphs
6608
6787
  };
6609
6788
  const working = clone(root);
@@ -6621,8 +6800,7 @@ var PixodeskAnimatorReact = (() => {
6621
6800
  const originalId = typeof node.id === "string" ? node.id : void 0;
6622
6801
  const innerIdForContentRef = originalId ? ctx.contentRefInnerIds.get(originalId) : void 0;
6623
6802
  if (!fx && !innerIdForContentRef) return node;
6624
- const { transformation, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
6625
- const isCombinedShape = fx == null ? void 0 : fx.isCombinedShape;
6803
+ const { transformBy, repeater, maskedBy, clipPath, trimPath, clone: cloneFx, fillGradient, strokeGradient, textPath, text } = fx != null ? fx : {};
6626
6804
  if (fx) delete node.effects;
6627
6805
  let n = node;
6628
6806
  let consumedByGlyphs = false;
@@ -6642,15 +6820,15 @@ var PixodeskAnimatorReact = (() => {
6642
6820
  if (!consumedByGlyphs) n = applyTextPathEffect(n, textPath, ctx);
6643
6821
  n = applyFillGradientEffect(n, fillGradient, ctx);
6644
6822
  n = applyStrokeGradientEffect(n, strokeGradient, ctx);
6645
- n = applyTrimPathEffect(n, trimPath, isCombinedShape, ctx);
6823
+ n = applyTrimPathEffect(n, trimPath, ctx);
6646
6824
  n = applyRepeaterEffect(n, repeater, ctx);
6647
- n = applyMaskedByEffect(n, maskedBy, transformation, ctx);
6825
+ n = applyMaskedByEffect(n, maskedBy, transformBy, ctx);
6648
6826
  n = applyClipPathEffect(n, clipPath, ctx);
6649
6827
  if (innerIdForContentRef) {
6650
6828
  applyRefHref(n, cloneFx, ctx);
6651
- n = splitForContentRef(n, transformation, originalId, innerIdForContentRef, ctx);
6829
+ n = splitForContentRef(n, transformBy, originalId, innerIdForContentRef, ctx);
6652
6830
  } else {
6653
- n = applyRefAndTransformationEffect(n, cloneFx, transformation, ctx);
6831
+ n = applyRefAndTransformationEffect(n, cloneFx, transformBy, ctx);
6654
6832
  }
6655
6833
  if (cloneFx == null ? void 0 : cloneFx.retime) node.effects = { clone: { retime: cloneFx.retime } };
6656
6834
  if (originalId) ctx.idMap.set(originalId, n);
@@ -6665,7 +6843,7 @@ var PixodeskAnimatorReact = (() => {
6665
6843
  let root = applyPlayerEffects(doc).root;
6666
6844
  const duration = (_b = (_a = getAnimatorConfig(root)) == null ? void 0 : _a.duration) != null ? _b : DEFAULT_DURATION_MS;
6667
6845
  root = materialiseInternalLoopsInTree(root, duration);
6668
- if (engine === PxAnimatorEngine.webapi) {
6846
+ if (engine === PxAnimatorEngine.waapi) {
6669
6847
  root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
6670
6848
  root = materialiseAnimatedUseInstances(root);
6671
6849
  root = pruneUnreferencedDefs(root);
@@ -6977,62 +7155,6 @@ var PixodeskAnimatorReact = (() => {
6977
7155
  };
6978
7156
  return api;
6979
7157
  }
6980
- var SVG_NS = "http://www.w3.org/2000/svg";
6981
- function createElement(tagName, normalisedProps, style, children, textContent) {
6982
- if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
6983
- console.warn("SVG tag blocked (dangerous): ", tagName);
6984
- return null;
6985
- }
6986
- const element = document.createElementNS(SVG_NS, tagName);
6987
- for (const propName in normalisedProps) {
6988
- const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
6989
- if (sanitised === void 0) continue;
6990
- if (CSS_ONLY_STYLE_PROPS.has(propName)) {
6991
- element.style[propName] = String(sanitised);
6992
- continue;
6993
- }
6994
- element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
6995
- }
6996
- if (style) {
6997
- for (const styleProp in style) {
6998
- element.style[styleProp] = String(style[styleProp]);
6999
- }
7000
- }
7001
- if (children) {
7002
- for (const child of children) {
7003
- element.appendChild(child);
7004
- }
7005
- }
7006
- if (textContent) element.textContent = textContent;
7007
- return element;
7008
- }
7009
- function renderNode(node, defs) {
7010
- if (!node) return null;
7011
- const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
7012
- const feFuncType = props.funcType;
7013
- if (feFuncType !== void 0) delete props.funcType;
7014
- const nodeDefs = getDefs(node) || defs;
7015
- const resolvedStyle = resolveStyle(style, nodeDefs);
7016
- let childElements;
7017
- if (children) {
7018
- for (const ch of children) {
7019
- const child = renderNode(ch, nodeDefs);
7020
- if (child) {
7021
- if (!childElements) childElements = [];
7022
- childElements.push(child);
7023
- }
7024
- }
7025
- }
7026
- const element = createElement(
7027
- type || "g",
7028
- getNormalizedProps(props),
7029
- resolvedStyle,
7030
- childElements,
7031
- props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR]
7032
- );
7033
- if (element && feFuncType !== void 0) element.setAttribute("type", feFuncType);
7034
- return element;
7035
- }
7036
7158
  function setupAnimationTriggers(api, config) {
7037
7159
  const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
7038
7160
  const root = api.getRootElement();
@@ -7077,8 +7199,14 @@ var PixodeskAnimatorReact = (() => {
7077
7199
  break;
7078
7200
  }
7079
7201
  case "mouseOver": {
7080
- const mouseOverHandler = () => start();
7081
- const mouseOutHandler = () => handleEndAction();
7202
+ let enteredOnce = false;
7203
+ const mouseOverHandler = () => {
7204
+ enteredOnce = true;
7205
+ start();
7206
+ };
7207
+ const mouseOutHandler = () => {
7208
+ if (enteredOnce) handleEndAction();
7209
+ };
7082
7210
  root.addEventListener("mouseenter", mouseOverHandler);
7083
7211
  root.addEventListener("mouseleave", mouseOutHandler);
7084
7212
  break;
@@ -7095,17 +7223,32 @@ var PixodeskAnimatorReact = (() => {
7095
7223
  break;
7096
7224
  }
7097
7225
  case "scrollIntoView": {
7226
+ const effectiveRatio = (entry) => {
7227
+ var _a, _b;
7228
+ const target = entry.boundingClientRect;
7229
+ const visible = entry.intersectionRect;
7230
+ if (!(target == null ? void 0 : target.height) || !visible) return entry.intersectionRatio;
7231
+ const live = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : Infinity;
7232
+ const declared = (_b = (_a = entry.rootBounds) == null ? void 0 : _a.height) != null ? _b : Infinity;
7233
+ const viewport = Math.min(live, declared);
7234
+ const denom = Math.min(target.height, Number.isFinite(viewport) ? viewport : target.height);
7235
+ return denom > 0 ? visible.height / denom : entry.intersectionRatio;
7236
+ };
7237
+ const thresholdSteps = Array.from({ length: 21 }, (_, i) => i / 20);
7238
+ let wasIntersecting = false;
7098
7239
  const observer = new IntersectionObserver(
7099
7240
  (entries) => {
7100
7241
  entries.forEach((entry) => {
7101
- if (entry.isIntersecting && entry.intersectionRatio >= scrollIntoViewThreshold) {
7242
+ if (entry.isIntersecting && effectiveRatio(entry) >= scrollIntoViewThreshold) {
7243
+ wasIntersecting = true;
7102
7244
  start();
7103
- } else {
7245
+ } else if (wasIntersecting) {
7246
+ wasIntersecting = false;
7104
7247
  handleEndAction();
7105
7248
  }
7106
7249
  });
7107
7250
  },
7108
- { threshold: scrollIntoViewThreshold }
7251
+ { threshold: thresholdSteps }
7109
7252
  );
7110
7253
  observer.observe(root);
7111
7254
  break;
@@ -7196,7 +7339,7 @@ var PixodeskAnimatorReact = (() => {
7196
7339
  } else {
7197
7340
  cssValue = "" + value;
7198
7341
  }
7199
- if (!CSS.supports(cssKey, cssValue)) unsupportedSet.add(cssKey);
7342
+ if (!CSS.supports(camelCaseToKebabWordIfNeeded(cssKey), cssValue)) unsupportedSet.add(cssKey);
7200
7343
  cssKey = kebabToCamelCaseWord(cssKey);
7201
7344
  cssKf[cssKey] = cssValue;
7202
7345
  return cssKf;
@@ -7273,7 +7416,7 @@ var PixodeskAnimatorReact = (() => {
7273
7416
  console.warn("createFrameLoopAnimator: No root element provided");
7274
7417
  }
7275
7418
  }
7276
- const bindings = getNormalisedBindings(doc, PxAnimatorEngine.webapi);
7419
+ const bindings = getNormalisedBindings(doc, PxAnimatorEngine.waapi);
7277
7420
  const animations = [];
7278
7421
  const _iterations = config.iterations;
7279
7422
  let iterations;
@@ -7418,8 +7561,7 @@ var PixodeskAnimatorReact = (() => {
7418
7561
  }
7419
7562
  return api;
7420
7563
  }
7421
- function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
7422
- const animatorConfig = getAnimatorConfig(doc) || {};
7564
+ function finaliseAnimator(animatorConfig, callbacks, make) {
7423
7565
  let apiRef;
7424
7566
  let effectiveCallbacks = callbacks;
7425
7567
  if (animatorConfig.resetOnFinish) {
@@ -7431,29 +7573,92 @@ var PixodeskAnimatorReact = (() => {
7431
7573
  }
7432
7574
  });
7433
7575
  }
7434
- let res;
7435
- if (animatorConfig.mode === PxAnimatorMode.frames) {
7436
- res = createFrameLoopAnimator(doc, adapter, effectiveCallbacks, rootElement);
7437
- } else {
7438
- res = createWebApiAnimator(
7439
- doc,
7440
- effectiveCallbacks,
7441
- rootElement,
7442
- animatorConfig.mode === PxAnimatorMode.webapi
7443
- // forcing webapi
7444
- ) || createFrameLoopAnimator(doc, adapter, effectiveCallbacks, rootElement);
7445
- }
7576
+ const res = make(effectiveCallbacks);
7446
7577
  apiRef = res;
7447
7578
  if (animatorConfig.debugInstName) {
7448
7579
  window[animatorConfig.debugInstName] = res;
7449
7580
  }
7450
7581
  return res;
7451
7582
  }
7583
+ function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
7584
+ const animatorConfig = getAnimatorConfig(doc) || {};
7585
+ return finaliseAnimator(animatorConfig, callbacks, (cb) => {
7586
+ if (animatorConfig.mode === PxAnimatorMode.frames) {
7587
+ return createFrameLoopAnimator(doc, adapter, cb, rootElement);
7588
+ }
7589
+ return createWebApiAnimator(
7590
+ doc,
7591
+ cb,
7592
+ rootElement,
7593
+ animatorConfig.mode === PxAnimatorMode.waapi
7594
+ // forcing waapi
7595
+ ) || createFrameLoopAnimator(doc, adapter, cb, rootElement);
7596
+ });
7597
+ }
7598
+ var SVG_NS = "http://www.w3.org/2000/svg";
7599
+ function createElement(tagName, normalisedProps, style, children, textContent) {
7600
+ if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
7601
+ console.warn("SVG tag blocked (dangerous): ", tagName);
7602
+ return null;
7603
+ }
7604
+ const element = document.createElementNS(SVG_NS, tagName);
7605
+ for (const propName in normalisedProps) {
7606
+ const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
7607
+ if (sanitised === void 0) continue;
7608
+ if (CSS_ONLY_STYLE_PROPS.has(propName)) {
7609
+ element.style[propName] = String(sanitised);
7610
+ continue;
7611
+ }
7612
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
7613
+ }
7614
+ if (style) {
7615
+ for (const styleProp in style) {
7616
+ element.style[styleProp] = String(style[styleProp]);
7617
+ }
7618
+ }
7619
+ if (children) {
7620
+ for (const child of children) {
7621
+ element.appendChild(child);
7622
+ }
7623
+ }
7624
+ if (textContent) element.textContent = textContent;
7625
+ return element;
7626
+ }
7627
+ function renderNode(node, defs) {
7628
+ if (!node) return null;
7629
+ const _a = node, { type, children, style } = _a, props = __objRest(_a, ["type", "children", "style"]);
7630
+ const domType = props.domType;
7631
+ if (domType !== void 0) delete props.domType;
7632
+ const nodeDefs = getDefs(node) || defs;
7633
+ const resolvedStyle = resolveStyle(style, nodeDefs);
7634
+ let childElements;
7635
+ if (children) {
7636
+ for (const ch of children) {
7637
+ const child = renderNode(ch, nodeDefs);
7638
+ if (child) {
7639
+ if (!childElements) childElements = [];
7640
+ childElements.push(child);
7641
+ }
7642
+ }
7643
+ }
7644
+ const element = createElement(
7645
+ type || "g",
7646
+ getNormalizedProps(props),
7647
+ resolvedStyle,
7648
+ childElements,
7649
+ props[TEXT_CONTENT_ATTR] || props[TEXT_ATTR]
7650
+ );
7651
+ if (element && domType !== void 0) element.setAttribute("type", domType);
7652
+ return element;
7653
+ }
7654
+ function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
7655
+ return bindWithEngineChoice(doc, adapter, callbacks, rootElement);
7656
+ }
7452
7657
  function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
7453
7658
  const effectsWarnings = validateNodeEffects(doc);
7454
7659
  for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
7455
7660
  const animatorConfig = getAnimatorConfig(doc) || {};
7456
- const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.webapi;
7661
+ const engine = animatorConfig.mode === PxAnimatorMode.frames ? PxAnimatorEngine.frames : PxAnimatorEngine.waapi;
7457
7662
  doc = materialiseAllInTree(doc, engine);
7458
7663
  let rootElement = null;
7459
7664
  if (containerElement) {