@pixodesk/svg-animator-vue 1.0.35 → 1.0.39

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
@@ -57054,7 +57054,7 @@ ${codeFrame}` : message);
57054
57054
  }
57055
57055
  return void 0;
57056
57056
  }
57057
- var COLOUR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
57057
+ var COLOR_ATTR_NAMES = /* @__PURE__ */ new Set(["color", "fill", "flood-color", "lighting-color", "stop-color", "stroke"]);
57058
57058
  var TRANSFORM_FN_NAMES = /* @__PURE__ */ new Set(["translate", "rotate", "scale", "skew"]);
57059
57059
  var PCT_BASED_ATTR_NAMES = /* @__PURE__ */ new Set(["offset-distance", "offsetDistance"]);
57060
57060
  function composeTransformParts(parts, opts) {
@@ -57433,6 +57433,7 @@ ${codeFrame}` : message);
57433
57433
  return false;
57434
57434
  }
57435
57435
  };
57436
+ var UNION_MEMBER_ERROR_LIMIT = 4;
57436
57437
  var Union = class extends Base {
57437
57438
  constructor(schemas, defaultVal) {
57438
57439
  super();
@@ -57450,7 +57451,35 @@ ${codeFrame}` : message);
57450
57451
  var _a2;
57451
57452
  const probe = ctx && { errors: [], warnings: [], strict: ctx.strict };
57452
57453
  if (this.schemas.some((s) => s.isValid(raw, probe, path ? [...path] : void 0))) return true;
57453
- ctx == null ? void 0 : ctx.errors.push(pathStr(path != null ? path : []) + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
57454
+ if (!ctx) return false;
57455
+ const base = pathStr(path != null ? path : []);
57456
+ ctx.errors.push(base + ": no union member matched for value " + ((_a2 = JSON.stringify(raw)) != null ? _a2 : "").slice(0, 240));
57457
+ let best;
57458
+ let bestDepth = -1;
57459
+ const leafExpectations = [];
57460
+ for (const member of this.schemas) {
57461
+ const sink = { errors: [], warnings: [], strict: ctx.strict };
57462
+ member.isValid(raw, sink, path ? [...path] : void 0);
57463
+ if (!sink.errors.length) continue;
57464
+ const depth = Math.max(...sink.errors.map((e) => e.slice(0, e.indexOf(":")).length));
57465
+ if (depth > bestDepth || depth === bestDepth && best && sink.errors.length < best.length) {
57466
+ bestDepth = depth;
57467
+ best = sink.errors;
57468
+ }
57469
+ if (depth <= base.length) {
57470
+ for (const e of sink.errors) {
57471
+ const m = /: expected (.+?), got /.exec(e);
57472
+ if (m && !leafExpectations.includes(m[1])) leafExpectations.push(m[1]);
57473
+ }
57474
+ }
57475
+ }
57476
+ if (best && bestDepth > base.length) {
57477
+ for (const e of best.slice(0, UNION_MEMBER_ERROR_LIMIT)) {
57478
+ if (!ctx.errors.includes(e)) ctx.errors.push(e);
57479
+ }
57480
+ } else if (leafExpectations.length) {
57481
+ ctx.errors.push(base + ": expected " + leafExpectations.join(" | "));
57482
+ }
57454
57483
  return false;
57455
57484
  }
57456
57485
  _canSanitize(raw) {
@@ -57807,10 +57836,76 @@ ${codeFrame}` : message);
57807
57836
  }
57808
57837
  var _a;
57809
57838
  var PLAYER_WIRE_VERSION = (_a = parseWireVersion(PX_PLAYER_SCHEMA_VERSION)) != null ? _a : { a: 1, b: 1, c: 0 };
57810
- var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
57811
- var PX_ANIM_ATTR_NAME = "_px_animator";
57839
+ var PxFillMode = {
57840
+ forwards: "forwards",
57841
+ backwards: "backwards",
57842
+ both: "both",
57843
+ none: "none"
57844
+ };
57845
+ var PxPlaybackDirection = {
57846
+ normal: "normal",
57847
+ reverse: "reverse",
57848
+ alternate: "alternate",
57849
+ alternateReverse: "alternate-reverse"
57850
+ };
57851
+ var PxStartOn = {
57852
+ load: "load",
57853
+ mouseOver: "mouseOver",
57854
+ click: "click",
57855
+ scrollIntoView: "scrollIntoView",
57856
+ programmatic: "programmatic"
57857
+ };
57858
+ var PxOutAction = {
57859
+ continue: "continue",
57860
+ pause: "pause",
57861
+ reset: "reset",
57862
+ reverse: "reverse"
57863
+ };
57864
+ var PxFinishAction = {
57865
+ hold: "hold",
57866
+ reset: "reset"
57867
+ };
57868
+ var PxScrollKind = {
57869
+ view: "view",
57870
+ scroll: "scroll"
57871
+ };
57872
+ var PxScrollAxis = {
57873
+ block: "block",
57874
+ inline: "inline",
57875
+ x: "x",
57876
+ y: "y"
57877
+ };
57878
+ var PxScrollSource = {
57879
+ nearest: "nearest",
57880
+ root: "root"
57881
+ };
57882
+ var PxPinAlign = {
57883
+ top: "top",
57884
+ center: "center",
57885
+ bottom: "bottom"
57886
+ };
57887
+ var PxScrollPhase = {
57888
+ cover: "cover",
57889
+ contain: "contain",
57890
+ entry: "entry",
57891
+ exit: "exit",
57892
+ entryCrossing: "entry-crossing",
57893
+ exitCrossing: "exit-crossing"
57894
+ };
57895
+ var PxAlongPathMode = {
57896
+ sampled: "sampled",
57897
+ offsetPath: "offsetPath"
57898
+ };
57812
57899
  var PX_TIMELINE_SHARED_KEYS = ["duration", "iterations", "engine", "frameRate"];
57813
57900
  var PX_TIME_ONLY_TIMELINE_KEYS = ["trigger", "delay", "fillMode", "direction"];
57901
+ var PX_FLAT_RUNTIME_VIEW_KEYS = [
57902
+ ...PX_TIMELINE_SHARED_KEYS,
57903
+ ...PX_TIME_ONLY_TIMELINE_KEYS,
57904
+ "fill",
57905
+ "resetOnFinish",
57906
+ "timelineSource",
57907
+ "scroll"
57908
+ ];
57814
57909
  var PxTimelineEngine = {
57815
57910
  native: "native",
57816
57911
  js: "js"
@@ -57827,6 +57922,50 @@ ${codeFrame}` : message);
57827
57922
  function mayUseNativeScrollTimeline(engine) {
57828
57923
  return engine !== PxTimelineEngineExtra.js;
57829
57924
  }
57925
+ var PX_TRIGGER_DEFAULTS = {
57926
+ startOn: "load",
57927
+ outAction: "continue",
57928
+ scrollIntoViewThreshold: 0
57929
+ };
57930
+ var PxControlMode = {
57931
+ /** No control props — the document's trigger decides, and nothing is taken over. */
57932
+ static: "static",
57933
+ /** `progress` / `time` — the host scrubs; the component seeks and stays paused. */
57934
+ fixedTime: "fixedTime",
57935
+ /** `play` / `pause` — the host drives playback with booleans. */
57936
+ play: "play",
57937
+ /** `autoplay` — the document's own trigger starts it. */
57938
+ autoplay: "autoplay"
57939
+ };
57940
+ function resolveControlMode(props) {
57941
+ const hasFixedTime = props.progress !== void 0 || props.time !== void 0;
57942
+ const hasPlayPause = props.play !== void 0 || props.pause !== void 0;
57943
+ const hasAutoplay = !!props.autoplay;
57944
+ const warnings = [];
57945
+ const named = (a, b, winner) => a + " and " + b + " were both set \u2014 " + winner + " wins, " + (winner === a ? b : a) + " is ignored.";
57946
+ if (hasFixedTime) {
57947
+ if (hasPlayPause) warnings.push(named("progress/time", "play/pause", "progress/time"));
57948
+ if (hasAutoplay) warnings.push(named("progress/time", "autoplay", "progress/time"));
57949
+ return { mode: PxControlMode.fixedTime, warnings };
57950
+ }
57951
+ if (hasPlayPause) {
57952
+ if (hasAutoplay) warnings.push(named("play/pause", "autoplay", "play/pause"));
57953
+ return { mode: PxControlMode.play, warnings };
57954
+ }
57955
+ if (hasAutoplay) return { mode: PxControlMode.autoplay, warnings };
57956
+ return { mode: PxControlMode.static, warnings };
57957
+ }
57958
+ function controlModeTakesOverTrigger(mode) {
57959
+ return mode !== PxControlMode.autoplay;
57960
+ }
57961
+ function resolveTrigger(trigger) {
57962
+ var _a2, _b, _c;
57963
+ return {
57964
+ startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
57965
+ outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
57966
+ scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
57967
+ };
57968
+ }
57830
57969
  var PxLoopRepeatAt = {
57831
57970
  /** Segment from the START; the repetition runs BEFORE the first keyframe
57832
57971
  * (intro loops that play until the main timeline begins). */
@@ -57873,7 +58012,6 @@ ${codeFrame}` : message);
57873
58012
  separate: "separate",
57874
58013
  combined: "combined"
57875
58014
  };
57876
- var TEXT_ATTR = "text";
57877
58015
  var TEXT_CONTENT_ATTR = "textContent";
57878
58016
  var CLASS_ATTR = "class";
57879
58017
  var TRANSFORM_ATTR = "transform";
@@ -57885,7 +58023,6 @@ ${codeFrame}` : message);
57885
58023
  "meta",
57886
58024
  "animate",
57887
58025
  "effects",
57888
- TEXT_ATTR,
57889
58026
  TEXT_CONTENT_ATTR
57890
58027
  ]);
57891
58028
  var TRANSFORM_PART = {
@@ -57900,10 +58037,6 @@ ${codeFrame}` : message);
57900
58037
  TRANSFORM_PART.scale,
57901
58038
  TRANSFORM_PART.origin
57902
58039
  ];
57903
- var PxGradientUnits = {
57904
- userSpaceOnUse: "userSpaceOnUse",
57905
- objectBoundingBox: "objectBoundingBox"
57906
- };
57907
58040
  var PxGradientSpreadMethod = {
57908
58041
  pad: "pad",
57909
58042
  reflect: "reflect",
@@ -57922,8 +58055,18 @@ ${codeFrame}` : message);
57922
58055
  function getAnimatorConfig(doc) {
57923
58056
  var _a2;
57924
58057
  const cfg = (doc == null ? void 0 : doc.animator) || ((_a2 = doc == null ? void 0 : doc.meta) == null ? void 0 : _a2.animator);
57925
- return cfg ? flattenAnimatorTimeline(cfg) : void 0;
57926
- }
58058
+ if (!cfg) return void 0;
58059
+ const memoised = wireViewMemo.get(cfg);
58060
+ if (memoised) return memoised;
58061
+ const wire = cfg;
58062
+ const stray = PX_FLAT_RUNTIME_VIEW_KEYS.filter((k) => wire[k] !== void 0);
58063
+ const source = stray.length ? __spreadValues2({}, wire) : cfg;
58064
+ for (const k of stray) delete source[k];
58065
+ const view = flattenAnimatorTimeline(source);
58066
+ wireViewMemo.set(cfg, view);
58067
+ return view;
58068
+ }
58069
+ var wireViewMemo = /* @__PURE__ */ new WeakMap();
57927
58070
  var flattenMemo = /* @__PURE__ */ new WeakMap();
57928
58071
  function flattenAnimatorTimeline(cfg) {
57929
58072
  const timeline = cfg.timeline;
@@ -57949,7 +58092,7 @@ ${codeFrame}` : message);
57949
58092
  else if (pin && typeof pin === "object") {
57950
58093
  scroll.pin = true;
57951
58094
  if (pin.align !== void 0) scroll.pinAlign = pin.align;
57952
- if (pin.top !== void 0) scroll.pinTop = pin.top;
58095
+ if (pin.offset !== void 0) scroll.pinOffset = pin.offset;
57953
58096
  if (pin.distance !== void 0) scroll.pinDistance = pin.distance;
57954
58097
  }
57955
58098
  flat.scroll = scroll;
@@ -57989,14 +58132,13 @@ ${codeFrame}` : message);
57989
58132
  // e.g. for colors
57990
58133
  px.number(),
57991
58134
  px.array(px.number()),
57992
- // ORDER LAW: the key-discriminated object shapes (`{path}`, `{paths}`) come BEFORE the
58135
+ // ORDER LAW: the key-discriminated object shape (`{pathData}`) comes BEFORE the
57993
58136
  // all-optional transform-parts record. In default (non-strict) mode that record accepts
57994
58137
  // ANY object (every key optional, unknown keys ignored), so listing it earlier made
57995
- // Union.sanitize route `{path}`/`{paths}` values into it and strip them to `{}` —
58138
+ // Union.sanitize route `{pathData}` values into it and strip them to `{}` —
57996
58139
  // silent morph-data loss (repro: the editor's keyframeValueSanitize spec). Validity is
57997
58140
  // order-independent (`some()`); only sanitize routing depends on this order.
57998
- px.object({ path: px.string() }),
57999
- px.lazy(() => px.object({ paths: px.array(PxBezierPathSchema) }), { paths: [] }),
58141
+ px.object({ pathData: px.string() }),
58000
58142
  // Gradient `stops` timeline — each kf value is the full stops-array snapshot.
58001
58143
  px.lazy(() => px.array(PxGradientStopSchema), []),
58002
58144
  px.lazy(() => PxTransformPartsSchema, {})
@@ -58036,7 +58178,7 @@ ${codeFrame}` : message);
58036
58178
  keyframes: px.array(PxKeyframeSchema).optional(),
58037
58179
  loop: px.union([PxLoopSchema, px.boolean()]).optional(),
58038
58180
  autoOrient: px.boolean().optional(),
58039
- alongPathMode: px.enum(["sampled", "offsetPath"]).optional()
58181
+ alongPathMode: px.enum([PxAlongPathMode.sampled, PxAlongPathMode.offsetPath]).optional()
58040
58182
  }));
58041
58183
  var PxTransformPartsSchema = implementsInterface()(px.object({
58042
58184
  translate: px.tuple([px.number(), px.number()]).optional(),
@@ -58060,17 +58202,17 @@ ${codeFrame}` : message);
58060
58202
  PxAnimationDefinitionSchema
58061
58203
  ]));
58062
58204
  var PxTriggerSchema = implementsInterface()(px.object({
58063
- startOn: px.enum(["load", "mouseOver", "click", "scrollIntoView", "programmatic"]).optional(),
58064
- outAction: px.enum(["continue", "pause", "reset", "reverse"]).optional(),
58205
+ startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
58206
+ outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
58065
58207
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
58066
58208
  // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
58067
58209
  // happens when the trigger condition ends"); both end-of-life knobs now read alike.
58068
- finishAction: px.enum(["hold", "reset"]).optional(),
58210
+ finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
58069
58211
  scrollIntoViewThreshold: px.number().optional()
58070
58212
  }));
58071
58213
  var PxGlyphSchema = implementsInterface()(px.object({
58072
58214
  width: px.number(),
58073
- d: px.string()
58215
+ pathData: px.string()
58074
58216
  }));
58075
58217
  var PxGlyphFontSchema = implementsInterface()(px.object({
58076
58218
  fontFamily: px.string(),
@@ -58087,9 +58229,15 @@ ${codeFrame}` : message);
58087
58229
  styles: px.record(px.record(px.union([px.string(), px.number()]))).optional(),
58088
58230
  fonts: px.record(PxGlyphFontSchema).optional()
58089
58231
  }));
58090
- var PX_SCROLL_PHASES = ["cover", "contain", "entry", "exit", "entry-crossing", "exit-crossing"];
58091
58232
  var PxScrollRangePointSchema = implementsInterface()(px.object({
58092
- phase: px.enum(PX_SCROLL_PHASES).optional(),
58233
+ phase: px.enum([
58234
+ PxScrollPhase.cover,
58235
+ PxScrollPhase.contain,
58236
+ PxScrollPhase.entry,
58237
+ PxScrollPhase.exit,
58238
+ PxScrollPhase.entryCrossing,
58239
+ PxScrollPhase.exitCrossing
58240
+ ]).optional(),
58093
58241
  fraction: px.number().optional()
58094
58242
  }));
58095
58243
  var PxScrollRangeSchema = px.object({
@@ -58097,21 +58245,21 @@ ${codeFrame}` : message);
58097
58245
  end: PxScrollRangePointSchema.optional()
58098
58246
  });
58099
58247
  var PxScrollSchema = implementsInterface()(px.object({
58100
- kind: px.enum(["view", "scroll"]).optional(),
58101
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
58102
- source: px.enum(["nearest", "root"]).optional(),
58248
+ kind: px.enum([PxScrollKind.view, PxScrollKind.scroll]).optional(),
58249
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
58250
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
58103
58251
  // Free-form: the two keywords `parent`/`scroller` plus any CSS selector.
58104
58252
  subject: px.string().optional(),
58105
58253
  smoothing: px.number().optional(),
58106
58254
  pin: px.boolean().optional(),
58107
- pinAlign: px.enum(["top", "center", "bottom"]).optional(),
58108
- pinTop: px.number().optional(),
58255
+ pinAlign: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
58256
+ pinOffset: px.number().optional(),
58109
58257
  pinDistance: px.number().optional(),
58110
58258
  range: PxScrollRangeSchema.optional()
58111
58259
  }));
58112
58260
  var PxTimelinePinSchema = implementsInterface()(px.object({
58113
- align: px.enum(["top", "center", "bottom"]).optional(),
58114
- top: px.number().optional(),
58261
+ align: px.enum([PxPinAlign.top, PxPinAlign.center, PxPinAlign.bottom]).optional(),
58262
+ offset: px.number().optional(),
58115
58263
  distance: px.number().optional()
58116
58264
  }));
58117
58265
  var PxTimelineEngineSchema = px.enum([PxTimelineEngineExtra.auto, PxTimelineEngineExtra.native, PxTimelineEngineExtra.js]).optional();
@@ -58126,8 +58274,8 @@ ${codeFrame}` : message);
58126
58274
  iterations: px.union([px.number(), px.literal("infinite")]).optional(),
58127
58275
  // `fillMode` on the wire (CSS `animation-fill-mode`; the runtime view calls it `fill`)
58128
58276
  // — never `fill`, which is paint everywhere else in the format.
58129
- fillMode: px.enum(["forwards", "backwards", "both", "none"]).optional(),
58130
- direction: px.enum(["normal", "reverse", "alternate", "alternate-reverse"]).optional()
58277
+ fillMode: px.enum([PxFillMode.forwards, PxFillMode.backwards, PxFillMode.both, PxFillMode.none]).optional(),
58278
+ direction: px.enum([PxPlaybackDirection.normal, PxPlaybackDirection.reverse, PxPlaybackDirection.alternate, PxPlaybackDirection.alternateReverse]).optional()
58131
58279
  }));
58132
58280
  var scrollishTimelineShape = {
58133
58281
  // §2.8: duration is a property of the TIMELINE — under scrubbing it is the keyframe
@@ -58138,8 +58286,8 @@ ${codeFrame}` : message);
58138
58286
  iterations: px.number().optional(),
58139
58287
  engine: PxTimelineEngineSchema,
58140
58288
  frameRate: px.number().optional(),
58141
- axis: px.enum(["block", "inline", "x", "y"]).optional(),
58142
- source: px.enum(["nearest", "root"]).optional(),
58289
+ axis: px.enum([PxScrollAxis.block, PxScrollAxis.inline, PxScrollAxis.x, PxScrollAxis.y]).optional(),
58290
+ source: px.enum([PxScrollSource.nearest, PxScrollSource.root]).optional(),
58143
58291
  subject: px.string().optional(),
58144
58292
  // 'parent' | 'scroller' | any CSS selector
58145
58293
  smoothing: px.number().optional(),
@@ -58228,7 +58376,7 @@ ${codeFrame}` : message);
58228
58376
  height: px.number().optional()
58229
58377
  }));
58230
58378
  var PxClipPathEffectSchema = implementsInterface()(px.object({
58231
- d: PxAnimatableStringSchema.optional()
58379
+ pathData: PxAnimatableStringSchema.optional()
58232
58380
  }));
58233
58381
  var PxStrokeTrimEffectSchema = implementsInterface()(px.object({
58234
58382
  offset: PxAnimatableNumberSchema.optional(),
@@ -58265,7 +58413,7 @@ ${codeFrame}` : message);
58265
58413
  radius: PxAnimatableNumberSchema.optional(),
58266
58414
  focal: PxAnimatableVec2Schema.optional(),
58267
58415
  stops: PxAnimatableGradientStopsSchema.optional(),
58268
- gradientUnits: px.enum([PxGradientUnits.userSpaceOnUse, PxGradientUnits.objectBoundingBox]).optional(),
58416
+ gradientUnits: px.enum([PxUnits.userSpaceOnUse, PxUnits.objectBoundingBox]).optional(),
58269
58417
  spreadMethod: px.enum([PxGradientSpreadMethod.pad, PxGradientSpreadMethod.reflect, PxGradientSpreadMethod.repeat]).optional(),
58270
58418
  gradientTransform: px.string().optional()
58271
58419
  }));
@@ -58311,11 +58459,71 @@ ${codeFrame}` : message);
58311
58459
  walk(root, "root");
58312
58460
  return warnings;
58313
58461
  }
58314
- function validateDocument(doc) {
58315
- const ctx = { errors: [], warnings: [], strict: true };
58462
+ function validateGlyphFontRefs(root, fonts) {
58463
+ if (!fonts || !Object.keys(fonts).length) return [];
58464
+ const problems = [];
58465
+ const walk = (node, path, inherited, inGlyphText) => {
58466
+ var _a2, _b;
58467
+ if (!node) return;
58468
+ const own = typeof node.fontFamily === "string" ? node.fontFamily : void 0;
58469
+ const family = own != null ? own : inherited;
58470
+ const isGlyphText = inGlyphText || node.type === "text" && !!((_b = (_a2 = node.effects) == null ? void 0 : _a2.text) == null ? void 0 : _b.useGlyphs);
58471
+ if (isGlyphText && own && !Object.prototype.hasOwnProperty.call(fonts, own)) {
58472
+ const problem = path + ': glyph-mode text uses font-family "' + own + '", which has no entry in animator.definitions.fonts';
58473
+ if (!problems.includes(problem)) problems.push(problem);
58474
+ }
58475
+ if (Array.isArray(node.children)) {
58476
+ node.children.forEach((c, i) => walk(c, path + ".children[" + i + "]", family, isGlyphText));
58477
+ }
58478
+ };
58479
+ walk(root, "root", void 0, false);
58480
+ return problems;
58481
+ }
58482
+ function validateEasingRefs(root, easings) {
58483
+ const problems = [];
58484
+ const walk = (node, path) => {
58485
+ if (Array.isArray(node)) {
58486
+ node.forEach((item, i) => walk(item, path + "[" + i + "]"));
58487
+ return;
58488
+ }
58489
+ if (!node || typeof node !== "object") return;
58490
+ const easing = node.easing;
58491
+ if (typeof easing === "string" && !(easings && Object.prototype.hasOwnProperty.call(easings, easing))) {
58492
+ const problem = path + '.easing: "' + easing + '" names no entry in animator.definitions.easings \u2014 it will play linear';
58493
+ if (!problems.includes(problem)) problems.push(problem);
58494
+ }
58495
+ for (const [key, value] of Object.entries(node)) {
58496
+ if (key === "easing") continue;
58497
+ if (value && typeof value === "object") walk(value, path + "." + key);
58498
+ }
58499
+ };
58500
+ walk(root, "root");
58501
+ return problems;
58502
+ }
58503
+ function validateVersionStamp(doc) {
58504
+ var _a2;
58505
+ const version = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.version;
58506
+ if (version === void 0) return [];
58507
+ if (parseWireVersion(version) !== void 0) return [];
58508
+ return ["root.animator.version: " + JSON.stringify(version) + ' is not a version stamp ("a.b" or "a.b.c") \u2014 it reads as unstamped'];
58509
+ }
58510
+ function validateDocument(doc, opts) {
58511
+ var _a2;
58512
+ const strict = (opts == null ? void 0 : opts.strict) !== false;
58513
+ const ctx = { errors: [], warnings: [], strict };
58316
58514
  const problems = PxAnimatedSvgDocumentSchema.isValid(doc, ctx, ["root"]) ? [] : [...ctx.errors];
58317
58515
  if (doc && typeof doc === "object") {
58318
- for (const w of validateNodeEffects(doc, { strict: true })) {
58516
+ for (const w of validateNodeEffects(doc, { strict })) {
58517
+ if (!problems.includes(w)) problems.push(w);
58518
+ }
58519
+ const defs = (_a2 = getAnimatorConfig(doc)) == null ? void 0 : _a2.definitions;
58520
+ for (const w of validateGlyphFontRefs(doc, defs == null ? void 0 : defs.fonts)) {
58521
+ if (!problems.includes(w)) problems.push(w);
58522
+ }
58523
+ for (const w of validateEasingRefs(doc, defs == null ? void 0 : defs.easings)) {
58524
+ if (!problems.includes(w)) problems.push(w);
58525
+ }
58526
+ for (const w of validateVersionStamp(doc)) {
58319
58527
  if (!problems.includes(w)) problems.push(w);
58320
58528
  }
58321
58529
  }
@@ -58338,10 +58546,13 @@ ${codeFrame}` : message);
58338
58546
  // documented — because a wire key that is not in a schema is invisible to the
58339
58547
  // minifier's reserve list and gets renamed (MINIFICATION-BOUNDARY-PLAN.md §1.1).
58340
58548
  domType: px.string().optional(),
58549
+ // Text content of a `<text>` / `<tspan>`. Declared, so a non-string value is a schema error
58550
+ // and the minifier reserves the key; `text` is NOT an alias for it and is not read anywhere.
58551
+ textContent: px.string().optional(),
58341
58552
  id: px.string().optional(),
58342
58553
  meta: px.any().optional(),
58343
58554
  // Player-effects bucket emitted by the Editor's lightweight design format.
58344
- // Consumed and removed by `applyPlayerEffects` before any other normalisation
58555
+ // Consumed and removed by `applyPlayerEffects` before any other normalization
58345
58556
  // (see `createAnimatorImpl`), so downstream code never sees it.
58346
58557
  effects: PxEffectsSchema.optional(),
58347
58558
  // `PxElementAnimation` (not just `PxAnimationDefinition`) — accepts
@@ -58525,7 +58736,7 @@ ${codeFrame}` : message);
58525
58736
  if (nameLower.startsWith("on")) return true;
58526
58737
  return false;
58527
58738
  }
58528
- function sanitiseAttributeValue(name, value) {
58739
+ function sanitizeAttributeValue(name, value) {
58529
58740
  const nameLower = name.toLowerCase();
58530
58741
  if (isDangerousAttrName(nameLower)) {
58531
58742
  console.warn("Attribute blocked (event handler / dangerous): ", nameLower);
@@ -58564,7 +58775,7 @@ ${codeFrame}` : message);
58564
58775
  if (INTERNAL_ATTRS.has(key)) continue;
58565
58776
  if (key === "style") continue;
58566
58777
  let value = props[rawKey];
58567
- if (COLOUR_ATTR_NAMES.has(key) && Array.isArray(value)) {
58778
+ if (COLOR_ATTR_NAMES.has(key) && Array.isArray(value)) {
58568
58779
  propsCopy[key] = toRGBA(value);
58569
58780
  } else if (key === "transform" && value !== null && typeof value === "object" && !Array.isArray(value) && !value.keyframes) {
58570
58781
  const parts = value.value && typeof value.value === "object" ? value.value : value;
@@ -58664,7 +58875,7 @@ ${codeFrame}` : message);
58664
58875
  var DEFAULT_FLATNESS_TOL = 0.5;
58665
58876
  var DEFAULT_ROTATION_TOL = 5;
58666
58877
  var DEFAULT_MAX_SAMPLES = 32;
58667
- function materialiseMotionPathInPropAnim(anim, opts) {
58878
+ function materializeMotionPathInPropAnim(anim, opts) {
58668
58879
  var _a2, _b, _c;
58669
58880
  if (!propAnimIsMotionPath(anim)) return anim;
58670
58881
  const kfs = anim.keyframes;
@@ -58696,7 +58907,7 @@ ${codeFrame}` : message);
58696
58907
  if (autoOrient && i > 0) {
58697
58908
  insertSharpCornerStepKfIfNeeded(out, prevKf, nextKf, prevPos, nextPos, rotationTol);
58698
58909
  }
58699
- materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
58910
+ materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples);
58700
58911
  }
58701
58912
  const lastInE = getKfEasing(kfs[kfs.length - 1]);
58702
58913
  if (lastInE) out[out.length - 1].e = lastInE;
@@ -58810,7 +59021,7 @@ ${codeFrame}` : message);
58810
59021
  out.push(makeOutKf(stepTime, dupValue));
58811
59022
  }
58812
59023
  var CORNER_STEP_AFTER_BOUNDARY_MS = 0.05;
58813
- function materialiseSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
59024
+ function materializeSegment(out, prevKf, nextKf, prevPos, nextPos, autoOrient, flatnessTol, rotationTol, maxSamples) {
58814
59025
  const seg = getSegmentCache(prevKf, nextKf, prevPos, nextPos);
58815
59026
  const prevTime = getKfTime(prevKf);
58816
59027
  const nextTime = getKfTime(nextKf);
@@ -58933,16 +59144,16 @@ ${codeFrame}` : message);
58933
59144
  const cross = (q[0] - pA[0]) * dy - (q[1] - pA[1]) * dx;
58934
59145
  return Math.abs(cross) / Math.sqrt(len2);
58935
59146
  }
58936
- function materialiseMotionPathsInTree(root, opts) {
58937
- const out = walkAndMaterialise(root, opts);
59147
+ function materializeMotionPathsInTree(root, opts) {
59148
+ const out = walkAndMaterialize(root, opts);
58938
59149
  return out != null ? out : root;
58939
59150
  }
58940
- function walkAndMaterialise(node, opts) {
59151
+ function walkAndMaterialize(node, opts) {
58941
59152
  let newChildren;
58942
59153
  if (node.children) {
58943
59154
  for (let i = 0; i < node.children.length; i++) {
58944
59155
  const ch = node.children[i];
58945
- const ret = walkAndMaterialise(ch, opts);
59156
+ const ret = walkAndMaterialize(ch, opts);
58946
59157
  if (ret !== null) {
58947
59158
  if (!newChildren) newChildren = node.children.slice();
58948
59159
  newChildren[i] = ret;
@@ -58955,9 +59166,9 @@ ${codeFrame}` : message);
58955
59166
  const animDef = animBucket;
58956
59167
  const transformAnim = animDef.transform;
58957
59168
  if (transformAnim && typeof transformAnim === "object" && propAnimIsMotionPath(transformAnim)) {
58958
- const materialised = materialiseMotionPathInPropAnim(transformAnim, opts);
58959
- if (materialised !== transformAnim) {
58960
- newAnimate = __spreadProps2(__spreadValues2({}, animDef), { transform: materialised });
59169
+ const materialized = materializeMotionPathInPropAnim(transformAnim, opts);
59170
+ if (materialized !== transformAnim) {
59171
+ newAnimate = __spreadProps2(__spreadValues2({}, animDef), { transform: materialized });
58961
59172
  }
58962
59173
  }
58963
59174
  }
@@ -59058,8 +59269,8 @@ ${codeFrame}` : message);
59058
59269
  return typeof value === "string" && extractPathData(value) !== void 0;
59059
59270
  }
59060
59271
  function normalizePathValue(value) {
59061
- if (value && typeof value === "object" && typeof value.path === "string") {
59062
- const d = extractPathData(value.path);
59272
+ if (value && typeof value === "object" && typeof value.pathData === "string") {
59273
+ const d = extractPathData(value.pathData);
59063
59274
  return d ? { paths: parseSvgPathToBezier(d) } : value;
59064
59275
  }
59065
59276
  if (value && typeof value === "object" && "paths" in value) {
@@ -59143,7 +59354,7 @@ ${codeFrame}` : message);
59143
59354
  const bPaths = (_b = b == null ? void 0 : b.paths) != null ? _b : Array.isArray(b) ? b : [];
59144
59355
  return { paths: interpolateBeziers(aPaths, bPaths, t) };
59145
59356
  }
59146
- if (COLOUR_ATTR_NAMES.has(propName)) {
59357
+ if (COLOR_ATTR_NAMES.has(propName)) {
59147
59358
  return interpolateColor(a || [0, 0, 0, 1], b || [0, 0, 0, 1], t);
59148
59359
  }
59149
59360
  if (propName === "transform" && typeof a === "object" && a !== null && !Array.isArray(a) && typeof b === "object" && b !== null && !Array.isArray(b)) {
@@ -59365,7 +59576,7 @@ ${codeFrame}` : message);
59365
59576
  value = normalizePathValue(value);
59366
59577
  }
59367
59578
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
59368
- if (COLOUR_ATTR_NAMES.has(propNameKebab)) {
59579
+ if (COLOR_ATTR_NAMES.has(propNameKebab)) {
59369
59580
  value = (_a2 = parseColor(value)) != null ? _a2 : value;
59370
59581
  }
59371
59582
  const normKf = {
@@ -59399,20 +59610,20 @@ ${codeFrame}` : message);
59399
59610
  }
59400
59611
  return merged;
59401
59612
  }
59402
- function materialiseInternalLoopsInPropAnim(propName, propAnim, duration) {
59613
+ function materializeInternalLoopsInPropAnim(propName, propAnim, duration) {
59403
59614
  const loopRaw = propAnim.loop;
59404
59615
  if (loopRaw === void 0 || loopRaw === null || loopRaw === false) return propAnim;
59405
59616
  const loop = loopRaw === true ? {} : loopRaw;
59406
59617
  const rawKfs = propAnim.keyframes;
59407
59618
  if (!Array.isArray(rawKfs) || rawKfs.length < 2) return propAnim;
59408
59619
  const propNameKebab = isCamelCaseWord(propName) ? camelCaseToKebabWordIfNeeded(propName) : propName;
59409
- const isColour = COLOUR_ATTR_NAMES.has(propNameKebab);
59620
+ const isColor = COLOR_ATTR_NAMES.has(propNameKebab);
59410
59621
  const kfs = rawKfs.map((kf) => {
59411
59622
  var _a2;
59412
59623
  const t = kfTime(kf);
59413
59624
  let v = kfValue(kf);
59414
59625
  if (propName === "d") v = normalizePathValue(v);
59415
- if (isColour) v = (_a2 = parseColor(v)) != null ? _a2 : v;
59626
+ if (isColor) v = (_a2 = parseColor(v)) != null ? _a2 : v;
59416
59627
  const e = kfEasing(kf);
59417
59628
  const out2 = { t, v, e };
59418
59629
  const tIn = kfTangentIn(kf);
@@ -59426,15 +59637,15 @@ ${codeFrame}` : message);
59426
59637
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
59427
59638
  return out;
59428
59639
  }
59429
- function materialiseInternalLoopsInTree(root, duration) {
59430
- const ret = walkAndMaterialiseLoops(root, duration);
59640
+ function materializeInternalLoopsInTree(root, duration) {
59641
+ const ret = walkAndMaterializeLoops(root, duration);
59431
59642
  return ret != null ? ret : root;
59432
59643
  }
59433
- function walkAndMaterialiseLoops(node, duration) {
59644
+ function walkAndMaterializeLoops(node, duration) {
59434
59645
  let newChildren;
59435
59646
  if (node.children) {
59436
59647
  for (let i = 0; i < node.children.length; i++) {
59437
- const ret = walkAndMaterialiseLoops(node.children[i], duration);
59648
+ const ret = walkAndMaterializeLoops(node.children[i], duration);
59438
59649
  if (ret !== null) {
59439
59650
  if (!newChildren) newChildren = node.children.slice();
59440
59651
  newChildren[i] = ret;
@@ -59447,10 +59658,10 @@ ${codeFrame}` : message);
59447
59658
  const animDef = animBucket;
59448
59659
  for (const propName of Object.keys(animDef)) {
59449
59660
  const propAnim = animDef[propName];
59450
- const materialised = materialiseInternalLoopsInPropAnim(propName, propAnim, duration);
59451
- if (materialised !== propAnim) {
59661
+ const materialized = materializeInternalLoopsInPropAnim(propName, propAnim, duration);
59662
+ if (materialized !== propAnim) {
59452
59663
  if (!newAnimate) newAnimate = __spreadValues2({}, animDef);
59453
- newAnimate[propName] = materialised;
59664
+ newAnimate[propName] = materialized;
59454
59665
  }
59455
59666
  }
59456
59667
  }
@@ -59505,12 +59716,12 @@ ${codeFrame}` : message);
59505
59716
  const out = { keyframes: normalizedKfs };
59506
59717
  if (propAnim.autoOrient !== void 0) out.autoOrient = propAnim.autoOrient;
59507
59718
  if (propAnim.loop !== void 0) out.loop = propAnim.loop;
59508
- normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materialiseMotionPathInPropAnim(out) : out;
59719
+ normalized[propName] = engine === PxTimelineEngine.native && propName === "transform" ? materializeMotionPathInPropAnim(out) : out;
59509
59720
  }
59510
59721
  }
59511
59722
  return normalized;
59512
59723
  }
59513
- function getNormalisedBindings(doc, engine = PxTimelineEngine.native) {
59724
+ function getNormalizedBindings(doc, engine = PxTimelineEngine.native) {
59514
59725
  const animatorConfig = getAnimatorConfig(doc) || {};
59515
59726
  const defs = getDefs(doc);
59516
59727
  const duration = animatorConfig.duration || 1e3;
@@ -59601,7 +59812,7 @@ ${codeFrame}` : message);
59601
59812
  nextPaths,
59602
59813
  localProgress
59603
59814
  ).map((bz) => bezierToSvgPath(bz)).join("");
59604
- } else if (COLOUR_ATTR_NAMES.has(cssAttrName)) {
59815
+ } else if (COLOR_ATTR_NAMES.has(cssAttrName)) {
59605
59816
  cssValue = toRGBA(interpolateColor(
59606
59817
  prevV || [0, 0, 0, 1],
59607
59818
  nextV || [0, 0, 0, 1],
@@ -59759,7 +59970,7 @@ ${codeFrame}` : message);
59759
59970
  }
59760
59971
  return gNode;
59761
59972
  }
59762
- function materialiseAnimatedUseInstances(root) {
59973
+ function materializeAnimatedUseInstances(root) {
59763
59974
  var _a2;
59764
59975
  const idMap = buildIdMap(root);
59765
59976
  const animatedIds = computeAnimatedSubtreeIds(root, idMap);
@@ -59768,7 +59979,7 @@ ${codeFrame}` : message);
59768
59979
  const genId3 = () => "_lw_use_mat_" + ++idCounter;
59769
59980
  const rootViewport = readRootViewport(root);
59770
59981
  const defsCollector = [];
59771
- const walked = walkAndMaterialise2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
59982
+ const walked = walkAndMaterialize2(root, idMap, animatedIds, genId3, defsCollector, rootViewport);
59772
59983
  if (defsCollector.length === 0) return walked;
59773
59984
  const defsNode = { type: "defs", children: defsCollector };
59774
59985
  const newChildren = [...(_a2 = walked.children) != null ? _a2 : [], defsNode];
@@ -59841,7 +60052,7 @@ ${codeFrame}` : message);
59841
60052
  if (typeof href !== "string") return void 0;
59842
60053
  return href.startsWith("#") ? href.slice(1) : href;
59843
60054
  }
59844
- function materialiseOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
60055
+ function materializeOneUse(useNode, target, idMap, animatedIds, genId3, defsCollector, rootViewport) {
59845
60056
  var _a2, _b, _c, _d;
59846
60057
  const clone2 = deepClonePxNode(target);
59847
60058
  regenerateIdsAndRewriteRefs(clone2, genId3);
@@ -59849,8 +60060,8 @@ ${codeFrame}` : message);
59849
60060
  const useW = (_b = (_a2 = numericAttr(useNode.width)) != null ? _a2 : symbolViewBox == null ? void 0 : symbolViewBox[2]) != null ? _b : rootViewport[0];
59850
60061
  const useH = (_d = (_c = numericAttr(useNode.height)) != null ? _c : symbolViewBox == null ? void 0 : symbolViewBox[3]) != null ? _d : rootViewport[1];
59851
60062
  const rewrittenClone = clone2.type === "symbol" ? rewriteSymbolRootToGroup(clone2, genId3, defsCollector, useW, useH) : clone2;
59852
- const materialisedClone = walkAndMaterialise2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
59853
- const newNode = __spreadProps2(__spreadValues2({}, useNode), { type: "g", children: [materialisedClone] });
60063
+ const materializedClone = walkAndMaterialize2(rewrittenClone, idMap, animatedIds, genId3, defsCollector, rootViewport);
60064
+ const newNode = __spreadProps2(__spreadValues2({}, useNode), { type: "g", children: [materializedClone] });
59854
60065
  delete newNode.href;
59855
60066
  delete newNode.width;
59856
60067
  delete newNode.height;
@@ -59888,18 +60099,18 @@ ${codeFrame}` : message);
59888
60099
  if (parts.length < 4 || parts.some((n) => !Number.isFinite(n))) return void 0;
59889
60100
  return [parts[0], parts[1], parts[2], parts[3]];
59890
60101
  }
59891
- function walkAndMaterialise2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
60102
+ function walkAndMaterialize2(node, idMap, animatedIds, genId3, defsCollector, rootViewport) {
59892
60103
  if (node.type === "use" && typeof node.href === "string") {
59893
60104
  const targetId = stripHash(node.href);
59894
60105
  if (targetId && animatedIds.has(targetId)) {
59895
60106
  const target = idMap.get(targetId);
59896
- if (target) return materialiseOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
60107
+ if (target) return materializeOneUse(node, target, idMap, animatedIds, genId3, defsCollector, rootViewport);
59897
60108
  }
59898
60109
  }
59899
60110
  if (!node.children) return node;
59900
60111
  let changed = false;
59901
60112
  const newChildren = node.children.map((ch) => {
59902
- const m = walkAndMaterialise2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
60113
+ const m = walkAndMaterialize2(ch, idMap, animatedIds, genId3, defsCollector, rootViewport);
59903
60114
  if (m !== ch) changed = true;
59904
60115
  return m;
59905
60116
  });
@@ -59925,7 +60136,7 @@ ${codeFrame}` : message);
59925
60136
  const obj = raw;
59926
60137
  const kfs = obj.keyframes;
59927
60138
  if (kfs) {
59928
- const out = { kind: "animated", keyframes: kfs.map(normaliseKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
60139
+ const out = { kind: "animated", keyframes: kfs.map(normalizeKeyframe), autoOrient: obj.autoOrient, loop: obj.loop };
59929
60140
  const base = (_a2 = obj.value) != null ? _a2 : obj.v;
59930
60141
  if (base !== void 0 && out.kind === "animated") out.base = base;
59931
60142
  return out;
@@ -59953,7 +60164,7 @@ ${codeFrame}` : message);
59953
60164
  const baseline = (_d = (_b = read.base) != null ? _b : (_a2 = read.keyframes[0]) == null ? void 0 : _a2.value) != null ? _d : (_c = read.keyframes[0]) == null ? void 0 : _c.v;
59954
60165
  if (baseline !== void 0) node[attrName] = toOut(baseline);
59955
60166
  }
59956
- function normaliseKeyframe(kf) {
60167
+ function normalizeKeyframe(kf) {
59957
60168
  if (!kf || typeof kf !== "object") return kf;
59958
60169
  const k = kf;
59959
60170
  if (k.t === void 0 && k.v === void 0 && k.e === void 0 && k.to === void 0 && k.ti === void 0) {
@@ -60455,10 +60666,10 @@ ${codeFrame}` : message);
60455
60666
  return pct + "%";
60456
60667
  }
60457
60668
  function applyClipPathEffect(node, fx, ctx) {
60458
- if (!(fx == null ? void 0 : fx.d)) return node;
60669
+ if (!(fx == null ? void 0 : fx.pathData)) return node;
60459
60670
  const clipId = genId(ctx, "clip");
60460
60671
  const pathChild = { type: "path" };
60461
- const read = readAnimatable(fx.d);
60672
+ const read = readAnimatable(fx.pathData);
60462
60673
  if (read.kind !== "absent") {
60463
60674
  if (read.kind === "static") {
60464
60675
  pathChild.d = pathString(read.value);
@@ -60473,7 +60684,7 @@ ${codeFrame}` : message);
60473
60684
  }
60474
60685
  function pathString(v) {
60475
60686
  if (typeof v === "string") return v;
60476
- if (v && typeof v === "object" && typeof v.path === "string") return v.path;
60687
+ if (v && typeof v === "object" && typeof v.pathData === "string") return v.pathData;
60477
60688
  return void 0;
60478
60689
  }
60479
60690
  function applyMaskedByEffect(node, fx, transformBy, ctx) {
@@ -60518,8 +60729,8 @@ ${codeFrame}` : message);
60518
60729
  }
60519
60730
  function wrapInversePart(inner, part, raw, origin, ctx) {
60520
60731
  if (raw === void 0) return inner;
60521
- const normalisedRaw = part === "scale" && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
60522
- const v = readAnimatable(normalisedRaw);
60732
+ const normalizedRaw = part === "scale" && Array.isArray(raw) ? [raw[0] / 100, raw[1] / 100] : raw;
60733
+ const v = readAnimatable(normalizedRaw);
60523
60734
  if (v.kind === "static") {
60524
60735
  return { type: "g", transform: { value: partsRecord(part, invertPartValue(part, v.value), origin) }, children: [inner] };
60525
60736
  }
@@ -60914,7 +61125,7 @@ ${codeFrame}` : message);
60914
61125
  const scalePower = (v) => [Math.pow(v[0], i), Math.pow(v[1], i)];
60915
61126
  return mapAnimatable(raw, scalePower, true);
60916
61127
  }
60917
- var RETIME_MATERIALISATION_MODE_INLINE_G = false;
61128
+ var RETIME_MATERIALIZATION_MODE_INLINE_G = false;
60918
61129
  function asRetime(r) {
60919
61130
  var _a2, _b;
60920
61131
  return { start: (_a2 = r.start) != null ? _a2 : 0, stretch: (_b = r.stretch) != null ? _b : 1 };
@@ -60999,11 +61210,11 @@ ${codeFrame}` : message);
60999
61210
  if (!retime) continue;
61000
61211
  const crop = retime.timeCrop;
61001
61212
  clearCloneRetime(useNode);
61002
- materialiseRetime(useNode, asRetime(retime), ctx);
61213
+ materializeRetime(useNode, asRetime(retime), ctx);
61003
61214
  if (crop) applyTimeCrop(useNode, crop, ctx);
61004
61215
  }
61005
61216
  }
61006
- function materialiseRetime(useNode, retime, ctx) {
61217
+ function materializeRetime(useNode, retime, ctx) {
61007
61218
  const targetId = stripHash2(useNode.href);
61008
61219
  if (!targetId) {
61009
61220
  ctx.errors.push("retime: <use> has no href to follow");
@@ -61011,7 +61222,7 @@ ${codeFrame}` : message);
61011
61222
  }
61012
61223
  const chainRootId = buildChainClone(targetId, retime, ctx, /* @__PURE__ */ new Set());
61013
61224
  if (!chainRootId) return;
61014
- if (RETIME_MATERIALISATION_MODE_INLINE_G) {
61225
+ if (RETIME_MATERIALIZATION_MODE_INLINE_G) {
61015
61226
  const cloneNode = ctx.idMap.get(chainRootId);
61016
61227
  useNode.type = "g";
61017
61228
  delete useNode.href;
@@ -61051,13 +61262,13 @@ ${codeFrame}` : message);
61051
61262
  if (subId2) cloneNode.href = "#" + subId2;
61052
61263
  }
61053
61264
  } else {
61054
- materialiseNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
61265
+ materializeNestedRetimeUses(cloneNode, accum, ctx, chain, targetId);
61055
61266
  }
61056
61267
  ctx.defs.push(cloneNode);
61057
61268
  if (typeof cloneNode.id === "string") ctx.idMap.set(cloneNode.id, cloneNode);
61058
61269
  return typeof cloneNode.id === "string" ? cloneNode.id : void 0;
61059
61270
  }
61060
- function materialiseNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
61271
+ function materializeNestedRetimeUses(node, accum, ctx, chain, parentTargetId) {
61061
61272
  const visit = (n) => {
61062
61273
  var _a2;
61063
61274
  const retime = readCloneRetime(n);
@@ -61254,10 +61465,10 @@ ${codeFrame}` : message);
61254
61465
  function estimateTextAdvance(node) {
61255
61466
  let chars = 0, maxFont = 16;
61256
61467
  const walk = (el) => {
61257
- var _a2, _b;
61468
+ var _a2;
61258
61469
  const fs = parseFloat(String((_a2 = el.fontSize) != null ? _a2 : "")) || 0;
61259
61470
  if (fs) maxFont = Math.max(maxFont, fs);
61260
- const t = (_b = el.text) != null ? _b : el.textContent;
61471
+ const t = el.textContent;
61261
61472
  if (typeof t === "string") chars += t.length;
61262
61473
  if (el.children) for (const c of el.children) walk(c);
61263
61474
  };
@@ -61406,7 +61617,6 @@ ${codeFrame}` : message);
61406
61617
  "stroke",
61407
61618
  "strokeWidth",
61408
61619
  "effects",
61409
- TEXT_ATTR,
61410
61620
  TEXT_CONTENT_ATTR,
61411
61621
  "xml:space"
61412
61622
  ];
@@ -61516,8 +61726,8 @@ ${codeFrame}` : message);
61516
61726
  const ix0 = x0 + t, ix1 = x1 - t, iyb = -t, iyt = y1 + t;
61517
61727
  return outer + "M" + ix0 + " " + iyb + "L" + ix0 + " " + iyt + "L" + ix1 + " " + iyt + "L" + ix1 + " " + iyb + "Z";
61518
61728
  }
61519
- function materialiseGlyphTextHorizontal(node, opts) {
61520
- var _a2, _b, _c, _d;
61729
+ function materializeGlyphTextHorizontal(node, opts) {
61730
+ var _a2, _b, _c;
61521
61731
  const { glyphs, create = jsonElementFactory, warnings } = opts;
61522
61732
  const soleFont = soleFontOf(glyphs);
61523
61733
  const pen = { x: (_a2 = parseLen(node.x)) != null ? _a2 : 0, y: (_b = parseLen(node.y)) != null ? _b : 0 };
@@ -61534,8 +61744,8 @@ ${codeFrame}` : message);
61534
61744
  for (let i = 0; i < content.length; i++) {
61535
61745
  const ch = content.charAt(i);
61536
61746
  const g = gf == null ? void 0 : gf.glyphs[ch];
61537
- if (g && g.d) {
61538
- placements.push({ glyphD: g.d, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
61747
+ if (g && g.pathData) {
61748
+ placements.push({ glyphD: g.pathData, m: [scale, 0, 0, scale, pen.x, pen.y], paint, line, x: pen.x, y: pen.y, scale });
61539
61749
  pen.x += g.width * scale;
61540
61750
  } else if (/\S/.test(ch)) {
61541
61751
  const advEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * upm;
@@ -61549,7 +61759,7 @@ ${codeFrame}` : message);
61549
61759
  }
61550
61760
  };
61551
61761
  const walk = (el, parentStyle) => {
61552
- var _a3, _b2, _c2, _d2;
61762
+ var _a3, _b2, _c2;
61553
61763
  const s = resolveStyle2(el, parentStyle);
61554
61764
  const x = parseLen(el.x);
61555
61765
  const y = parseLen(el.y);
@@ -61561,14 +61771,14 @@ ${codeFrame}` : message);
61561
61771
  if (y !== void 0) pen.y = y;
61562
61772
  pen.x += (_a3 = parseLen(el.dx)) != null ? _a3 : 0;
61563
61773
  pen.y += (_b2 = parseLen(el.dy)) != null ? _b2 : 0;
61564
- const content = (_c2 = str(el[TEXT_CONTENT_ATTR])) != null ? _c2 : str(el[TEXT_ATTR]);
61565
- if (content && !((_d2 = el.children) == null ? void 0 : _d2.length)) renderChars(content, s);
61774
+ const content = str(el[TEXT_CONTENT_ATTR]);
61775
+ if (content && !((_c2 = el.children) == null ? void 0 : _c2.length)) renderChars(content, s);
61566
61776
  if (el.children) for (const ch of el.children) walk(ch, s);
61567
61777
  };
61568
61778
  const rootStyle = rootStyleOf(node);
61569
61779
  if (node.children) for (const ch of node.children) walk(ch, rootStyle);
61570
- const rootContent = (_c = str(node[TEXT_CONTENT_ATTR])) != null ? _c : str(node[TEXT_ATTR]);
61571
- if (rootContent && !((_d = node.children) == null ? void 0 : _d.length)) renderChars(rootContent, rootStyle);
61780
+ const rootContent = str(node[TEXT_CONTENT_ATTR]);
61781
+ if (rootContent && !((_c = node.children) == null ? void 0 : _c.length)) renderChars(rootContent, rootStyle);
61572
61782
  const anchor = str(node.textAnchor);
61573
61783
  if (anchor === "middle" || anchor === "end") {
61574
61784
  for (const p of placements) {
@@ -61583,21 +61793,21 @@ ${codeFrame}` : message);
61583
61793
  const cells = [];
61584
61794
  let adv = 0;
61585
61795
  const walk = (el, parentStyle) => {
61586
- var _a2, _b, _c;
61796
+ var _a2, _b;
61587
61797
  const s = resolveStyle2(el, parentStyle);
61588
- const content = (_a2 = str(el[TEXT_CONTENT_ATTR])) != null ? _a2 : str(el[TEXT_ATTR]);
61589
- if (content && !((_b = el.children) == null ? void 0 : _b.length)) {
61798
+ const content = str(el[TEXT_CONTENT_ATTR]);
61799
+ if (content && !((_a2 = el.children) == null ? void 0 : _a2.length)) {
61590
61800
  const gf = glyphFontFor(s, glyphs, soleFont, warnings);
61591
61801
  if (gf) {
61592
61802
  const scale = s.fontSize / gf.unitsPerEm;
61593
- const ascentEm = (_c = gf.ascent) != null ? _c : 0.9 * gf.unitsPerEm;
61803
+ const ascentEm = (_b = gf.ascent) != null ? _b : 0.9 * gf.unitsPerEm;
61594
61804
  const paint = paintOf(s);
61595
61805
  for (let i = 0; i < content.length; i++) {
61596
61806
  const ch = content.charAt(i);
61597
61807
  const g = gf.glyphs[ch];
61598
- if (g && g.d) {
61808
+ if (g && g.pathData) {
61599
61809
  const glyphAdv = g.width * scale;
61600
- cells.push({ glyphD: g.d, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
61810
+ cells.push({ glyphD: g.pathData, widthEm: g.width, scale, paint, midBase: adv + glyphAdv / 2 });
61601
61811
  adv += glyphAdv;
61602
61812
  } else if (/\S/.test(ch)) {
61603
61813
  const wEm = g && g.width > 0 ? g.width : MISSING_GLYPH_ADVANCE_EM * gf.unitsPerEm;
@@ -61628,7 +61838,7 @@ ${codeFrame}` : message);
61628
61838
  perp: (_c = parseLen(node.dy)) != null ? _c : 0
61629
61839
  };
61630
61840
  }
61631
- function materialiseGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
61841
+ function materializeGlyphTextAlongPath(node, pathD, startOffset, opts, textLength, pathOverflow) {
61632
61842
  const { glyphs, create = jsonElementFactory, warnings } = opts;
61633
61843
  const sampler = pathD ? createPathSampler(pathD) : null;
61634
61844
  if (!sampler) {
@@ -61707,8 +61917,8 @@ ${codeFrame}` : message);
61707
61917
  const onPath = (dist) => dist >= 0 && dist <= sampler.totalLength;
61708
61918
  const out = [];
61709
61919
  for (const c of cells) {
61710
- const centred = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
61711
- const d = transformPathData(c.glyphD, centred);
61920
+ const centered = [c.scale, 0, 0, c.scale, -c.scale * (c.widthEm / 2), 0];
61921
+ const d = transformPathData(c.glyphD, centered);
61712
61922
  const sampleKf = (dist, time) => {
61713
61923
  const { x, y, angle } = sampler.sampleAtDistance(dist);
61714
61924
  const cos = Math.cos(angle), sin = Math.sin(angle);
@@ -61812,14 +62022,14 @@ ${codeFrame}` : message);
61812
62022
  ctx.warnings.push("textGlyphs: no definitions.fonts \u2014 left as native <text>");
61813
62023
  return node;
61814
62024
  }
61815
- return materialiseGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
62025
+ return materializeGlyphTextHorizontal(node, { glyphs: ctx.glyphs, warnings: ctx.warnings });
61816
62026
  }
61817
62027
  function applyTextGlyphsAlongPath(node, ctx, pathD, startOffset, textLength, pathOverflow) {
61818
62028
  if (!ctx.glyphs) {
61819
62029
  ctx.warnings.push("textGlyphs: no definitions.fonts");
61820
62030
  return null;
61821
62031
  }
61822
- return materialiseGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
62032
+ return materializeGlyphTextAlongPath(node, pathD, startOffset, { glyphs: ctx.glyphs, warnings: ctx.warnings }, textLength, pathOverflow);
61823
62033
  }
61824
62034
  function applyStrokeTrimEffect(node, strokeTrim, ctx) {
61825
62035
  if (!strokeTrim) return node;
@@ -62281,7 +62491,7 @@ ${codeFrame}` : message);
62281
62491
  }
62282
62492
  return { pathStr: d, distanceKfs, autoOrient: !!propAnim.autoOrient, anchor };
62283
62493
  }
62284
- function materialiseOffsetPathsInTree(root) {
62494
+ function materializeOffsetPathsInTree(root) {
62285
62495
  const walk = (node) => {
62286
62496
  var _a2;
62287
62497
  let out = node;
@@ -62324,15 +62534,15 @@ ${codeFrame}` : message);
62324
62534
  };
62325
62535
  return walk(root);
62326
62536
  }
62327
- function materialiseAllInTree(doc, engine, opts) {
62537
+ function materializeAllInTree(doc, engine, opts) {
62328
62538
  var _a2, _b;
62329
62539
  let root = applyPlayerEffects(doc).root;
62330
- root = materialiseOffsetPathsInTree(root);
62540
+ root = materializeOffsetPathsInTree(root);
62331
62541
  const duration = (_b = (_a2 = getAnimatorConfig(root)) == null ? void 0 : _a2.duration) != null ? _b : DEFAULT_DURATION_MS;
62332
- root = materialiseInternalLoopsInTree(root, duration);
62542
+ root = materializeInternalLoopsInTree(root, duration);
62333
62543
  if (engine === PxTimelineEngine.native) {
62334
- root = materialiseMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
62335
- root = materialiseAnimatedUseInstances(root);
62544
+ root = materializeMotionPathsInTree(root, opts == null ? void 0 : opts.motionPath);
62545
+ root = materializeAnimatedUseInstances(root);
62336
62546
  root = pruneUnreferencedDefs(root);
62337
62547
  }
62338
62548
  return root;
@@ -62366,6 +62576,38 @@ ${codeFrame}` : message);
62366
62576
  }
62367
62577
  return root;
62368
62578
  }
62579
+ var PX_RATE_REJECTED = "setPlaybackRate: rate must be finite and non-zero";
62580
+ function isValidPlaybackRate(rate) {
62581
+ return Number.isFinite(rate) && rate !== 0;
62582
+ }
62583
+ function seekCeilingMs(durationMs, iterations) {
62584
+ if (!(durationMs > 0)) return 0;
62585
+ if (iterations === Infinity) return Infinity;
62586
+ return durationMs * (iterations > 0 ? iterations : 1);
62587
+ }
62588
+ function progressSpanMs(durationMs, iterations) {
62589
+ if (!(durationMs > 0)) return 0;
62590
+ if (iterations === Infinity) return durationMs;
62591
+ return durationMs * (iterations > 0 ? iterations : 1);
62592
+ }
62593
+ function clampSeekMs(timeMs, ceilingMs) {
62594
+ if (Number.isNaN(timeMs) || timeMs < 0) return 0;
62595
+ if (Number.isFinite(ceilingMs)) return timeMs > ceilingMs ? ceilingMs : timeMs;
62596
+ return Number.isFinite(timeMs) ? timeMs : 0;
62597
+ }
62598
+ function timeToProgress(timeMs, durationMs, iterations) {
62599
+ const span = progressSpanMs(durationMs, iterations);
62600
+ if (!(span > 0) || !Number.isFinite(timeMs)) return 0;
62601
+ if (timeMs <= 0) return 0;
62602
+ if (iterations === Infinity) return timeMs % span / span;
62603
+ return timeMs >= span ? 1 : timeMs / span;
62604
+ }
62605
+ function progressToTimeMs(progress, durationMs, iterations) {
62606
+ const span = progressSpanMs(durationMs, iterations);
62607
+ if (!(span > 0) || !Number.isFinite(progress)) return 0;
62608
+ if (progress <= 0) return 0;
62609
+ return progress >= 1 ? span : progress * span;
62610
+ }
62369
62611
  function requestFrame(cb) {
62370
62612
  const g = globalThis;
62371
62613
  if (typeof g.requestAnimationFrame === "function") return g.requestAnimationFrame(cb);
@@ -62382,7 +62624,7 @@ ${codeFrame}` : message);
62382
62624
  function createBasicFrameLoopAnimator(doc, adapter, callbacks) {
62383
62625
  var _a2;
62384
62626
  const config = getAnimatorConfig(doc) || {};
62385
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.js);
62627
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.js);
62386
62628
  const _iterations = config.iterations;
62387
62629
  let iterations = 1;
62388
62630
  if (typeof _iterations === "number") iterations = _iterations || 1;
@@ -62612,8 +62854,8 @@ ${codeFrame}` : message);
62612
62854
  finishAnim(true);
62613
62855
  },
62614
62856
  "setPlaybackRate": (rate) => {
62615
- if (!isFinite(rate) || rate === 0) {
62616
- console.warn("setPlaybackRate: rate must be finite and non-zero");
62857
+ if (!isValidPlaybackRate(rate)) {
62858
+ console.warn(PX_RATE_REJECTED);
62617
62859
  return;
62618
62860
  }
62619
62861
  let current = getRawAnimTime();
@@ -62627,13 +62869,16 @@ ${codeFrame}` : message);
62627
62869
  return getAnimCurrentTime();
62628
62870
  },
62629
62871
  "setCurrentTime": (newTime) => {
62630
- if (newTime < 0) newTime = 0;
62631
- if (Number.isFinite(totalDuration) && newTime > totalDuration) newTime = totalDuration;
62872
+ newTime = clampSeekMs(newTime, totalDuration);
62632
62873
  timeBeforeLastStartMs = newTime;
62633
62874
  if (playing) lastStartedTs = Date.now();
62634
62875
  if (!Number.isFinite(totalDuration) || newTime < totalDuration) finishCalled = false;
62635
62876
  renderFrame(getAnimCurrentTime());
62636
62877
  },
62878
+ "getCurrentProgress": () => timeToProgress(getAnimCurrentTime(), duration, iterations),
62879
+ "setCurrentProgress": (progress) => {
62880
+ api.setCurrentTime(progressToTimeMs(progress, duration, iterations));
62881
+ },
62637
62882
  "destroy": () => {
62638
62883
  var _a3;
62639
62884
  api.cancel();
@@ -62642,6 +62887,49 @@ ${codeFrame}` : message);
62642
62887
  };
62643
62888
  return api;
62644
62889
  }
62890
+ var PxDiagnosticKind = {
62891
+ /** The document is wrong — regenerate or repair the file. */
62892
+ document: "document",
62893
+ /** The page or app cannot provide what the document asks for — fix the mount. */
62894
+ host: "host",
62895
+ /** The platform cannot do it and the player degraded — usually nothing to fix. */
62896
+ platform: "platform",
62897
+ /** The call is wrong or self-contradictory — fix the options or props you passed. */
62898
+ usage: "usage",
62899
+ /** The player failed where it did not expect to — report it to us. */
62900
+ internal: "internal"
62901
+ };
62902
+ function asError(error) {
62903
+ return typeof error === "string" ? new Error(error) : error;
62904
+ }
62905
+ function isSilenced(silent, kind) {
62906
+ if (!silent) return false;
62907
+ return silent === true || silent.includes(kind);
62908
+ }
62909
+ function createDiagnostics(config, prefix) {
62910
+ const tag = prefix ? prefix + " " : "";
62911
+ return {
62912
+ warn: (kind, message, detail) => {
62913
+ if (config == null ? void 0 : config.onWarn) {
62914
+ config.onWarn({ kind, message, detail });
62915
+ return;
62916
+ }
62917
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
62918
+ const line = tag + kind + ": " + message;
62919
+ if (detail === void 0) console.warn(line);
62920
+ else console.warn(line, detail);
62921
+ },
62922
+ error: (kind, error) => {
62923
+ const err = asError(error);
62924
+ if (config == null ? void 0 : config.onError) {
62925
+ config.onError({ kind, message: err.message, error: err });
62926
+ return;
62927
+ }
62928
+ if (isSilenced(config == null ? void 0 : config.silent, kind)) return;
62929
+ console.error(tag + kind + ": " + err.message);
62930
+ }
62931
+ };
62932
+ }
62645
62933
  var FLAT_ONLY_KEYS = [
62646
62934
  "timelineSource",
62647
62935
  "scroll",
@@ -62704,32 +62992,30 @@ ${codeFrame}` : message);
62704
62992
  }
62705
62993
  return merged;
62706
62994
  }
62707
- function foldAnimatorConfigShortcuts(config, shortcuts) {
62995
+ function foldTimelineOverride(timeline, shortcuts) {
62708
62996
  let base;
62709
- if (typeof config === "string") {
62997
+ if (typeof timeline === "string") {
62710
62998
  try {
62711
- base = JSON.parse(config);
62999
+ base = JSON.parse(timeline);
62712
63000
  } catch (e) {
62713
- console.warn("animator config: not valid JSON \u2014 ignored", e);
63001
+ console.warn("timeline override: not valid JSON \u2014 ignored", e);
62714
63002
  base = void 0;
62715
63003
  }
62716
63004
  } else {
62717
- base = config != null ? config : void 0;
63005
+ base = timeline != null ? timeline : void 0;
62718
63006
  }
62719
63007
  const { duration, delay, iterations, startOn } = shortcuts;
62720
63008
  if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
62721
- return base;
63009
+ return base === void 0 ? void 0 : { timeline: base };
62722
63010
  }
62723
63011
  const out = isPlainObject(base) ? __spreadValues2({}, base) : {};
62724
- const timeline = __spreadValues2({}, out.timeline);
62725
- if (duration !== void 0) timeline.duration = duration;
62726
- if (delay !== void 0) timeline.delay = delay;
62727
- if (iterations !== void 0) timeline.iterations = iterations;
63012
+ if (duration !== void 0) out.duration = duration;
63013
+ if (delay !== void 0) out.delay = delay;
63014
+ if (iterations !== void 0) out.iterations = iterations;
62728
63015
  if (startOn !== void 0) {
62729
- timeline.trigger = __spreadProps2(__spreadValues2({}, timeline.trigger), { startOn });
63016
+ out.trigger = __spreadProps2(__spreadValues2({}, out.trigger), { startOn });
62730
63017
  }
62731
- out.timeline = timeline;
62732
- return out;
63018
+ return { timeline: out };
62733
63019
  }
62734
63020
  function mergeAnimatorConfig(base, patch) {
62735
63021
  const warnings = [];
@@ -62795,26 +63081,12 @@ ${codeFrame}` : message);
62795
63081
  return { doc: __spreadProps2(__spreadValues2({}, anyDoc), { animator: merged.config }), warnings };
62796
63082
  }
62797
63083
  var MAX_REPORTED = 6;
62798
- var LEGACY_FLAT_KEYS = [
62799
- ...PX_TIMELINE_SHARED_KEYS,
62800
- ...PX_TIME_ONLY_TIMELINE_KEYS,
62801
- "fill",
62802
- "resetOnFinish",
62803
- "timelineSource",
62804
- "scroll"
62805
- ];
62806
- var isLegacyFlatAnimatorKey = (w) => LEGACY_FLAT_KEYS.some((k) => w.indexOf("animator." + k + ":") >= 0);
62807
63084
  function diagnoseDocument(doc) {
62808
- let all;
62809
63085
  try {
62810
- all = validateDocument(doc);
63086
+ return { problems: validateDocument(doc) };
62811
63087
  } catch (e) {
62812
- return { problems: [], legacy: [] };
63088
+ return { problems: [] };
62813
63089
  }
62814
- const problems = [];
62815
- const legacy = [];
62816
- for (const w of all) (isLegacyFlatAnimatorKey(w) ? legacy : problems).push(w);
62817
- return { problems, legacy };
62818
63090
  }
62819
63091
  function reportDocumentDiagnostics(doc, where) {
62820
63092
  const { problems } = diagnoseDocument(doc);
@@ -62825,12 +63097,34 @@ ${codeFrame}` : message);
62825
63097
  where + ": this document does not match the animation schema in " + problems.length + " place" + (problems.length === 1 ? "" : "s") + ".\n" + shown.map((p) => " - " + p).join("\n") + (more > 0 ? "\n \u2026 and " + more + " more" : "") + "\n\nIf you did not author these keys, the usual cause is a build that MANGLES PROPERTY NAMES. An animation document is data loaded at runtime, so renaming the property reads inside the player stops them matching the keys in the JSON, and the animation silently does nothing. Feed the published reserved-name list to your minifier \u2014 @pixodesk/svg-animator-web/mangle-reserved.json \u2014 see docs/library/minification.md."
62826
63098
  );
62827
63099
  }
62828
- function setupAnimationTriggers(api, config) {
62829
- const { startOn, outAction = "continue", scrollIntoViewThreshold = 0 } = config;
63100
+ function toEngineCallbacks(inline) {
63101
+ const { onPlay, onPause, onCancel, onFinish, onRemove, onStop, onWarn, onError, silent } = inline != null ? inline : {};
63102
+ const withStop = (own) => own || onStop ? () => {
63103
+ own == null ? void 0 : own();
63104
+ onStop == null ? void 0 : onStop();
63105
+ } : void 0;
63106
+ return {
63107
+ onPlay,
63108
+ onPause: withStop(onPause),
63109
+ onCancel: withStop(onCancel),
63110
+ onFinish: withStop(onFinish),
63111
+ onRemove: withStop(onRemove),
63112
+ onWarn,
63113
+ onError,
63114
+ silent
63115
+ };
63116
+ }
63117
+ function setupAnimationTriggers(api, config, diag) {
63118
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
63119
+ const cleanups = [];
63120
+ const dispose = () => {
63121
+ for (const undo of cleanups.splice(0)) undo();
63122
+ };
63123
+ const { startOn, outAction, scrollIntoViewThreshold } = resolveTrigger(config);
62830
63124
  const root = api.getRootElement();
62831
63125
  if (!root) {
62832
- console.warn("setupAnimationTriggers: No root element found for animation.");
62833
- return api;
63126
+ report.warn(PxDiagnosticKind.host, "setupAnimationTriggers: No root element found for animation.");
63127
+ return dispose;
62834
63128
  }
62835
63129
  let reversed = false;
62836
63130
  const start = () => {
@@ -62865,6 +63159,7 @@ ${codeFrame}` : message);
62865
63159
  startHandler();
62866
63160
  } else {
62867
63161
  window.addEventListener("load", startHandler, { once: true });
63162
+ cleanups.push(() => window.removeEventListener("load", startHandler));
62868
63163
  }
62869
63164
  break;
62870
63165
  }
@@ -62879,6 +63174,10 @@ ${codeFrame}` : message);
62879
63174
  };
62880
63175
  root.addEventListener("mouseenter", mouseOverHandler);
62881
63176
  root.addEventListener("mouseleave", mouseOutHandler);
63177
+ cleanups.push(() => {
63178
+ root.removeEventListener("mouseenter", mouseOverHandler);
63179
+ root.removeEventListener("mouseleave", mouseOutHandler);
63180
+ });
62882
63181
  break;
62883
63182
  }
62884
63183
  case "click": {
@@ -62890,6 +63189,7 @@ ${codeFrame}` : message);
62890
63189
  }
62891
63190
  };
62892
63191
  root.addEventListener("click", clickHandler);
63192
+ cleanups.push(() => root.removeEventListener("click", clickHandler));
62893
63193
  break;
62894
63194
  }
62895
63195
  case "scrollIntoView": {
@@ -62921,46 +63221,53 @@ ${codeFrame}` : message);
62921
63221
  { threshold: thresholdSteps }
62922
63222
  );
62923
63223
  observer.observe(root);
63224
+ cleanups.push(() => observer.disconnect());
62924
63225
  break;
62925
63226
  }
62926
63227
  case "programmatic":
62927
63228
  break;
62928
63229
  }
62929
- return api;
63230
+ return dispose;
62930
63231
  }
62931
63232
  function getSelector(id) {
62932
63233
  return "#" + id;
62933
63234
  }
62934
63235
  function createFrameLoopAnimator(doc, adapter, callbacks, rootElement) {
63236
+ var _a2;
62935
63237
  const config = getAnimatorConfig(doc) || {};
63238
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
62936
63239
  if (!rootElement) {
62937
63240
  if (doc.id) {
62938
63241
  const rootSelector = getSelector(doc.id);
62939
63242
  rootElement = document.querySelector(rootSelector);
62940
- if (!rootElement) console.warn("createFrameLoopAnimator: No root element found for selector: ", rootSelector);
63243
+ if (!rootElement) diag.warn(PxDiagnosticKind.host, "createFrameLoopAnimator: No root element found for selector: " + rootSelector);
62941
63244
  } else {
62942
- console.warn("createFrameLoopAnimator: No root element provided");
63245
+ diag.warn(PxDiagnosticKind.host, "createFrameLoopAnimator: No root element provided");
62943
63246
  }
62944
63247
  }
62945
63248
  const basicApi = createBasicFrameLoopAnimator(
62946
63249
  doc,
62947
- adapter || createDomAdapter(rootElement),
63250
+ adapter || createDomAdapter(rootElement, diag),
62948
63251
  callbacks
62949
63252
  );
62950
63253
  const api = __spreadProps(__spreadValues({}, basicApi), {
62951
63254
  "getRootElement": () => rootElement || null
62952
63255
  });
62953
- if (config.trigger) {
62954
- if (isScrollTimeline(config)) {
62955
- console.warn("scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
62956
- } else {
62957
- setupAnimationTriggers(api, config.trigger);
62958
- }
63256
+ if (isScrollTimeline(config)) {
63257
+ if (config.trigger) diag.warn(PxDiagnosticKind.usage, "scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
63258
+ } else {
63259
+ const detachTriggers = setupAnimationTriggers(api, (_a2 = config.trigger) != null ? _a2 : {}, diag);
63260
+ const destroyEngine = api.destroy.bind(api);
63261
+ api.destroy = () => {
63262
+ detachTriggers();
63263
+ destroyEngine();
63264
+ };
62959
63265
  }
62960
63266
  return api;
62961
63267
  }
62962
- function createDomAdapter(rootElement) {
63268
+ function createDomAdapter(rootElement, diag) {
62963
63269
  const warnedSelectors = /* @__PURE__ */ new Set();
63270
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
62964
63271
  const adapter = {
62965
63272
  isConnected: () => {
62966
63273
  if (!rootElement) return true;
@@ -62972,7 +63279,7 @@ ${codeFrame}` : message);
62972
63279
  const elements = (rootElement == null ? void 0 : rootElement.querySelectorAll(selector)) || document.querySelectorAll(selector);
62973
63280
  if (elements.length === 0 && !warnedSelectors.has(selector)) {
62974
63281
  warnedSelectors.add(selector);
62975
- console.warn('setAttribute: No elements found for selector "' + selector + '"');
63282
+ report.warn(PxDiagnosticKind.host, 'setAttribute: No elements found for selector "' + selector + '"');
62976
63283
  }
62977
63284
  for (let i = 0; i < elements.length; i++) {
62978
63285
  const element = elements[i];
@@ -62995,7 +63302,7 @@ ${codeFrame}` : message);
62995
63302
  };
62996
63303
  let cssValue;
62997
63304
  let cssKey = propName;
62998
- if (COLOUR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
63305
+ if (COLOR_ATTR_NAMES.has(propName) && Array.isArray(value)) {
62999
63306
  cssValue = toRGBA(value);
63000
63307
  } else if (propName === "transform" && value !== null && typeof value === "object" && !Array.isArray(value)) {
63001
63308
  cssValue = composeTransformParts(value, { withUnits: true });
@@ -63082,18 +63389,19 @@ ${codeFrame}` : message);
63082
63389
  return result;
63083
63390
  }
63084
63391
  function createWebApiAnimator(doc, callbacks, rootElement, forceEvenIfHasUnsupportedAttrs, scrollTimeline) {
63085
- var _a2;
63392
+ var _a2, _b;
63086
63393
  const config = getAnimatorConfig(doc) || {};
63394
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
63087
63395
  if (!rootElement) {
63088
63396
  if (doc.id) {
63089
63397
  const rootSelector = getSelector(doc.id);
63090
63398
  rootElement = document.querySelector(rootSelector);
63091
- if (!rootElement) console.warn("createFrameLoopAnimator: No root element found for selector: ", rootSelector);
63399
+ if (!rootElement) diag.warn(PxDiagnosticKind.host, "createWebApiAnimator: No root element found for selector: " + rootSelector);
63092
63400
  } else {
63093
- console.warn("createFrameLoopAnimator: No root element provided");
63401
+ diag.warn(PxDiagnosticKind.host, "createWebApiAnimator: No root element provided");
63094
63402
  }
63095
63403
  }
63096
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.native);
63404
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.native);
63097
63405
  const animations = [];
63098
63406
  const _iterations = config.iterations;
63099
63407
  let iterations;
@@ -63103,18 +63411,18 @@ ${codeFrame}` : message);
63103
63411
  let finishNotified = false;
63104
63412
  let removeCalled = false;
63105
63413
  if (!(bindings == null ? void 0 : bindings.length)) {
63106
- console.warn("createWebApiAnimator: No animation bindings defined");
63414
+ diag.warn(PxDiagnosticKind.document, "createWebApiAnimator: No animation bindings defined");
63107
63415
  }
63108
63416
  for (const binding of bindings || []) {
63109
63417
  const animDef = binding.animate;
63110
63418
  if (!animDef || typeof animDef !== "object" || Array.isArray(animDef)) {
63111
- console.warn("createWebApiAnimator: Empty or unresolved binding", binding);
63419
+ diag.warn(PxDiagnosticKind.document, "createWebApiAnimator: Empty or unresolved binding", binding);
63112
63420
  continue;
63113
63421
  }
63114
63422
  const selector = getSelector(binding.id);
63115
63423
  const elements = (rootElement == null ? void 0 : rootElement.querySelectorAll(selector)) || document.querySelectorAll(selector);
63116
63424
  if (elements.length === 0) {
63117
- console.warn('createWebApiAnimator: No elements found for selector "' + selector + '"');
63425
+ diag.warn(PxDiagnosticKind.host, 'createWebApiAnimator: No elements found for selector "' + selector + '"');
63118
63426
  }
63119
63427
  const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
63120
63428
  const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
@@ -63163,14 +63471,14 @@ ${codeFrame}` : message);
63163
63471
  }
63164
63472
  animations.push(anim);
63165
63473
  } catch (e) {
63166
- console.warn(e);
63474
+ diag.warn(PxDiagnosticKind.internal, "createWebApiAnimator: could not build the animation", e);
63167
63475
  }
63168
63476
  }
63169
63477
  }
63170
63478
  }
63171
63479
  }
63172
63480
  if (!forceEvenIfHasUnsupportedAttrs && unsupportedSet.size) {
63173
- console.warn("Unsupported CSS attrs: " + [...unsupportedSet].join(", "));
63481
+ diag.warn(PxDiagnosticKind.platform, "Unsupported CSS attrs: " + [...unsupportedSet].join(", "));
63174
63482
  return null;
63175
63483
  }
63176
63484
  const api = {
@@ -63214,20 +63522,36 @@ ${codeFrame}` : message);
63214
63522
  }
63215
63523
  },
63216
63524
  "setPlaybackRate": (rate) => {
63525
+ if (!isValidPlaybackRate(rate)) {
63526
+ diag.warn(PxDiagnosticKind.usage, PX_RATE_REJECTED);
63527
+ return api;
63528
+ }
63217
63529
  animations.forEach((a) => a.playbackRate = rate);
63218
63530
  return api;
63219
63531
  },
63220
63532
  "getCurrentTime": () => {
63221
- var _a3, _b;
63222
- const res = (_b = (_a3 = animations[0]) == null ? void 0 : _a3.currentTime) != null ? _b : null;
63533
+ var _a3, _b2;
63534
+ const res = (_b2 = (_a3 = animations[0]) == null ? void 0 : _a3.currentTime) != null ? _b2 : null;
63223
63535
  return res !== null ? +res : null;
63224
63536
  },
63225
63537
  "setCurrentTime": (time) => {
63538
+ var _a3;
63539
+ const ceiling = seekCeilingMs((_a3 = config.duration) != null ? _a3 : 0, iterations != null ? iterations : 1);
63540
+ const seek = ceiling > 0 ? clampSeekMs(time, ceiling) : Math.max(0, time);
63226
63541
  finishNotified = false;
63227
63542
  animations.forEach((a) => {
63228
- a.currentTime = time;
63543
+ a.currentTime = seek;
63229
63544
  });
63230
63545
  },
63546
+ "getCurrentProgress": () => {
63547
+ var _a3;
63548
+ const t = api.getCurrentTime();
63549
+ return t === null ? null : timeToProgress(t, (_a3 = config.duration) != null ? _a3 : 0, iterations != null ? iterations : 1);
63550
+ },
63551
+ "setCurrentProgress": (progress) => {
63552
+ var _a3;
63553
+ api.setCurrentTime(progressToTimeMs(progress, (_a3 = config.duration) != null ? _a3 : 0, iterations != null ? iterations : 1));
63554
+ },
63231
63555
  "destroy": () => {
63232
63556
  var _a3;
63233
63557
  api.cancel();
@@ -63238,12 +63562,15 @@ ${codeFrame}` : message);
63238
63562
  }
63239
63563
  }
63240
63564
  };
63241
- if (config.trigger) {
63242
- if (config.timelineSource === "scroll") {
63243
- console.warn("scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
63244
- } else {
63245
- setupAnimationTriggers(api, config.trigger);
63246
- }
63565
+ if (config.timelineSource === "scroll") {
63566
+ if (config.trigger) diag.warn(PxDiagnosticKind.usage, "scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
63567
+ } else {
63568
+ const detachTriggers = setupAnimationTriggers(api, (_b = config.trigger) != null ? _b : {}, diag);
63569
+ const destroyEngine = api.destroy.bind(api);
63570
+ api.destroy = () => {
63571
+ detachTriggers();
63572
+ destroyEngine();
63573
+ };
63247
63574
  }
63248
63575
  if (scrollTimeline) {
63249
63576
  animations.forEach((a) => a.play());
@@ -63257,13 +63584,14 @@ ${codeFrame}` : message);
63257
63584
  if (pct === void 0) return void 0;
63258
63585
  return view ? { rangeName: (_c = point == null ? void 0 : point.phase) != null ? _c : "cover", offset: pct } : { offset: pct };
63259
63586
  }
63260
- function createNativeScrollTimeline(subject, config) {
63587
+ function createNativeScrollTimeline(subject, config, diag) {
63261
63588
  var _a2, _b, _c, _d;
63589
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
63262
63590
  if (!config || !isScrollTimeline(config)) return null;
63263
63591
  const scroll = config.scroll || {};
63264
63592
  const kind = (_a2 = scroll.kind) != null ? _a2 : "view";
63265
63593
  if (scroll.smoothing) {
63266
- console.warn("scroll timeline: `smoothing` needs the built-in driver \u2014 using the built-in driver instead of the browser timeline");
63594
+ report.warn(PxDiagnosticKind.platform, "scroll timeline: `smoothing` needs the built-in driver \u2014 using the built-in driver instead of the browser timeline");
63267
63595
  return null;
63268
63596
  }
63269
63597
  const g = globalThis;
@@ -63274,13 +63602,13 @@ ${codeFrame}` : message);
63274
63602
  let timeline;
63275
63603
  try {
63276
63604
  if (view) {
63277
- timeline = new Ctor({ subject: resolveScrollSubject(subject, scroll.subject), axis });
63605
+ timeline = new Ctor({ subject: resolveScrollSubject(subject, scroll.subject, report), axis });
63278
63606
  } else {
63279
63607
  const source = scroll.source === "root" ? documentScroller() : findNearestScroller(subject, "y") || findNearestScroller(subject, "x") || documentScroller();
63280
63608
  timeline = new Ctor({ source, axis });
63281
63609
  }
63282
63610
  } catch (e) {
63283
- console.warn("scroll timeline: native timeline construction failed \u2014 falling back to the player measuring progress itself", e);
63611
+ report.warn(PxDiagnosticKind.platform, "scroll timeline: native timeline construction failed \u2014 falling back to the player measuring progress itself", e);
63284
63612
  return null;
63285
63613
  }
63286
63614
  return {
@@ -63307,8 +63635,9 @@ ${codeFrame}` : message);
63307
63635
  }
63308
63636
  var SUBJECT_PARENT = "parent";
63309
63637
  var SUBJECT_SCROLLER = "scroller";
63310
- function resolveScrollSubject(svgRoot, subject) {
63638
+ function resolveScrollSubject(svgRoot, subject, diag) {
63311
63639
  var _a2, _b;
63640
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
63312
63641
  const spec = subject == null ? void 0 : subject.trim();
63313
63642
  if (!spec) return svgRoot;
63314
63643
  if (spec === SUBJECT_PARENT) {
@@ -63326,21 +63655,22 @@ ${codeFrame}` : message);
63326
63655
  try {
63327
63656
  found = document.querySelector(spec);
63328
63657
  } catch (e) {
63329
- console.warn('scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
63658
+ report.warn(PxDiagnosticKind.document, 'scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
63330
63659
  return svgRoot;
63331
63660
  }
63332
63661
  if (!found) {
63333
- console.warn('scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
63662
+ report.warn(PxDiagnosticKind.host, 'scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
63334
63663
  return svgRoot;
63335
63664
  }
63336
63665
  return found;
63337
63666
  }
63338
- function createScrollDriver(subject, config, onProgress) {
63667
+ function createScrollDriver(subject, config, onProgress, diag) {
63339
63668
  var _a2, _b;
63340
63669
  if (!config || !isScrollTimeline(config)) return null;
63670
+ const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
63341
63671
  const scroll = config.scroll || {};
63342
63672
  const kind = (_a2 = scroll.kind) != null ? _a2 : "view";
63343
- const measured = resolveScrollSubject(subject, scroll.subject);
63673
+ const measured = resolveScrollSubject(subject, scroll.subject, report);
63344
63674
  const nearest = findNearestScroller(subject, "y") || findNearestScroller(subject, "x");
63345
63675
  const scroller = kind === "scroll" && scroll.source === "root" ? documentScroller() : nearest || documentScroller();
63346
63676
  const isRootScroller = scroller === documentScroller();
@@ -63459,7 +63789,7 @@ ${codeFrame}` : message);
63459
63789
  const alignFactor = scroll.pinAlign === "center" ? 0.5 : scroll.pinAlign === "bottom" ? 1 : 0;
63460
63790
  const applyTop = () => {
63461
63791
  var _a2;
63462
- const extra = (_a2 = scroll.pinTop) != null ? _a2 : 0;
63792
+ const extra = (_a2 = scroll.pinOffset) != null ? _a2 : 0;
63463
63793
  if (!alignFactor) {
63464
63794
  style.top = extra + "px";
63465
63795
  return;
@@ -63519,6 +63849,7 @@ ${codeFrame}` : message);
63519
63849
  }
63520
63850
  function bindWithEngineChoice(doc, adapter, callbacks, rootElement) {
63521
63851
  const animatorConfig = getAnimatorConfig(doc) || {};
63852
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
63522
63853
  if (isScrollTimeline(animatorConfig)) {
63523
63854
  return finaliseAnimator(animatorConfig, callbacks, (cb) => {
63524
63855
  var _a2;
@@ -63526,7 +63857,7 @@ ${codeFrame}` : message);
63526
63857
  };
63527
63858
  if (mayUseNativeScrollTimeline(animatorConfig.engine) && rootElement) {
63528
63859
  unpin = applyScrollPin(rootElement, animatorConfig.scroll);
63529
- const native = createNativeScrollTimeline(rootElement, animatorConfig);
63860
+ const native = createNativeScrollTimeline(rootElement, animatorConfig, diag);
63530
63861
  if (native) {
63531
63862
  const api2 = createWebApiAnimator(
63532
63863
  doc,
@@ -63556,7 +63887,8 @@ ${codeFrame}` : message);
63556
63887
  const driver = createScrollDriver(
63557
63888
  subject,
63558
63889
  animatorConfig,
63559
- (progress) => api.setCurrentTime(progress * totalMs)
63890
+ (progress) => api.setCurrentTime(progress * totalMs),
63891
+ diag
63560
63892
  );
63561
63893
  if (driver) {
63562
63894
  const destroy = api.destroy.bind(api);
@@ -63567,7 +63899,7 @@ ${codeFrame}` : message);
63567
63899
  };
63568
63900
  }
63569
63901
  } else {
63570
- console.warn("scroll timeline: no root element to observe \u2014 animation will stay at frame 0");
63902
+ diag.warn(PxDiagnosticKind.host, "scroll timeline: no root element to observe \u2014 animation will stay at frame 0");
63571
63903
  }
63572
63904
  return api;
63573
63905
  });
@@ -63585,35 +63917,36 @@ ${codeFrame}` : message);
63585
63917
  });
63586
63918
  }
63587
63919
  var SVG_NS = "http://www.w3.org/2000/svg";
63588
- function createElement(tagName, normalisedProps, style, children, textContent) {
63920
+ function createElement(tagName, normalizedProps, style, children, textContent, diag) {
63589
63921
  if (DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
63590
- console.warn("SVG tag blocked (dangerous): ", tagName);
63922
+ (diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]")).warn(PxDiagnosticKind.document, "SVG tag blocked (dangerous): " + tagName);
63591
63923
  return null;
63592
63924
  }
63593
63925
  const element = document.createElementNS(SVG_NS, tagName);
63594
- for (const propName in normalisedProps) {
63595
- const sanitised = sanitiseAttributeValue(propName, normalisedProps[propName]);
63596
- if (sanitised === void 0) continue;
63926
+ for (const propName in normalizedProps) {
63927
+ const sanitized = sanitizeAttributeValue(propName, normalizedProps[propName]);
63928
+ if (sanitized === void 0) continue;
63597
63929
  if (CSS_ONLY_STYLE_PROPS.has(propName)) {
63598
- element.style[propName] = String(sanitised);
63930
+ element.style[propName] = String(sanitized);
63599
63931
  continue;
63600
63932
  }
63601
- element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitised);
63933
+ element.setAttribute(camelCaseToKebabWordIfNeeded(propName), sanitized);
63602
63934
  }
63603
63935
  if (style) {
63604
63936
  for (const styleProp in style) {
63605
63937
  element.style[styleProp] = String(style[styleProp]);
63606
63938
  }
63607
63939
  }
63608
- if (children) {
63940
+ if (children == null ? void 0 : children.length) {
63609
63941
  for (const child of children) {
63610
63942
  element.appendChild(child);
63611
63943
  }
63944
+ } else if (textContent) {
63945
+ element.textContent = textContent;
63612
63946
  }
63613
- if (textContent) element.textContent = textContent;
63614
63947
  return element;
63615
63948
  }
63616
- function renderNode(node, defs) {
63949
+ function renderNode(node, defs, diag) {
63617
63950
  if (!node) return null;
63618
63951
  const _a2 = node, { type, children, style } = _a2, props = __objRest(_a2, ["type", "children", "style"]);
63619
63952
  const domType = props.domType;
@@ -63623,7 +63956,7 @@ ${codeFrame}` : message);
63623
63956
  let childElements;
63624
63957
  if (children) {
63625
63958
  for (const ch of children) {
63626
- const child = renderNode(ch, nodeDefs);
63959
+ const child = renderNode(ch, nodeDefs, diag);
63627
63960
  if (child) {
63628
63961
  if (!childElements) childElements = [];
63629
63962
  childElements.push(child);
@@ -63635,7 +63968,8 @@ ${codeFrame}` : message);
63635
63968
  getNormalizedProps(props),
63636
63969
  resolvedStyle,
63637
63970
  childElements,
63638
- props[TEXT_CONTENT_ATTR] || props[TEXT_ATTR]
63971
+ props[TEXT_CONTENT_ATTR],
63972
+ diag
63639
63973
  );
63640
63974
  if (element && domType !== void 0) element.setAttribute("type", domType);
63641
63975
  return element;
@@ -63643,24 +63977,25 @@ ${codeFrame}` : message);
63643
63977
  function createAnimatorFromConfig(doc, adapter, callbacks, rootElement) {
63644
63978
  return bindWithEngineChoice(doc, adapter, callbacks, rootElement);
63645
63979
  }
63646
- function createAnimatorImpl(doc, adapter, callbacks, containerElement, config, resetDocDefaults) {
63980
+ function createAnimatorImpl(doc, adapter, callbacks, containerElement, patch, resetTimeline) {
63981
+ const diag = createDiagnostics(callbacks, "[PxAnimator]");
63647
63982
  const effectsWarnings = validateNodeEffects(doc);
63648
- for (const w of effectsWarnings) console.warn("[PxAnimator] effects shape warning:", w);
63983
+ for (const w of effectsWarnings) diag.warn(PxDiagnosticKind.document, "effects shape: " + w);
63649
63984
  reportDocumentDiagnostics(doc, "[PxAnimator] createAnimator");
63650
- if (config !== void 0 || resetDocDefaults) {
63651
- const patched = applyAnimatorConfig(doc, config != null ? config : {}, { resetDefaults: !!resetDocDefaults });
63652
- for (const w of patched.warnings) console.warn("[PxAnimator] config override:", w);
63985
+ if (patch !== void 0 || resetTimeline) {
63986
+ const patched = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetDefaults: !!resetTimeline });
63987
+ for (const w of patched.warnings) diag.warn(PxDiagnosticKind.usage, "timeline override: " + w);
63653
63988
  doc = patched.doc;
63654
63989
  }
63655
63990
  const animatorConfig = getAnimatorConfig(doc) || {};
63656
63991
  const engine = resolveTimelineEngine(animatorConfig.engine);
63657
- doc = materialiseAllInTree(doc, engine);
63992
+ doc = materializeAllInTree(doc, engine);
63658
63993
  let rootElement = null;
63659
63994
  if (containerElement) {
63660
63995
  doc = generateNewIds(doc);
63661
63996
  const containerEl = typeof containerElement === "string" ? document.querySelector(containerElement) : containerElement;
63662
63997
  if (containerEl) {
63663
- rootElement = renderNode(doc);
63998
+ rootElement = renderNode(doc, void 0, diag);
63664
63999
  if (rootElement) {
63665
64000
  containerEl.replaceChildren(rootElement);
63666
64001
  }
@@ -63677,21 +64012,22 @@ ${codeFrame}` : message);
63677
64012
  }
63678
64013
  return api;
63679
64014
  }
63680
- function resolveAnimatorConfigOption(options) {
63681
- const { config, duration, delay, iterations, startOn } = options;
63682
- return foldAnimatorConfigShortcuts(config, { duration, delay, iterations, startOn });
64015
+ function resolveTimelineOption(options) {
64016
+ const { timeline, duration, delay, iterations, startOn } = options;
64017
+ return foldTimelineOverride(timeline, { duration, delay, iterations, startOn });
63683
64018
  }
63684
64019
  function createAnimator(options) {
63685
- const { src, data, adapter, callbacks, container, resetDocDefaults } = options;
63686
- const config = resolveAnimatorConfigOption(options);
63687
- if (data !== void 0 && src !== void 0) {
63688
- throw new Error("createAnimator: provide either `src` or `data`, not both");
64020
+ const { src, doc, adapter, container, resetTimeline } = options;
64021
+ const patch = resolveTimelineOption(options);
64022
+ const callbacks = toEngineCallbacks(options);
64023
+ if (doc !== void 0 && src !== void 0) {
64024
+ throw new Error("createAnimator: provide either `src` or `doc`, not both");
63689
64025
  }
63690
- if (data === void 0 && src === void 0) {
63691
- throw new Error("createAnimator: either `src` or `data` is required");
64026
+ if (doc === void 0 && src === void 0) {
64027
+ throw new Error("createAnimator: either `src` or `doc` is required");
63692
64028
  }
63693
- if (data !== void 0) {
63694
- return createAnimatorImpl(data, adapter, callbacks, container, config, resetDocDefaults);
64029
+ if (doc !== void 0) {
64030
+ return createAnimatorImpl(doc, adapter, callbacks, container, patch, resetTimeline);
63695
64031
  }
63696
64032
  let animator = null;
63697
64033
  let pending = [];
@@ -63703,19 +64039,27 @@ ${codeFrame}` : message);
63703
64039
  pending.push(call);
63704
64040
  }
63705
64041
  };
64042
+ const loadDiag = createDiagnostics(callbacks, "[PxAnimator]");
63706
64043
  fetch(src).then((res) => res.json()).then((json) => {
63707
64044
  if (destroyed) return;
63708
64045
  if (isPxElementFileFormat(json)) {
63709
- animator = createAnimatorImpl(json, adapter, callbacks, container, config, resetDocDefaults);
64046
+ animator = createAnimatorImpl(json, adapter, callbacks, container, patch, resetTimeline);
63710
64047
  const queued = pending;
63711
64048
  pending = null;
63712
64049
  queued == null ? void 0 : queued.forEach((call) => call(animator));
63713
64050
  } else {
63714
- console.error('createAnimator: invalid animation document format at "' + src + '"');
64051
+ loadDiag.error(
64052
+ PxDiagnosticKind.document,
64053
+ 'createAnimator: invalid animation document format at "' + src + '"'
64054
+ );
63715
64055
  }
63716
64056
  }).catch((err) => {
64057
+ var _a2;
63717
64058
  pending = null;
63718
- console.error('createAnimator: failed to load "' + src + '"', err);
64059
+ loadDiag.error(
64060
+ PxDiagnosticKind.host,
64061
+ 'createAnimator: failed to load "' + src + '" \u2014 ' + ((_a2 = err == null ? void 0 : err.message) != null ? _a2 : String(err))
64062
+ );
63719
64063
  });
63720
64064
  return {
63721
64065
  "isReady": () => !!animator,
@@ -63740,6 +64084,10 @@ ${codeFrame}` : message);
63740
64084
  "setCurrentTime": (time) => {
63741
64085
  enqueue((api) => api.setCurrentTime(time));
63742
64086
  },
64087
+ "getCurrentProgress": () => animator ? animator.getCurrentProgress() : null,
64088
+ "setCurrentProgress": (progress) => {
64089
+ enqueue((api) => api.setCurrentProgress(progress));
64090
+ },
63743
64091
  "destroy": () => {
63744
64092
  destroyed = true;
63745
64093
  pending = null;
@@ -63747,23 +64095,6 @@ ${codeFrame}` : message);
63747
64095
  }
63748
64096
  };
63749
64097
  }
63750
- function loadTagAnimators() {
63751
- const elements = document.querySelectorAll("[" + PX_ANIM_SRC_ATTR_NAME + "]");
63752
- for (let i = 0; i < elements.length; i++) {
63753
- const element = elements[i];
63754
- if (!element[PX_ANIM_ATTR_NAME]) {
63755
- const src = element.getAttribute(PX_ANIM_SRC_ATTR_NAME);
63756
- if (src) {
63757
- element[PX_ANIM_ATTR_NAME] = createAnimator({ src, container: element });
63758
- }
63759
- }
63760
- }
63761
- }
63762
- if (typeof window !== "undefined") {
63763
- window["loadTagAnimators"] = loadTagAnimators;
63764
- window["createAnimator"] = createAnimator;
63765
- window["setupAnimationTriggers"] = setupAnimationTriggers;
63766
- }
63767
64098
 
63768
64099
  // ../../node_modules/.pnpm/vue@3.5.28_typescript@5.9.3/node_modules/vue/index.mjs
63769
64100
  var vue_exports = {};
@@ -63771,7 +64102,7 @@ ${codeFrame}` : message);
63771
64102
 
63772
64103
  // src/PixodeskSvgAnimator.ts
63773
64104
  var VUE_PROP = { ref: "ref" };
63774
- function createVueAdapter(elementRefs) {
64105
+ function createVueAdapter(elementRefs, diag) {
63775
64106
  const warnedSelectors = /* @__PURE__ */ new Set();
63776
64107
  const adapter = {
63777
64108
  isConnected: () => true,
@@ -63780,7 +64111,7 @@ ${codeFrame}` : message);
63780
64111
  const element = elementRefs.get(id);
63781
64112
  if (!element && !warnedSelectors.has(id)) {
63782
64113
  warnedSelectors.add(id);
63783
- console.warn('setAttribute: No elements found for id "' + id + '"');
64114
+ diag.warn(PxDiagnosticKind.host, 'setAttribute: No elements found for id "' + id + '"');
63784
64115
  }
63785
64116
  if (element) {
63786
64117
  element.setAttribute(attrName, value);
@@ -63792,19 +64123,19 @@ ${codeFrame}` : message);
63792
64123
  };
63793
64124
  return adapter;
63794
64125
  }
63795
- function applyDocOverrides(doc, props, compMode) {
63796
- const { config, resetDocDefaults, duration, delay, iterations, startOn } = props;
63797
- const patch = foldAnimatorConfigShortcuts(config, { duration, delay, iterations, startOn });
63798
- const fullPatch = compMode !== "autoplay" /* autoplay */ ? {
64126
+ function applyDocOverrides(doc, props, compMode, diag) {
64127
+ const { timeline, resetTimeline, duration, delay, iterations, startOn } = props;
64128
+ const patch = foldTimelineOverride(timeline, { duration, delay, iterations, startOn });
64129
+ const fullPatch = controlModeTakesOverTrigger(compMode) ? {
63799
64130
  ...patch ?? {},
63800
64131
  timeline: {
63801
64132
  ...patch?.timeline ?? {},
63802
64133
  trigger: { ...patch?.timeline?.trigger ?? {}, startOn: "programmatic" }
63803
64134
  }
63804
64135
  } : patch;
63805
- if (fullPatch !== void 0 || resetDocDefaults) {
63806
- const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetDefaults: !!resetDocDefaults });
63807
- for (const w of applied.warnings) console.warn("[PixodeskSvgAnimator] config override:", w);
64136
+ if (fullPatch !== void 0 || resetTimeline) {
64137
+ const applied = applyAnimatorConfig(doc, fullPatch ?? {}, { resetDefaults: !!resetTimeline });
64138
+ for (const w of applied.warnings) diag.warn(PxDiagnosticKind.usage, "timeline override: " + w);
63808
64139
  doc = applied.doc;
63809
64140
  }
63810
64141
  return doc;
@@ -63814,9 +64145,9 @@ ${codeFrame}` : message);
63814
64145
  const animator = getAnimatorConfig(doc) || {};
63815
64146
  if (props.progress !== void 0) {
63816
64147
  const iterationsValue = props.iterations ?? animator.iterations;
63817
- const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
63818
- const singleDuration = props.duration ?? animator.duration ?? 1e3;
63819
- seekMs = props.progress * singleDuration * iterationsCount;
64148
+ const iterationsCount = iterationsValue === "infinite" ? Infinity : typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
64149
+ const singleDuration = props.duration ?? animator.duration ?? DEFAULT_DURATION_MS;
64150
+ seekMs = progressToTimeMs(props.progress, singleDuration, iterationsCount);
63820
64151
  }
63821
64152
  if (props.time !== void 0) seekMs = props.time;
63822
64153
  return seekMs;
@@ -63826,10 +64157,10 @@ ${codeFrame}` : message);
63826
64157
  props: {
63827
64158
  // -- Source
63828
64159
  doc: { type: Object, required: true },
63829
- // -- Playback override: one object spelled exactly like `animator` in the file,
63830
- // plus the four shortcuts people reach for most.
63831
- config: { type: [Object, String] },
63832
- resetDocDefaults: { type: Boolean, default: void 0 },
64160
+ // -- Playback override: the document's `timeline` block as a patch (or a JSON string),
64161
+ // plus the four shortcuts people reach for most. The same names as React / RN.
64162
+ timeline: { type: [Object, String] },
64163
+ resetTimeline: { type: Boolean, default: void 0 },
63833
64164
  duration: { type: Number },
63834
64165
  delay: { type: Number },
63835
64166
  iterations: { type: [Number, String] },
@@ -63840,21 +64171,41 @@ ${codeFrame}` : message);
63840
64171
  pause: { type: Boolean, default: void 0 },
63841
64172
  // -- Controlled time
63842
64173
  progress: { type: Number },
63843
- time: { type: Number }
64174
+ time: { type: Number },
64175
+ // -- Diagnostics (API review §5).
64176
+ // Function PROPS, not emits, on purpose: an emit handler always exists, so wiring
64177
+ // these to `emit` would permanently suppress the console fallback for anyone who
64178
+ // never listens. As props, "not given" really is undefined and the console still
64179
+ // speaks by default — the same contract as React and React Native.
64180
+ onWarn: { type: Function },
64181
+ onError: { type: Function },
64182
+ // `silent` takes `true` or just the kinds to quiet, so `platform` chatter can be
64183
+ // silenced while `document` problems still speak.
64184
+ silent: { type: [Boolean, Array], default: void 0 }
63844
64185
  },
63845
64186
  emits: ["play", "stop", "pause", "cancel", "finish", "remove"],
63846
64187
  setup(props, { expose, emit }) {
63847
64188
  const elementRefs = /* @__PURE__ */ new Map();
63848
64189
  const apiRef = (0, vue_exports.shallowRef)(null);
63849
- const compMode = (0, vue_exports.computed)(() => {
63850
- if (props.autoplay) return "autoplay" /* autoplay */;
63851
- if (props.progress !== void 0 || props.time !== void 0) return "fixedTime" /* fixedTime */;
63852
- if (props.play !== void 0 || props.pause !== void 0) return "play" /* play */;
63853
- return "static" /* static */;
63854
- });
64190
+ const makeDiag = () => createDiagnostics(
64191
+ { onWarn: props.onWarn, onError: props.onError, silent: props.silent },
64192
+ "[PixodeskSvgAnimator]"
64193
+ );
64194
+ const resolvedMode = (0, vue_exports.computed)(() => resolveControlMode({
64195
+ progress: props.progress,
64196
+ time: props.time,
64197
+ play: props.play,
64198
+ pause: props.pause,
64199
+ autoplay: props.autoplay
64200
+ }));
64201
+ const compMode = (0, vue_exports.computed)(() => resolvedMode.value.mode);
64202
+ (0, vue_exports.watch)(resolvedMode, (r) => {
64203
+ const diag = makeDiag();
64204
+ for (const w of r.warnings) diag.warn(PxDiagnosticKind.usage, w);
64205
+ }, { immediate: true });
63855
64206
  const resolvedDoc = (0, vue_exports.computed)(() => {
63856
64207
  let doc = generateNewIds(props.doc);
63857
- return applyDocOverrides(doc, props, compMode.value);
64208
+ return applyDocOverrides(doc, props, compMode.value, makeDiag());
63858
64209
  });
63859
64210
  function renderNode2(node) {
63860
64211
  if (!node) return null;
@@ -63871,32 +64222,27 @@ ${codeFrame}` : message);
63871
64222
  };
63872
64223
  }
63873
64224
  const childVNodes = children?.map((child) => renderNode2(child)).filter(Boolean);
63874
- return (0, vue_exports.h)(type, normProps, childVNodes);
64225
+ const text = typeof node.textContent === "string" ? node.textContent : void 0;
64226
+ return (0, vue_exports.h)(type, normProps, childVNodes?.length ? childVNodes : text);
63875
64227
  }
63876
64228
  function createApi() {
63877
64229
  destroyApi();
63878
64230
  const doc = resolvedDoc.value;
63879
64231
  if (!doc) return;
63880
- const callbacks = {
64232
+ apiRef.value = createAnimator({
64233
+ doc,
64234
+ adapter: createVueAdapter(elementRefs, makeDiag()),
63881
64235
  onPlay: () => emit("play"),
63882
- onPause: () => {
63883
- emit("pause");
63884
- emit("stop");
63885
- },
63886
- onCancel: () => {
63887
- emit("cancel");
63888
- emit("stop");
63889
- },
63890
- onFinish: () => {
63891
- emit("finish");
63892
- emit("stop");
63893
- },
63894
- onRemove: () => {
63895
- emit("remove");
63896
- emit("stop");
63897
- }
63898
- };
63899
- apiRef.value = createAnimator({ data: doc, adapter: createVueAdapter(elementRefs), callbacks });
64236
+ onPause: () => emit("pause"),
64237
+ onCancel: () => emit("cancel"),
64238
+ onFinish: () => emit("finish"),
64239
+ onRemove: () => emit("remove"),
64240
+ onStop: () => emit("stop"),
64241
+ // The player's own diagnostics reach the same handlers as the component's.
64242
+ onWarn: props.onWarn,
64243
+ onError: props.onError,
64244
+ silent: props.silent
64245
+ });
63900
64246
  syncPlayState();
63901
64247
  applySeek();
63902
64248
  }
@@ -63905,19 +64251,19 @@ ${codeFrame}` : message);
63905
64251
  apiRef.value = null;
63906
64252
  }
63907
64253
  function syncPlayState() {
63908
- if (compMode.value !== "play" /* play */) return;
64254
+ if (compMode.value !== PxControlMode.play) return;
63909
64255
  if (props.play && !props.pause) {
63910
64256
  apiRef.value?.play();
63911
64257
  } else if (props.pause) {
63912
64258
  apiRef.value?.pause();
63913
64259
  } else if (props.play === false) {
63914
- apiRef.value?.finish();
64260
+ apiRef.value?.pause();
63915
64261
  } else {
63916
64262
  apiRef.value?.play();
63917
64263
  }
63918
64264
  }
63919
64265
  function applySeek() {
63920
- if (compMode.value !== "fixedTime" /* fixedTime */) return;
64266
+ if (compMode.value !== PxControlMode.fixedTime) return;
63921
64267
  const doc = resolvedDoc.value;
63922
64268
  if (!doc) return;
63923
64269
  const seekMs = calcSeekMs(doc, props);
@@ -63941,7 +64287,9 @@ ${codeFrame}` : message);
63941
64287
  finish: () => apiRef.value?.finish(),
63942
64288
  setPlaybackRate: (rate) => apiRef.value?.setPlaybackRate(rate),
63943
64289
  getCurrentTime: () => apiRef.value?.getCurrentTime() ?? null,
63944
- setCurrentTime: (time) => apiRef.value?.setCurrentTime(time)
64290
+ setCurrentTime: (time) => apiRef.value?.setCurrentTime(time),
64291
+ getCurrentProgress: () => apiRef.value?.getCurrentProgress() ?? null,
64292
+ setCurrentProgress: (progress) => apiRef.value?.setCurrentProgress(progress)
63945
64293
  };
63946
64294
  expose(publicApi);
63947
64295
  return () => {
@@ -63958,7 +64306,8 @@ ${codeFrame}` : message);
63958
64306
  inheritAttrs: false,
63959
64307
  props: {
63960
64308
  startOn: { type: String, default: "load" },
63961
- outAction: { type: String, default: "continue" }
64309
+ outAction: { type: String, default: "continue" },
64310
+ scrollIntoViewThreshold: { type: Number, default: PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold }
63962
64311
  },
63963
64312
  setup(props, { slots }) {
63964
64313
  const attrs = (0, vue_exports.useAttrs)();
@@ -63973,11 +64322,13 @@ ${codeFrame}` : message);
63973
64322
  const el = divRef.value;
63974
64323
  if (!el) return;
63975
64324
  const outState = props.outAction === "reset" ? "idle" : props.outAction === "pause" ? "paused" : "playing";
64325
+ const threshold = props.scrollIntoViewThreshold;
64326
+ const visible = (entry) => threshold > 0 ? entry.intersectionRatio >= threshold : entry.isIntersecting;
63976
64327
  const observer = new IntersectionObserver(
63977
64328
  ([entry]) => {
63978
- state.value = entry.isIntersecting ? "playing" : outState;
64329
+ state.value = visible(entry) ? "playing" : outState;
63979
64330
  },
63980
- { threshold: 0.1 }
64331
+ { threshold }
63981
64332
  );
63982
64333
  observer.observe(el);
63983
64334
  observerCleanup = () => observer.disconnect();