@pixodesk/svg-animator-rn 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/README.md +31 -21
- package/dist/index.cjs +104 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -64
- package/dist/index.d.ts +39 -64
- package/dist/index.js +121 -53
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/PixodeskSvgAnimator.tsx +153 -136
- package/src/PxRnErrorBoundary.tsx +5 -1
- package/src/PxRnMatrix.test.ts +2 -2
- package/src/PxRnMatrix.ts +1 -1
- package/src/PxRnPropNames.ts +2 -2
- package/src/PxRnRender.tsx +14 -15
- package/src/PxRnTracks.test.ts +12 -12
- package/src/PxRnTracks.ts +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,72 +1,44 @@
|
|
|
1
|
-
import { PxAnimatedSvgDocument,
|
|
1
|
+
import { PxPlaybackOverrideProps, PxControlProps, PxComponentCallbacks, PxAnimatedSvgDocument, PxTimelinePatch, PxAnimatorHandle, PxDefs, PxNode, PxDiagnostics } from '@pixodesk/svg-animator-core';
|
|
2
2
|
import React, { ReactElement, ComponentType, ReactNode, Component, ErrorInfo } from 'react';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/** Returns the current playback time in milliseconds. */
|
|
19
|
-
getCurrentTime(): number | null;
|
|
20
|
-
/** Jumps to a specific time (in milliseconds) in the animation. */
|
|
21
|
-
setCurrentTime(time: number): void;
|
|
22
|
-
}
|
|
23
|
-
interface PixodeskSvgAnimatorProps {
|
|
4
|
+
/**
|
|
5
|
+
* The imperative handle `apiRef` is filled with — core's `PxAnimatorHandle` under this package's
|
|
6
|
+
* name (review §9). It no longer "mirrors" the React one by hand: the local copy had already
|
|
7
|
+
* drifted (its `setPlaybackRate` comment lost "negative plays backwards"). One definition.
|
|
8
|
+
*/
|
|
9
|
+
type RnAnimatorApi = PxAnimatorHandle;
|
|
10
|
+
/**
|
|
11
|
+
* The component's props. The playback override, the control props and the callbacks are core's
|
|
12
|
+
* shared shapes (review §9) — `PxPlaybackOverrideProps`, `PxControlProps` and
|
|
13
|
+
* `PxComponentCallbacks` — so React, Vue and React Native cannot drift apart. Only what differs
|
|
14
|
+
* on this platform is declared here: `onError` keeps its richer signature (the error boundary
|
|
15
|
+
* hands it a component stack), and `fallback` has no web counterpart.
|
|
16
|
+
*/
|
|
17
|
+
interface PixodeskSvgAnimatorProps extends PxPlaybackOverrideProps, PxControlProps, Omit<PxComponentCallbacks, 'onError'> {
|
|
24
18
|
/** The animation document to render. */
|
|
25
19
|
doc: PxAnimatedSvgDocument;
|
|
26
|
-
/** Duration of a single iteration in milliseconds. */
|
|
27
|
-
duration?: number;
|
|
28
|
-
/** Delay before the animation starts, in milliseconds. */
|
|
29
|
-
delay?: number;
|
|
30
|
-
/** Number of iterations, or 'infinite' for endless looping. */
|
|
31
|
-
iterations?: number | 'infinite';
|
|
32
|
-
/** Shortcut for `config.timeline.trigger.startOn`. */
|
|
33
|
-
startOn?: StartOn;
|
|
34
20
|
/**
|
|
35
|
-
* Per-instance override of the document's `
|
|
36
|
-
* in SCHEMA.md, deep-merged over what the document says; `null` at a slot deletes it.
|
|
37
|
-
* Replaces the former flat `fill` / `direction` / `resetOnFinish` / `outAction` props, so
|
|
38
|
-
* every surface takes one vocabulary. Also accepts a JSON string.
|
|
21
|
+
* Per-instance override of the document's `timeline` — see `PxPlaybackOverrideProps`.
|
|
39
22
|
*
|
|
40
|
-
* `
|
|
41
|
-
*
|
|
23
|
+
* `engine` is accepted but ignored here: React Native always uses the `native` (fully
|
|
24
|
+
* flattened) materialization, because react-native-svg has no `<use>` shadow-tree
|
|
25
|
+
* propagation.
|
|
26
|
+
*/
|
|
27
|
+
timeline?: PxTimelinePatch | string;
|
|
28
|
+
/**
|
|
29
|
+
* Ref populated with the imperative playback API. Filled in EVERY mode and never picks one
|
|
30
|
+
* (review §1): `autoplay` next to it still autoplays.
|
|
42
31
|
*/
|
|
43
|
-
config?: PxAnimatorConfigPatch | string;
|
|
44
|
-
/** Start from the player's defaults instead of the document's playback settings. */
|
|
45
|
-
resetDocDefaults?: boolean;
|
|
46
|
-
/** When true, honours the document trigger (`startOn: 'load'` plays on mount). */
|
|
47
|
-
autoplay?: boolean;
|
|
48
|
-
/** Starts playback unconditionally. */
|
|
49
|
-
play?: boolean;
|
|
50
|
-
/** Pauses current playback. */
|
|
51
|
-
pause?: boolean;
|
|
52
|
-
/** Ref populated with the imperative playback API. */
|
|
53
32
|
apiRef?: React.RefObject<RnAnimatorApi | null>;
|
|
54
|
-
/** Seek to a fraction (0–1) of the whole timeline (duration × iterations). */
|
|
55
|
-
progress?: number;
|
|
56
|
-
/** Seek to a specific time in milliseconds. */
|
|
57
|
-
time?: number;
|
|
58
|
-
onPlay?: () => void;
|
|
59
|
-
onStop?: () => void;
|
|
60
|
-
onPause?: () => void;
|
|
61
|
-
onCancel?: () => void;
|
|
62
|
-
onFinish?: () => void;
|
|
63
33
|
/**
|
|
64
34
|
* Called when a document cannot be compiled or rendered. The component
|
|
65
35
|
* renders {@link fallback} instead of throwing, so a single broken
|
|
66
36
|
* animation never takes down the screen around it.
|
|
67
37
|
*
|
|
68
38
|
* Only JavaScript failures reach this — a crash inside react-native-svg's
|
|
69
|
-
* native renderer bypasses JavaScript entirely.
|
|
39
|
+
* native renderer bypasses JavaScript entirely. Richer than the web's
|
|
40
|
+
* `onError(diagnostic)` because the error boundary hands it a component stack; it is
|
|
41
|
+
* adapted into the shared diagnostics channel rather than narrowed to match it.
|
|
70
42
|
*/
|
|
71
43
|
onError?: (error: Error, componentStack?: string) => void;
|
|
72
44
|
/** Rendered in place of the animation after a failure. Default: nothing. */
|
|
@@ -75,14 +47,15 @@ interface PixodeskSvgAnimatorProps {
|
|
|
75
47
|
/**
|
|
76
48
|
* React Native component for rendering and controlling Pixodesk SVG animations.
|
|
77
49
|
*
|
|
78
|
-
* The document is
|
|
50
|
+
* The document is materialized once through the shared core pipeline (effects,
|
|
79
51
|
* loops, motion-path sampling, animated-`<use>` inlining — identical to the
|
|
80
|
-
* web
|
|
52
|
+
* web's `native` engine, NOT the frame loop, which keeps `<use>` live), compiled
|
|
53
|
+
* into densely sampled per-element tracks, and
|
|
81
54
|
* played back natively: a single reanimated progress value driven by
|
|
82
55
|
* `withTiming`/`withRepeat` on the UI thread, with per-element worklets
|
|
83
56
|
* indexing the precompiled tracks. No JS-thread frame loop.
|
|
84
57
|
*/
|
|
85
|
-
declare function PixodeskSvgAnimator({ doc,
|
|
58
|
+
declare function PixodeskSvgAnimator({ doc, timeline, resetTimeline, duration, delay, iterations, startOn, autoplay, play, pause, apiRef, progress: progressProp, time, onPlay, onStop, onPause, onCancel, onFinish, onRemove, onError, fallback, onWarn, silent, }: PixodeskSvgAnimatorProps): ReactElement | null;
|
|
86
59
|
|
|
87
60
|
interface RenderRnNodeOptions {
|
|
88
61
|
/** Collects non-fatal issues (unsupported tags, dropped attrs). */
|
|
@@ -102,13 +75,13 @@ interface RenderRnNodeOptions {
|
|
|
102
75
|
decorate?: (node: PxNode, Component: ComponentType<any>, props: Record<string, any>, children: ReactNode, key: string | number | undefined) => ReactElement | undefined;
|
|
103
76
|
}
|
|
104
77
|
/**
|
|
105
|
-
* Converts core-
|
|
106
|
-
* naming,
|
|
78
|
+
* Converts core-normalized wire props into react-native-svg props: RN prop
|
|
79
|
+
* naming, sanitization (same security rules as the web renderer), numeric
|
|
107
80
|
* coercion where possible.
|
|
108
81
|
*/
|
|
109
82
|
declare function toRnProps(props: Record<string, any>, warnings?: Array<string>, tag?: string): Record<string, any>;
|
|
110
83
|
/**
|
|
111
|
-
* Renders a (
|
|
84
|
+
* Renders a (materialized) PxNode tree to react-native-svg elements.
|
|
112
85
|
* Mirrors the web `renderNode` contract: unsupported/dangerous tags are
|
|
113
86
|
* skipped with a warning, never a crash.
|
|
114
87
|
*/
|
|
@@ -119,6 +92,8 @@ interface PxRnErrorBoundaryProps {
|
|
|
119
92
|
/** Rendered instead of the children once something has thrown. */
|
|
120
93
|
fallback?: (error: Error) => ReactNode;
|
|
121
94
|
onError?: (error: Error, info?: string) => void;
|
|
95
|
+
/** Where to report the failure (API review §5). Defaults to the console. */
|
|
96
|
+
diag?: PxDiagnostics;
|
|
122
97
|
}
|
|
123
98
|
interface State {
|
|
124
99
|
error: Error | null;
|
|
@@ -173,7 +148,7 @@ declare function openClosedTextPathTargets(doc: PxNode, warnings?: Array<string>
|
|
|
173
148
|
* The compiler densely samples every animated property through core's
|
|
174
149
|
* `calcAnimationValues` — the exact function the web frames engine renders
|
|
175
150
|
* with — so RN playback is value-identical to the web player. Easing, loops,
|
|
176
|
-
* transform composition,
|
|
151
|
+
* transform composition, color interpolation and path morphing are all baked
|
|
177
152
|
* into the samples at compile time; the UI-thread worklet only indexes arrays.
|
|
178
153
|
*/
|
|
179
154
|
interface PxElementTracks {
|
|
@@ -218,7 +193,7 @@ interface CompileTracksOptions {
|
|
|
218
193
|
native?: boolean;
|
|
219
194
|
}
|
|
220
195
|
/**
|
|
221
|
-
* Compiles a
|
|
196
|
+
* Compiles a MATERIALIZED document (run `materializeAllInTree(doc, 'frames')`
|
|
222
197
|
* + `generateNewIds` first) into densely sampled per-element tracks.
|
|
223
198
|
*/
|
|
224
199
|
declare function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksOptions): PxCompiledTracks;
|
|
@@ -235,7 +210,7 @@ declare function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksO
|
|
|
235
210
|
declare function sampleProps(tracks: PxElementTracks, tMs: number, stepMs: number, sampleCount: number, native?: boolean): Record<string, string | number | Array<number>>;
|
|
236
211
|
|
|
237
212
|
/**
|
|
238
|
-
* Converts one
|
|
213
|
+
* Converts one normalized wire attribute name (camelCase after core's
|
|
239
214
|
* `getNormalizedProps`, or kebab-case raw) to a react-native-svg prop name.
|
|
240
215
|
* Returns undefined for props that must be dropped.
|
|
241
216
|
*
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,30 @@ var __objRest = (source, exclude) => {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
// src/PixodeskSvgAnimator.tsx
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
clampSeekMs,
|
|
36
|
+
createDiagnostics as createDiagnostics2,
|
|
37
|
+
createRunClock,
|
|
38
|
+
isValidPlaybackRate,
|
|
39
|
+
progressSpanMs,
|
|
40
|
+
progressToTimeMs,
|
|
41
|
+
PX_RATE_REJECTED,
|
|
42
|
+
PxDiagnosticKind as PxDiagnosticKind2,
|
|
43
|
+
seekCeilingMs,
|
|
44
|
+
timeToProgress,
|
|
45
|
+
reportDocumentDiagnostics,
|
|
46
|
+
generateNewIds,
|
|
47
|
+
getAnimatorConfig as getAnimatorConfig2,
|
|
48
|
+
getDefs,
|
|
49
|
+
materializeAllInTree,
|
|
50
|
+
resolveTrigger,
|
|
51
|
+
validateNodeEffects,
|
|
52
|
+
PxTimelineEngine as PxTimelineEngine2,
|
|
53
|
+
PxControlMode,
|
|
54
|
+
resolveControlMode,
|
|
55
|
+
applyAnimatorConfig,
|
|
56
|
+
foldTimelineOverride
|
|
57
|
+
} from "@pixodesk/svg-animator-core";
|
|
35
58
|
import { createElement as createElement2, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
36
59
|
import { Dimensions, Platform, Pressable, View } from "react-native";
|
|
37
60
|
import Animated, {
|
|
@@ -50,7 +73,7 @@ import Animated, {
|
|
|
50
73
|
import {
|
|
51
74
|
calcAnimationValues,
|
|
52
75
|
getAnimatorConfig,
|
|
53
|
-
|
|
76
|
+
getNormalizedBindings,
|
|
54
77
|
DEFAULT_DURATION_MS,
|
|
55
78
|
PxTimelineEngine
|
|
56
79
|
} from "@pixodesk/svg-animator-core";
|
|
@@ -173,7 +196,7 @@ function compileTracks(doc, opts) {
|
|
|
173
196
|
((_a2 = n == null ? void 0 : n.children) != null ? _a2 : []).forEach(indexTags);
|
|
174
197
|
};
|
|
175
198
|
indexTags(doc);
|
|
176
|
-
const bindings =
|
|
199
|
+
const bindings = getNormalizedBindings(doc, PxTimelineEngine.js) || [];
|
|
177
200
|
const elements = [];
|
|
178
201
|
for (const binding of bindings) {
|
|
179
202
|
const animDef = binding.animate;
|
|
@@ -236,9 +259,8 @@ function sampleProps(tracks, tMs, stepMs, sampleCount, native = false) {
|
|
|
236
259
|
import {
|
|
237
260
|
getNormalizedProps,
|
|
238
261
|
resolveStyle,
|
|
239
|
-
|
|
262
|
+
sanitizeAttributeValue,
|
|
240
263
|
DISALLOWED_SVG_TAGS_LOWER,
|
|
241
|
-
TEXT_ATTR,
|
|
242
264
|
TEXT_CONTENT_ATTR
|
|
243
265
|
} from "@pixodesk/svg-animator-core";
|
|
244
266
|
import { createElement } from "react";
|
|
@@ -357,14 +379,14 @@ var RN_SVG_COMPONENTS = {
|
|
|
357
379
|
|
|
358
380
|
// src/PxRnRender.tsx
|
|
359
381
|
function toRnProps(props, warnings, tag) {
|
|
360
|
-
const
|
|
382
|
+
const normalized = getNormalizedProps(props);
|
|
361
383
|
const out = {};
|
|
362
|
-
for (const key of Object.keys(
|
|
363
|
-
const
|
|
364
|
-
if (
|
|
384
|
+
for (const key of Object.keys(normalized)) {
|
|
385
|
+
const sanitized = sanitizeAttributeValue(key, normalized[key]);
|
|
386
|
+
if (sanitized === void 0) continue;
|
|
365
387
|
const rnKey = toRnPropName(key);
|
|
366
388
|
if (!rnKey) continue;
|
|
367
|
-
out[rnKey] = toRnPropValue(rnKey, String(
|
|
389
|
+
out[rnKey] = toRnPropValue(rnKey, String(sanitized), tag);
|
|
368
390
|
}
|
|
369
391
|
return out;
|
|
370
392
|
}
|
|
@@ -391,12 +413,12 @@ function renderRnNode(node, opts = {}, key) {
|
|
|
391
413
|
for (const [k, v] of Object.entries(resolved)) {
|
|
392
414
|
const rnKey = toRnPropName(k);
|
|
393
415
|
if (!rnKey || rnKey in rnProps) continue;
|
|
394
|
-
const
|
|
395
|
-
if (
|
|
396
|
-
rnProps[rnKey] = toRnPropValue(rnKey, String(
|
|
416
|
+
const sanitized = sanitizeAttributeValue(rnKey, v);
|
|
417
|
+
if (sanitized === void 0) continue;
|
|
418
|
+
rnProps[rnKey] = toRnPropValue(rnKey, String(sanitized), tag);
|
|
397
419
|
}
|
|
398
420
|
}
|
|
399
|
-
const textContent = props[
|
|
421
|
+
const textContent = props[TEXT_CONTENT_ATTR];
|
|
400
422
|
let childElements = void 0;
|
|
401
423
|
if (Array.isArray(children) && children.length > 0) {
|
|
402
424
|
childElements = children.map((ch, i) => {
|
|
@@ -422,6 +444,7 @@ function renderRnNode(node, opts = {}, key) {
|
|
|
422
444
|
|
|
423
445
|
// src/PxRnErrorBoundary.tsx
|
|
424
446
|
import { Component } from "react";
|
|
447
|
+
import { createDiagnostics, PxDiagnosticKind } from "@pixodesk/svg-animator-core";
|
|
425
448
|
var PxRnErrorBoundary = class extends Component {
|
|
426
449
|
constructor() {
|
|
427
450
|
super(...arguments);
|
|
@@ -431,9 +454,9 @@ var PxRnErrorBoundary = class extends Component {
|
|
|
431
454
|
return { error };
|
|
432
455
|
}
|
|
433
456
|
componentDidCatch(error, info) {
|
|
434
|
-
var _a, _b, _c, _d;
|
|
457
|
+
var _a, _b, _c, _d, _e;
|
|
435
458
|
(_c = (_b = this.props).onError) == null ? void 0 : _c.call(_b, error, (_a = info == null ? void 0 : info.componentStack) != null ? _a : void 0);
|
|
436
|
-
|
|
459
|
+
((_d = this.props.diag) != null ? _d : createDiagnostics(void 0, "[PixodeskSvgAnimator]")).warn(PxDiagnosticKind.internal, "render failed: " + ((_e = error == null ? void 0 : error.message) != null ? _e : String(error)));
|
|
437
460
|
}
|
|
438
461
|
componentDidUpdate(prev) {
|
|
439
462
|
if (this.state.error && prev.children !== this.props.children) {
|
|
@@ -592,18 +615,18 @@ var EMPTY_TRACKS = {
|
|
|
592
615
|
sampleCount: 2,
|
|
593
616
|
elements: []
|
|
594
617
|
};
|
|
595
|
-
function compileDocument(doc, overrides) {
|
|
596
|
-
const {
|
|
618
|
+
function compileDocument(doc, overrides, diag) {
|
|
619
|
+
const { timeline, resetTimeline, duration, delay, iterations, startOn } = overrides;
|
|
597
620
|
const warnings = validateNodeEffects(doc);
|
|
598
|
-
for (const w of warnings)
|
|
621
|
+
for (const w of warnings) diag.warn(PxDiagnosticKind2.document, "effects shape: " + w);
|
|
599
622
|
reportDocumentDiagnostics(doc, "[PixodeskSvgAnimator]");
|
|
600
|
-
const patch =
|
|
601
|
-
if (patch !== void 0 ||
|
|
602
|
-
const applied = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetDefaults: !!
|
|
603
|
-
for (const w of applied.warnings)
|
|
623
|
+
const patch = foldTimelineOverride(timeline, { duration, delay, iterations, startOn });
|
|
624
|
+
if (patch !== void 0 || resetTimeline) {
|
|
625
|
+
const applied = applyAnimatorConfig(doc, patch != null ? patch : {}, { resetDefaults: !!resetTimeline });
|
|
626
|
+
for (const w of applied.warnings) diag.warn(PxDiagnosticKind2.usage, "timeline override: " + w);
|
|
604
627
|
doc = applied.doc;
|
|
605
628
|
}
|
|
606
|
-
let prepared =
|
|
629
|
+
let prepared = materializeAllInTree(doc, PxTimelineEngine2.native);
|
|
607
630
|
if (NATIVE_SVG_VIEWS) {
|
|
608
631
|
prepared = openClosedTextPathTargets(prepared);
|
|
609
632
|
}
|
|
@@ -613,8 +636,8 @@ function compileDocument(doc, overrides) {
|
|
|
613
636
|
}
|
|
614
637
|
function PixodeskSvgAnimator({
|
|
615
638
|
doc,
|
|
616
|
-
|
|
617
|
-
|
|
639
|
+
timeline,
|
|
640
|
+
resetTimeline,
|
|
618
641
|
duration,
|
|
619
642
|
delay,
|
|
620
643
|
iterations,
|
|
@@ -631,25 +654,42 @@ function PixodeskSvgAnimator({
|
|
|
631
654
|
onPause,
|
|
632
655
|
onCancel,
|
|
633
656
|
onFinish,
|
|
657
|
+
onRemove,
|
|
634
658
|
onError,
|
|
635
|
-
fallback
|
|
659
|
+
fallback,
|
|
660
|
+
onWarn,
|
|
661
|
+
silent
|
|
636
662
|
}) {
|
|
637
|
-
var _a, _b
|
|
638
|
-
const
|
|
663
|
+
var _a, _b;
|
|
664
|
+
const timelineKey = typeof timeline === "string" ? timeline : JSON.stringify(timeline != null ? timeline : null);
|
|
665
|
+
const makeDiag = () => createDiagnostics2({
|
|
666
|
+
onWarn,
|
|
667
|
+
// This component's public `onError` is richer — `(error, componentStack?)` — and the
|
|
668
|
+
// error boundary hands it a component stack. Adapt rather than narrow it; the ternary
|
|
669
|
+
// keeps "not given" as undefined, so the console fallback still fires.
|
|
670
|
+
onError: onError ? (d) => {
|
|
671
|
+
var _a2;
|
|
672
|
+
return onError((_a2 = d.error) != null ? _a2 : new Error(d.message));
|
|
673
|
+
} : void 0,
|
|
674
|
+
silent
|
|
675
|
+
}, "[PixodeskSvgAnimator]");
|
|
639
676
|
const compiled = useMemo(() => {
|
|
640
677
|
try {
|
|
641
678
|
return compileDocument(
|
|
642
679
|
doc,
|
|
643
|
-
{
|
|
680
|
+
{ timeline, resetTimeline, duration, delay, iterations, startOn },
|
|
681
|
+
makeDiag()
|
|
644
682
|
);
|
|
645
683
|
} catch (e) {
|
|
646
684
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
647
|
-
|
|
685
|
+
makeDiag().warn(PxDiagnosticKind2.internal, "could not compile the document: " + error.message);
|
|
648
686
|
return { doc: null, tracks: EMPTY_TRACKS, error };
|
|
649
687
|
}
|
|
650
|
-
}, [doc,
|
|
688
|
+
}, [doc, timelineKey, resetTimeline, duration, delay, iterations, startOn]);
|
|
651
689
|
const tracks = compiled.tracks;
|
|
652
|
-
const totalDuration = tracks.duration
|
|
690
|
+
const totalDuration = progressSpanMs(tracks.duration, tracks.iterations);
|
|
691
|
+
const seekCeiling = seekCeilingMs(tracks.duration, tracks.iterations);
|
|
692
|
+
const runClock = useMemo(() => createRunClock(seekCeiling), [seekCeiling]);
|
|
653
693
|
const progress = useSharedValue(0);
|
|
654
694
|
const playingRef = useRef(false);
|
|
655
695
|
const rateRef = useRef(1);
|
|
@@ -661,6 +701,8 @@ function PixodeskSvgAnimator({
|
|
|
661
701
|
};
|
|
662
702
|
const notifyFinish = () => {
|
|
663
703
|
playingRef.current = false;
|
|
704
|
+
runClock.seek(Number.isFinite(seekCeiling) ? seekCeiling : tracks.duration);
|
|
705
|
+
runClock.stop();
|
|
664
706
|
progress.value = restingPosition();
|
|
665
707
|
onFinish == null ? void 0 : onFinish();
|
|
666
708
|
onStop == null ? void 0 : onStop();
|
|
@@ -697,12 +739,15 @@ function PixodeskSvgAnimator({
|
|
|
697
739
|
const api = {
|
|
698
740
|
isPlaying: () => playingRef.current,
|
|
699
741
|
play: () => {
|
|
742
|
+
if (Number.isFinite(seekCeiling) && runClock.now() >= seekCeiling) runClock.seek(0);
|
|
743
|
+
runClock.start(rateRef.current);
|
|
700
744
|
startFrom(progress.value);
|
|
701
745
|
onPlay == null ? void 0 : onPlay();
|
|
702
746
|
},
|
|
703
747
|
pause: () => {
|
|
704
748
|
cancelAnimation(progress);
|
|
705
749
|
playingRef.current = false;
|
|
750
|
+
runClock.stop();
|
|
706
751
|
onPause == null ? void 0 : onPause();
|
|
707
752
|
onStop == null ? void 0 : onStop();
|
|
708
753
|
},
|
|
@@ -710,62 +755,82 @@ function PixodeskSvgAnimator({
|
|
|
710
755
|
cancelAnimation(progress);
|
|
711
756
|
progress.value = 0;
|
|
712
757
|
playingRef.current = false;
|
|
758
|
+
runClock.seek(0);
|
|
759
|
+
runClock.stop();
|
|
713
760
|
onCancel == null ? void 0 : onCancel();
|
|
714
761
|
onStop == null ? void 0 : onStop();
|
|
715
762
|
},
|
|
716
763
|
finish: () => {
|
|
717
764
|
cancelAnimation(progress);
|
|
718
765
|
playingRef.current = false;
|
|
766
|
+
runClock.seek(Number.isFinite(seekCeiling) ? seekCeiling : tracks.duration);
|
|
767
|
+
runClock.stop();
|
|
719
768
|
progress.value = restingPosition();
|
|
720
769
|
onFinish == null ? void 0 : onFinish();
|
|
721
770
|
onStop == null ? void 0 : onStop();
|
|
722
771
|
},
|
|
723
772
|
setPlaybackRate: (rate) => {
|
|
724
|
-
if (!
|
|
725
|
-
|
|
773
|
+
if (!isValidPlaybackRate(rate)) {
|
|
774
|
+
makeDiag().warn(PxDiagnosticKind2.usage, PX_RATE_REJECTED);
|
|
726
775
|
return;
|
|
727
776
|
}
|
|
728
777
|
rateRef.current = rate;
|
|
729
|
-
if (playingRef.current)
|
|
778
|
+
if (playingRef.current) {
|
|
779
|
+
runClock.start(rate);
|
|
780
|
+
startFrom(progress.value);
|
|
781
|
+
}
|
|
730
782
|
},
|
|
731
|
-
|
|
783
|
+
// Ms from the start of the WHOLE run, like every other engine (review §3). This used
|
|
784
|
+
// to return `progress.value`, which is ms within the current iteration — so a slider
|
|
785
|
+
// built on it jumped back to 0 every time the animation repeated.
|
|
786
|
+
getCurrentTime: () => runClock.now(),
|
|
732
787
|
setCurrentTime: (t) => {
|
|
733
788
|
const wasPlaying = playingRef.current;
|
|
734
789
|
cancelAnimation(progress);
|
|
735
790
|
playingRef.current = false;
|
|
736
|
-
const clamped =
|
|
791
|
+
const clamped = clampSeekMs(t, seekCeiling);
|
|
792
|
+
runClock.seek(clamped);
|
|
737
793
|
const withinIteration = tracks.duration > 0 ? clamped % tracks.duration || (clamped === 0 ? 0 : tracks.duration) : 0;
|
|
738
794
|
progress.value = withinIteration;
|
|
739
795
|
if (wasPlaying) startFrom(withinIteration);
|
|
796
|
+
else runClock.stop();
|
|
797
|
+
},
|
|
798
|
+
getCurrentProgress: () => timeToProgress(runClock.now(), tracks.duration, tracks.iterations),
|
|
799
|
+
setCurrentProgress: (p) => {
|
|
800
|
+
api.setCurrentTime(progressToTimeMs(p, tracks.duration, tracks.iterations));
|
|
740
801
|
}
|
|
741
802
|
};
|
|
742
803
|
useImperativeHandle(apiRef, () => api, [compiled]);
|
|
743
|
-
const trigger = compiled.doc ? (_a = getAnimatorConfig2(compiled.doc)) == null ? void 0 : _a.trigger : void 0;
|
|
744
|
-
const effectiveStartOn =
|
|
745
|
-
const effectiveOutAction =
|
|
804
|
+
const trigger = resolveTrigger(compiled.doc ? (_a = getAnimatorConfig2(compiled.doc)) == null ? void 0 : _a.trigger : void 0);
|
|
805
|
+
const effectiveStartOn = trigger.startOn;
|
|
806
|
+
const effectiveOutAction = trigger.outAction;
|
|
807
|
+
const { mode: compMode, warnings: modeWarnings } = resolveControlMode({ progress: progressProp, time, play, pause, autoplay });
|
|
808
|
+
useEffect(() => {
|
|
809
|
+
const diag = makeDiag();
|
|
810
|
+
for (const w of modeWarnings) diag.warn(PxDiagnosticKind2.usage, w);
|
|
811
|
+
}, [modeWarnings.join("|")]);
|
|
746
812
|
useEffect(() => {
|
|
747
|
-
if (
|
|
748
|
-
const seekMs = time !== void 0 ? time : (progressProp != null ? progressProp : 0
|
|
813
|
+
if (compMode === PxControlMode.fixedTime) {
|
|
814
|
+
const seekMs = time !== void 0 ? time : progressToTimeMs(progressProp != null ? progressProp : 0, tracks.duration, tracks.iterations);
|
|
749
815
|
api.setCurrentTime(seekMs);
|
|
750
816
|
return;
|
|
751
817
|
}
|
|
752
|
-
if (
|
|
818
|
+
if (compMode === PxControlMode.play) {
|
|
753
819
|
if (play && !pause) api.play();
|
|
754
820
|
else if (pause) api.pause();
|
|
755
|
-
else if (play === false) api.
|
|
821
|
+
else if (play === false) api.pause();
|
|
756
822
|
else api.play();
|
|
757
823
|
return;
|
|
758
824
|
}
|
|
759
|
-
if (autoplay && effectiveStartOn === "load") {
|
|
825
|
+
if (compMode === PxControlMode.autoplay && effectiveStartOn === "load") {
|
|
760
826
|
api.play();
|
|
761
827
|
}
|
|
762
|
-
}, [compiled, autoplay, play, pause, progressProp, time]);
|
|
828
|
+
}, [compiled, compMode, autoplay, play, pause, progressProp, time]);
|
|
763
829
|
const scrollRef = useRef(null);
|
|
764
830
|
const inViewRef = useRef(false);
|
|
765
831
|
useEffect(() => {
|
|
766
|
-
var _a2;
|
|
767
832
|
if (!autoplay || effectiveStartOn !== "scrollIntoView") return;
|
|
768
|
-
const threshold =
|
|
833
|
+
const threshold = trigger.scrollIntoViewThreshold;
|
|
769
834
|
inViewRef.current = false;
|
|
770
835
|
const check = () => {
|
|
771
836
|
const node = scrollRef.current;
|
|
@@ -796,6 +861,8 @@ function PixodeskSvgAnimator({
|
|
|
796
861
|
return () => {
|
|
797
862
|
cancelAnimation(progress);
|
|
798
863
|
playingRef.current = false;
|
|
864
|
+
onRemove == null ? void 0 : onRemove();
|
|
865
|
+
onStop == null ? void 0 : onStop();
|
|
799
866
|
};
|
|
800
867
|
}, [compiled]);
|
|
801
868
|
const trackById = useMemo(() => {
|
|
@@ -851,14 +918,15 @@ function PixodeskSvgAnimator({
|
|
|
851
918
|
} catch (e) {
|
|
852
919
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
853
920
|
renderErrorRef.current = error;
|
|
854
|
-
|
|
921
|
+
makeDiag().warn(PxDiagnosticKind2.internal, "could not render the document: " + error.message);
|
|
855
922
|
return null;
|
|
856
923
|
}
|
|
857
924
|
}, [compiled, trackById]);
|
|
858
925
|
useEffect(() => {
|
|
859
|
-
|
|
926
|
+
const diag = makeDiag();
|
|
927
|
+
for (const w of warningsRef.current) diag.warn(PxDiagnosticKind2.platform, w);
|
|
860
928
|
}, [root]);
|
|
861
|
-
const failure = (
|
|
929
|
+
const failure = (_b = compiled.error) != null ? _b : renderErrorRef.current;
|
|
862
930
|
useEffect(() => {
|
|
863
931
|
if (failure) onError == null ? void 0 : onError(failure);
|
|
864
932
|
}, [failure]);
|
|
@@ -886,7 +954,7 @@ function PixodeskSvgAnimator({
|
|
|
886
954
|
}
|
|
887
955
|
);
|
|
888
956
|
}
|
|
889
|
-
return /* @__PURE__ */ jsx(PxRnErrorBoundary, { onError, fallback, children: content });
|
|
957
|
+
return /* @__PURE__ */ jsx(PxRnErrorBoundary, { onError, fallback, diag: makeDiag(), children: content });
|
|
890
958
|
}
|
|
891
959
|
var PixodeskSvgAnimator_default = PixodeskSvgAnimator;
|
|
892
960
|
export {
|