@pixodesk/svg-animator-rn 1.0.35 → 1.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -31,7 +31,8 @@ var __objRest = (source, exclude) => {
31
31
  };
32
32
 
33
33
  // src/PixodeskSvgAnimator.tsx
34
- import { reportDocumentDiagnostics, generateNewIds, getAnimatorConfig as getAnimatorConfig2, getDefs, materialiseAllInTree, validateNodeEffects, PxTimelineEngine as PxTimelineEngine2, applyAnimatorConfig, foldAnimatorConfigShortcuts } from "@pixodesk/svg-animator-core";
34
+ import { clampSeekMs, createRunClock, isValidPlaybackRate, progressSpanMs, progressToTimeMs, PX_RATE_REJECTED, PxDiagnosticKind as PxDiagnosticKind2, seekCeilingMs, timeToProgress, generateNewIds, getAnimatorConfig as getAnimatorConfig2, getDefs, materializeAllInTree, resolveTrigger, validateNodeEffects, PxTimelineEngine as PxTimelineEngine2, PxControlMode, resolveControlMode, applyAnimatorConfig, foldTimelineOverride } from "@pixodesk/svg-animator-core";
35
+ import { createDiagnostics as createDiagnostics2, reportDocumentDiagnostics } from "@pixodesk/svg-animator-core/internal";
35
36
  import { createElement as createElement2, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
36
37
  import { Dimensions, Platform, Pressable, View } from "react-native";
37
38
  import Animated, {
@@ -47,16 +48,11 @@ import Animated, {
47
48
  } from "react-native-reanimated";
48
49
 
49
50
  // src/PxRnTracks.ts
50
- import {
51
- calcAnimationValues,
52
- getAnimatorConfig,
53
- getNormalisedBindings,
54
- DEFAULT_DURATION_MS,
55
- PxTimelineEngine
56
- } from "@pixodesk/svg-animator-core";
51
+ import { calcAnimationValues, getAnimatorConfig, getNormalizedBindings, PxTimelineEngine } from "@pixodesk/svg-animator-core";
52
+ import { DEFAULT_DURATION_MS } from "@pixodesk/svg-animator-core/internal";
57
53
 
58
54
  // src/PxRnPropNames.ts
59
- import { kebabToCamelCaseWord } from "@pixodesk/svg-animator-core";
55
+ import { kebabToCamelCaseWord } from "@pixodesk/svg-animator-core/internal";
60
56
 
61
57
  // src/PxRnMatrix.ts
62
58
  var DEG = Math.PI / 180;
@@ -173,7 +169,7 @@ function compileTracks(doc, opts) {
173
169
  ((_a2 = n == null ? void 0 : n.children) != null ? _a2 : []).forEach(indexTags);
174
170
  };
175
171
  indexTags(doc);
176
- const bindings = getNormalisedBindings(doc, PxTimelineEngine.js) || [];
172
+ const bindings = getNormalizedBindings(doc, PxTimelineEngine.js) || [];
177
173
  const elements = [];
178
174
  for (const binding of bindings) {
179
175
  const animDef = binding.animate;
@@ -233,14 +229,8 @@ function sampleProps(tracks, tMs, stepMs, sampleCount, native = false) {
233
229
  }
234
230
 
235
231
  // src/PxRnRender.tsx
236
- import {
237
- getNormalizedProps,
238
- resolveStyle,
239
- sanitiseAttributeValue,
240
- DISALLOWED_SVG_TAGS_LOWER,
241
- TEXT_ATTR,
242
- TEXT_CONTENT_ATTR
243
- } from "@pixodesk/svg-animator-core";
232
+ import { getNormalizedProps } from "@pixodesk/svg-animator-core";
233
+ import { sanitizeAttributeValue, DISALLOWED_SVG_TAGS_LOWER, TEXT_CONTENT_ATTR } from "@pixodesk/svg-animator-core/internal";
244
234
  import { createElement } from "react";
245
235
 
246
236
  // src/PxRnTypeMap.ts
@@ -357,14 +347,14 @@ var RN_SVG_COMPONENTS = {
357
347
 
358
348
  // src/PxRnRender.tsx
359
349
  function toRnProps(props, warnings, tag) {
360
- const normalised = getNormalizedProps(props);
350
+ const normalized = getNormalizedProps(props);
361
351
  const out = {};
362
- for (const key of Object.keys(normalised)) {
363
- const sanitised = sanitiseAttributeValue(key, normalised[key]);
364
- if (sanitised === void 0) continue;
352
+ for (const key of Object.keys(normalized)) {
353
+ const sanitized = sanitizeAttributeValue(key, normalized[key]);
354
+ if (sanitized === void 0) continue;
365
355
  const rnKey = toRnPropName(key);
366
356
  if (!rnKey) continue;
367
- out[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);
357
+ out[rnKey] = toRnPropValue(rnKey, String(sanitized), tag);
368
358
  }
369
359
  return out;
370
360
  }
@@ -386,17 +376,17 @@ function renderRnNode(node, opts = {}, key) {
386
376
  }
387
377
  const rnProps = toRnProps(props, opts.warnings, tag);
388
378
  if (domType !== void 0) rnProps.type = domType;
389
- const resolved = resolveStyle(style, opts.defs);
379
+ const resolved = style;
390
380
  if (resolved) {
391
381
  for (const [k, v] of Object.entries(resolved)) {
392
382
  const rnKey = toRnPropName(k);
393
383
  if (!rnKey || rnKey in rnProps) continue;
394
- const sanitised = sanitiseAttributeValue(rnKey, v);
395
- if (sanitised === void 0) continue;
396
- rnProps[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);
384
+ const sanitized = sanitizeAttributeValue(rnKey, v);
385
+ if (sanitized === void 0) continue;
386
+ rnProps[rnKey] = toRnPropValue(rnKey, String(sanitized), tag);
397
387
  }
398
388
  }
399
- const textContent = props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR];
389
+ const textContent = props[TEXT_CONTENT_ATTR];
400
390
  let childElements = void 0;
401
391
  if (Array.isArray(children) && children.length > 0) {
402
392
  childElements = children.map((ch, i) => {
@@ -422,6 +412,8 @@ function renderRnNode(node, opts = {}, key) {
422
412
 
423
413
  // src/PxRnErrorBoundary.tsx
424
414
  import { Component } from "react";
415
+ import { PxDiagnosticKind } from "@pixodesk/svg-animator-core";
416
+ import { createDiagnostics } from "@pixodesk/svg-animator-core/internal";
425
417
  var PxRnErrorBoundary = class extends Component {
426
418
  constructor() {
427
419
  super(...arguments);
@@ -431,9 +423,8 @@ var PxRnErrorBoundary = class extends Component {
431
423
  return { error };
432
424
  }
433
425
  componentDidCatch(error, info) {
434
- var _a, _b, _c, _d;
435
- (_c = (_b = this.props).onError) == null ? void 0 : _c.call(_b, error, (_a = info == null ? void 0 : info.componentStack) != null ? _a : void 0);
436
- console.warn("[PixodeskSvgAnimator] render failed:", (_d = error == null ? void 0 : error.message) != null ? _d : error);
426
+ var _a, _b;
427
+ ((_a = this.props.diag) != null ? _a : createDiagnostics(void 0, "[PixodeskSvgAnimator]")).error(PxDiagnosticKind.internal, error, { componentStack: (_b = info == null ? void 0 : info.componentStack) != null ? _b : void 0 });
437
428
  }
438
429
  componentDidUpdate(prev) {
439
430
  if (this.state.error && prev.children !== this.props.children) {
@@ -448,7 +439,7 @@ var PxRnErrorBoundary = class extends Component {
448
439
  };
449
440
 
450
441
  // src/PxRnSafety.ts
451
- import { deepClone, generateUniqueId } from "@pixodesk/svg-animator-core";
442
+ import { deepClone, generateUniqueId } from "@pixodesk/svg-animator-core/internal";
452
443
  function isClosedPath(d) {
453
444
  return typeof d === "string" && /[zZ]/.test(d);
454
445
  }
@@ -592,18 +583,18 @@ var EMPTY_TRACKS = {
592
583
  sampleCount: 2,
593
584
  elements: []
594
585
  };
595
- function compileDocument(doc, overrides) {
596
- const { config, resetDocDefaults, duration, delay, iterations, startOn } = overrides;
586
+ function compileDocument(doc, overrides, diag) {
587
+ const { timeline, resetTimeline, duration, delay, iterations, startOn } = overrides;
597
588
  const warnings = validateNodeEffects(doc);
598
- for (const w of warnings) console.warn("[PixodeskSvgAnimator] effects shape warning:", w);
589
+ for (const w of warnings) diag.warn(PxDiagnosticKind2.document, "effects shape: " + w);
599
590
  reportDocumentDiagnostics(doc, "[PixodeskSvgAnimator]");
600
- const patch = foldAnimatorConfigShortcuts(config, { duration, delay, iterations, startOn });
601
- if (patch !== void 0 || resetDocDefaults) {
602
- const applied = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetDefaults: !!resetDocDefaults });
603
- for (const w of applied.warnings) console.warn("[PixodeskSvgAnimator] config override:", w);
591
+ const patch = foldTimelineOverride(timeline, { duration, delay, iterations, startOn });
592
+ if (patch !== void 0 || resetTimeline) {
593
+ const applied = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetDefaults: !!resetTimeline });
594
+ for (const w of applied.warnings) diag.warn(PxDiagnosticKind2.usage, "timeline override: " + w);
604
595
  doc = applied.doc;
605
596
  }
606
- let prepared = materialiseAllInTree(doc, PxTimelineEngine2.native);
597
+ let prepared = materializeAllInTree(doc, PxTimelineEngine2.native);
607
598
  if (NATIVE_SVG_VIEWS) {
608
599
  prepared = openClosedTextPathTargets(prepared);
609
600
  }
@@ -613,8 +604,8 @@ function compileDocument(doc, overrides) {
613
604
  }
614
605
  function PixodeskSvgAnimator({
615
606
  doc,
616
- config,
617
- resetDocDefaults,
607
+ timeline,
608
+ resetTimeline,
618
609
  duration,
619
610
  delay,
620
611
  iterations,
@@ -631,25 +622,36 @@ function PixodeskSvgAnimator({
631
622
  onPause,
632
623
  onCancel,
633
624
  onFinish,
625
+ onRemove,
634
626
  onError,
635
- fallback
627
+ fallback,
628
+ onWarn,
629
+ muteWarn,
630
+ muteError
636
631
  }) {
637
- var _a, _b, _c, _d;
638
- const configKey = typeof config === "string" ? config : JSON.stringify(config != null ? config : null);
632
+ var _a, _b;
633
+ const timelineKey = typeof timeline === "string" ? timeline : JSON.stringify(timeline != null ? timeline : null);
634
+ const makeDiag = () => createDiagnostics2(
635
+ { onWarn, onError, muteWarn, muteError },
636
+ "[PixodeskSvgAnimator]"
637
+ );
639
638
  const compiled = useMemo(() => {
640
639
  try {
641
640
  return compileDocument(
642
641
  doc,
643
- { config, resetDocDefaults, duration, delay, iterations, startOn }
642
+ { timeline, resetTimeline, duration, delay, iterations, startOn },
643
+ makeDiag()
644
644
  );
645
645
  } catch (e) {
646
646
  const error = e instanceof Error ? e : new Error(String(e));
647
- console.warn("[PixodeskSvgAnimator] could not compile the document:", error.message);
647
+ makeDiag().error(PxDiagnosticKind2.internal, error, { phase: "compile" });
648
648
  return { doc: null, tracks: EMPTY_TRACKS, error };
649
649
  }
650
- }, [doc, configKey, resetDocDefaults, duration, delay, iterations, startOn]);
650
+ }, [doc, timelineKey, resetTimeline, duration, delay, iterations, startOn]);
651
651
  const tracks = compiled.tracks;
652
- const totalDuration = tracks.duration * (tracks.iterations === Infinity ? 1 : tracks.iterations);
652
+ const totalDuration = progressSpanMs(tracks.duration, tracks.iterations);
653
+ const seekCeiling = seekCeilingMs(tracks.duration, tracks.iterations);
654
+ const runClock = useMemo(() => createRunClock(seekCeiling), [seekCeiling]);
653
655
  const progress = useSharedValue(0);
654
656
  const playingRef = useRef(false);
655
657
  const rateRef = useRef(1);
@@ -661,6 +663,8 @@ function PixodeskSvgAnimator({
661
663
  };
662
664
  const notifyFinish = () => {
663
665
  playingRef.current = false;
666
+ runClock.seek(Number.isFinite(seekCeiling) ? seekCeiling : tracks.duration);
667
+ runClock.stop();
664
668
  progress.value = restingPosition();
665
669
  onFinish == null ? void 0 : onFinish();
666
670
  onStop == null ? void 0 : onStop();
@@ -697,12 +701,15 @@ function PixodeskSvgAnimator({
697
701
  const api = {
698
702
  isPlaying: () => playingRef.current,
699
703
  play: () => {
704
+ if (Number.isFinite(seekCeiling) && runClock.now() >= seekCeiling) runClock.seek(0);
705
+ runClock.start(rateRef.current);
700
706
  startFrom(progress.value);
701
707
  onPlay == null ? void 0 : onPlay();
702
708
  },
703
709
  pause: () => {
704
710
  cancelAnimation(progress);
705
711
  playingRef.current = false;
712
+ runClock.stop();
706
713
  onPause == null ? void 0 : onPause();
707
714
  onStop == null ? void 0 : onStop();
708
715
  },
@@ -710,62 +717,82 @@ function PixodeskSvgAnimator({
710
717
  cancelAnimation(progress);
711
718
  progress.value = 0;
712
719
  playingRef.current = false;
720
+ runClock.seek(0);
721
+ runClock.stop();
713
722
  onCancel == null ? void 0 : onCancel();
714
723
  onStop == null ? void 0 : onStop();
715
724
  },
716
725
  finish: () => {
717
726
  cancelAnimation(progress);
718
727
  playingRef.current = false;
728
+ runClock.seek(Number.isFinite(seekCeiling) ? seekCeiling : tracks.duration);
729
+ runClock.stop();
719
730
  progress.value = restingPosition();
720
731
  onFinish == null ? void 0 : onFinish();
721
732
  onStop == null ? void 0 : onStop();
722
733
  },
723
734
  setPlaybackRate: (rate) => {
724
- if (!isFinite(rate) || rate === 0) {
725
- console.warn("setPlaybackRate: rate must be finite and non-zero");
735
+ if (!isValidPlaybackRate(rate)) {
736
+ makeDiag().warn(PxDiagnosticKind2.usage, PX_RATE_REJECTED);
726
737
  return;
727
738
  }
728
739
  rateRef.current = rate;
729
- if (playingRef.current) startFrom(progress.value);
740
+ if (playingRef.current) {
741
+ runClock.start(rate);
742
+ startFrom(progress.value);
743
+ }
730
744
  },
731
- getCurrentTime: () => progress.value,
745
+ // Ms from the start of the WHOLE run, like every other engine (review §3). This used
746
+ // to return `progress.value`, which is ms within the current iteration — so a slider
747
+ // built on it jumped back to 0 every time the animation repeated.
748
+ getCurrentTime: () => runClock.now(),
732
749
  setCurrentTime: (t) => {
733
750
  const wasPlaying = playingRef.current;
734
751
  cancelAnimation(progress);
735
752
  playingRef.current = false;
736
- const clamped = Math.max(0, Math.min(t, totalDuration));
753
+ const clamped = clampSeekMs(t, seekCeiling);
754
+ runClock.seek(clamped);
737
755
  const withinIteration = tracks.duration > 0 ? clamped % tracks.duration || (clamped === 0 ? 0 : tracks.duration) : 0;
738
756
  progress.value = withinIteration;
739
757
  if (wasPlaying) startFrom(withinIteration);
758
+ else runClock.stop();
759
+ },
760
+ getCurrentProgress: () => timeToProgress(runClock.now(), tracks.duration, tracks.iterations),
761
+ setCurrentProgress: (p) => {
762
+ api.setCurrentTime(progressToTimeMs(p, tracks.duration, tracks.iterations));
740
763
  }
741
764
  };
742
765
  useImperativeHandle(apiRef, () => api, [compiled]);
743
- const trigger = compiled.doc ? (_a = getAnimatorConfig2(compiled.doc)) == null ? void 0 : _a.trigger : void 0;
744
- const effectiveStartOn = (_b = trigger == null ? void 0 : trigger.startOn) != null ? _b : "load";
745
- const effectiveOutAction = (_c = trigger == null ? void 0 : trigger.outAction) != null ? _c : "pause";
766
+ const trigger = resolveTrigger(compiled.doc ? (_a = getAnimatorConfig2(compiled.doc)) == null ? void 0 : _a.trigger : void 0);
767
+ const effectiveStartOn = trigger.startOn;
768
+ const effectiveOutAction = trigger.outAction;
769
+ const { mode: compMode, warnings: modeWarnings } = resolveControlMode({ progress: progressProp, time, play, pause, autoplay });
770
+ useEffect(() => {
771
+ const diag = makeDiag();
772
+ for (const w of modeWarnings) diag.warn(PxDiagnosticKind2.usage, w);
773
+ }, [modeWarnings.join("|")]);
746
774
  useEffect(() => {
747
- if (progressProp !== void 0 || time !== void 0) {
748
- const seekMs = time !== void 0 ? time : (progressProp != null ? progressProp : 0) * totalDuration;
775
+ if (compMode === PxControlMode.fixedTime) {
776
+ const seekMs = time !== void 0 ? time : progressToTimeMs(progressProp != null ? progressProp : 0, tracks.duration, tracks.iterations);
749
777
  api.setCurrentTime(seekMs);
750
778
  return;
751
779
  }
752
- if (play !== void 0 || pause !== void 0) {
780
+ if (compMode === PxControlMode.play) {
753
781
  if (play && !pause) api.play();
754
782
  else if (pause) api.pause();
755
- else if (play === false) api.finish();
783
+ else if (play === false) api.pause();
756
784
  else api.play();
757
785
  return;
758
786
  }
759
- if (autoplay && effectiveStartOn === "load") {
787
+ if (compMode === PxControlMode.autoplay && effectiveStartOn === "load") {
760
788
  api.play();
761
789
  }
762
- }, [compiled, autoplay, play, pause, progressProp, time]);
790
+ }, [compiled, compMode, autoplay, play, pause, progressProp, time]);
763
791
  const scrollRef = useRef(null);
764
792
  const inViewRef = useRef(false);
765
793
  useEffect(() => {
766
- var _a2;
767
794
  if (!autoplay || effectiveStartOn !== "scrollIntoView") return;
768
- const threshold = (_a2 = trigger == null ? void 0 : trigger.scrollIntoViewThreshold) != null ? _a2 : 0;
795
+ const threshold = trigger.scrollIntoViewThreshold;
769
796
  inViewRef.current = false;
770
797
  const check = () => {
771
798
  const node = scrollRef.current;
@@ -796,6 +823,8 @@ function PixodeskSvgAnimator({
796
823
  return () => {
797
824
  cancelAnimation(progress);
798
825
  playingRef.current = false;
826
+ onRemove == null ? void 0 : onRemove();
827
+ onStop == null ? void 0 : onStop();
799
828
  };
800
829
  }, [compiled]);
801
830
  const trackById = useMemo(() => {
@@ -851,17 +880,15 @@ function PixodeskSvgAnimator({
851
880
  } catch (e) {
852
881
  const error = e instanceof Error ? e : new Error(String(e));
853
882
  renderErrorRef.current = error;
854
- console.warn("[PixodeskSvgAnimator] could not render the document:", error.message);
883
+ makeDiag().error(PxDiagnosticKind2.internal, error, { phase: "render" });
855
884
  return null;
856
885
  }
857
886
  }, [compiled, trackById]);
858
887
  useEffect(() => {
859
- for (const w of warningsRef.current) console.warn("[PixodeskSvgAnimator]", w);
888
+ const diag = makeDiag();
889
+ for (const w of warningsRef.current) diag.warn(PxDiagnosticKind2.platform, w);
860
890
  }, [root]);
861
- const failure = (_d = compiled.error) != null ? _d : renderErrorRef.current;
862
- useEffect(() => {
863
- if (failure) onError == null ? void 0 : onError(failure);
864
- }, [failure]);
891
+ const failure = (_b = compiled.error) != null ? _b : renderErrorRef.current;
865
892
  if (failure) return fallback ? fallback(failure) : null;
866
893
  let content = root;
867
894
  if (autoplay && effectiveStartOn === "scrollIntoView" && root) {
@@ -886,19 +913,11 @@ function PixodeskSvgAnimator({
886
913
  }
887
914
  );
888
915
  }
889
- return /* @__PURE__ */ jsx(PxRnErrorBoundary, { onError, fallback, children: content });
916
+ return /* @__PURE__ */ jsx(PxRnErrorBoundary, { fallback, diag: makeDiag(), children: content });
890
917
  }
891
918
  var PixodeskSvgAnimator_default = PixodeskSvgAnimator;
892
919
  export {
893
920
  PixodeskSvgAnimator,
894
- PxRnErrorBoundary,
895
- RN_SVG_COMPONENTS,
896
- compileTracks,
897
- PixodeskSvgAnimator_default as default,
898
- openClosedTextPathTargets,
899
- renderRnNode,
900
- sampleProps,
901
- toRnPropName,
902
- toRnProps
921
+ PixodeskSvgAnimator_default as default
903
922
  };
904
923
  //# sourceMappingURL=index.js.map