@pixodesk/svg-animator-core 1.0.44 → 1.0.46

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
@@ -110,6 +110,7 @@ __export(index_exports, {
110
110
  PxTextPathEffectSchema: () => PxTextPathEffectSchema,
111
111
  PxTextPathMethod: () => PxTextPathMethod,
112
112
  PxTextPathSpacing: () => PxTextPathSpacing,
113
+ PxTimeTimelineSchema: () => PxTimeTimelineSchema,
113
114
  PxTimelineEngine: () => PxTimelineEngine,
114
115
  PxTimelineEngineSetting: () => PxTimelineEngineSetting,
115
116
  PxTimelineSchema: () => PxTimelineSchema,
@@ -181,19 +182,31 @@ function pathStr(path) {
181
182
  return result;
182
183
  }
183
184
  var Base = class {
185
+ /** Structural schemas (objects, arrays, unions of objects…) pass `false`: they state no scalar default. */
186
+ constructor(_statesDefault) {
187
+ this._statesDefault = _statesDefault;
188
+ }
184
189
  _canSanitize(raw) {
185
190
  return this.isValid(raw);
186
191
  }
192
+ /** A REQUIRED field is never absent; its default is the repair value. */
193
+ absentDefault() {
194
+ return this._default;
195
+ }
187
196
  optional() {
188
197
  return new Optional(this);
189
198
  }
190
199
  };
191
200
  var Optional = class extends Base {
192
201
  constructor(inner) {
193
- super();
202
+ super(inner._statesDefault);
194
203
  this.inner = inner;
195
204
  this._default = void 0;
196
205
  }
206
+ /** Absent means the inner schema's STATED default — or nothing at all when it states none. */
207
+ absentDefault() {
208
+ return this.inner._statesDefault ? this.inner._default : void 0;
209
+ }
197
210
  sanitize(raw) {
198
211
  if (raw === void 0 || raw === null) return void 0;
199
212
  return this.inner._canSanitize(raw) ? this.inner.sanitize(raw) : void 0;
@@ -207,8 +220,8 @@ var Optional = class extends Base {
207
220
  }
208
221
  };
209
222
  var Str = class extends Base {
210
- constructor(_default = "") {
211
- super();
223
+ constructor(_default, statesDefault) {
224
+ super(statesDefault);
212
225
  this._default = _default;
213
226
  }
214
227
  sanitize(raw) {
@@ -221,8 +234,8 @@ var Str = class extends Base {
221
234
  }
222
235
  };
223
236
  var Num = class extends Base {
224
- constructor(_default = 0) {
225
- super();
237
+ constructor(_default, statesDefault) {
238
+ super(statesDefault);
226
239
  this._default = _default;
227
240
  }
228
241
  sanitize(raw) {
@@ -235,8 +248,8 @@ var Num = class extends Base {
235
248
  }
236
249
  };
237
250
  var Bool = class extends Base {
238
- constructor(_default = false) {
239
- super();
251
+ constructor(_default, statesDefault) {
252
+ super(statesDefault);
240
253
  this._default = _default;
241
254
  }
242
255
  sanitize(raw) {
@@ -249,8 +262,9 @@ var Bool = class extends Base {
249
262
  }
250
263
  };
251
264
  var Literal = class extends Base {
265
+ /** A literal IS its own value: absent means it. */
252
266
  constructor(value) {
253
- super();
267
+ super(true);
254
268
  this.value = value;
255
269
  this._default = value;
256
270
  }
@@ -264,8 +278,8 @@ var Literal = class extends Base {
264
278
  }
265
279
  };
266
280
  var Enum = class extends Base {
267
- constructor(values, defaultVal) {
268
- super();
281
+ constructor(values, defaultVal, statesDefault) {
282
+ super(statesDefault);
269
283
  this.values = values;
270
284
  this._default = defaultVal != null ? defaultVal : values[0];
271
285
  }
@@ -280,8 +294,8 @@ var Enum = class extends Base {
280
294
  };
281
295
  var UNION_MEMBER_ERROR_LIMIT = 4;
282
296
  var Union = class extends Base {
283
- constructor(schemas, defaultVal) {
284
- super();
297
+ constructor(schemas, defaultVal, statesDefault) {
298
+ super(statesDefault);
285
299
  this.schemas = schemas;
286
300
  /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Union from Tuple. */
287
301
  this._kind = "union";
@@ -335,7 +349,7 @@ var Union = class extends Base {
335
349
  var DiscriminatedUnion = class extends Base {
336
350
  constructor(_key, _schemas, defaultVal) {
337
351
  var _a2;
338
- super();
352
+ super(false);
339
353
  this._key = _key;
340
354
  this._schemas = _schemas;
341
355
  /** Structural tag read by {@link describeSchema}. */
@@ -375,13 +389,19 @@ var DiscriminatedUnion = class extends Base {
375
389
  return schema ? schema._canSanitize(raw) : this._schemas[0]._canSanitize(raw);
376
390
  }
377
391
  };
392
+ function statedDefaults(shape) {
393
+ const out = {};
394
+ for (const key of Object.keys(shape)) if (shape[key]._statesDefault) out[key] = shape[key].absentDefault();
395
+ return Object.freeze(out);
396
+ }
378
397
  var Obj = class extends Base {
379
398
  constructor(_shape) {
380
- super();
399
+ super(false);
381
400
  this._shape = _shape;
382
401
  const d = {};
383
402
  for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
384
403
  this._default = d;
404
+ this.defaults = statedDefaults(_shape);
385
405
  }
386
406
  sanitize(raw) {
387
407
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
@@ -423,12 +443,13 @@ var Obj = class extends Base {
423
443
  };
424
444
  var OpenObj = class extends Base {
425
445
  constructor(_shape, _openSchema) {
426
- super();
446
+ super(false);
427
447
  this._shape = _shape;
428
448
  this._openSchema = _openSchema;
429
449
  const d = {};
430
450
  for (const key of Object.keys(_shape)) d[key] = _shape[key]._default;
431
451
  this._default = d;
452
+ this.defaults = statedDefaults(_shape);
432
453
  }
433
454
  sanitize(raw) {
434
455
  const src = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
@@ -473,7 +494,7 @@ var OpenObj = class extends Base {
473
494
  };
474
495
  var Arr = class extends Base {
475
496
  constructor(item) {
476
- super();
497
+ super(false);
477
498
  this.item = item;
478
499
  this._default = [];
479
500
  }
@@ -505,7 +526,7 @@ var Arr = class extends Base {
505
526
  };
506
527
  var Rec = class extends Base {
507
528
  constructor(value) {
508
- super();
529
+ super(false);
509
530
  this.value = value;
510
531
  /** Structural tag read by {@link describeSchema}. */
511
532
  this._kind = "record";
@@ -539,7 +560,7 @@ var Rec = class extends Base {
539
560
  };
540
561
  var Any = class extends Base {
541
562
  constructor() {
542
- super(...arguments);
563
+ super(false);
543
564
  this._default = void 0;
544
565
  }
545
566
  sanitize(raw) {
@@ -554,7 +575,7 @@ var Any = class extends Base {
554
575
  };
555
576
  var Defined = class extends Base {
556
577
  constructor() {
557
- super(...arguments);
578
+ super(false);
558
579
  this._default = void 0;
559
580
  }
560
581
  sanitize(raw) {
@@ -571,7 +592,7 @@ var Defined = class extends Base {
571
592
  };
572
593
  var Lazy = class extends Base {
573
594
  constructor(fn, _default) {
574
- super();
595
+ super(false);
575
596
  this.fn = fn;
576
597
  this._default = _default;
577
598
  this.resolved = null;
@@ -592,7 +613,7 @@ var Lazy = class extends Base {
592
613
  };
593
614
  var Tuple = class extends Base {
594
615
  constructor(schemas) {
595
- super();
616
+ super(false);
596
617
  this.schemas = schemas;
597
618
  /** Structural tag read by {@link describeSchema} — `schemas` alone cannot tell Tuple from Union. */
598
619
  this._kind = "tuple";
@@ -648,22 +669,29 @@ function describeSchema(schema) {
648
669
  if ("fn" in s) return { kind: "lazy", resolved: (_a2 = s.resolved) != null ? _a2 : s.resolved = s.fn() };
649
670
  return { kind: "leaf" };
650
671
  }
672
+ function string(defaultVal) {
673
+ return defaultVal === void 0 ? new Str("", false) : new Str(defaultVal, true);
674
+ }
675
+ function number(defaultVal) {
676
+ return defaultVal === void 0 ? new Num(0, false) : new Num(defaultVal, true);
677
+ }
678
+ function boolean(defaultVal) {
679
+ return defaultVal === void 0 ? new Bool(false, false) : new Bool(defaultVal, true);
680
+ }
681
+ function oneOf(values, defaultVal) {
682
+ return defaultVal === void 0 ? new Enum(values, void 0, false) : new Enum(values, defaultVal, true);
683
+ }
684
+ function unionOf(schemas, defaultVal) {
685
+ return defaultVal === void 0 ? new Union(schemas, void 0, false) : new Union(schemas, defaultVal, true);
686
+ }
651
687
  var px = {
652
- /** Matches a string. Default: '' or provided value. */
653
- string: (defaultVal = "") => new Str(defaultVal),
654
- /** Matches a finite number. Default: 0 or provided value. */
655
- number: (defaultVal = 0) => new Num(defaultVal),
656
- /** Matches a boolean. Default: false or provided value. */
657
- boolean: (defaultVal = false) => new Bool(defaultVal),
658
- /** Matches one exact primitive value; its default is the value itself. */
688
+ string,
689
+ number,
690
+ boolean,
691
+ /** Matches one exact primitive value; absent means the value itself. */
659
692
  literal: (value) => new Literal(value),
660
- /** Matches one of a fixed set of string/number values. Default: first value. */
661
- enum: (values, defaultVal) => new Enum(values, defaultVal),
662
- /**
663
- * Returns the first schema whose isValid passes.
664
- * TypeScript infers the union of all member types automatically.
665
- */
666
- union: (schemas, defaultVal) => new Union(schemas, defaultVal),
693
+ enum: oneOf,
694
+ union: unionOf,
667
695
  /**
668
696
  * Discriminated union — reads `raw[key]`, finds the member schema whose
669
697
  * literal at `key` matches, then delegates sanitize/isValid to that member.
@@ -671,7 +699,8 @@ var px = {
671
699
  * TypeScript infers the union of all member types automatically.
672
700
  */
673
701
  discriminatedUnion: (key, schemas) => new DiscriminatedUnion(key, schemas),
674
- /** Typed object — unknown keys are stripped. Required fields fall back to their default. */
702
+ /** Typed object — unknown keys are stripped. Required fields fall back to their default.
703
+ * Its `defaults` say what each stated field means when a document leaves it out. */
675
704
  object: (shape) => new Obj(shape),
676
705
  /**
677
706
  * Open object — validates known keys; passes unknown keys through as-is,
@@ -1015,8 +1044,11 @@ var PX_TRIGGER_DEFAULTS = {
1015
1044
  offScreen: "pause",
1016
1045
  mouseOut: "continue",
1017
1046
  visibilityThreshold: 0.5,
1018
- visibilityDebounce: 150
1047
+ visibilityDebounce: 150,
1048
+ finish: "hold"
1019
1049
  };
1050
+ var PX_DEFAULT_DURATION_MS = 1e3;
1051
+ var PX_DEFAULT_ITERATIONS = 1;
1020
1052
  var PxControlMode = {
1021
1053
  /** No control props — the document's trigger decides, and nothing is taken over. */
1022
1054
  static: "static",
@@ -1331,15 +1363,15 @@ var keyframeTangentIn = (kf) => anyKf(kf).tangentIn;
1331
1363
  var keyframeTangentOut = (kf) => anyKf(kf).tangentOut;
1332
1364
  var PxLoopSchema = implementsInterface()(px.object({
1333
1365
  segmentCount: px.number().optional(),
1334
- repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end]).optional(),
1335
- direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate]).optional()
1366
+ repeatAt: px.enum([PxLoopRepeatAt.start, PxLoopRepeatAt.end], PxLoopRepeatAt.end).optional(),
1367
+ direction: px.enum([PxLoopDirection.normal, PxLoopDirection.alternate], PxLoopDirection.normal).optional()
1336
1368
  }));
1337
1369
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1338
1370
  value: PxKeyframeValueSchema.optional(),
1339
1371
  keyframes: px.array(PxKeyframeSchema).optional(),
1340
1372
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1341
1373
  autoOrient: px.boolean().optional(),
1342
- alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
1374
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath], PxAlongPathMode.sampled).optional()
1343
1375
  }));
1344
1376
  var PxTransformPartsSchema = implementsInterface()(px.object({
1345
1377
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -1369,9 +1401,9 @@ var PxTriggerSchema = implementsInterface()(px.object({
1369
1401
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1370
1402
  // `fill`) or `'reset'` (snap back to the start state). One of four occasion keys
1371
1403
  // (`start`, `offScreen`, `mouseOut`, `finish`), all named the same way.
1372
- finish: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
1373
- visibilityThreshold: px.number().optional(),
1374
- visibilityDebounce: px.number().optional()
1404
+ finish: px.enum([PxFinishAction.hold, PxFinishAction.reset], PX_TRIGGER_DEFAULTS.finish).optional(),
1405
+ visibilityThreshold: px.number(PX_TRIGGER_DEFAULTS.visibilityThreshold).optional(),
1406
+ visibilityDebounce: px.number(PX_TRIGGER_DEFAULTS.visibilityDebounce).optional()
1375
1407
  }));
1376
1408
  var PxGlyphSchema = implementsInterface()(px.object({
1377
1409
  width: px.number(),
@@ -1397,7 +1429,7 @@ var PxScrollRangePointSchema = implementsInterface()(px.object({
1397
1429
  PxScrollPhase.exit,
1398
1430
  PxScrollPhase.entryCrossing,
1399
1431
  PxScrollPhase.exitCrossing
1400
- ]).optional(),
1432
+ ], PxScrollPhase.cover).optional(),
1401
1433
  fraction: px.number().optional()
1402
1434
  }));
1403
1435
  var PxScrollRangeSchema = px.object({
@@ -1405,37 +1437,37 @@ var PxScrollRangeSchema = px.object({
1405
1437
  end: PxScrollRangePointSchema.optional()
1406
1438
  });
1407
1439
  var PxScrollSchema = implementsInterface()(px.object({
1408
- kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
1409
- axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1410
- source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1440
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll], PxScrollKind.view).optional(),
1441
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y], PxScrollAxis.block).optional(),
1442
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root], PxScrollSource.nearest).optional(),
1411
1443
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
1412
1444
  subject: px.string().optional(),
1413
1445
  smoothing: px.number().optional(),
1414
- pin: px.boolean().optional(),
1415
- pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1446
+ pin: px.boolean(false).optional(),
1447
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom], PxPinAlign.top).optional(),
1416
1448
  pinOffset: px.number().optional(),
1417
1449
  pinDistance: px.number().optional(),
1418
1450
  range: PxScrollRangeSchema.optional()
1419
1451
  }));
1420
1452
  var PxTimelinePinSchema = implementsInterface()(px.object({
1421
- align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
1453
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom], PxPinAlign.top).optional(),
1422
1454
  offset: px.number().optional(),
1423
1455
  distance: px.number().optional()
1424
1456
  }));
1425
- var PxTimelineEngineSchema = px.enum([PxTimelineEngineSetting.auto, PxTimelineEngineSetting.native, PxTimelineEngineSetting.js]).optional();
1457
+ var PxTimelineEngineSchema = px.enum([PxTimelineEngineSetting.auto, PxTimelineEngineSetting.native, PxTimelineEngineSetting.js], PxTimelineEngineSetting.auto).optional();
1426
1458
  var PxTimeTimelineSchema = implementsInterface()(px.object({
1427
1459
  type: px.literal("time").optional(),
1428
1460
  engine: PxTimelineEngineSchema,
1429
1461
  frameRate: px.number().optional(),
1430
1462
  // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1431
- duration: px.number().optional(),
1463
+ duration: px.number(PX_DEFAULT_DURATION_MS).optional(),
1432
1464
  trigger: PxTriggerSchema.optional(),
1433
- delay: px.number().optional(),
1434
- iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1465
+ delay: px.number(0).optional(),
1466
+ iterations: px.union([px.number(PX_DEFAULT_ITERATIONS), px.literal("infinite")], PX_DEFAULT_ITERATIONS).optional(),
1435
1467
  // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
1436
1468
  // — never `fill`, which is paint everywhere else in the format.
1437
- fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
1438
- direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
1469
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none], PxFillMode.forwards).optional(),
1470
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse], PxPlaybackDirection.normal).optional()
1439
1471
  }));
1440
1472
  var scrollishTimelineShape = {
1441
1473
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
@@ -1446,8 +1478,8 @@ var scrollishTimelineShape = {
1446
1478
  iterations: px.number().optional(),
1447
1479
  engine: PxTimelineEngineSchema,
1448
1480
  frameRate: px.number().optional(),
1449
- axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
1450
- source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
1481
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y], PxScrollAxis.block).optional(),
1482
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root], PxScrollSource.nearest).optional(),
1451
1483
  subject: px.string().optional(),
1452
1484
  // 'parent' | 'scroller' | any CSS selector
1453
1485
  smoothing: px.number().optional(),
@@ -1527,9 +1559,10 @@ var PxRepeaterEffectSchema = implementsInterface()(px.object({
1527
1559
  }));
1528
1560
  var PxMaskedByEffectSchema = implementsInterface()(px.object({
1529
1561
  source: px.string().optional(),
1530
- maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha]).optional(),
1531
- maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1532
- maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1562
+ // SVG's own initial values — what a <mask> does when the attribute is not there.
1563
+ maskType: px.enum([PxMaskType.luminance, PxMaskType.alpha], PxMaskType.luminance).optional(),
1564
+ maskUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox], PxUnits.objectBoundingBox).optional(),
1565
+ maskContentUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox], PxUnits.userSpaceOnUse).optional(),
1533
1566
  x: px.number().optional(),
1534
1567
  y: px.number().optional(),
1535
1568
  width: px.number().optional(),
@@ -1541,7 +1574,7 @@ var PxClipPathEffectSchema = implementsInterface()(px.object({
1541
1574
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1542
1575
  offset: PxAnimatableNumberSchema.optional(),
1543
1576
  range: PxAnimatableVec2Schema.optional(),
1544
- subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1577
+ subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined], PxStrokeTrimSubPaths.separate).optional()
1545
1578
  }));
1546
1579
  var PxRetimeEffectSchema = implementsInterface()(px.object({
1547
1580
  start: px.number().optional(),
@@ -1573,17 +1606,20 @@ var PxFillGradientEffectSchema = implementsInterface()(px.object({
1573
1606
  radius: PxAnimatableNumberSchema.optional(),
1574
1607
  focal: PxAnimatableVec2Schema.optional(),
1575
1608
  stops: PxAnimatableGradientStopsSchema.optional(),
1576
- gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
1577
- spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
1609
+ // SVG's own initial values — what a gradient does when the attribute is not there.
1610
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox], PxUnits.objectBoundingBox).optional(),
1611
+ spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat], PxGradientSpreadMethod.pad).optional(),
1578
1612
  gradientTransform: px.string().optional()
1579
1613
  }));
1580
1614
  var PxStrokeGradientEffectSchema = PxFillGradientEffectSchema;
1581
1615
  var PxTextPathEffectSchema = implementsInterface()(px.object({
1582
1616
  pathData: px.string(),
1583
- pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend]).optional(),
1584
- lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs]).optional(),
1585
- method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch]).optional(),
1586
- spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact]).optional(),
1617
+ // `extend` is what an omitted pathOverflow means (glyphs continue along the tangent); the
1618
+ // other three are SVG's own initial values for the native <textPath> attributes.
1619
+ pathOverflow: px.enum([PxPathOverflow.clip, PxPathOverflow.extend], PxPathOverflow.extend).optional(),
1620
+ lengthAdjust: px.enum([PxLengthAdjust.spacing, PxLengthAdjust.spacingAndGlyphs], PxLengthAdjust.spacing).optional(),
1621
+ method: px.enum([PxTextPathMethod.align, PxTextPathMethod.stretch], PxTextPathMethod.align).optional(),
1622
+ spacing: px.enum([PxTextPathSpacing.auto, PxTextPathSpacing.exact], PxTextPathSpacing.exact).optional(),
1587
1623
  startOffset: PxAnimatableNumberSchema.optional(),
1588
1624
  textLength: PxAnimatableNumberSchema.optional()
1589
1625
  }));
@@ -2150,7 +2186,6 @@ function parseTransformParts(str2) {
2150
2186
  if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
2151
2187
  return Object.keys(out).length ? out : void 0;
2152
2188
  }
2153
- var PX_DEFAULT_DURATION_MS = 1e3;
2154
2189
  function kebabToCamelCaseWord(kebab) {
2155
2190
  return kebab.includes("-") ? kebab.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()) : kebab;
2156
2191
  }
@@ -2341,6 +2376,38 @@ function toDomProps(props) {
2341
2376
  return propsCopy;
2342
2377
  }
2343
2378
 
2379
+ // src/animation/PxStaticTransformMerge.ts
2380
+ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2381
+ if (!animDef) return animDef;
2382
+ const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
2383
+ if (!staticParts || !Object.keys(staticParts).length) return animDef;
2384
+ const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
2385
+ const transformAnim = animDef[TRANSFORM_ATTR];
2386
+ if (transformAnim && typeof transformAnim === "object") {
2387
+ const anim = transformAnim;
2388
+ if (Array.isArray(anim.keyframes)) {
2389
+ const out = __spreadProps(__spreadValues({}, anim), {
2390
+ keyframes: anim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: mergeKfValue(kf.value) }))
2391
+ });
2392
+ if (out.value !== void 0) out.value = mergeKfValue(out.value);
2393
+ return __spreadProps(__spreadValues({}, animDef), { transform: out });
2394
+ }
2395
+ return animDef;
2396
+ }
2397
+ const channels = Object.keys(animDef).filter((k) => PX_TRANSFORM_FN_NAMES.has(k));
2398
+ if (channels.length !== 1) return animDef;
2399
+ const ch = channels[0];
2400
+ const chAnim = animDef[ch];
2401
+ if (!chAnim || typeof chAnim !== "object" || !Array.isArray(chAnim.keyframes)) return animDef;
2402
+ const lifted = __spreadProps(__spreadValues({}, chAnim), {
2403
+ keyframes: chAnim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: __spreadProps(__spreadValues({}, staticParts), { [ch]: kf.value }) }))
2404
+ });
2405
+ if (lifted.value !== void 0) lifted.value = __spreadProps(__spreadValues({}, staticParts), { [ch]: lifted.value });
2406
+ const rest = __spreadValues({}, animDef);
2407
+ delete rest[ch];
2408
+ return __spreadProps(__spreadValues({}, rest), { transform: lifted });
2409
+ }
2410
+
2344
2411
  // src/materialize/PxMotionPath.ts
2345
2412
  function getKfTranslate(kf) {
2346
2413
  const v = keyframeValue(kf);
@@ -2710,7 +2777,7 @@ function walkAndMaterialize(node, opts) {
2710
2777
  let newAnimate;
2711
2778
  const animBucket = node.animate;
2712
2779
  if (animBucket && typeof animBucket === "object" && !Array.isArray(animBucket)) {
2713
- const animDef = animBucket;
2780
+ const animDef = mergeStaticTransformIntoAnimDef(animBucket, node.transform);
2714
2781
  const transformAnim = animDef.transform;
2715
2782
  if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
2716
2783
  const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
@@ -3224,36 +3291,6 @@ var _elementIdCounter = 0;
3224
3291
  function generateElementId() {
3225
3292
  return "_px_el_" + ++_elementIdCounter;
3226
3293
  }
3227
- function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
3228
- if (!animDef) return animDef;
3229
- const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
3230
- if (!staticParts || !Object.keys(staticParts).length) return animDef;
3231
- const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues(__spreadValues({}, staticParts), v) : v;
3232
- const transformAnim = animDef[TRANSFORM_ATTR];
3233
- if (transformAnim && typeof transformAnim === "object") {
3234
- const anim = transformAnim;
3235
- if (Array.isArray(anim.keyframes)) {
3236
- const out = __spreadProps(__spreadValues({}, anim), {
3237
- keyframes: anim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: mergeKfValue(kf.value) }))
3238
- });
3239
- if (out.value !== void 0) out.value = mergeKfValue(out.value);
3240
- return __spreadProps(__spreadValues({}, animDef), { transform: out });
3241
- }
3242
- return animDef;
3243
- }
3244
- const channels = Object.keys(animDef).filter((k) => PX_TRANSFORM_FN_NAMES.has(k));
3245
- if (channels.length !== 1) return animDef;
3246
- const ch = channels[0];
3247
- const chAnim = animDef[ch];
3248
- if (!chAnim || typeof chAnim !== "object" || !Array.isArray(chAnim.keyframes)) return animDef;
3249
- const lifted = __spreadProps(__spreadValues({}, chAnim), {
3250
- keyframes: chAnim.keyframes.map((kf) => __spreadProps(__spreadValues({}, kf), { value: __spreadProps(__spreadValues({}, staticParts), { [ch]: kf.value }) }))
3251
- });
3252
- if (lifted.value !== void 0) lifted.value = __spreadProps(__spreadValues({}, staticParts), { [ch]: lifted.value });
3253
- const rest = __spreadValues({}, animDef);
3254
- delete rest[ch];
3255
- return __spreadProps(__spreadValues({}, rest), { transform: lifted });
3256
- }
3257
3294
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxTimelineEngine.native) {
3258
3295
  const normalized = {};
3259
3296
  for (const [propName, propAnim] of Object.entries(animDef)) {
@@ -3336,7 +3373,7 @@ function getKeyframesPair(keyframes, progress) {
3336
3373
  return { prevKf, nextKf };
3337
3374
  }
3338
3375
  function calcPropertyValue(propName, propAnim, progress) {
3339
- var _a2, _b, _c, _d;
3376
+ var _a2, _b, _c, _d, _e;
3340
3377
  const keyframes = propAnim.keyframes || [];
3341
3378
  if (keyframes.length === 0) return null;
3342
3379
  const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
@@ -3405,7 +3442,7 @@ function calcPropertyValue(propName, propAnim, progress) {
3405
3442
  !!propAnim.autoOrient
3406
3443
  );
3407
3444
  partsResult.translate = [sample.translate[0], sample.translate[1]];
3408
- if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg;
3445
+ if (sample.rotateDeg !== void 0) partsResult.rotate = sample.rotateDeg + ((_e = partsResult.rotate) != null ? _e : 0);
3409
3446
  }
3410
3447
  }
3411
3448
  cssValue = composeTransformParts(partsResult, { withUnits: false });
@@ -5888,12 +5925,17 @@ function buildOffsetPath(propAnim) {
5888
5925
  const first = keyframeValue(kfs[0]);
5889
5926
  const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
5890
5927
  const points = [];
5928
+ let keyframesCarryRotate = false;
5891
5929
  for (const kf of kfs) {
5892
5930
  const v = keyframeValue(kf);
5893
5931
  const tr = v == null ? void 0 : v.translate;
5894
5932
  if (!tr || tr.length < 2) return void 0;
5895
5933
  const parts = Object.keys(v);
5896
- if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5934
+ if (parts.some((p) => p !== TRANSFORM_PART.translate && p !== TRANSFORM_PART.origin && p !== TRANSFORM_PART.rotate)) return void 0;
5935
+ if ((v == null ? void 0 : v.rotate) !== void 0) {
5936
+ if (v.rotate !== 0) return void 0;
5937
+ keyframesCarryRotate = true;
5938
+ }
5897
5939
  const o = (_a2 = v == null ? void 0 : v.origin) != null ? _a2 : [0, 0];
5898
5940
  if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5899
5941
  points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
@@ -5921,7 +5963,7 @@ function buildOffsetPath(propAnim) {
5921
5963
  if (e !== void 0) out.e = e;
5922
5964
  distanceKfs.push(out);
5923
5965
  }
5924
- return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
5966
+ return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor, keyframesCarryRotate };
5925
5967
  }
5926
5968
  function materializeOffsetPathsInTree(root) {
5927
5969
  const walk = (node) => {
@@ -5943,6 +5985,7 @@ function materializeOffsetPathsInTree(root) {
5943
5985
  const t = __spreadValues({}, staticTr);
5944
5986
  delete t[TRANSFORM_PART.translate];
5945
5987
  delete t[TRANSFORM_PART.origin];
5988
+ if (built.keyframesCarryRotate) delete t[TRANSFORM_PART.rotate];
5946
5989
  newTransform = Object.keys(t).length ? t : void 0;
5947
5990
  }
5948
5991
  out = __spreadProps(__spreadValues({}, node), {
@@ -6115,6 +6158,103 @@ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, ro
6115
6158
  return changed ? __spreadProps(__spreadValues({}, node), { children: newChildren }) : node;
6116
6159
  }
6117
6160
 
6161
+ // src/materialize/PxRestPose.ts
6162
+ var TRANSFORM_CHANNEL = "transform";
6163
+ var REVERSED_DIRECTIONS = /* @__PURE__ */ new Set(["reverse", "alternate-reverse"]);
6164
+ var VERIFY_SAMPLE_FRACTIONS = [0, 0.25, 0.5, 0.75, 1];
6165
+ var SCRATCH_ID_PREFIX = "__px_rest_";
6166
+ function materializeRestPosesInTree(root, engine) {
6167
+ var _a2, _b;
6168
+ const out = deepClone(root);
6169
+ const config = getAnimatorConfig(out) || {};
6170
+ const duration = +(config.duration || PX_DEFAULT_DURATION_MS);
6171
+ const firstFrameTime = REVERSED_DIRECTIONS.has(String(config.direction)) ? duration : 0;
6172
+ const nodes = animatedNodes(out);
6173
+ if (!nodes.size) return out;
6174
+ const before = bindingsOf(out, engine);
6175
+ const added = /* @__PURE__ */ new Map();
6176
+ for (const [key, animate] of before) {
6177
+ const node = nodes.get(key);
6178
+ if (!node) continue;
6179
+ const channels = Object.keys(animate);
6180
+ for (const channel of channels) {
6181
+ if (PX_TRANSFORM_FN_NAMES.has(channel)) continue;
6182
+ if (!mayCarryRestPose(node, channel)) continue;
6183
+ const value = firstFrameValue(animate, channel, firstFrameTime);
6184
+ if (value === void 0) continue;
6185
+ node[channel] = value;
6186
+ added.set(key, [...(_a2 = added.get(key)) != null ? _a2 : [], channel]);
6187
+ }
6188
+ if (channels.some((channel) => PX_TRANSFORM_FN_NAMES.has(channel)) && mayCarryTransformRestPose(node)) {
6189
+ const parts = firstFrameTransformParts(animate, firstFrameTime);
6190
+ if (parts) {
6191
+ node[TRANSFORM_CHANNEL] = parts;
6192
+ added.set(key, [...(_b = added.get(key)) != null ? _b : [], TRANSFORM_CHANNEL]);
6193
+ }
6194
+ }
6195
+ }
6196
+ if (added.size) {
6197
+ const after = bindingsOf(out, engine);
6198
+ for (const [key, channels] of added) {
6199
+ if (writesTheSameFrames(before.get(key), after.get(key), duration)) continue;
6200
+ const node = nodes.get(key);
6201
+ if (node) for (const channel of channels) delete node[channel];
6202
+ }
6203
+ }
6204
+ return out;
6205
+ }
6206
+ function mayCarryRestPose(node, channel) {
6207
+ if (node[channel] !== void 0) return false;
6208
+ if (channel === TRANSFORM_CHANNEL) return mayCarryTransformRestPose(node);
6209
+ return true;
6210
+ }
6211
+ function mayCarryTransformRestPose(node) {
6212
+ if (node[TRANSFORM_CHANNEL] !== void 0) return false;
6213
+ for (const part of PX_TRANSFORM_FN_NAMES) if (node[part] !== void 0) return false;
6214
+ return true;
6215
+ }
6216
+ function firstFrameValue(animate, channel, timeMs) {
6217
+ const values = Object.values(calcAnimationValues({ [channel]: animate[channel] }, timeMs));
6218
+ return values.length === 1 && values[0] !== "" ? values[0] : void 0;
6219
+ }
6220
+ function firstFrameTransformParts(animate, timeMs) {
6221
+ const family = {};
6222
+ for (const channel of Object.keys(animate)) if (PX_TRANSFORM_FN_NAMES.has(channel)) family[channel] = animate[channel];
6223
+ const written = calcAnimationValues(family, timeMs)[TRANSFORM_CHANNEL];
6224
+ if (!written) return void 0;
6225
+ const parts = parseTransformParts(written.replace(/(px|deg)\b/g, ""));
6226
+ return parts && Object.keys(parts).length ? parts : void 0;
6227
+ }
6228
+ function writesTheSameFrames(a, b, durationMs) {
6229
+ if (!a || !b) return a === b;
6230
+ const frame = (animate, t) => JSON.stringify(calcAnimationValues(animate, t)).replace(/\s+/g, "");
6231
+ return VERIFY_SAMPLE_FRACTIONS.every((fraction) => frame(a, fraction * durationMs) === frame(b, fraction * durationMs));
6232
+ }
6233
+ function bindingsOf(tree, engine) {
6234
+ const scratch = deepClone(tree);
6235
+ const keyById = /* @__PURE__ */ new Map();
6236
+ for (const [key, node] of animatedNodes(scratch)) {
6237
+ if (node.id === void 0) node.id = SCRATCH_ID_PREFIX + key;
6238
+ keyById.set(String(node.id), key);
6239
+ }
6240
+ const out = /* @__PURE__ */ new Map();
6241
+ for (const binding of normalizeBindings(scratch, engine)) {
6242
+ const key = keyById.get(binding.id);
6243
+ if (key !== void 0) out.set(key, binding.animate);
6244
+ }
6245
+ return out;
6246
+ }
6247
+ function animatedNodes(tree) {
6248
+ const out = /* @__PURE__ */ new Map();
6249
+ let counter = 0;
6250
+ const visit = (node) => {
6251
+ if (node.animate) out.set(String(counter++), node);
6252
+ if (node.children) for (const child of node.children) visit(child);
6253
+ };
6254
+ if (tree.children) for (const child of tree.children) visit(child);
6255
+ return out;
6256
+ }
6257
+
6118
6258
  // src/materialize/PxAnimatorMaterializeAll.ts
6119
6259
  function materializeAllInTree(doc, engine, options) {
6120
6260
  var _a2, _b;
@@ -6127,6 +6267,7 @@ function materializeAllInTree(doc, engine, options) {
6127
6267
  root = materializeAnimatedUseInstances(root);
6128
6268
  root = pruneUnreferencedDefs(root);
6129
6269
  }
6270
+ root = materializeRestPosesInTree(root, engine);
6130
6271
  return root;
6131
6272
  }
6132
6273
  function pruneUnreferencedDefs(root) {
@@ -6239,13 +6380,13 @@ function createAdapterAnimator(doc, adapter, callbacks) {
6239
6380
  const bindings = normalizeBindings(doc, PxTimelineEngine.js);
6240
6381
  const _iterations = config.iterations;
6241
6382
  let iterations = 1;
6242
- if (typeof _iterations === "number") iterations = _iterations || 1;
6383
+ if (typeof _iterations === "number") iterations = _iterations || PX_DEFAULT_ITERATIONS;
6243
6384
  if (_iterations === "infinite") iterations = Infinity;
6244
6385
  if (iterations < 1) iterations = 1;
6245
6386
  const duration = +(config.duration || PX_DEFAULT_DURATION_MS);
6246
- const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : 1) * duration : 0;
6247
- const direction = config.direction || "normal";
6248
- const fill = (_a2 = config.fill) != null ? _a2 : "forwards";
6387
+ const totalDuration = duration && iterations ? duration * (iterations === Infinity ? Infinity : iterations) : duration ? (iterations != null ? iterations : PX_DEFAULT_ITERATIONS) * duration : 0;
6388
+ const direction = config.direction || PxTimeTimelineSchema.defaults.direction;
6389
+ const fill = (_a2 = config.fill) != null ? _a2 : PxTimeTimelineSchema.defaults.fillMode;
6249
6390
  const fillsForwards = fill === "forwards" || fill === "both";
6250
6391
  const fillsBackwards = fill === "backwards" || fill === "both";
6251
6392
  let timerId = null;
@@ -6768,6 +6909,7 @@ function diagnoseDocument(doc) {
6768
6909
  PxTextPathEffectSchema,
6769
6910
  PxTextPathMethod,
6770
6911
  PxTextPathSpacing,
6912
+ PxTimeTimelineSchema,
6771
6913
  PxTimelineEngine,
6772
6914
  PxTimelineEngineSetting,
6773
6915
  PxTimelineSchema,