@pixodesk/svg-animator-web 1.0.30 → 1.0.34

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.js CHANGED
@@ -315,6 +315,38 @@ function composeTransformParts(parts, opts) {
315
315
  if (o) segs.push("translate(" + -o[0] + tu + "," + -o[1] + tu + ")");
316
316
  return segs.join("");
317
317
  }
318
+ function parseTransformParts(str2) {
319
+ var _a, _b;
320
+ if (!str2 || typeof str2 !== "string") return void 0;
321
+ const out = {};
322
+ const re = /([a-zA-Z]+)\s*\(([^)]*)\)/g;
323
+ const order = ["translate", "rotate", "skewX", "scale"];
324
+ let lastIdx = -1;
325
+ let m;
326
+ while ((m = re.exec(str2)) !== null) {
327
+ const fn = m[1];
328
+ const idx = order.indexOf(fn);
329
+ if (idx < 0 || idx <= lastIdx) return void 0;
330
+ lastIdx = idx;
331
+ const nums = m[2].split(/[\s,]+/).filter(Boolean).map(Number);
332
+ if (nums.some((n) => Number.isNaN(n))) return void 0;
333
+ if (fn === "translate") {
334
+ if (nums.length < 1 || nums.length > 2) return void 0;
335
+ out.translate = [nums[0], (_a = nums[1]) != null ? _a : 0];
336
+ } else if (fn === "rotate") {
337
+ if (nums.length !== 1) return void 0;
338
+ out.rotate = nums[0];
339
+ } else if (fn === "skewX") {
340
+ if (nums.length !== 1) return void 0;
341
+ out.skew = nums[0];
342
+ } else {
343
+ if (nums.length < 1 || nums.length > 2) return void 0;
344
+ out.scale = [nums[0], (_b = nums[1]) != null ? _b : nums[0]];
345
+ }
346
+ }
347
+ if (str2.replace(/([a-zA-Z]+)\s*\(([^)]*)\)/g, "").replace(/[\s,]/g, "").length) return void 0;
348
+ return Object.keys(out).length ? out : void 0;
349
+ }
318
350
  var STYLE_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
319
351
  var DEFAULT_DURATION_MS = 1e3;
320
352
  function kebabToCamelCaseWord(kebab) {
@@ -642,6 +674,7 @@ var Union = class extends Base {
642
674
  constructor(schemas, defaultVal) {
643
675
  super();
644
676
  this.schemas = schemas;
677
+ this._kind = "union";
645
678
  this._default = defaultVal != null ? defaultVal : schemas[0]._default;
646
679
  }
647
680
  sanitize(raw) {
@@ -666,6 +699,7 @@ var DiscriminatedUnion = class extends Base {
666
699
  super();
667
700
  this._key = _key;
668
701
  this._schemas = _schemas;
702
+ this._kind = "discriminatedUnion";
669
703
  this._default = defaultVal != null ? defaultVal : _schemas[0]._default;
670
704
  this._map = /* @__PURE__ */ new Map();
671
705
  for (const s of _schemas) {
@@ -828,6 +862,7 @@ var Rec = class extends Base {
828
862
  constructor(value) {
829
863
  super();
830
864
  this.value = value;
865
+ this._kind = "record";
831
866
  this._default = {};
832
867
  }
833
868
  sanitize(raw) {
@@ -913,6 +948,7 @@ var Tuple = class extends Base {
913
948
  constructor(schemas) {
914
949
  super();
915
950
  this.schemas = schemas;
951
+ this._kind = "tuple";
916
952
  this._default = schemas.map((s) => s._default);
917
953
  }
918
954
  sanitize(raw) {
@@ -949,10 +985,20 @@ function schemaKeys(schema) {
949
985
  function describeSchema(schema) {
950
986
  var _a;
951
987
  const s = schema;
952
- if ("_shape" in s) return { kind: "shape", shape: s._shape };
988
+ switch (s._kind) {
989
+ case "union":
990
+ return { kind: "union", members: s.schemas };
991
+ case "discriminatedUnion":
992
+ return { kind: "discriminatedUnion", key: s._key, members: s._schemas };
993
+ case "record":
994
+ return { kind: "record", value: s.value };
995
+ case "tuple":
996
+ return { kind: "tuple", items: s.schemas };
997
+ }
998
+ if ("_shape" in s) return { kind: "shape", shape: s._shape, openValue: s._openSchema };
953
999
  if ("item" in s) return { kind: "array", item: s.item };
954
1000
  if ("inner" in s) return { kind: "optional", inner: s.inner };
955
- if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.fn() };
1001
+ if ("fn" in s) return { kind: "lazy", resolved: (_a = s.resolved) != null ? _a : s.resolved = s.fn() };
956
1002
  return { kind: "leaf" };
957
1003
  }
958
1004
  var px = {
@@ -1090,7 +1136,51 @@ function isPxElementFileFormat(fileJson) {
1090
1136
  }
1091
1137
  function getAnimatorConfig(doc) {
1092
1138
  var _a;
1093
- return (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
1139
+ const cfg = (doc == null ? void 0 : doc.animator) || ((_a = doc == null ? void 0 : doc.meta) == null ? void 0 : _a.animator);
1140
+ return cfg ? flattenAnimatorTimeline(cfg) : void 0;
1141
+ }
1142
+ var flattenMemo = /* @__PURE__ */ new WeakMap();
1143
+ function flattenAnimatorTimeline(cfg) {
1144
+ const timeline = cfg.timeline;
1145
+ if (timeline === void 0 || timeline === null || typeof timeline !== "object") return cfg;
1146
+ const memoised = flattenMemo.get(cfg);
1147
+ if (memoised) return memoised;
1148
+ const _a = cfg, { timeline: _dropped } = _a, flat = __objRest2(_a, ["timeline"]);
1149
+ if (timeline.type === "scroll" || timeline.type === "view") {
1150
+ flat.timelineSource = "scroll";
1151
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1152
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1153
+ const scroll = __spreadValues2({}, flat.scroll || {});
1154
+ scroll.kind = timeline.type;
1155
+ if (timeline.engine !== void 0) scroll.driver = timeline.engine;
1156
+ if (timeline.axis !== void 0) scroll.axis = timeline.axis;
1157
+ if (timeline.source !== void 0) scroll.source = timeline.source;
1158
+ if (timeline.subject !== void 0) scroll.subject = timeline.subject;
1159
+ if (timeline.smoothing !== void 0) scroll.smoothing = timeline.smoothing;
1160
+ if (timeline.range !== void 0) scroll.range = timeline.range;
1161
+ const pin = timeline.pin;
1162
+ if (typeof pin === "boolean") scroll.pin = pin;
1163
+ else if (pin && typeof pin === "object") {
1164
+ scroll.pin = true;
1165
+ if (pin.align !== void 0) scroll.pinAlign = pin.align;
1166
+ if (pin.top !== void 0) scroll.pinTop = pin.top;
1167
+ if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
1168
+ }
1169
+ flat.scroll = scroll;
1170
+ } else {
1171
+ if (timeline.duration !== void 0) flat.duration = timeline.duration;
1172
+ if (timeline.trigger !== void 0) {
1173
+ const _b = timeline.trigger, { onFinish } = _b, restTrigger = __objRest2(_b, ["onFinish"]);
1174
+ if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
1175
+ if (onFinish !== void 0) flat.resetOnFinish = onFinish === "reset";
1176
+ }
1177
+ if (timeline.delay !== void 0) flat.delay = timeline.delay;
1178
+ if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
1179
+ if (timeline.direction !== void 0) flat.direction = timeline.direction;
1180
+ if (timeline.fill !== void 0) flat.fill = timeline.fill;
1181
+ }
1182
+ flattenMemo.set(cfg, flat);
1183
+ return flat;
1094
1184
  }
1095
1185
  function getDefs(doc) {
1096
1186
  var _a;
@@ -1102,7 +1192,7 @@ function getBindings(doc) {
1102
1192
  if (!doc) return void 0;
1103
1193
  const animateById = (_a = getAnimatorConfig(doc)) == null ? void 0 : _a.animateById;
1104
1194
  if (!animateById) return void 0;
1105
- return Object.entries(animateById).map(([id, anim]) => ({ id, animate: anim }));
1195
+ return Object.entries(animateById).map(([id, anim]) => ({ id: id.startsWith("#") ? id.slice(1) : id, animate: anim }));
1106
1196
  }
1107
1197
  function getChildren(doc) {
1108
1198
  return doc == null ? void 0 : doc.children;
@@ -1116,27 +1206,27 @@ var PxKeyframeValueSchema = implementsInterface()(px.union([
1116
1206
  // e.g. for colors
1117
1207
  px.number(),
1118
1208
  px.array(px.number()),
1119
- px.lazy(() => PxTransformPartsSchema, {}),
1209
+ // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
1210
+ // all-optional transform-parts record. In default (non-strict) mode that record accepts
1211
+ // ANY object (every key optional, unknown keys ignored), so listing it earlier made
1212
+ // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
1213
+ // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
1214
+ // order-independent (`some()`); only sanitize routing depends on this order.
1120
1215
  px.object({ path: px.string() }),
1121
1216
  px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
1122
1217
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
1123
- px.lazy(() => px.array(PxGradientStopSchema), [])
1218
+ px.lazy(() => px.array(PxGradientStopSchema), []),
1219
+ px.lazy(() => PxTransformPartsSchema, {})
1124
1220
  ]));
1125
1221
  var PxKeyframeSchema = implementsInterface()(px.object({
1126
1222
  time: px.number().optional(),
1127
- t: px.number().optional(),
1128
1223
  value: PxKeyframeValueSchema.optional(),
1129
- v: PxKeyframeValueSchema.optional(),
1130
1224
  easing: PxEasingOrRefSchema.optional(),
1131
- e: PxEasingOrRefSchema.optional(),
1132
1225
  tangentOut: px.tuple([px.number(), px.number()]).optional(),
1133
- to: px.tuple([px.number(), px.number()]).optional(),
1134
- // short alias
1135
- tangentIn: px.tuple([px.number(), px.number()]).optional(),
1136
- ti: px.tuple([px.number(), px.number()]).optional(),
1137
- // short alias
1138
- selected: px.boolean().optional()
1139
- // editor-side UI state (Player ignores it)
1226
+ tangentIn: px.tuple([px.number(), px.number()]).optional()
1227
+ // (`selected` — editor timeline-selection UI state — was REMOVED from the wire
1228
+ // (review §1.3): editor data lives under `meta`. The editor still carries it on
1229
+ // its internal COPY-PASTE payload, which never validates against this schema.)
1140
1230
  }));
1141
1231
  var PxLoopSchema = implementsInterface()(px.object({
1142
1232
  segmentCount: px.number().optional(),
@@ -1146,7 +1236,6 @@ var PxLoopSchema = implementsInterface()(px.object({
1146
1236
  var PxPropertyAnimationSchema = implementsInterface()(px.object({
1147
1237
  value: PxKeyframeValueSchema.optional(),
1148
1238
  keyframes: px.array(PxKeyframeSchema).optional(),
1149
- kfs: px.array(PxKeyframeSchema).optional(),
1150
1239
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
1151
1240
  autoOrient: px.boolean().optional()
1152
1241
  }));
@@ -1174,6 +1263,11 @@ var PxElementAnimationSchema = implementsInterface()(px.union([
1174
1263
  var PxTriggerSchema = implementsInterface()(px.object({
1175
1264
  startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
1176
1265
  outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
1266
+ // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
1267
+ // `fill`) or `'reset'` (snap back to the start state). The trigger-vocabulary home of
1268
+ // the old top-level `resetOnFinish: boolean` (read-legacy) — review §2.3: both
1269
+ // "what happens at the end" knobs now sit side by side and share one style of value.
1270
+ onFinish: px.enum(["hold", "reset"]).optional(),
1177
1271
  scrollIntoViewThreshold: px.number().optional()
1178
1272
  }));
1179
1273
  var PxGlyphSchema = implementsInterface()(px.object({
@@ -1181,8 +1275,8 @@ var PxGlyphSchema = implementsInterface()(px.object({
1181
1275
  d: px.string()
1182
1276
  }));
1183
1277
  var PxGlyphFontSchema = implementsInterface()(px.object({
1184
- fFamily: px.string(),
1185
- style: px.string(),
1278
+ fontFamily: px.string(),
1279
+ fontStyle: px.string(),
1186
1280
  ascent: px.number(),
1187
1281
  unitsPerEm: px.number(),
1188
1282
  glyphs: px.record(PxGlyphSchema)
@@ -1190,7 +1284,9 @@ var PxGlyphFontSchema = implementsInterface()(px.object({
1190
1284
  var PxDefsSchema = implementsInterface()(px.object({
1191
1285
  easings: px.record(px.tuple([px.number(), px.number(), px.number(), px.number()])).optional(),
1192
1286
  animations: px.record(PxAnimationDefinitionSchema).optional(),
1193
- styles: px.record(px.any()).optional(),
1287
+ // Review §2.6: the schema now matches the declared type — a style preset is a flat
1288
+ // record of string|number attribute values, nothing nested.
1289
+ styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
1194
1290
  glyphs: px.record(PxGlyphFontSchema).optional()
1195
1291
  }));
1196
1292
  var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
@@ -1216,22 +1312,54 @@ var PxScrollSchema = implementsInterface()(px.object({
1216
1312
  pinDistance: px.number().optional(),
1217
1313
  range: PxScrollRangeSchema.optional()
1218
1314
  }));
1219
- var PxAnimatorConfigSchema = implementsInterface()(px.object({
1220
- mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1315
+ var PxTimelinePinSchema = px.object({
1316
+ align: px.enum(["top", "center", "bottom"]).optional(),
1317
+ top: px.number().optional(),
1318
+ distance: px.number().optional()
1319
+ });
1320
+ var PxClockTimelineSchema = px.object({
1321
+ type: px.literal("clock"),
1322
+ // §2.8: duration is a property of the TIMELINE — how long one pass takes.
1221
1323
  duration: px.number().optional(),
1324
+ trigger: PxTriggerSchema.optional(),
1222
1325
  delay: px.number().optional(),
1223
- // LAW (SCHEMA-DESIGN R3, S10): the ONE sanctioned string-in-number union
1224
- // (CSS animation-iteration-count familiarity) — do not add more mixed unions.
1225
1326
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
1226
1327
  fill: px.enum(["forwards", "backwards", "both", "none"]).optional(),
1227
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional(),
1328
+ direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
1329
+ });
1330
+ var scrollishTimelineShape = {
1331
+ // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
1332
+ // span the scroll range maps onto.
1333
+ duration: px.number().optional(),
1334
+ // Finite repeat count IS meaningful when scrubbing — the scroll range maps onto
1335
+ // duration × iterations (rule D4; `'infinite'` cannot map to a range, so no literal here).
1336
+ iterations: px.number().optional(),
1337
+ engine: px.enum(["custom", "native"]).optional(),
1338
+ axis: px.enum(["block", "inline", "x", "y"]).optional(),
1339
+ source: px.enum(["nearest", "root"]).optional(),
1340
+ subject: px.string().optional(),
1341
+ // 'parent' | 'scroller' | any CSS selector
1342
+ smoothing: px.number().optional(),
1343
+ // ms
1344
+ pin: px.union([px.boolean(), PxTimelinePinSchema]).optional(),
1345
+ range: PxScrollRangeSchema.optional()
1346
+ };
1347
+ var PxScrollTimelineSchema = px.object(__spreadValues2({ type: px.literal("scroll") }, scrollishTimelineShape));
1348
+ var PxViewTimelineSchema = px.object(__spreadValues2({ type: px.literal("view") }, scrollishTimelineShape));
1349
+ var PxTimelineSchema = px.discriminatedUnion("type", [
1350
+ PxClockTimelineSchema,
1351
+ PxScrollTimelineSchema,
1352
+ PxViewTimelineSchema
1353
+ ]);
1354
+ var PxAnimatorConfigSchema = implementsInterface()(px.object({
1355
+ mode: px.enum([PxAnimatorMode.auto, PxAnimatorMode.waapi, PxAnimatorMode.frames]).optional(),
1356
+ // (`duration` lives INSIDE `timeline` on the wire — §2.8; the flat field below
1357
+ // exists only on the runtime view, like the rest of the playback dynamics.)
1228
1358
  frameRate: px.number().optional(),
1229
- trigger: PxTriggerSchema.optional(),
1230
- resetOnFinish: px.boolean().optional(),
1359
+ // THE spelling of "what advances progress" — clock / scroll / view (review §2.1).
1360
+ timeline: PxTimelineSchema.optional(),
1231
1361
  definitions: PxDefsSchema.optional(),
1232
1362
  animateById: px.record(PxElementAnimationSchema).optional(),
1233
- timelineSource: px.string().optional(),
1234
- scroll: PxScrollSchema.optional(),
1235
1363
  debugInstName: px.string().optional()
1236
1364
  }));
1237
1365
  var PxBindingSchema = implementsInterface()(px.object({
@@ -1250,18 +1378,18 @@ var PxAttrValueSchema = px.union([
1250
1378
  ]);
1251
1379
  var PxAnimatableNumberSchema = px.union([
1252
1380
  px.number(),
1253
- px.object({ value: px.number() }),
1254
- PxPropertyAnimationSchema
1381
+ PxPropertyAnimationSchema,
1382
+ px.object({ value: px.number() })
1255
1383
  ]);
1256
1384
  var PxAnimatableVec2Schema = px.union([
1257
1385
  px.tuple([px.number(), px.number()]),
1258
- px.object({ value: px.tuple([px.number(), px.number()]) }),
1259
- PxPropertyAnimationSchema
1386
+ PxPropertyAnimationSchema,
1387
+ px.object({ value: px.tuple([px.number(), px.number()]) })
1260
1388
  ]);
1261
1389
  var PxAnimatableStringSchema = px.union([
1262
1390
  px.string(),
1263
- px.object({ value: px.string() }),
1264
- PxPropertyAnimationSchema
1391
+ PxPropertyAnimationSchema,
1392
+ px.object({ value: px.string() })
1265
1393
  ]);
1266
1394
  var PxTransformByEffectSchema = implementsInterface()(px.object({
1267
1395
  translate: PxAnimatableVec2Schema.optional(),
@@ -1291,8 +1419,7 @@ var PxMaskedByEffectSchema = implementsInterface()(px.object({
1291
1419
  height: px.number().optional()
1292
1420
  }));
1293
1421
  var PxClipPathEffectSchema = implementsInterface()(px.object({
1294
- d: PxAnimatableStringSchema.optional(),
1295
- animate: PxPropertyAnimationSchema.optional()
1422
+ d: PxAnimatableStringSchema.optional()
1296
1423
  }));
1297
1424
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1298
1425
  offset: PxAnimatableNumberSchema.optional(),
@@ -1300,7 +1427,6 @@ var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
1300
1427
  subPaths: px.enum([PxStrokeTrimSubPaths.separate, PxStrokeTrimSubPaths.combined]).optional()
1301
1428
  }));
1302
1429
  var PxRetimeEffectSchema = implementsInterface()(px.object({
1303
- sourceId: px.string().optional(),
1304
1430
  start: px.number().optional(),
1305
1431
  stretch: px.number().optional(),
1306
1432
  timeCrop: px.tuple([px.number(), px.number()]).optional()
@@ -1323,11 +1449,11 @@ var PxAnimatableGradientStopsSchema = px.union([
1323
1449
  var PxFillGradientEffectSchema = implementsInterface()(px.object({
1324
1450
  // Contextual kind — the `type` convention, see `PxNodeBase.type`.
1325
1451
  type: px.enum([PxGradientType.linear, PxGradientType.radial]),
1326
- p1: PxAnimatableVec2Schema.optional(),
1327
- p2: PxAnimatableVec2Schema.optional(),
1328
- c: PxAnimatableVec2Schema.optional(),
1329
- r: PxAnimatableNumberSchema.optional(),
1330
- fp: PxAnimatableVec2Schema.optional(),
1452
+ start: PxAnimatableVec2Schema.optional(),
1453
+ end: PxAnimatableVec2Schema.optional(),
1454
+ center: PxAnimatableVec2Schema.optional(),
1455
+ radius: PxAnimatableNumberSchema.optional(),
1456
+ focal: PxAnimatableVec2Schema.optional(),
1331
1457
  stops: PxAnimatableGradientStopsSchema.optional(),
1332
1458
  gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
1333
1459
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
@@ -1521,9 +1647,11 @@ function generateNewIds(doc) {
1521
1647
  const docAnimate = (_a = cloned.animator) == null ? void 0 : _a.animateById;
1522
1648
  if (docAnimate && typeof docAnimate === "object") {
1523
1649
  const updatedAnimate = {};
1524
- for (const [id, anim] of Object.entries(docAnimate)) {
1650
+ for (const [key, anim] of Object.entries(docAnimate)) {
1651
+ const hashed = key.startsWith("#");
1652
+ const id = hashed ? key.slice(1) : key;
1525
1653
  const newId = (_b = idMap.get(id)) != null ? _b : id;
1526
- updatedAnimate[newId] = anim;
1654
+ updatedAnimate[hashed ? "#" + newId : newId] = anim;
1527
1655
  }
1528
1656
  cloned.animator = __spreadProps2(__spreadValues2({}, cloned.animator), { animateById: updatedAnimate });
1529
1657
  }
@@ -1614,7 +1742,7 @@ function getNormalizedProps(props) {
1614
1742
  let value = props[rawKey];
1615
1743
  if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
1616
1744
  propsCopy[key] = toRGBA(value);
1617
- } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes && !value.kfs) {
1745
+ } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
1618
1746
  const parts = value.value && typeof value.value === "object" ? value.value : value;
1619
1747
  propsCopy["transform"] = composeTransformParts(parts, { withUnits: false });
1620
1748
  } else if (TRANSFORM_FN_NAMES.has(key)) {
@@ -1652,12 +1780,12 @@ function getKfEasing(kf) {
1652
1780
  return (_a = kf.easing) != null ? _a : kf.e;
1653
1781
  }
1654
1782
  function propAnimIsMotionPath(anim) {
1655
- var _a, _b, _c;
1656
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
1783
+ var _a, _b;
1784
+ const kfs = anim.keyframes;
1657
1785
  if (!Array.isArray(kfs)) return false;
1658
1786
  if (anim.autoOrient) return true;
1659
1787
  for (const kf of kfs) {
1660
- if (((_b = kf.tangentIn) != null ? _b : kf.ti) || ((_c = kf.tangentOut) != null ? _c : kf.to)) return true;
1788
+ if (((_a = kf.tangentIn) != null ? _a : kf.ti) || ((_b = kf.tangentOut) != null ? _b : kf.to)) return true;
1661
1789
  }
1662
1790
  return false;
1663
1791
  }
@@ -1718,14 +1846,14 @@ var DEFAULT_FLATNESS_TOL = 0.5;
1718
1846
  var DEFAULT_ROTATION_TOL = 5;
1719
1847
  var DEFAULT_MAX_SAMPLES = 32;
1720
1848
  function materialiseMotionPathInPropAnim(anim, opts) {
1721
- var _a, _b, _c, _d;
1849
+ var _a, _b, _c;
1722
1850
  if (!propAnimIsMotionPath(anim)) return anim;
1723
- const kfs = (_a = anim.keyframes) != null ? _a : anim.kfs;
1851
+ const kfs = anim.keyframes;
1724
1852
  if (!Array.isArray(kfs) || kfs.length < 2) return anim;
1725
1853
  const autoOrient = !!anim.autoOrient;
1726
- const flatnessTol = (_b = opts == null ? void 0 : opts.flatnessTolerance) != null ? _b : DEFAULT_FLATNESS_TOL;
1727
- const rotationTol = (_c = opts == null ? void 0 : opts.rotationTolerance) != null ? _c : DEFAULT_ROTATION_TOL;
1728
- const maxSamples = (_d = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _d : DEFAULT_MAX_SAMPLES;
1854
+ const flatnessTol = (_a = opts == null ? void 0 : opts.flatnessTolerance) != null ? _a : DEFAULT_FLATNESS_TOL;
1855
+ const rotationTol = (_b = opts == null ? void 0 : opts.rotationTolerance) != null ? _b : DEFAULT_ROTATION_TOL;
1856
+ const maxSamples = (_c = opts == null ? void 0 : opts.maxSamplesPerSegment) != null ? _c : DEFAULT_MAX_SAMPLES;
1729
1857
  const out = [];
1730
1858
  const firstPos = getKfTranslate(kfs[0]);
1731
1859
  if (!firstPos) return anim;
@@ -1754,7 +1882,7 @@ function materialiseMotionPathInPropAnim(anim, opts) {
1754
1882
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
1755
1883
  if (lastInE) out[out.length - 1].e = lastInE;
1756
1884
  if (autoOrient) unwrapAutoOrientRotations(out);
1757
- const result = { kfs: out };
1885
+ const result = { keyframes: out };
1758
1886
  if (anim.loop !== void 0) result.loop = anim.loop;
1759
1887
  return result;
1760
1888
  }
@@ -2414,7 +2542,7 @@ function expandLoopKeyframes(propName, keyframes, loop, duration) {
2414
2542
  }
2415
2543
  function normalizeKeyframes(propName, propAnim, duration, defs) {
2416
2544
  var _a, _b, _c, _d, _e, _f, _g;
2417
- const keyframes = propAnim.keyframes || propAnim.kfs || [];
2545
+ const keyframes = propAnim.keyframes || [];
2418
2546
  const normalized = [];
2419
2547
  for (const kf of keyframes) {
2420
2548
  const timePct = (_b = (_a = kf.time) != null ? _a : kf.t) != null ? _b : 0;
@@ -2459,17 +2587,16 @@ function mergeAnimationDefinitions(animations) {
2459
2587
  return merged;
2460
2588
  }
2461
2589
  function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2462
- var _a;
2463
2590
  const loopRaw = propAnim.loop;
2464
2591
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
2465
2592
  const loop = loopRaw === true ? {} : loopRaw;
2466
- const rawKfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
2593
+ const rawKfs = propAnim.keyframes;
2467
2594
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
2468
2595
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
2469
2596
  const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
2470
2597
  const kfs = rawKfs.map((kf) => {
2471
- var _a2, _b, _c, _d, _e, _f, _g, _h;
2472
- const t = (_a2 = kf.t) != null ? _a2 : kf.time;
2598
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2599
+ const t = (_a = kf.t) != null ? _a : kf.time;
2473
2600
  let v = (_b = kf.v) != null ? _b : kf.value;
2474
2601
  if (propName === "d") v = normalizePathValue(v);
2475
2602
  if (isColour) v = (_c = parseColor(v)) != null ? _c : v;
@@ -2480,7 +2607,7 @@ function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
2480
2607
  return out2;
2481
2608
  });
2482
2609
  const expanded = expandLoopKeyframes(propName, kfs, loop, duration);
2483
- const out = { kfs: expanded };
2610
+ const out = { keyframes: expanded };
2484
2611
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2485
2612
  return out;
2486
2613
  }
@@ -2522,6 +2649,36 @@ var _elementIdCounter = 0;
2522
2649
  function generateElementId() {
2523
2650
  return "_px_el_" + ++_elementIdCounter;
2524
2651
  }
2652
+ function mergeStaticTransformIntoAnimDef(animDef, staticTransform) {
2653
+ if (!animDef) return animDef;
2654
+ const staticParts = staticTransform && typeof staticTransform === "object" && !Array.isArray(staticTransform) ? staticTransform : parseTransformParts(staticTransform);
2655
+ if (!staticParts || !Object.keys(staticParts).length) return animDef;
2656
+ const mergeKfValue = (v) => v && typeof v === "object" && !Array.isArray(v) ? __spreadValues2(__spreadValues2({}, staticParts), v) : v;
2657
+ const transformAnim = animDef["transform"];
2658
+ if (transformAnim && typeof transformAnim === "object") {
2659
+ const anim = transformAnim;
2660
+ if (Array.isArray(anim.keyframes)) {
2661
+ const out = __spreadProps2(__spreadValues2({}, anim), {
2662
+ keyframes: anim.keyframes.map((kf) => __spreadProps2(__spreadValues2({}, kf), { value: mergeKfValue(kf.value) }))
2663
+ });
2664
+ if (out.value !== void 0) out.value = mergeKfValue(out.value);
2665
+ return __spreadProps2(__spreadValues2({}, animDef), { transform: out });
2666
+ }
2667
+ return animDef;
2668
+ }
2669
+ const channels = Object.keys(animDef).filter((k) => TRANSFORM_FN_NAMES.has(k));
2670
+ if (channels.length !== 1) return animDef;
2671
+ const ch = channels[0];
2672
+ const chAnim = animDef[ch];
2673
+ if (!chAnim || typeof chAnim !== "object" || !Array.isArray(chAnim.keyframes)) return animDef;
2674
+ const lifted = __spreadProps2(__spreadValues2({}, chAnim), {
2675
+ keyframes: chAnim.keyframes.map((kf) => __spreadProps2(__spreadValues2({}, kf), { value: __spreadProps2(__spreadValues2({}, staticParts), { [ch]: kf.value }) }))
2676
+ });
2677
+ if (lifted.value !== void 0) lifted.value = __spreadProps2(__spreadValues2({}, staticParts), { [ch]: lifted.value });
2678
+ const rest = __spreadValues2({}, animDef);
2679
+ delete rest[ch];
2680
+ return __spreadProps2(__spreadValues2({}, rest), { transform: lifted });
2681
+ }
2525
2682
  function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimatorEngine.waapi) {
2526
2683
  const normalized = {};
2527
2684
  for (const [propName, propAnim] of Object.entries(animDef)) {
@@ -2530,7 +2687,7 @@ function normalizeAnimationDefinition(animDef, duration, defs, engine = PxAnimat
2530
2687
  }
2531
2688
  const normalizedKfs = normalizeKeyframes(propName, propAnim, duration, defs);
2532
2689
  if (normalizedKfs.length > 0) {
2533
- const out = { kfs: normalizedKfs };
2690
+ const out = { keyframes: normalizedKfs };
2534
2691
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
2535
2692
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
2536
2693
  normalized[propName] = engine === PxAnimatorEngine.waapi && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
@@ -2543,11 +2700,11 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2543
2700
  const defs = getDefs(doc);
2544
2701
  const duration = animatorConfig.duration || 1e3;
2545
2702
  const bindings = [];
2546
- const processAnimation = (id, animate) => {
2703
+ const processAnimation = (id, animate, staticTransform) => {
2547
2704
  if (!animate) return null;
2548
2705
  const animDefs = resolveElementAnimation(animate, defs);
2549
2706
  if (animDefs.length === 0) return null;
2550
- const merged = mergeAnimationDefinitions(animDefs);
2707
+ const merged = mergeStaticTransformIntoAnimDef(mergeAnimationDefinitions(animDefs), staticTransform);
2551
2708
  const normalizedAnim = normalizeAnimationDefinition(merged, duration, defs, engine);
2552
2709
  if (Object.keys(normalizedAnim).length === 0) return null;
2553
2710
  return {
@@ -2567,7 +2724,7 @@ function getNormalisedBindings(doc, engine = PxAnimatorEngine.waapi) {
2567
2724
  if (inlineAnim && Object.keys(inlineAnim).length > 0) {
2568
2725
  const nodeId = node.id || generateElementId();
2569
2726
  node.id = nodeId;
2570
- const normalized = processAnimation(nodeId, inlineAnim);
2727
+ const normalized = processAnimation(nodeId, inlineAnim, node.transform);
2571
2728
  if (normalized) bindings.push(normalized);
2572
2729
  }
2573
2730
  if (node.children) {
@@ -2605,7 +2762,7 @@ function getKeyframesPair(keyframes, progress) {
2605
2762
  }
2606
2763
  function calcPropertyValue(propName, propAnim, progress) {
2607
2764
  var _a, _b, _c, _d, _e, _f, _g;
2608
- const keyframes = propAnim.kfs || propAnim.keyframes || [];
2765
+ const keyframes = propAnim.keyframes || [];
2609
2766
  if (keyframes.length === 0) return null;
2610
2767
  const { prevKf, nextKf } = getKeyframesPair(keyframes, progress);
2611
2768
  let localProgress = prevKf === nextKf ? 0 : remap(progress, (_a = prevKf.t) != null ? _a : 0, (_b = nextKf.t) != null ? _b : 0, 0, 1);
@@ -3220,7 +3377,7 @@ function liftBodyTranslate(node, transformBy) {
3220
3377
  if (split.rest) node.transform = split.rest;
3221
3378
  else delete node.transform;
3222
3379
  }
3223
- } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes && !node.transform.kfs) {
3380
+ } else if (node.transform && typeof node.transform === "object" && !Array.isArray(node.transform) && !node.transform.keyframes) {
3224
3381
  const wrapped = node.transform.value;
3225
3382
  const isWrapped = !!(wrapped && typeof wrapped === "object");
3226
3383
  const value = isWrapped ? wrapped : node.transform;
@@ -3353,12 +3510,12 @@ function synthesiseGradientDef(fx, id, ctx) {
3353
3510
  id
3354
3511
  };
3355
3512
  if (fx.type === PxGradientType.linear) {
3356
- applyGeomVec(out, "x1", "y1", fx.p1);
3357
- applyGeomVec(out, "x2", "y2", fx.p2);
3513
+ applyGeomVec(out, "x1", "y1", fx.start);
3514
+ applyGeomVec(out, "x2", "y2", fx.end);
3358
3515
  } else {
3359
- applyGeomVec(out, "cx", "cy", fx.c);
3360
- applyGeomNumber(out, "r", fx.r);
3361
- applyGeomVec(out, "fx", "fy", fx.fp);
3516
+ applyGeomVec(out, "cx", "cy", fx.center);
3517
+ applyGeomNumber(out, "r", fx.radius);
3518
+ applyGeomVec(out, "fx", "fy", fx.focal);
3362
3519
  }
3363
3520
  if (fx.gradientUnits) out.gradientUnits = fx.gradientUnits;
3364
3521
  if (fx.spreadMethod) out.spreadMethod = fx.spreadMethod;
@@ -3484,8 +3641,7 @@ function formatOffset(o) {
3484
3641
  return pct + "%";
3485
3642
  }
3486
3643
  function applyClipPathEffect(node, fx, ctx) {
3487
- var _a, _b;
3488
- if (!fx || !fx.d && !fx.animate) return node;
3644
+ if (!(fx == null ? void 0 : fx.d)) return node;
3489
3645
  const clipId = genId(ctx, "clip");
3490
3646
  const pathChild = { type: "path" };
3491
3647
  const read = readAnimatable(fx.d);
@@ -3497,11 +3653,6 @@ function applyClipPathEffect(node, fx, ctx) {
3497
3653
  if (pathChild.d !== void 0) pathChild.d = pathString(pathChild.d);
3498
3654
  }
3499
3655
  }
3500
- if (fx.animate && !((_a = pathChild.animate) == null ? void 0 : _a.d)) {
3501
- const animate = (_b = pathChild.animate) != null ? _b : {};
3502
- animate.d = fx.animate;
3503
- pathChild.animate = animate;
3504
- }
3505
3656
  ctx.defs.push({ type: "clipPath", id: clipId, children: [pathChild] });
3506
3657
  node.clipPath = "url(#" + clipId + ")";
3507
3658
  return node;
@@ -3644,7 +3795,7 @@ function readTransformationFromBody(node) {
3644
3795
  if (parts.origin) out.origin = parts.origin;
3645
3796
  return Object.keys(out).length ? out : void 0;
3646
3797
  }
3647
- if (node.transform && typeof node.transform === "object" && !node.transform.keyframes && !node.transform.kfs) {
3798
+ if (node.transform && typeof node.transform === "object" && !node.transform.keyframes) {
3648
3799
  const wrapped = node.transform.value;
3649
3800
  const value = wrapped && typeof wrapped === "object" ? wrapped : node.transform;
3650
3801
  if (value && typeof value === "object") {
@@ -5435,9 +5586,9 @@ var fmt2 = (n) => {
5435
5586
  return Object.is(r, -0) ? "0" : String(r);
5436
5587
  };
5437
5588
  function buildOffsetPath(propAnim) {
5438
- var _a, _b, _c, _d;
5589
+ var _a, _b, _c;
5439
5590
  if (propAnim.alongPathMode !== "offsetPath") return void 0;
5440
- const kfs = (_a = propAnim.keyframes) != null ? _a : propAnim.kfs;
5591
+ const kfs = propAnim.keyframes;
5441
5592
  if (!kfs || kfs.length < 2) return void 0;
5442
5593
  const first = kfValue(kfs[0]);
5443
5594
  const anchor = (first == null ? void 0 : first.origin) && first.origin.length >= 2 ? [first.origin[0], first.origin[1]] : [0, 0];
@@ -5448,7 +5599,7 @@ function buildOffsetPath(propAnim) {
5448
5599
  if (!tr || tr.length < 2) return void 0;
5449
5600
  const parts = Object.keys(v);
5450
5601
  if (parts.some((p) => p !== "translate" && p !== "origin")) return void 0;
5451
- const o = (_b = v == null ? void 0 : v.origin) != null ? _b : [0, 0];
5602
+ const o = (_a = v == null ? void 0 : v.origin) != null ? _a : [0, 0];
5452
5603
  if (o[0] !== anchor[0] || o[1] !== anchor[1]) return void 0;
5453
5604
  points.push([tr[0] + anchor[0], tr[1] + anchor[1]]);
5454
5605
  }
@@ -5457,8 +5608,8 @@ function buildOffsetPath(propAnim) {
5457
5608
  const segLens = [];
5458
5609
  for (let i = 0; i < points.length - 1; i++) {
5459
5610
  const p0 = points[i], p1 = points[i + 1];
5460
- const to = (_c = kfTangentOut(kfs[i])) != null ? _c : [0, 0];
5461
- const ti = (_d = kfTangentIn(kfs[i + 1])) != null ? _d : [0, 0];
5611
+ const to = (_b = kfTangentOut(kfs[i])) != null ? _b : [0, 0];
5612
+ const ti = (_c = kfTangentIn(kfs[i + 1])) != null ? _c : [0, 0];
5462
5613
  const c1 = [p0[0] + to[0], p0[1] + to[1]];
5463
5614
  const c2 = [p1[0] + ti[0], p1[1] + ti[1]];
5464
5615
  d += "C" + fmt2(c1[0]) + "," + fmt2(c1[1]) + "," + fmt2(c2[0]) + "," + fmt2(c2[1]) + "," + fmt2(p1[0]) + "," + fmt2(p1[1]);
@@ -6286,7 +6437,7 @@ function convertToWebApiKeyframes(animDef, unsupportedSet, config) {
6286
6437
  const result = /* @__PURE__ */ new Map();
6287
6438
  for (const [propName, propAnim] of Object.entries(animDef)) {
6288
6439
  const duration = config.duration || 1;
6289
- const clippedKeyframes = clipKeyframesToDuration(propName, propAnim.kfs || propAnim.keyframes || [], duration);
6440
+ const clippedKeyframes = clipKeyframesToDuration(propName, propAnim.keyframes || [], duration);
6290
6441
  const cssKeyframes = [];
6291
6442
  for (let i = 0; i < clippedKeyframes.length; i++) {
6292
6443
  const kf = clippedKeyframes[i];
@@ -6899,7 +7050,16 @@ function createAnimatorImpl(doc, adapter, callbacks, containerElement) {
6899
7050
  }
6900
7051
  }
6901
7052
  }
6902
- return createAnimatorFromConfig(doc, adapter, callbacks, rootElement);
7053
+ const api = createAnimatorFromConfig(doc, adapter, callbacks, rootElement);
7054
+ if (containerElement && rootElement) {
7055
+ const rendered = rootElement;
7056
+ const destroyNative = api.destroy.bind(api);
7057
+ api.destroy = () => {
7058
+ destroyNative();
7059
+ rendered.remove();
7060
+ };
7061
+ }
7062
+ return api;
6903
7063
  }
6904
7064
  function createAnimator(options) {
6905
7065
  const { src, data, adapter, callbacks, container } = options;