@pixodesk/svg-animator-web 1.0.41 → 1.0.44

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.
@@ -58,7 +58,9 @@ var PixodeskAnimator = (() => {
58
58
  PxTimelineEngineSetting: () => PxTimelineEngineSetting,
59
59
  createAnimator: () => createAnimator,
60
60
  generateNewIds: () => generateNewIds,
61
+ getAllAnimators: () => getAllAnimators,
61
62
  loadTagAnimators: () => loadTagAnimators,
63
+ onAnimatorsChange: () => onAnimatorsChange,
62
64
  setupAnimationTriggers: () => setupAnimationTriggers,
63
65
  validateDocument: () => validateDocument
64
66
  });
@@ -571,7 +573,7 @@ var PixodeskAnimator = (() => {
571
573
  };
572
574
 
573
575
  // ../svg-animator-core/src/version/PxSchemaVersion.ts
574
- var PX_WIRE_SCHEMA_VERSION = "1.1";
576
+ var PX_WIRE_SCHEMA_VERSION = "1.2";
575
577
 
576
578
  // ../svg-animator-core/src/version/PxWireVersion.ts
577
579
  var VERSION_RE = /^(\d+)\.(\d+)(?:\.(\d+))?$/;
@@ -599,14 +601,18 @@ var PixodeskAnimator = (() => {
599
601
  };
600
602
  var PX_ANIM_SRC_ATTR_NAME = "data-px-animation-src";
601
603
  var PX_ANIM_ATTR_NAME = "_px_animator";
602
- var PxStartOn = {
604
+ var PxTriggerStart = {
603
605
  load: "load",
604
606
  mouseOver: "mouseOver",
605
607
  click: "click",
606
- scrollIntoView: "scrollIntoView",
607
- programmatic: "programmatic"
608
+ none: "none"
609
+ };
610
+ var PxOffScreenAction = {
611
+ pause: "pause",
612
+ continue: "continue",
613
+ reset: "reset"
608
614
  };
609
- var PxOutAction = {
615
+ var PxMouseOutAction = {
610
616
  continue: "continue",
611
617
  pause: "pause",
612
618
  reset: "reset",
@@ -674,16 +680,20 @@ var PixodeskAnimator = (() => {
674
680
  return engine !== PxTimelineEngineSetting.js;
675
681
  }
676
682
  var PX_TRIGGER_DEFAULTS = {
677
- startOn: "load",
678
- outAction: "continue",
679
- scrollIntoViewThreshold: 0
683
+ start: "load",
684
+ offScreen: "pause",
685
+ mouseOut: "continue",
686
+ visibilityThreshold: 0.5,
687
+ visibilityDebounce: 150
680
688
  };
681
689
  function resolveTrigger(trigger) {
682
- var _a2, _b, _c;
690
+ var _a2, _b, _c, _d, _e;
683
691
  return {
684
- startOn: (_a2 = trigger == null ? void 0 : trigger.startOn) != null ? _a2 : PX_TRIGGER_DEFAULTS.startOn,
685
- outAction: (_b = trigger == null ? void 0 : trigger.outAction) != null ? _b : PX_TRIGGER_DEFAULTS.outAction,
686
- scrollIntoViewThreshold: (_c = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _c : PX_TRIGGER_DEFAULTS.scrollIntoViewThreshold
692
+ start: (_a2 = trigger == null ? void 0 : trigger.start) != null ? _a2 : PX_TRIGGER_DEFAULTS.start,
693
+ offScreen: (_b = trigger == null ? void 0 : trigger.offScreen) != null ? _b : PX_TRIGGER_DEFAULTS.offScreen,
694
+ mouseOut: (_c = trigger == null ? void 0 : trigger.mouseOut) != null ? _c : PX_TRIGGER_DEFAULTS.mouseOut,
695
+ visibilityThreshold: (_d = trigger == null ? void 0 : trigger.visibilityThreshold) != null ? _d : PX_TRIGGER_DEFAULTS.visibilityThreshold,
696
+ visibilityDebounce: (_e = trigger == null ? void 0 : trigger.visibilityDebounce) != null ? _e : PX_TRIGGER_DEFAULTS.visibilityDebounce
687
697
  };
688
698
  }
689
699
  var PxLoopRepeatAt = {
@@ -819,9 +829,9 @@ var PixodeskAnimator = (() => {
819
829
  } else {
820
830
  if (timeline.duration !== void 0) flat.duration = timeline.duration;
821
831
  if (timeline.trigger !== void 0) {
822
- const _b = timeline.trigger, { finishAction } = _b, restTrigger = __objRest(_b, ["finishAction"]);
832
+ const _b = timeline.trigger, { finish } = _b, restTrigger = __objRest(_b, ["finish"]);
823
833
  if (Object.keys(restTrigger).length) flat.trigger = restTrigger;
824
- if (finishAction !== void 0) flat.resetOnFinish = finishAction === "reset";
834
+ if (finish !== void 0) flat.resetOnFinish = finish === "reset";
825
835
  }
826
836
  if (timeline.delay !== void 0) flat.delay = timeline.delay;
827
837
  if (timeline.iterations !== void 0) flat.iterations = timeline.iterations;
@@ -922,13 +932,15 @@ var PixodeskAnimator = (() => {
922
932
  PxAnimationDefinitionSchema
923
933
  ]));
924
934
  var PxTriggerSchema = implementsInterface()(px.object({
925
- startOn: px.enum([PxStartOn.load, PxStartOn.mouseOver, PxStartOn.click, PxStartOn.scrollIntoView, PxStartOn.programmatic], PX_TRIGGER_DEFAULTS.startOn).optional(),
926
- outAction: px.enum([PxOutAction.continue, PxOutAction.pause, PxOutAction.reset, PxOutAction.reverse], PX_TRIGGER_DEFAULTS.outAction).optional(),
935
+ start: px.enum([PxTriggerStart.load, PxTriggerStart.mouseOver, PxTriggerStart.click, PxTriggerStart.none], PX_TRIGGER_DEFAULTS.start).optional(),
936
+ offScreen: px.enum([PxOffScreenAction.pause, PxOffScreenAction.continue, PxOffScreenAction.reset], PX_TRIGGER_DEFAULTS.offScreen).optional(),
937
+ mouseOut: px.enum([PxMouseOutAction.continue, PxMouseOutAction.pause, PxMouseOutAction.reset, PxMouseOutAction.reverse], PX_TRIGGER_DEFAULTS.mouseOut).optional(),
927
938
  // What happens after a NATURAL finish — `'hold'` (default: keep the end state per
928
- // `fill`) or `'reset'` (snap back to the start state). Pairs with `outAction` ("what
929
- // happens when the trigger condition ends"); both end-of-life knobs now read alike.
930
- finishAction: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
931
- scrollIntoViewThreshold: px.number().optional()
939
+ // `fill`) or `'reset'` (snap back to the start state). One of four occasion keys
940
+ // (`start`, `offScreen`, `mouseOut`, `finish`), all named the same way.
941
+ finish: px.enum([PxFinishAction.hold, PxFinishAction.reset]).optional(),
942
+ visibilityThreshold: px.number().optional(),
943
+ visibilityDebounce: px.number().optional()
932
944
  }));
933
945
  var PxGlyphSchema = implementsInterface()(px.object({
934
946
  width: px.number(),
@@ -6103,32 +6115,34 @@ var PixodeskAnimator = (() => {
6103
6115
  /** The player failed where it did not expect to — report it to us. */
6104
6116
  internal: "internal"
6105
6117
  };
6106
- function asError(error) {
6107
- return typeof error === "string" ? new Error(error) : error;
6118
+ var DOCS_URL = "https://github.com/pixodesk/pixodesk-svg-animator/blob/main/docs/diagnostics.md";
6119
+ function codeLine(code) {
6120
+ return "PX" + code + " " + DOCS_URL + "#px" + code;
6121
+ }
6122
+ function errorIn(data) {
6123
+ return data.find((d) => d instanceof Error);
6108
6124
  }
6109
6125
  function createDiagnostics(config, prefix) {
6110
6126
  const tag = prefix ? prefix + " " : "";
6111
6127
  return {
6112
- warn: (kind, message, detail) => {
6128
+ warn: (kind, code, ...data) => {
6129
+ const message = codeLine(code);
6113
6130
  if (config == null ? void 0 : config.onWarn) {
6114
- config.onWarn({ kind, message, detail });
6131
+ config.onWarn({ code, kind, data, message });
6115
6132
  return;
6116
6133
  }
6117
6134
  if (config == null ? void 0 : config.muteWarn) return;
6118
- const line = tag + kind + ": " + message;
6119
- if (detail === void 0) console.warn(line);
6120
- else console.warn(line, detail);
6135
+ console.warn(tag + kind + " " + message, ...data);
6121
6136
  },
6122
- error: (kind, error, detail) => {
6123
- const err = asError(error);
6137
+ error: (kind, code, ...data) => {
6138
+ const message = codeLine(code);
6139
+ const error = errorIn(data);
6124
6140
  if (config == null ? void 0 : config.onError) {
6125
- config.onError({ kind, message: err.message, error: err, detail });
6141
+ config.onError({ code, kind, data, message, error });
6126
6142
  return;
6127
6143
  }
6128
6144
  if (config == null ? void 0 : config.muteError) return;
6129
- const line = tag + kind + ": " + err.message;
6130
- if (detail === void 0) console.error(line);
6131
- else console.error(line, detail);
6145
+ console.error(tag + kind + " " + message, ...data);
6132
6146
  }
6133
6147
  };
6134
6148
  }
@@ -6208,16 +6222,16 @@ var PixodeskAnimator = (() => {
6208
6222
  } else {
6209
6223
  base = timeline != null ? timeline : void 0;
6210
6224
  }
6211
- const { duration, delay, iterations, startOn } = shortcuts;
6212
- if (duration === void 0 && delay === void 0 && iterations === void 0 && startOn === void 0) {
6225
+ const { duration, delay, iterations, start } = shortcuts;
6226
+ if (duration === void 0 && delay === void 0 && iterations === void 0 && start === void 0) {
6213
6227
  return base === void 0 ? void 0 : { timeline: base };
6214
6228
  }
6215
6229
  const out = isPlainObject(base) ? __spreadValues({}, base) : {};
6216
6230
  if (duration !== void 0) out.duration = duration;
6217
6231
  if (delay !== void 0) out.delay = delay;
6218
6232
  if (iterations !== void 0) out.iterations = iterations;
6219
- if (startOn !== void 0) {
6220
- out.trigger = __spreadProps(__spreadValues({}, out.trigger), { startOn });
6233
+ if (start !== void 0) {
6234
+ out.trigger = __spreadProps(__spreadValues({}, out.trigger), { start });
6221
6235
  }
6222
6236
  return { timeline: out };
6223
6237
  }
@@ -6383,6 +6397,202 @@ var PixodeskAnimator = (() => {
6383
6397
  return e instanceof Error ? e : new Error(String(e));
6384
6398
  }
6385
6399
 
6400
+ // src/registry/PxAnimatorRegistry.ts
6401
+ var STORE_KEY = /* @__PURE__ */ Symbol.for("@pixodesk/svg-animator-web:animators");
6402
+ var GLOBAL_NAME = "__pixodeskAnimators";
6403
+ function store() {
6404
+ const g = globalThis;
6405
+ let s = g[STORE_KEY];
6406
+ if (!s) {
6407
+ const animators = /* @__PURE__ */ new Set();
6408
+ const listeners = /* @__PURE__ */ new Set();
6409
+ s = {
6410
+ animators,
6411
+ listeners,
6412
+ getAll: () => Array.from(animators),
6413
+ subscribe: (listener) => {
6414
+ listeners.add(listener);
6415
+ return () => {
6416
+ listeners.delete(listener);
6417
+ };
6418
+ }
6419
+ };
6420
+ g[STORE_KEY] = s;
6421
+ if (g[GLOBAL_NAME] === void 0) g[GLOBAL_NAME] = s;
6422
+ }
6423
+ return s;
6424
+ }
6425
+ function getAllAnimators() {
6426
+ return store().getAll();
6427
+ }
6428
+ function onAnimatorsChange(listener) {
6429
+ return store().subscribe(listener);
6430
+ }
6431
+ function notify(event, animator) {
6432
+ for (const listener of store().listeners) {
6433
+ try {
6434
+ listener(event, animator);
6435
+ } catch (e) {
6436
+ setTimeout(() => {
6437
+ throw e;
6438
+ }, 0);
6439
+ }
6440
+ }
6441
+ }
6442
+ function registerAnimator(animator) {
6443
+ const s = store();
6444
+ if (s.animators.has(animator)) return;
6445
+ s.animators.add(animator);
6446
+ notify("add", animator);
6447
+ const destroy = animator.destroy.bind(animator);
6448
+ animator.destroy = () => {
6449
+ destroy();
6450
+ if (s.animators.delete(animator)) notify("remove", animator);
6451
+ };
6452
+ }
6453
+ function withRegistryEvents(callbacks, api) {
6454
+ const fire = (event) => {
6455
+ const a = api();
6456
+ if (a) notify(event, a);
6457
+ };
6458
+ return __spreadProps(__spreadValues({}, callbacks), {
6459
+ onPlay: () => {
6460
+ var _a2;
6461
+ (_a2 = callbacks == null ? void 0 : callbacks.onPlay) == null ? void 0 : _a2.call(callbacks);
6462
+ fire("play");
6463
+ },
6464
+ onPause: () => {
6465
+ var _a2;
6466
+ (_a2 = callbacks == null ? void 0 : callbacks.onPause) == null ? void 0 : _a2.call(callbacks);
6467
+ fire("pause");
6468
+ },
6469
+ onCancel: () => {
6470
+ var _a2;
6471
+ (_a2 = callbacks == null ? void 0 : callbacks.onCancel) == null ? void 0 : _a2.call(callbacks);
6472
+ fire("cancel");
6473
+ },
6474
+ onFinish: () => {
6475
+ var _a2;
6476
+ (_a2 = callbacks == null ? void 0 : callbacks.onFinish) == null ? void 0 : _a2.call(callbacks);
6477
+ fire("finish");
6478
+ }
6479
+ });
6480
+ }
6481
+
6482
+ // src/triggers/PxVisibilityGate.ts
6483
+ var PLAY_WHEN_VISIBLE_DEFAULTS = {
6484
+ offScreen: PX_TRIGGER_DEFAULTS.offScreen,
6485
+ visibilityThreshold: PX_TRIGGER_DEFAULTS.visibilityThreshold,
6486
+ visibilityDebounce: PX_TRIGGER_DEFAULTS.visibilityDebounce
6487
+ };
6488
+ var THRESHOLD_STEPS = Array.from({ length: 21 }, (_, i) => i / 20);
6489
+ function effectiveRatio(entry) {
6490
+ var _a2, _b;
6491
+ const target = entry.boundingClientRect;
6492
+ const visible = entry.intersectionRect;
6493
+ if (!(target == null ? void 0 : target.height) || !visible) return entry.intersectionRatio;
6494
+ const live = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : Infinity;
6495
+ const declared = (_b = (_a2 = entry.rootBounds) == null ? void 0 : _a2.height) != null ? _b : Infinity;
6496
+ const viewport = Math.min(live, declared);
6497
+ const denom = Math.min(target.height, Number.isFinite(viewport) ? viewport : target.height);
6498
+ return denom > 0 ? visible.height / denom : entry.intersectionRatio;
6499
+ }
6500
+ function openGate(host) {
6501
+ return {
6502
+ requestStart: () => host.play(),
6503
+ dispose: () => {
6504
+ }
6505
+ };
6506
+ }
6507
+ function isGated(offScreen) {
6508
+ return offScreen !== PxOffScreenAction.continue;
6509
+ }
6510
+ function createVisibilityGate(root, trigger, host) {
6511
+ if (!isGated(trigger.offScreen)) return openGate(host);
6512
+ if (typeof IntersectionObserver === "undefined") return openGate(host);
6513
+ const threshold = trigger.visibilityThreshold;
6514
+ const debounceMs = trigger.visibilityDebounce;
6515
+ let isOpen = void 0;
6516
+ let startPending = false;
6517
+ let pausedByGate = false;
6518
+ let lastRatio = 0;
6519
+ let openTimer;
6520
+ const cancelPendingOpen = () => {
6521
+ if (openTimer !== void 0) {
6522
+ clearTimeout(openTimer);
6523
+ openTimer = void 0;
6524
+ }
6525
+ };
6526
+ const open = () => {
6527
+ openTimer = void 0;
6528
+ if (isOpen === true) return;
6529
+ isOpen = true;
6530
+ if (startPending || pausedByGate) {
6531
+ startPending = false;
6532
+ pausedByGate = false;
6533
+ host.play();
6534
+ }
6535
+ };
6536
+ const close = () => {
6537
+ cancelPendingOpen();
6538
+ if (isOpen === false) return;
6539
+ isOpen = false;
6540
+ if (!host.isPlaying()) return;
6541
+ if (trigger.offScreen === PxOffScreenAction.reset) {
6542
+ host.cancel();
6543
+ } else {
6544
+ host.pause();
6545
+ }
6546
+ pausedByGate = true;
6547
+ };
6548
+ const apply2 = (ratio) => {
6549
+ lastRatio = ratio;
6550
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
6551
+ close();
6552
+ return;
6553
+ }
6554
+ if (ratio >= threshold) {
6555
+ if (isOpen === true || openTimer !== void 0) return;
6556
+ if (debounceMs > 0) openTimer = setTimeout(open, debounceMs);
6557
+ else open();
6558
+ return;
6559
+ }
6560
+ if (ratio <= 0) {
6561
+ close();
6562
+ return;
6563
+ }
6564
+ if (isOpen !== true) cancelPendingOpen();
6565
+ };
6566
+ const observer = new IntersectionObserver((entries) => {
6567
+ const last = entries[entries.length - 1];
6568
+ if (last) apply2(last.isIntersecting ? effectiveRatio(last) : 0);
6569
+ }, { threshold: THRESHOLD_STEPS });
6570
+ observer.observe(root);
6571
+ const onVisibilityChange = () => {
6572
+ apply2(lastRatio);
6573
+ };
6574
+ const hasDocument = typeof document !== "undefined";
6575
+ if (hasDocument) document.addEventListener("visibilitychange", onVisibilityChange);
6576
+ return {
6577
+ requestStart: (immediate) => {
6578
+ if (immediate || isOpen === true) {
6579
+ cancelPendingOpen();
6580
+ isOpen = true;
6581
+ startPending = false;
6582
+ pausedByGate = false;
6583
+ host.play();
6584
+ return;
6585
+ }
6586
+ startPending = true;
6587
+ },
6588
+ dispose: () => {
6589
+ cancelPendingOpen();
6590
+ observer.disconnect();
6591
+ if (hasDocument) document.removeEventListener("visibilitychange", onVisibilityChange);
6592
+ }
6593
+ };
6594
+ }
6595
+
6386
6596
  // src/triggers/PxAnimatorTriggers.ts
6387
6597
  function setupAnimationTriggers(api, trigger, diag) {
6388
6598
  const report = diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]");
@@ -6390,10 +6600,10 @@ var PixodeskAnimator = (() => {
6390
6600
  const dispose = () => {
6391
6601
  for (const undo of cleanups.splice(0)) undo();
6392
6602
  };
6393
- const { startOn, outAction, scrollIntoViewThreshold } = resolveTrigger(trigger);
6603
+ const resolved = resolveTrigger(trigger);
6394
6604
  const root = api.getRootElement();
6395
6605
  if (!root) {
6396
- report.warn(PxDiagnosticKind.host, "setupAnimationTriggers: No root element found for animation.");
6606
+ report.warn(PxDiagnosticKind.host, 1201 /* triggersNoRoot */);
6397
6607
  return dispose;
6398
6608
  }
6399
6609
  let reversed = false;
@@ -6404,27 +6614,34 @@ var PixodeskAnimator = (() => {
6404
6614
  }
6405
6615
  api.play();
6406
6616
  };
6407
- const handleEndAction = () => {
6408
- switch (outAction) {
6409
- case "pause":
6617
+ const gate = createVisibilityGate(root, resolved, {
6618
+ isPlaying: () => api.isPlaying(),
6619
+ play: start,
6620
+ pause: () => api.pause(),
6621
+ cancel: () => api.cancel()
6622
+ });
6623
+ cleanups.push(() => gate.dispose());
6624
+ const handleMouseOut = () => {
6625
+ switch (resolved.mouseOut) {
6626
+ case PxMouseOutAction.pause:
6410
6627
  api.pause();
6411
6628
  break;
6412
- case "reset":
6629
+ case PxMouseOutAction.reset:
6413
6630
  api.cancel();
6414
6631
  break;
6415
- case "reverse":
6632
+ case PxMouseOutAction.reverse:
6416
6633
  reversed = true;
6417
6634
  api.setPlaybackRate(-1);
6418
6635
  api.play();
6419
6636
  break;
6420
- case "continue":
6637
+ case PxMouseOutAction.continue:
6421
6638
  default:
6422
6639
  break;
6423
6640
  }
6424
6641
  };
6425
- switch (startOn) {
6426
- case "load": {
6427
- const startHandler = () => start();
6642
+ switch (resolved.start) {
6643
+ case PxTriggerStart.load: {
6644
+ const startHandler = () => gate.requestStart(false);
6428
6645
  if (document.readyState === "complete") {
6429
6646
  startHandler();
6430
6647
  } else {
@@ -6433,14 +6650,14 @@ var PixodeskAnimator = (() => {
6433
6650
  }
6434
6651
  break;
6435
6652
  }
6436
- case "mouseOver": {
6653
+ case PxTriggerStart.mouseOver: {
6437
6654
  let enteredOnce = false;
6438
6655
  const mouseOverHandler = () => {
6439
6656
  enteredOnce = true;
6440
- start();
6657
+ gate.requestStart(true);
6441
6658
  };
6442
6659
  const mouseOutHandler = () => {
6443
- if (enteredOnce) handleEndAction();
6660
+ if (enteredOnce) handleMouseOut();
6444
6661
  };
6445
6662
  root.addEventListener("mouseenter", mouseOverHandler);
6446
6663
  root.addEventListener("mouseleave", mouseOutHandler);
@@ -6450,51 +6667,16 @@ var PixodeskAnimator = (() => {
6450
6667
  });
6451
6668
  break;
6452
6669
  }
6453
- case "click": {
6670
+ case PxTriggerStart.click: {
6454
6671
  const clickHandler = () => {
6455
- if (api.isPlaying()) {
6456
- handleEndAction();
6457
- } else {
6458
- start();
6459
- }
6672
+ if (api.isPlaying()) api.pause();
6673
+ else gate.requestStart(true);
6460
6674
  };
6461
6675
  root.addEventListener("click", clickHandler);
6462
6676
  cleanups.push(() => root.removeEventListener("click", clickHandler));
6463
6677
  break;
6464
6678
  }
6465
- case "scrollIntoView": {
6466
- const effectiveRatio = (entry) => {
6467
- var _a2, _b;
6468
- const target = entry.boundingClientRect;
6469
- const visible = entry.intersectionRect;
6470
- if (!(target == null ? void 0 : target.height) || !visible) return entry.intersectionRatio;
6471
- const live = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : Infinity;
6472
- const declared = (_b = (_a2 = entry.rootBounds) == null ? void 0 : _a2.height) != null ? _b : Infinity;
6473
- const viewport = Math.min(live, declared);
6474
- const denom = Math.min(target.height, Number.isFinite(viewport) ? viewport : target.height);
6475
- return denom > 0 ? visible.height / denom : entry.intersectionRatio;
6476
- };
6477
- const thresholdSteps = Array.from({ length: 21 }, (_, i) => i / 20);
6478
- let wasIntersecting = false;
6479
- const observer = new IntersectionObserver(
6480
- (entries) => {
6481
- entries.forEach((entry) => {
6482
- if (entry.isIntersecting && effectiveRatio(entry) >= scrollIntoViewThreshold) {
6483
- wasIntersecting = true;
6484
- start();
6485
- } else if (wasIntersecting) {
6486
- wasIntersecting = false;
6487
- handleEndAction();
6488
- }
6489
- });
6490
- },
6491
- { threshold: thresholdSteps }
6492
- );
6493
- observer.observe(root);
6494
- cleanups.push(() => observer.disconnect());
6495
- break;
6496
- }
6497
- case "programmatic":
6679
+ case PxTriggerStart.none:
6498
6680
  break;
6499
6681
  }
6500
6682
  return dispose;
@@ -6502,7 +6684,12 @@ var PixodeskAnimator = (() => {
6502
6684
 
6503
6685
  // src/engines/PxAnimatorFrameLoop.ts
6504
6686
  function getSelector(id) {
6505
- return "#" + id;
6687
+ return "#" + escapeCssId(id);
6688
+ }
6689
+ function escapeCssId(id) {
6690
+ const css = globalThis.CSS;
6691
+ if (typeof (css == null ? void 0 : css.escape) === "function") return css.escape(id);
6692
+ return id.replace(/^([0-9])/, (_all, digit) => "\\3" + digit + " ").replace(/([^\w\-\\ ])/g, "\\$1");
6506
6693
  }
6507
6694
  function createFrameLoopAnimator(doc, adapter, callbacks, rootElement) {
6508
6695
  var _a2;
@@ -6512,9 +6699,9 @@ var PixodeskAnimator = (() => {
6512
6699
  if (doc.id) {
6513
6700
  const rootSelector = getSelector(doc.id);
6514
6701
  rootElement = document.querySelector(rootSelector);
6515
- if (!rootElement) diag.warn(PxDiagnosticKind.host, "createFrameLoopAnimator: No root element found for selector: " + rootSelector);
6702
+ if (!rootElement) diag.warn(PxDiagnosticKind.host, 1202 /* noRootForSelector */, rootSelector);
6516
6703
  } else {
6517
- diag.warn(PxDiagnosticKind.host, "createFrameLoopAnimator: No root element provided");
6704
+ diag.warn(PxDiagnosticKind.host, 1203 /* noRootElement */);
6518
6705
  }
6519
6706
  }
6520
6707
  const basicApi = createAdapterAnimator(
@@ -6526,7 +6713,7 @@ var PixodeskAnimator = (() => {
6526
6713
  "getRootElement": () => rootElement || null
6527
6714
  });
6528
6715
  if (isScrollTimeline(config)) {
6529
- if (config.trigger) diag.warn(PxDiagnosticKind.usage, "scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
6716
+ if (config.trigger) diag.warn(PxDiagnosticKind.usage, 1306 /* scrollTriggerIgnored */);
6530
6717
  } else {
6531
6718
  const detachTriggers = setupAnimationTriggers(api, (_a2 = config.trigger) != null ? _a2 : {}, diag);
6532
6719
  const destroyEngine = api.destroy.bind(api);
@@ -6551,7 +6738,7 @@ var PixodeskAnimator = (() => {
6551
6738
  const elements = (rootElement == null ? void 0 : rootElement.querySelectorAll(selector)) || document.querySelectorAll(selector);
6552
6739
  if (elements.length === 0 && !warnedSelectors.has(selector)) {
6553
6740
  warnedSelectors.add(selector);
6554
- report.warn(PxDiagnosticKind.host, 'setAttribute: No elements found for selector "' + selector + '"');
6741
+ report.warn(PxDiagnosticKind.host, 1207 /* setAttributeNoElement */, selector);
6555
6742
  }
6556
6743
  for (let i = 0; i < elements.length; i++) {
6557
6744
  const element = elements[i];
@@ -6670,9 +6857,9 @@ var PixodeskAnimator = (() => {
6670
6857
  if (doc.id) {
6671
6858
  const rootSelector = getSelector(doc.id);
6672
6859
  rootElement = document.querySelector(rootSelector);
6673
- if (!rootElement) diag.warn(PxDiagnosticKind.host, "createWebApiAnimator: No root element found for selector: " + rootSelector);
6860
+ if (!rootElement) diag.warn(PxDiagnosticKind.host, 1202 /* noRootForSelector */, rootSelector);
6674
6861
  } else {
6675
- diag.warn(PxDiagnosticKind.host, "createWebApiAnimator: No root element provided");
6862
+ diag.warn(PxDiagnosticKind.host, 1203 /* noRootElement */);
6676
6863
  }
6677
6864
  }
6678
6865
  const bindings = normalizeBindings(doc, PxTimelineEngine.native);
@@ -6685,18 +6872,18 @@ var PixodeskAnimator = (() => {
6685
6872
  let finishNotified = false;
6686
6873
  let removeCalled = false;
6687
6874
  if (!(bindings == null ? void 0 : bindings.length)) {
6688
- diag.warn(PxDiagnosticKind.document, "createWebApiAnimator: No animation bindings defined");
6875
+ diag.warn(PxDiagnosticKind.document, 1105 /* noBindings */);
6689
6876
  }
6690
6877
  for (const binding of bindings || []) {
6691
6878
  const animDef = binding.animate;
6692
6879
  if (!animDef || typeof animDef !== "object" || Array.isArray(animDef)) {
6693
- diag.warn(PxDiagnosticKind.document, "createWebApiAnimator: Empty or unresolved binding", binding);
6880
+ diag.warn(PxDiagnosticKind.document, 1106 /* unresolvedBinding */, binding);
6694
6881
  continue;
6695
6882
  }
6696
6883
  const selector = getSelector(binding.id);
6697
6884
  const elements = (rootElement == null ? void 0 : rootElement.querySelectorAll(selector)) || document.querySelectorAll(selector);
6698
6885
  if (elements.length === 0) {
6699
- diag.warn(PxDiagnosticKind.host, 'createWebApiAnimator: No elements found for selector "' + selector + '"');
6886
+ diag.warn(PxDiagnosticKind.host, 1206 /* noElementsForSelector */, selector);
6700
6887
  }
6701
6888
  const keyframesMap = convertToWebApiKeyframes(animDef, unsupportedSet, config);
6702
6889
  const positiveDelay = config.delay && config.delay > 0 ? config.delay : void 0;
@@ -6745,14 +6932,14 @@ var PixodeskAnimator = (() => {
6745
6932
  }
6746
6933
  animations.push(anim);
6747
6934
  } catch (e) {
6748
- diag.warn(PxDiagnosticKind.internal, "createWebApiAnimator: could not build the animation", e);
6935
+ diag.warn(PxDiagnosticKind.internal, 1004 /* animationBuildFailed */, e);
6749
6936
  }
6750
6937
  }
6751
6938
  }
6752
6939
  }
6753
6940
  }
6754
6941
  if (!forceEvenIfHasUnsupportedAttrs && unsupportedSet.size) {
6755
- diag.warn(PxDiagnosticKind.platform, "Unsupported CSS attrs: " + [...unsupportedSet].join(", "));
6942
+ diag.warn(PxDiagnosticKind.platform, 1104 /* unsupportedAnimatedAttrs */, [...unsupportedSet].join(", "));
6756
6943
  return null;
6757
6944
  }
6758
6945
  const api = {
@@ -6797,7 +6984,7 @@ var PixodeskAnimator = (() => {
6797
6984
  },
6798
6985
  "setPlaybackRate": (rate) => {
6799
6986
  if (!isValidPlaybackRate(rate)) {
6800
- diag.warn(PxDiagnosticKind.usage, PX_RATE_REJECTED);
6987
+ diag.warn(PxDiagnosticKind.usage, 1401 /* rateRejected */);
6801
6988
  return api;
6802
6989
  }
6803
6990
  animations.forEach((a) => a.playbackRate = rate);
@@ -6837,7 +7024,7 @@ var PixodeskAnimator = (() => {
6837
7024
  }
6838
7025
  };
6839
7026
  if (config.timelineSource === "scroll") {
6840
- if (config.trigger) diag.warn(PxDiagnosticKind.usage, "scroll timeline: `animator.trigger` is ignored (triggers do not apply to scroll-driven playback)");
7027
+ if (config.trigger) diag.warn(PxDiagnosticKind.usage, 1306 /* scrollTriggerIgnored */);
6841
7028
  } else {
6842
7029
  const detachTriggers = setupAnimationTriggers(api, (_b = config.trigger) != null ? _b : {}, diag);
6843
7030
  const destroyEngine = api.destroy.bind(api);
@@ -6867,7 +7054,7 @@ var PixodeskAnimator = (() => {
6867
7054
  const scroll = config.scroll || {};
6868
7055
  const kind = (_a2 = scroll.kind) != null ? _a2 : "view";
6869
7056
  if (scroll.smoothing) {
6870
- report.warn(PxDiagnosticKind.platform, "scroll timeline: `smoothing` needs the built-in driver \u2014 using the built-in driver instead of the browser timeline");
7057
+ report.warn(PxDiagnosticKind.platform, 1301 /* scrollSmoothingNeedsOwnDriver */);
6871
7058
  return null;
6872
7059
  }
6873
7060
  const g = globalThis;
@@ -6884,7 +7071,7 @@ var PixodeskAnimator = (() => {
6884
7071
  timeline = new Ctor({ source, axis });
6885
7072
  }
6886
7073
  } catch (e) {
6887
- report.warn(PxDiagnosticKind.platform, "scroll timeline: native timeline construction failed \u2014 falling back to the player measuring progress itself", e);
7074
+ report.warn(PxDiagnosticKind.platform, 1302 /* scrollNativeUnavailable */, e);
6888
7075
  return null;
6889
7076
  }
6890
7077
  return {
@@ -6931,11 +7118,11 @@ var PixodeskAnimator = (() => {
6931
7118
  try {
6932
7119
  found = document.querySelector(spec);
6933
7120
  } catch (e) {
6934
- report.warn(PxDiagnosticKind.document, 'scroll timeline: subject "' + spec + '" is not a valid selector \u2014 measuring the SVG itself');
7121
+ report.warn(PxDiagnosticKind.document, 1303 /* scrollSubjectInvalid */, spec);
6935
7122
  return svgRoot;
6936
7123
  }
6937
7124
  if (!found) {
6938
- report.warn(PxDiagnosticKind.host, 'scroll timeline: subject "' + spec + '" matched no element \u2014 measuring the SVG itself');
7125
+ report.warn(PxDiagnosticKind.host, 1304 /* scrollSubjectNoMatch */, spec);
6939
7126
  return svgRoot;
6940
7127
  }
6941
7128
  return found;
@@ -7177,7 +7364,7 @@ var PixodeskAnimator = (() => {
7177
7364
  };
7178
7365
  }
7179
7366
  } else {
7180
- diag.warn(PxDiagnosticKind.host, "scroll timeline: no root element to observe \u2014 animation will stay at frame 0");
7367
+ diag.warn(PxDiagnosticKind.host, 1305 /* scrollNoRootToObserve */);
7181
7368
  }
7182
7369
  return api;
7183
7370
  });
@@ -7199,7 +7386,7 @@ var PixodeskAnimator = (() => {
7199
7386
  var SVG_NS = "http://www.w3.org/2000/svg";
7200
7387
  function createElement(tagName, normalizedProps, style, children, textContent, diag) {
7201
7388
  if (PX_DISALLOWED_SVG_TAGS_LOWER.has(tagName.toLowerCase())) {
7202
- (diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]")).warn(PxDiagnosticKind.document, "SVG tag blocked (dangerous): " + tagName);
7389
+ (diag != null ? diag : createDiagnostics(void 0, "[PxAnimator]")).warn(PxDiagnosticKind.document, 1103 /* blockedTag */, tagName);
7203
7390
  return null;
7204
7391
  }
7205
7392
  const element = document.createElementNS(SVG_NS, tagName);
@@ -7265,11 +7452,11 @@ var PixodeskAnimator = (() => {
7265
7452
  function createAnimatorImpl(doc, adapter, callbacks, containerElement, patch, resetTimeline) {
7266
7453
  const diag = createDiagnostics(callbacks, "[PxAnimator]");
7267
7454
  const effectsWarnings = validateNodeEffects(doc);
7268
- for (const w of effectsWarnings) diag.warn(PxDiagnosticKind.document, "effects shape: " + w);
7455
+ for (const w of effectsWarnings) diag.warn(PxDiagnosticKind.document, 1101 /* effectsShape */, w);
7269
7456
  reportDocumentDiagnostics(doc, "[PxAnimator] createAnimator");
7270
7457
  if (patch !== void 0 || resetTimeline) {
7271
7458
  const patched = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetTimeline: !!resetTimeline });
7272
- for (const w of patched.warnings) diag.warn(PxDiagnosticKind.usage, "timeline override: " + w);
7459
+ for (const w of patched.warnings) diag.warn(PxDiagnosticKind.usage, 1102 /* timelineOverrideIgnored */, w);
7273
7460
  doc = patched.doc;
7274
7461
  }
7275
7462
  const animatorConfig = getAnimatorConfig(doc) || {};
@@ -7301,14 +7488,15 @@ var PixodeskAnimator = (() => {
7301
7488
  return "adapter" in options;
7302
7489
  }
7303
7490
  function resolveTimelineOption(options) {
7304
- const { timeline, duration, delay, iterations, startOn } = options;
7305
- return foldTimelineOverride(timeline, { duration, delay, iterations, startOn });
7491
+ const { timeline, duration, delay, iterations, start } = options;
7492
+ return foldTimelineOverride(timeline, { duration, delay, iterations, start });
7306
7493
  }
7307
7494
  function createAnimator(options) {
7308
7495
  const { src, doc, container, resetTimeline } = options;
7309
7496
  const adapter = isInternalOptions(options) ? options.adapter : void 0;
7310
7497
  const patch = resolveTimelineOption(options);
7311
- const callbacks = toEngineCallbacks(options);
7498
+ let proxy;
7499
+ const callbacks = withRegistryEvents(toEngineCallbacks(options), () => proxy);
7312
7500
  if (doc !== void 0 && src !== void 0) {
7313
7501
  throw new Error("createAnimator: provide either `src` or `doc`, not both");
7314
7502
  }
@@ -7332,31 +7520,19 @@ var PixodeskAnimator = (() => {
7332
7520
  pending = null;
7333
7521
  queued == null ? void 0 : queued.forEach((call) => call(api));
7334
7522
  };
7335
- const failed = (kind, message, detail) => {
7523
+ const failed = (kind, code, ...data) => {
7336
7524
  pending = null;
7337
- diag.error(kind, message, detail);
7525
+ diag.error(kind, code, ...data);
7338
7526
  };
7339
7527
  const build = (document2) => {
7340
7528
  try {
7341
7529
  ready(createAnimatorImpl(document2, adapter, callbacks, container, patch, resetTimeline));
7342
7530
  } catch (e) {
7343
7531
  const err = asThrownError(e);
7344
- failed(PxDiagnosticKind.internal, "createAnimator: could not build the player \u2014 " + err.message, err);
7532
+ failed(PxDiagnosticKind.internal, 1001 /* buildFailed */, err);
7345
7533
  }
7346
7534
  };
7347
- if (doc !== void 0) {
7348
- build(doc);
7349
- } else {
7350
- fetch(src).then((res) => res.json()).then((json) => {
7351
- if (destroyed) return;
7352
- if (isPxDocument(json)) build(json);
7353
- else failed(PxDiagnosticKind.document, 'createAnimator: invalid animation document format at "' + src + '"');
7354
- }).catch((err) => {
7355
- var _a2;
7356
- failed(PxDiagnosticKind.host, 'createAnimator: failed to load "' + src + '" \u2014 ' + ((_a2 = err == null ? void 0 : err.message) != null ? _a2 : String(err)));
7357
- });
7358
- }
7359
- return {
7535
+ proxy = {
7360
7536
  "isReady": () => !!animator,
7361
7537
  "getRootElement": () => animator ? animator.getRootElement() : null,
7362
7538
  "isPlaying": () => (animator == null ? void 0 : animator.isPlaying()) || false,
@@ -7389,6 +7565,20 @@ var PixodeskAnimator = (() => {
7389
7565
  animator == null ? void 0 : animator.destroy();
7390
7566
  }
7391
7567
  };
7568
+ registerAnimator(proxy);
7569
+ if (doc !== void 0) {
7570
+ build(doc);
7571
+ } else {
7572
+ fetch(src).then((res) => res.json()).then((json) => {
7573
+ if (destroyed) return;
7574
+ if (isPxDocument(json)) build(json);
7575
+ else failed(PxDiagnosticKind.document, 1002 /* invalidDocumentAtSrc */, src);
7576
+ }).catch((err) => {
7577
+ var _a2;
7578
+ failed(PxDiagnosticKind.host, 1003 /* loadFailed */, src, (_a2 = err == null ? void 0 : err.message) != null ? _a2 : String(err));
7579
+ });
7580
+ }
7581
+ return proxy;
7392
7582
  }
7393
7583
  function loadTagAnimators(options) {
7394
7584
  const elements = document.querySelectorAll("[" + PX_ANIM_SRC_ATTR_NAME + "]");