@pixodesk/svg-animator-react 1.0.19 → 1.0.20
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 +10 -4
- package/dist/index.cjs +61 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -5
- package/dist/index.d.ts +13 -5
- package/dist/index.js +61 -23
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +301 -88
- package/dist/index.umd.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ const api = useRef<ReactAnimatorApi>(null);
|
|
|
60
60
|
<button onClick={() => api.current?.finish()}>Finish</button>
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`ReactAnimatorApi` methods: `play()`, `pause()`, `cancel()`, `finish()`, `isPlaying()`, `getCurrentTime()`, `setCurrentTime(ms)`.
|
|
63
|
+
`ReactAnimatorApi` methods: `play()`, `pause()`, `cancel()`, `finish()`, `isPlaying()`, `setPlaybackRate(rate)`, `getCurrentTime()`, `setCurrentTime(ms)`.
|
|
64
64
|
|
|
65
65
|
### Controlled time
|
|
66
66
|
|
|
@@ -89,7 +89,7 @@ const [timeMs, setTimeMs] = useState(0);
|
|
|
89
89
|
| `play` | `boolean` | Start playback, ignoring document triggers |
|
|
90
90
|
| `pause` | `boolean` | Pause current playback |
|
|
91
91
|
| `apiRef` | `RefObject<ReactAnimatorApi>` | Ref for imperative control |
|
|
92
|
-
| `time` | `number` | Seek to a
|
|
92
|
+
| `time` | `number` | Seek to a fraction (0–1) of the whole timeline (duration × iterations) |
|
|
93
93
|
| `timeMs` | `number` | Seek to a time in milliseconds |
|
|
94
94
|
| `mode` | `'auto' \| 'webapi' \| 'frames'` | Animation engine |
|
|
95
95
|
| `duration` | `number` | Duration override (ms) |
|
|
@@ -104,5 +104,11 @@ const [timeMs, setTimeMs] = useState(0);
|
|
|
104
104
|
| `onPause` | `() => void` | Called on pause |
|
|
105
105
|
| `onFinish` | `() => void` | Called on natural finish |
|
|
106
106
|
| `onCancel` | `() => void` | Called on cancel |
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
107
|
+
| `onRemove` | `() => void` | Called when the animation is destroyed (e.g. unmount) |
|
|
108
|
+
| `onStop` | `() => void` | Called whenever playback halts (pause / cancel / finish / remove) |
|
|
109
|
+
| `className` | `string` | CSS class applied to the rendered root `<svg>` |
|
|
110
|
+
| `style` | `CSSProperties` | Inline styles applied to the rendered root `<svg>` |
|
|
111
|
+
|
|
112
|
+
With none of `autoplay` / `play` / `pause` / `apiRef` / `time` / `timeMs` set, the component renders the animation statically (initial state, no playback).
|
|
113
|
+
|
|
114
|
+
Note: recreating the animator (unmount or a `doc` swap) emits `onCancel`, `onRemove`, and `onStop` for the torn-down instance. Scrubbing `time` / `timeMs` does **not** recreate the animator — it seeks the existing one.
|
package/dist/index.cjs
CHANGED
|
@@ -136,22 +136,40 @@ var PixodeskSvgAnimatorImpl = ({
|
|
|
136
136
|
style,
|
|
137
137
|
doc,
|
|
138
138
|
compMode,
|
|
139
|
-
apiHolderRef
|
|
139
|
+
apiHolderRef,
|
|
140
|
+
callbacksRef
|
|
140
141
|
}) => {
|
|
141
142
|
doc = (0, import_svg_animator_web.generateNewIds)(doc);
|
|
142
143
|
const elementRefs = (0, import_react2.useRef)(/* @__PURE__ */ new Map());
|
|
143
|
-
const renderNode = (node) => {
|
|
144
|
+
const renderNode = (node, isRoot = false) => {
|
|
144
145
|
if (!node) return null;
|
|
145
146
|
const { type, animate, meta, children, ...props } = node;
|
|
146
147
|
const normProps = (0, import_svg_animator_web.getNormalizedProps)(props);
|
|
147
148
|
normProps["ref"] = (domEl) => {
|
|
148
149
|
if (node["id"]) elementRefs.current.set(node["id"], domEl);
|
|
149
150
|
};
|
|
151
|
+
if (isRoot) {
|
|
152
|
+
if (className) {
|
|
153
|
+
normProps["className"] = normProps["className"] ? normProps["className"] + " " + className : className;
|
|
154
|
+
}
|
|
155
|
+
if (style) normProps["style"] = style;
|
|
156
|
+
}
|
|
150
157
|
return (0, import_react2.createElement)(type, normProps, children?.map((child) => renderNode(child)));
|
|
151
158
|
};
|
|
152
|
-
const root = doc ? renderNode(doc) : null;
|
|
159
|
+
const root = doc ? renderNode(doc, true) : null;
|
|
153
160
|
(0, import_react2.useEffect)(() => {
|
|
154
|
-
|
|
161
|
+
const cb = (name, alsoStop = false) => () => {
|
|
162
|
+
callbacksRef.current?.[name]?.();
|
|
163
|
+
if (alsoStop) callbacksRef.current?.onStop?.();
|
|
164
|
+
};
|
|
165
|
+
const callbacks = {
|
|
166
|
+
onPlay: cb("onPlay"),
|
|
167
|
+
onPause: cb("onPause", true),
|
|
168
|
+
onCancel: cb("onCancel", true),
|
|
169
|
+
onFinish: cb("onFinish", true),
|
|
170
|
+
onRemove: cb("onRemove", true)
|
|
171
|
+
};
|
|
172
|
+
let api = (0, import_svg_animator_web.createAnimator)({ data: doc, adapter: createReactAdapter(elementRefs), callbacks });
|
|
155
173
|
apiHolderRef.current = api;
|
|
156
174
|
return () => {
|
|
157
175
|
api?.destroy();
|
|
@@ -175,7 +193,6 @@ var PixodeskSvgAnimator = ({
|
|
|
175
193
|
time,
|
|
176
194
|
timeMs,
|
|
177
195
|
apiRef,
|
|
178
|
-
timeline,
|
|
179
196
|
// Overrides
|
|
180
197
|
mode,
|
|
181
198
|
delay,
|
|
@@ -186,7 +203,13 @@ var PixodeskSvgAnimator = ({
|
|
|
186
203
|
frameRate,
|
|
187
204
|
startOn,
|
|
188
205
|
outAction,
|
|
189
|
-
scrollIntoViewThreshold
|
|
206
|
+
scrollIntoViewThreshold,
|
|
207
|
+
onPlay,
|
|
208
|
+
onStop,
|
|
209
|
+
onPause,
|
|
210
|
+
onCancel,
|
|
211
|
+
onFinish,
|
|
212
|
+
onRemove
|
|
190
213
|
}) => {
|
|
191
214
|
let compMode = "static" /* static */;
|
|
192
215
|
if (apiRef) {
|
|
@@ -195,7 +218,7 @@ var PixodeskSvgAnimator = ({
|
|
|
195
218
|
compMode = "autoplay" /* autoplay */;
|
|
196
219
|
} else if (time !== void 0 || timeMs !== void 0) {
|
|
197
220
|
compMode = "fixedTime" /* fixedTime */;
|
|
198
|
-
} else {
|
|
221
|
+
} else if (play !== void 0 || pause !== void 0) {
|
|
199
222
|
compMode = "play" /* play */;
|
|
200
223
|
}
|
|
201
224
|
if (compMode !== "autoplay" /* autoplay */) {
|
|
@@ -245,20 +268,20 @@ var PixodeskSvgAnimator = ({
|
|
|
245
268
|
}
|
|
246
269
|
};
|
|
247
270
|
}
|
|
271
|
+
let seekMs;
|
|
248
272
|
if (compMode === "fixedTime" /* fixedTime */) {
|
|
249
|
-
let delay2 = 0;
|
|
250
|
-
if (time !== void 0) delay2 = -time;
|
|
251
|
-
if (timeMs !== void 0) delay2 = -timeMs;
|
|
252
273
|
const animator = doc.animator || {};
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
274
|
+
if (time !== void 0) {
|
|
275
|
+
const iterationsValue = iterations ?? animator.iterations;
|
|
276
|
+
const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
|
|
277
|
+
const singleDuration = duration ?? animator.duration ?? 1e3;
|
|
278
|
+
seekMs = time * singleDuration * iterationsCount;
|
|
279
|
+
}
|
|
280
|
+
if (timeMs !== void 0) seekMs = timeMs;
|
|
260
281
|
}
|
|
261
282
|
const apiHolderRef = (0, import_react2.useRef)(null);
|
|
283
|
+
const callbacksRef = (0, import_react2.useRef)({});
|
|
284
|
+
callbacksRef.current = { onPlay, onStop, onPause, onCancel, onFinish, onRemove };
|
|
262
285
|
(0, import_react2.useImperativeHandle)(apiRef, () => {
|
|
263
286
|
return {
|
|
264
287
|
isPlaying: () => apiHolderRef.current?.isPlaying() || false,
|
|
@@ -266,18 +289,22 @@ var PixodeskSvgAnimator = ({
|
|
|
266
289
|
pause: () => apiHolderRef.current?.pause(),
|
|
267
290
|
cancel: () => apiHolderRef.current?.cancel(),
|
|
268
291
|
finish: () => apiHolderRef.current?.finish(),
|
|
269
|
-
|
|
292
|
+
setPlaybackRate: (rate) => apiHolderRef.current?.setPlaybackRate(rate),
|
|
293
|
+
getCurrentTime: () => apiHolderRef.current?.getCurrentTime() ?? null,
|
|
270
294
|
setCurrentTime: (time2) => apiHolderRef.current?.setCurrentTime(time2)
|
|
271
295
|
};
|
|
272
296
|
}, []);
|
|
297
|
+
const key = useDepsVersion(compMode, doc, className, style);
|
|
273
298
|
(0, import_react2.useEffect)(() => {
|
|
274
299
|
if (compMode === "play" /* play */) {
|
|
275
300
|
if (play && !pause) {
|
|
276
301
|
apiHolderRef.current?.play();
|
|
277
302
|
} else if (pause) {
|
|
278
303
|
apiHolderRef.current?.pause();
|
|
279
|
-
} else {
|
|
304
|
+
} else if (play === false) {
|
|
280
305
|
apiHolderRef.current?.finish();
|
|
306
|
+
} else {
|
|
307
|
+
apiHolderRef.current?.play();
|
|
281
308
|
}
|
|
282
309
|
}
|
|
283
310
|
return () => {
|
|
@@ -285,14 +312,22 @@ var PixodeskSvgAnimator = ({
|
|
|
285
312
|
apiHolderRef.current?.pause();
|
|
286
313
|
}
|
|
287
314
|
};
|
|
288
|
-
}, [compMode, play, pause]);
|
|
289
|
-
|
|
315
|
+
}, [compMode, play, pause, key]);
|
|
316
|
+
(0, import_react2.useEffect)(() => {
|
|
317
|
+
if (compMode === "fixedTime" /* fixedTime */ && seekMs !== void 0) {
|
|
318
|
+
apiHolderRef.current?.setCurrentTime(seekMs);
|
|
319
|
+
apiHolderRef.current?.pause();
|
|
320
|
+
}
|
|
321
|
+
}, [compMode, seekMs, key]);
|
|
290
322
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
291
323
|
PixodeskSvgAnimatorImplOnce,
|
|
292
324
|
{
|
|
325
|
+
className,
|
|
326
|
+
style,
|
|
293
327
|
compMode,
|
|
294
328
|
doc,
|
|
295
|
-
apiHolderRef
|
|
329
|
+
apiHolderRef,
|
|
330
|
+
callbacksRef
|
|
296
331
|
},
|
|
297
332
|
key
|
|
298
333
|
);
|
|
@@ -325,7 +360,10 @@ var PixodeskSvgCssAnimator = ({ className, style, children, startOn = "load", ou
|
|
|
325
360
|
"div",
|
|
326
361
|
{
|
|
327
362
|
ref,
|
|
328
|
-
className:
|
|
363
|
+
className: [
|
|
364
|
+
className,
|
|
365
|
+
state === "playing" ? "px-anim-enabled px-anim-playing" : state === "paused" ? "px-anim-enabled" : ""
|
|
366
|
+
].filter(Boolean).join(" "),
|
|
329
367
|
style,
|
|
330
368
|
...handlers,
|
|
331
369
|
children
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/PixodeskSvgAnimator.tsx","../src/Utils.ts","../src/PixodeskSvgCssAnimator.tsx"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport PixodeskSvgAnimator from './PixodeskSvgAnimator';\nexport type { ReactAnimatorApi } from './PixodeskSvgAnimator';\nexport { PixodeskSvgAnimator };\n\nimport PixodeskSvgCssAnimator from './PixodeskSvgCssAnimator';\nexport { PixodeskSvgCssAnimator };\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { JsMode, OutAction, PxAnimatedSvgDocument, PxAnimatorAPI, PxNode, PxPlatformAdapter, PxTrigger, StartOn } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES } from '@pixodesk/svg-animator-web';\nimport type { CSSProperties, FC, ReactElement } from 'react';\nimport React, { createElement, useEffect, useImperativeHandle, useRef } from 'react';\nimport { useDepsVersion } from './Utils';\n\n\n// -- Public types -----------------------------------------------------------\n\nexport interface ReactAnimatorApi {\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /** Returns the current playback time in milliseconds. */\n getCurrentTime(): number | null;\n\n /** Jumps to a specific time (in milliseconds) in the animation. */\n setCurrentTime(time: number): void;\n}\n\nexport interface PixodeskSvgAnimatorImplProps {\n className?: string;\n style?: CSSProperties;\n doc: PxAnimatedSvgDocument;\n compMode: PixodeskSvgAnimatorCompMode;\n\n /** Imperative API handle populated by the inner component. */\n apiHolderRef: React.RefObject<PxAnimatorAPI | null>;\n}\n\nexport interface PixodeskSvgAnimatorProps {\n\n className?: string;\n\n style?: CSSProperties;\n\n // -- Source ---------------------------------------------------------------\n\n /**\n * The animation document to render.\n *\n * TODO: Accept PxFileConfig | string to support URL-based loading, e.g.\n * <PixodeskSvgAnimator doc=\"/animation.json\" />\n */\n doc: PxAnimatedSvgDocument;\n\n // -- Timeline ------------------------------------------------------------\n\n timeline?: 'time' | 'scroll';\n\n // -- Rendering mode ------------------------------------------------------\n\n /** Forces a specific rendering engine. Defaults to 'auto'. */\n mode?: JsMode;\n\n // -- Timing overrides ----------------------------------------------------\n\n /** Delay before the animation starts, in milliseconds. */\n delay?: number;\n\n /** Defines the element's style when the animation is not active. */\n fill?: FillMode;\n\n /** Number of iterations, or 'infinite' for endless looping. */\n iterations?: number | 'infinite';\n\n /** Duration of a single iteration in milliseconds. */\n duration?: number;\n\n /** Playback direction. */\n direction?: PlaybackDirection;\n\n /** Target frame rate (frames per second). */\n frameRate?: number;\n\n // -- Trigger overrides ---------------------------------------------------\n\n /** The event that starts the animation. When omitted, uses the value from the document config. */\n startOn?: StartOn;\n\n /** Behaviour when the trigger condition ends (e.g. mouse-out, second click). */\n outAction?: OutAction;\n\n /** Visibility ratio (0.0–1.0) required to trigger a scrollIntoView animation. Defaults to 0.5. */\n scrollIntoViewThreshold?: number;\n\n // -- Declarative control -------------------------------------------------\n\n /** When true, uses triggers defined in the animation document. */\n autoplay?: boolean;\n\n /**\n * Starts the animation unconditionally, ignoring document triggers.\n * Equivalent to `startOn=\"load\"` / `outAction=\"continue\"`.\n */\n play?: boolean;\n\n /** Pauses current playback. Only meaningful when `play` or `autoplay` is set. */\n pause?: boolean;\n\n // -- Imperative control --------------------------------------------------\n\n /** Ref populated with the imperative playback API. */\n apiRef?: React.RefObject<ReactAnimatorApi | null>;\n\n // -- Controlled (external) time ------------------------------------------\n\n /** Seek to a specific point in the animation (fractional). */\n time?: number;\n\n /** Seek to a specific point in the animation (milliseconds). */\n timeMs?: number;\n\n // -- Callbacks -----------------------------------------------------------\n\n /** Called when the animation starts or resumes. */\n onPlay?: () => void;\n\n /** Called when the animation stops for any reason (pause / cancel / finish / removal). */\n onStop?: () => void; // FIXME: consider a more descriptive name\n\n /** Called when the animation is paused. */\n onPause?: () => void;\n\n /** Called when the animation is cancelled. */\n onCancel?: () => void;\n\n /** Called when the animation finishes naturally. */\n onFinish?: () => void;\n\n /** Called when the animation is removed. */\n onRemove?: () => void;\n\n // -- Diagnostics ---------------------------------------------------------\n\n onWarning?: (msg: string) => void;\n onError?: (msg: string) => void;\n}\n\n\n// -- Internal types ---------------------------------------------------------\n\nenum PixodeskSvgAnimatorCompMode {\n static = 'static',\n autoplay = 'autoplay',\n play = 'play',\n imperativeApi = 'imperativeApi',\n fixedTime = 'fixedTime'\n}\n\n\n// -- React ↔ Animator bridge ------------------------------------------------\n\n/**\n * Creates a platform adapter that routes animator attribute updates\n * to the corresponding React-managed DOM refs.\n */\nexport function createReactAdapter(elementRefs: React.RefObject<Map<string, any>>) {\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => {\n return true;\n },\n setAttribute: (id, attrName, value) => {\n\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const selector = getSelector(id);\n\n const element = elementRefs.current.get(id);\n\n if (!element && !warnedSelectors.has(selector)) {\n warnedSelectors.add(selector);\n console.warn('setAttribute: No elements found for selector \"' + selector + '\"');\n console.warn(elementRefs.current);\n }\n\n if (element) {\n element.setAttribute(attrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\n}\n\nexport function getSelector(id: string) {\n return '#' + id;\n}\n\n// FIXME: add model validation (e.g. isElementFileJson check)\n\n\n// -- Inner component (memoised, never re-renders) ---------------------------\n\nconst PixodeskSvgAnimatorImpl: FC<PixodeskSvgAnimatorImplProps> = ({\n className, style, doc, compMode, apiHolderRef\n}) => {\n\n doc = generateNewIds(doc);\n\n const elementRefs = useRef(new Map<string, any>());\n\n const renderNode = (node: PxNode | undefined): ReactElement | null => {\n if (!node) return null;\n\n const { type, animate, meta, children, ...props } = node;\n\n const normProps = getNormalizedProps(props);\n\n normProps['ref'] = (domEl: any) => {\n if (node['id']) elementRefs.current.set(node['id'], domEl);\n // return () => {};\n };\n\n return createElement(type, normProps, children?.map(child => renderNode(child)));\n };\n\n const root = doc ? renderNode(doc) : null;\n\n // Create the animator once per document and tear it down on unmount.\n useEffect(() => {\n\n let api: PxAnimatorAPI | undefined = createAnimator({ data: doc, adapter: createReactAdapter(elementRefs) });\n apiHolderRef.current = api;\n\n return () => {\n api?.destroy();\n apiHolderRef.current = null;\n };\n }, [doc, apiHolderRef]);\n\n return root;\n};\n\n/** Memoised wrapper — the inner component never re-renders (props are stable by design). */\nconst PixodeskSvgAnimatorImplOnce = React.memo(\n PixodeskSvgAnimatorImpl,\n () => true // Don't re-render\n);\n\n\n// -- Main public component --------------------------------------------------\n\n/**\n * React component for rendering and controlling Pixodesk SVG animations.\n *\n * Supports four mutually-exclusive control modes:\n *\n * 1. **Autoplay** – uses triggers from the animation document.\n * ```tsx\n * <PixodeskSvgAnimator doc={animation} autoplay />\n * ```\n *\n * 2. **Declarative play/pause** – controlled via boolean props.\n * ```tsx\n * <PixodeskSvgAnimator doc={animation} play pause={false} />\n * ```\n *\n * 3. **Imperative** – exposes a ref-based API for full programmatic control.\n * ```tsx\n * const api = useRef<ReactAnimatorApi>(null);\n * <PixodeskSvgAnimator doc={animation} apiRef={api} />\n * <button onClick={() => api.current?.play()}>Play</button>\n * ```\n *\n * 4. **Controlled time** – renders a single frame at a given time.\n * ```tsx\n * <PixodeskSvgAnimator doc={animation} time={0.5} />\n * <PixodeskSvgAnimator doc={animation} timeMs={500} />\n * ```\n */\nconst PixodeskSvgAnimator: FC<PixodeskSvgAnimatorProps> = ({\n className, style,\n doc, autoplay, play, pause, time, timeMs, apiRef,\n timeline,\n\n // Overrides\n mode, delay, fill, iterations, duration, direction, frameRate,\n\n startOn, outAction, scrollIntoViewThreshold\n}) => {\n\n // Determine which control mode is active.\n let compMode = PixodeskSvgAnimatorCompMode.static;\n if (apiRef) {\n compMode = PixodeskSvgAnimatorCompMode.imperativeApi;\n } else if (autoplay) {\n compMode = PixodeskSvgAnimatorCompMode.autoplay;\n } else if (time !== undefined || timeMs !== undefined) {\n compMode = PixodeskSvgAnimatorCompMode.fixedTime;\n } else {\n compMode = PixodeskSvgAnimatorCompMode.play;\n }\n\n // In non-autoplay modes, override the document trigger to 'programmatic'\n // so the component can manage playback itself.\n if (compMode !== PixodeskSvgAnimatorCompMode.autoplay) {\n const startOn = doc.animator?.trigger?.startOn;\n if (\n startOn &&\n startOn !== 'programmatic' // FIXME: use enum\n ) {\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...doc.animator?.trigger,\n startOn: 'programmatic' // FIXME: use enum\n }\n }\n };\n }\n }\n\n // Apply timing overrides from props onto the document config.\n if (\n mode !== undefined ||\n duration !== undefined ||\n delay !== undefined ||\n iterations !== undefined ||\n fill !== undefined ||\n direction !== undefined ||\n frameRate !== undefined\n ) {\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n mode: mode !== undefined ? mode : animator.mode,\n duration: duration !== undefined ? duration : animator.duration,\n delay: delay !== undefined ? delay : animator.delay,\n iterations: iterations !== undefined ? iterations : animator.iterations,\n fill: fill !== undefined ? fill : animator.fill,\n direction: direction !== undefined ? direction : animator.direction,\n frameRate: frameRate !== undefined ? frameRate : animator.frameRate\n }\n };\n }\n\n // Apply trigger overrides from props.\n if (\n startOn !== undefined ||\n outAction !== undefined ||\n scrollIntoViewThreshold !== undefined\n ) {\n const trigger: PxTrigger = doc.animator?.trigger || {};\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...trigger,\n startOn: startOn !== undefined ? startOn : trigger.startOn,\n outAction: outAction !== undefined ? outAction : trigger.outAction,\n scrollIntoViewThreshold: scrollIntoViewThreshold !== undefined ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold\n }\n }\n };\n }\n\n // In controlled-time mode, use a negative delay to seek to the given frame.\n if (compMode === PixodeskSvgAnimatorCompMode.fixedTime) {\n let delay = 0;\n if (time !== undefined) delay = -time; // FIXME: time as a fraction of total duration?\n if (timeMs !== undefined) delay = -timeMs;\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n delay\n }\n };\n }\n\n const apiHolderRef = useRef<PxAnimatorAPI | null>(null);\n\n // Expose the imperative API via the consumer-provided ref.\n useImperativeHandle(apiRef, () => {\n return {\n isPlaying: () => apiHolderRef.current?.isPlaying() || false,\n play: () => apiHolderRef.current?.play(),\n pause: () => apiHolderRef.current?.pause(),\n cancel: () => apiHolderRef.current?.cancel(),\n finish: () => apiHolderRef.current?.finish(),\n getCurrentTime: () => apiHolderRef.current?.getCurrentTime() || null,\n setCurrentTime: (time: number) => apiHolderRef.current?.setCurrentTime(time),\n };\n }, []);\n\n // Sync declarative play/pause props with the animator.\n useEffect(() => {\n\n if (compMode === PixodeskSvgAnimatorCompMode.play) {\n if (play && !pause) {\n apiHolderRef.current?.play();\n } else if (pause) {\n apiHolderRef.current?.pause();\n } else {\n apiHolderRef.current?.finish();\n }\n }\n\n return () => {\n if (compMode === PixodeskSvgAnimatorCompMode.play) {\n apiHolderRef.current?.pause(); // FIXME - implement\n }\n };\n }, [compMode, play, pause]);\n\n // Increment key when the document or mode changes to force a full remount.\n const key = useDepsVersion(compMode, doc);\n\n return (\n <PixodeskSvgAnimatorImplOnce\n key={key}\n compMode={compMode}\n doc={doc}\n apiHolderRef={apiHolderRef}\n />\n );\n};\n\nexport default PixodeskSvgAnimator;","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { useRef } from 'react';\n\nexport function deepEquals(a: any, b: any): boolean {\n // Handle primitives and null\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n\n // Check for cycles using WeakSet\n const seen = new WeakSet();\n\n function equals(x: any, y: any): boolean {\n // Primitive/null check\n if (x === y) return true;\n if (x == null || y == null) return false;\n if (typeof x !== 'object' || typeof y !== 'object') return false;\n\n // Cycle detection\n if (seen.has(x)) {\n throw new Error('Circular reference detected');\n }\n seen.add(x);\n\n // Array check\n const xIsArray = Array.isArray(x);\n const yIsArray = Array.isArray(y);\n if (xIsArray !== yIsArray) return false;\n\n if (xIsArray) {\n if (x.length !== y.length) return false;\n for (let i = 0; i < x.length; i++) {\n if (!equals(x[i], y[i])) return false;\n }\n return true;\n }\n\n // Object check\n const xKeys = Object.keys(x);\n const yKeys = Object.keys(y);\n if (xKeys.length !== yKeys.length) return false;\n\n for (const key of xKeys) {\n if (!yKeys.includes(key)) return false;\n if (!equals(x[key], y[key])) return false;\n }\n\n return true;\n }\n\n return equals(a, b);\n}\n\n\n/**\n * Compares two arrays of dependencies using identity check first (===),\n * falling back to deep equality if references differ.\n * This is optimized for immutable data that may be recreated with same values.\n */\nfunction areDepsEqual(prevDeps: Array<any>, nextDeps: Array<any>): boolean {\n if (prevDeps.length !== nextDeps.length) return false;\n\n for (let i = 0; i < prevDeps.length; i++) {\n // Fast path: same reference (common for immutable data)\n if (prevDeps[i] === nextDeps[i]) continue;\n\n // Slow path: different reference but possibly same content\n if (!deepEquals(prevDeps[i], nextDeps[i])) return false;\n }\n\n return true;\n}\n\n/**\n * Returns a stable numeric version ID that only increments when dependencies\n * actually change (by reference or deep equality).\n */\nexport function useDepsVersion(...deps: Array<any>): number {\n const cache = useRef<{\n versionId: number;\n deps: Array<any>;\n } | null>(null);\n\n // First render - initialize with version 1\n if (cache.current === null) {\n cache.current = {\n versionId: 1,\n deps: deps\n };\n return 1;\n }\n\n // Check if any dependency changed (by reference or value)\n if (!areDepsEqual(cache.current.deps, deps)) {\n // Dependencies changed - increment version and update cache\n cache.current = {\n versionId: cache.current.versionId + 1,\n deps: deps\n };\n }\n\n return cache.current.versionId;\n}","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { OutAction, StartOn } from \"@pixodesk/svg-animator-web\";\nimport { CSSProperties, FC, ReactNode, useEffect, useRef, useState } from \"react\";\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n/**\n * Controls playback of a SVG+CSS animated files by toggling class names on a wrapper div.\n *\n * Intended for use with SVG files exported from the Pixodesk editor using the\n * **CSS Keyframes** (no `<script>` tag). Import the SVG as a React component\n * via SVGR (`vite-plugin-svgr` or `@svgr/webpack`) and pass it as `children`:\n *\n * ```tsx\n * import AnimationSvg from './animation.svg?react'; // SVGR\n *\n * <PixodeskSvgCssAnimator startOn=\"mouseOver\" outAction=\"pause\">\n * <AnimationSvg />\n * </PixodeskSvgCssAnimator>\n * ```\n *\n * The wrapper div carries one of three animation states via CSS class names:\n * - *(no class)* — idle, animation not started\n * - `px-anim-enabled` — started but paused\n * - `px-anim-enabled px-anim-playing` — actively playing\n *\n * @param children - The SVGR-imported SVG component to animate.\n * @param startOn - What triggers the animation to start:\n * - `'load'` — plays immediately on mount (default)\n * - `'mouseOver'` — plays on hover\n * - `'click'` — plays on click, toggles on second click\n * - `'scrollIntoView'` — plays when the element enters the viewport\n * @param outAction - What happens when the trigger ends (hover/scroll out, second click):\n * - `'continue'` — keeps playing (default)\n * - `'pause'` — pauses at the current frame\n * - `'reset'` — resets to the beginning\n * @param className - Additional CSS class names to apply to the wrapper div.\n * @param style - Inline styles for the wrapper div (e.g. `{ width: 400, height: 400 }`).\n */\nconst PixodeskSvgCssAnimator: FC<{\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n startOn?: StartOn;\n outAction?: OutAction;\n}> = ({ className, style, children, startOn = 'load', outAction = 'continue' }) => {\n\n const [state, setState] = useState<AnimState>(startOn === 'load' ? 'playing' : 'idle');\n\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (startOn !== 'scrollIntoView') return;\n const el = ref.current;\n if (!el) return;\n const outState: AnimState = (\n outAction === 'reset' ? 'idle' :\n outAction === 'pause' ? 'paused' : 'playing'\n );\n const observer = new IntersectionObserver(\n ([entry]) => setState(entry.isIntersecting ? 'playing' : outState),\n { threshold: 0.1 }\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [startOn, outAction]);\n\n const goOut = () => setState(\n outAction === 'reset' ? 'idle' :\n outAction === 'pause' ? 'paused' : 'playing'\n );\n\n const handlers =\n startOn === 'mouseOver' ? { onMouseEnter: () => setState('playing'), onMouseLeave: goOut } :\n startOn === 'click' ? { onClick: () => state === 'playing' ? goOut() : setState('playing') } :\n {};\n\n return (\n <div\n ref={ref}\n className={className + (\n state === 'playing' ? 'px-anim-enabled px-anim-playing' :\n state === 'paused' ? 'px-anim-enabled' : ''\n )}\n style={style}\n {...handlers}\n >\n {children}\n </div>\n );\n};\nexport default PixodeskSvgCssAnimator;"],"mappings":"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","names":["import_react","React","startOn","delay","time","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/PixodeskSvgAnimator.tsx","../src/Utils.ts","../src/PixodeskSvgCssAnimator.tsx"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport PixodeskSvgAnimator from './PixodeskSvgAnimator';\nexport type { PixodeskSvgAnimatorCallbacks, PixodeskSvgAnimatorProps, ReactAnimatorApi } from './PixodeskSvgAnimator';\nexport { PixodeskSvgAnimator };\n\nimport PixodeskSvgCssAnimator from './PixodeskSvgCssAnimator';\nexport { PixodeskSvgCssAnimator };\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport type { JsMode, OutAction, PxAnimatedSvgDocument, PxAnimatorAPI, PxNode, PxPlatformAdapter, PxTrigger, StartOn } from '@pixodesk/svg-animator-web';\nimport { camelCaseToKebabWordIfNeeded, createAnimator, FillMode, generateNewIds, getNormalizedProps, STYLE_ATTR_NAMES } from '@pixodesk/svg-animator-web';\nimport type { CSSProperties, FC, ReactElement } from 'react';\nimport React, { createElement, useEffect, useImperativeHandle, useRef } from 'react';\nimport { useDepsVersion } from './Utils';\n\n\n// -- Public types -----------------------------------------------------------\n\nexport interface ReactAnimatorApi {\n /** Returns true if the animation is currently running. */\n isPlaying(): boolean;\n\n /** Starts or resumes the animation. */\n play(): void;\n\n /** Pauses the animation at its current state. */\n pause(): void;\n\n /** Stops the animation and resets it to its initial state. */\n cancel(): void;\n\n /** Jumps to the end of the animation and holds the final state. */\n finish(): void;\n\n /** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */\n setPlaybackRate(rate: number): void;\n\n /** Returns the current playback time in milliseconds. */\n getCurrentTime(): number | null;\n\n /** Jumps to a specific time (in milliseconds) in the animation. */\n setCurrentTime(time: number): void;\n}\n\nexport interface PixodeskSvgAnimatorImplProps {\n className?: string;\n style?: CSSProperties;\n doc: PxAnimatedSvgDocument;\n compMode: PixodeskSvgAnimatorCompMode;\n\n /** Imperative API handle populated by the inner component. */\n apiHolderRef: React.RefObject<PxAnimatorAPI | null>;\n\n /**\n * Latest lifecycle callbacks, read at invocation time so the memoised\n * inner component always calls the current props even though it never\n * re-renders.\n */\n callbacksRef: React.RefObject<PixodeskSvgAnimatorCallbacks>;\n}\n\n/** Lifecycle callback props (subset of {@link PixodeskSvgAnimatorProps}). */\nexport interface PixodeskSvgAnimatorCallbacks {\n onPlay?: () => void;\n onStop?: () => void;\n onPause?: () => void;\n onCancel?: () => void;\n onFinish?: () => void;\n onRemove?: () => void;\n}\n\nexport interface PixodeskSvgAnimatorProps {\n\n className?: string;\n\n style?: CSSProperties;\n\n // -- Source ---------------------------------------------------------------\n\n /**\n * The animation document to render.\n *\n * TODO: Accept PxFileConfig | string to support URL-based loading, e.g.\n * <PixodeskSvgAnimator doc=\"/animation.json\" />\n */\n doc: PxAnimatedSvgDocument;\n\n // -- Rendering mode ------------------------------------------------------\n\n /** Forces a specific rendering engine. Defaults to 'auto'. */\n mode?: JsMode;\n\n // -- Timing overrides ----------------------------------------------------\n\n /** Delay before the animation starts, in milliseconds. */\n delay?: number;\n\n /** Defines the element's style when the animation is not active. */\n fill?: FillMode;\n\n /** Number of iterations, or 'infinite' for endless looping. */\n iterations?: number | 'infinite';\n\n /** Duration of a single iteration in milliseconds. */\n duration?: number;\n\n /** Playback direction. */\n direction?: PlaybackDirection;\n\n /** Target frame rate (frames per second). */\n frameRate?: number;\n\n // -- Trigger overrides ---------------------------------------------------\n\n /** The event that starts the animation. When omitted, uses the value from the document config. */\n startOn?: StartOn;\n\n /** Behaviour when the trigger condition ends (e.g. mouse-out, second click). */\n outAction?: OutAction;\n\n /** Visibility ratio (0.0–1.0) required to trigger a scrollIntoView animation. Defaults to 0.5. */\n scrollIntoViewThreshold?: number;\n\n // -- Declarative control -------------------------------------------------\n\n /** When true, uses triggers defined in the animation document. */\n autoplay?: boolean;\n\n /**\n * Starts the animation unconditionally, ignoring document triggers.\n * Equivalent to `startOn=\"load\"` / `outAction=\"continue\"`.\n */\n play?: boolean;\n\n /** Pauses current playback. Only meaningful when `play` or `autoplay` is set. */\n pause?: boolean;\n\n // -- Imperative control --------------------------------------------------\n\n /** Ref populated with the imperative playback API. */\n apiRef?: React.RefObject<ReactAnimatorApi | null>;\n\n // -- Controlled (external) time ------------------------------------------\n\n /** Seek to a specific point in the animation, as a fraction (0–1) of the whole timeline (duration × iterations). */\n time?: number;\n\n /** Seek to a specific point in the animation (milliseconds). */\n timeMs?: number;\n\n // -- Callbacks -----------------------------------------------------------\n\n /** Called when the animation starts or resumes. */\n onPlay?: () => void;\n\n /** Called when the animation stops for any reason (pause / cancel / finish / removal). */\n onStop?: () => void;\n\n /** Called when the animation is paused. */\n onPause?: () => void;\n\n /** Called when the animation is cancelled. */\n onCancel?: () => void;\n\n /** Called when the animation finishes naturally. */\n onFinish?: () => void;\n\n /** Called when the animation is removed. */\n onRemove?: () => void;\n}\n\n\n// -- Internal types ---------------------------------------------------------\n\nenum PixodeskSvgAnimatorCompMode {\n static = 'static',\n autoplay = 'autoplay',\n play = 'play',\n imperativeApi = 'imperativeApi',\n fixedTime = 'fixedTime'\n}\n\n\n// -- React ↔ Animator bridge ------------------------------------------------\n\n/**\n * Creates a platform adapter that routes animator attribute updates\n * to the corresponding React-managed DOM refs.\n */\nexport function createReactAdapter(elementRefs: React.RefObject<Map<string, any>>) {\n const warnedSelectors = new Set<string>();\n\n const adapter: PxPlatformAdapter = {\n isConnected: () => {\n return true;\n },\n setAttribute: (id, attrName, value) => {\n\n attrName = camelCaseToKebabWordIfNeeded(attrName);\n\n const selector = getSelector(id);\n\n const element = elementRefs.current.get(id);\n\n if (!element && !warnedSelectors.has(selector)) {\n warnedSelectors.add(selector);\n console.warn('setAttribute: No elements found for selector \"' + selector + '\"');\n console.warn(elementRefs.current);\n }\n\n if (element) {\n element.setAttribute(attrName, value);\n if (STYLE_ATTR_NAMES.has(attrName)) {\n (element as HTMLElement).style[attrName as any] = value;\n }\n }\n },\n };\n return adapter;\n}\n\nexport function getSelector(id: string) {\n return '#' + id;\n}\n\n// FIXME: add model validation (e.g. isElementFileJson check)\n\n\n// -- Inner component (memoised, never re-renders) ---------------------------\n\nconst PixodeskSvgAnimatorImpl: FC<PixodeskSvgAnimatorImplProps> = ({\n className, style, doc, compMode, apiHolderRef, callbacksRef\n}) => {\n\n doc = generateNewIds(doc);\n\n const elementRefs = useRef(new Map<string, any>());\n\n const renderNode = (node: PxNode | undefined, isRoot = false): ReactElement | null => {\n if (!node) return null;\n\n const { type, animate, meta, children, ...props } = node;\n\n const normProps = getNormalizedProps(props);\n\n normProps['ref'] = (domEl: any) => {\n if (node['id']) elementRefs.current.set(node['id'], domEl);\n // return () => {};\n };\n\n // Apply the component's className/style props to the root SVG element.\n if (isRoot) {\n if (className) {\n normProps['className'] = normProps['className']\n ? normProps['className'] + ' ' + className\n : className;\n }\n if (style) normProps['style'] = style;\n }\n\n return createElement(type, normProps, children?.map(child => renderNode(child)));\n };\n\n const root = doc ? renderNode(doc, true) : null;\n\n // Create the animator once per document and tear it down on unmount.\n useEffect(() => {\n\n // Route lifecycle events through `callbacksRef` so the latest callback\n // props are invoked even though this component never re-renders.\n const cb = (name: keyof PixodeskSvgAnimatorCallbacks, alsoStop = false) => () => {\n callbacksRef.current?.[name]?.();\n if (alsoStop) callbacksRef.current?.onStop?.();\n };\n const callbacks = {\n onPlay: cb('onPlay'),\n onPause: cb('onPause', true),\n onCancel: cb('onCancel', true),\n onFinish: cb('onFinish', true),\n onRemove: cb('onRemove', true),\n };\n\n let api: PxAnimatorAPI | undefined = createAnimator({ data: doc, adapter: createReactAdapter(elementRefs), callbacks });\n apiHolderRef.current = api;\n\n return () => {\n api?.destroy();\n apiHolderRef.current = null;\n };\n }, [doc, apiHolderRef]);\n\n return root;\n};\n\n/** Memoised wrapper — the inner component never re-renders (props are stable by design). */\nconst PixodeskSvgAnimatorImplOnce = React.memo(\n PixodeskSvgAnimatorImpl,\n () => true // Don't re-render\n);\n\n\n// -- Main public component --------------------------------------------------\n\n/**\n * React component for rendering and controlling Pixodesk SVG animations.\n *\n * Supports four mutually-exclusive control modes:\n *\n * 1. **Autoplay** – uses triggers from the animation document.\n * ```tsx\n * <PixodeskSvgAnimator doc={animation} autoplay />\n * ```\n *\n * 2. **Declarative play/pause** – controlled via boolean props.\n * ```tsx\n * <PixodeskSvgAnimator doc={animation} play pause={false} />\n * ```\n *\n * 3. **Imperative** – exposes a ref-based API for full programmatic control.\n * ```tsx\n * const api = useRef<ReactAnimatorApi>(null);\n * <PixodeskSvgAnimator doc={animation} apiRef={api} />\n * <button onClick={() => api.current?.play()}>Play</button>\n * ```\n *\n * 4. **Controlled time** – renders a single frame at a given time.\n * ```tsx\n * <PixodeskSvgAnimator doc={animation} time={0.5} />\n * <PixodeskSvgAnimator doc={animation} timeMs={500} />\n * ```\n */\nconst PixodeskSvgAnimator: FC<PixodeskSvgAnimatorProps> = ({\n className, style,\n doc, autoplay, play, pause, time, timeMs, apiRef,\n\n // Overrides\n mode, delay, fill, iterations, duration, direction, frameRate,\n\n startOn, outAction, scrollIntoViewThreshold,\n\n onPlay, onStop, onPause, onCancel, onFinish, onRemove\n}) => {\n\n // Determine which control mode is active.\n let compMode = PixodeskSvgAnimatorCompMode.static;\n if (apiRef) {\n compMode = PixodeskSvgAnimatorCompMode.imperativeApi;\n } else if (autoplay) {\n compMode = PixodeskSvgAnimatorCompMode.autoplay;\n } else if (time !== undefined || timeMs !== undefined) {\n compMode = PixodeskSvgAnimatorCompMode.fixedTime;\n } else if (play !== undefined || pause !== undefined) {\n compMode = PixodeskSvgAnimatorCompMode.play;\n }\n\n // In non-autoplay modes, override the document trigger to 'programmatic'\n // so the component can manage playback itself.\n if (compMode !== PixodeskSvgAnimatorCompMode.autoplay) {\n const startOn = doc.animator?.trigger?.startOn;\n if (\n startOn &&\n startOn !== 'programmatic' // FIXME: use enum\n ) {\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...doc.animator?.trigger,\n startOn: 'programmatic' // FIXME: use enum\n }\n }\n };\n }\n }\n\n // Apply timing overrides from props onto the document config.\n if (\n mode !== undefined ||\n duration !== undefined ||\n delay !== undefined ||\n iterations !== undefined ||\n fill !== undefined ||\n direction !== undefined ||\n frameRate !== undefined\n ) {\n const animator = doc.animator || {};\n doc = {\n ...doc,\n animator: {\n ...animator,\n mode: mode !== undefined ? mode : animator.mode,\n duration: duration !== undefined ? duration : animator.duration,\n delay: delay !== undefined ? delay : animator.delay,\n iterations: iterations !== undefined ? iterations : animator.iterations,\n fill: fill !== undefined ? fill : animator.fill,\n direction: direction !== undefined ? direction : animator.direction,\n frameRate: frameRate !== undefined ? frameRate : animator.frameRate\n }\n };\n }\n\n // Apply trigger overrides from props.\n if (\n startOn !== undefined ||\n outAction !== undefined ||\n scrollIntoViewThreshold !== undefined\n ) {\n const trigger: PxTrigger = doc.animator?.trigger || {};\n doc = {\n ...doc,\n animator: {\n ...doc.animator,\n trigger: {\n ...trigger,\n startOn: startOn !== undefined ? startOn : trigger.startOn,\n outAction: outAction !== undefined ? outAction : trigger.outAction,\n scrollIntoViewThreshold: scrollIntoViewThreshold !== undefined ? scrollIntoViewThreshold : trigger.scrollIntoViewThreshold\n }\n }\n };\n }\n\n // Controlled-time mode: compute the absolute seek target. `time` is a\n // fraction (0–1) of the WHOLE timeline (duration × iterations); `timeMs`\n // is absolute milliseconds. The seek is applied through the animator API\n // (setCurrentTime) below — the document itself stays stable, so scrubbing\n // does NOT recreate the animator.\n let seekMs: number | undefined;\n if (compMode === PixodeskSvgAnimatorCompMode.fixedTime) {\n const animator = doc.animator || {};\n if (time !== undefined) {\n const iterationsValue = iterations ?? animator.iterations;\n const iterationsCount = typeof iterationsValue === 'number' && iterationsValue >= 1 ? iterationsValue : 1;\n const singleDuration = duration ?? animator.duration ?? 1000; // engine default duration\n seekMs = time * singleDuration * iterationsCount;\n }\n if (timeMs !== undefined) seekMs = timeMs;\n }\n\n const apiHolderRef = useRef<PxAnimatorAPI | null>(null);\n\n // Keep the latest callback props readable by the memoised inner component.\n const callbacksRef = useRef<PixodeskSvgAnimatorCallbacks>({});\n callbacksRef.current = { onPlay, onStop, onPause, onCancel, onFinish, onRemove };\n\n // Expose the imperative API via the consumer-provided ref.\n useImperativeHandle(apiRef, () => {\n return {\n isPlaying: () => apiHolderRef.current?.isPlaying() || false,\n play: () => apiHolderRef.current?.play(),\n pause: () => apiHolderRef.current?.pause(),\n cancel: () => apiHolderRef.current?.cancel(),\n finish: () => apiHolderRef.current?.finish(),\n setPlaybackRate: (rate: number) => apiHolderRef.current?.setPlaybackRate(rate),\n getCurrentTime: () => apiHolderRef.current?.getCurrentTime() ?? null,\n setCurrentTime: (time: number) => apiHolderRef.current?.setCurrentTime(time),\n };\n }, []);\n\n // Increment key when the document, mode, or root styling changes to force\n // a full remount (the inner component is memoised and never re-renders).\n const key = useDepsVersion(compMode, doc, className, style);\n\n // Sync declarative play/pause props with the animator. Re-runs after a\n // remount (`key` in deps) so a doc swap re-applies the current state.\n useEffect(() => {\n\n if (compMode === PixodeskSvgAnimatorCompMode.play) {\n if (play && !pause) {\n apiHolderRef.current?.play();\n } else if (pause) {\n apiHolderRef.current?.pause();\n } else if (play === false) {\n // explicit play=false → jump to the end state\n apiHolderRef.current?.finish();\n } else {\n // pause-only usage: pause switched off → resume\n apiHolderRef.current?.play();\n }\n }\n\n return () => {\n if (compMode === PixodeskSvgAnimatorCompMode.play) {\n apiHolderRef.current?.pause();\n }\n };\n }, [compMode, play, pause, key]);\n\n // Controlled-time mode: seek through the animator API. Scrubbing `time` /\n // `timeMs` only re-runs this effect — the animator is NOT recreated.\n useEffect(() => {\n if (compMode === PixodeskSvgAnimatorCompMode.fixedTime && seekMs !== undefined) {\n apiHolderRef.current?.setCurrentTime(seekMs);\n apiHolderRef.current?.pause();\n }\n }, [compMode, seekMs, key]);\n\n return (\n <PixodeskSvgAnimatorImplOnce\n key={key}\n className={className}\n style={style}\n compMode={compMode}\n doc={doc}\n apiHolderRef={apiHolderRef}\n callbacksRef={callbacksRef}\n />\n );\n};\n\nexport default PixodeskSvgAnimator;","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { useRef } from 'react';\n\nexport function deepEquals(a: any, b: any): boolean {\n // Handle primitives and null\n if (a === b) return true;\n if (a == null || b == null) return false;\n if (typeof a !== 'object' || typeof b !== 'object') return false;\n\n // Check for cycles using WeakSet\n const seen = new WeakSet();\n\n function equals(x: any, y: any): boolean {\n // Primitive/null check\n if (x === y) return true;\n if (x == null || y == null) return false;\n if (typeof x !== 'object' || typeof y !== 'object') return false;\n\n // Cycle detection\n if (seen.has(x)) {\n throw new Error('Circular reference detected');\n }\n seen.add(x);\n\n // Array check\n const xIsArray = Array.isArray(x);\n const yIsArray = Array.isArray(y);\n if (xIsArray !== yIsArray) return false;\n\n if (xIsArray) {\n if (x.length !== y.length) return false;\n for (let i = 0; i < x.length; i++) {\n if (!equals(x[i], y[i])) return false;\n }\n return true;\n }\n\n // Object check\n const xKeys = Object.keys(x);\n const yKeys = Object.keys(y);\n if (xKeys.length !== yKeys.length) return false;\n\n for (const key of xKeys) {\n if (!yKeys.includes(key)) return false;\n if (!equals(x[key], y[key])) return false;\n }\n\n return true;\n }\n\n return equals(a, b);\n}\n\n\n/**\n * Compares two arrays of dependencies using identity check first (===),\n * falling back to deep equality if references differ.\n * This is optimized for immutable data that may be recreated with same values.\n */\nfunction areDepsEqual(prevDeps: Array<any>, nextDeps: Array<any>): boolean {\n if (prevDeps.length !== nextDeps.length) return false;\n\n for (let i = 0; i < prevDeps.length; i++) {\n // Fast path: same reference (common for immutable data)\n if (prevDeps[i] === nextDeps[i]) continue;\n\n // Slow path: different reference but possibly same content\n if (!deepEquals(prevDeps[i], nextDeps[i])) return false;\n }\n\n return true;\n}\n\n/**\n * Returns a stable numeric version ID that only increments when dependencies\n * actually change (by reference or deep equality).\n */\nexport function useDepsVersion(...deps: Array<any>): number {\n const cache = useRef<{\n versionId: number;\n deps: Array<any>;\n } | null>(null);\n\n // First render - initialize with version 1\n if (cache.current === null) {\n cache.current = {\n versionId: 1,\n deps: deps\n };\n return 1;\n }\n\n // Check if any dependency changed (by reference or value)\n if (!areDepsEqual(cache.current.deps, deps)) {\n // Dependencies changed - increment version and update cache\n cache.current = {\n versionId: cache.current.versionId + 1,\n deps: deps\n };\n }\n\n return cache.current.versionId;\n}","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nimport { OutAction, StartOn } from \"@pixodesk/svg-animator-web\";\nimport { CSSProperties, FC, ReactNode, useEffect, useRef, useState } from \"react\";\n\n\ntype AnimState = 'idle' | 'paused' | 'playing';\n\n/**\n * Controls playback of a SVG+CSS animated files by toggling class names on a wrapper div.\n *\n * Intended for use with SVG files exported from the Pixodesk editor using the\n * **CSS Keyframes** (no `<script>` tag). Import the SVG as a React component\n * via SVGR (`vite-plugin-svgr` or `@svgr/webpack`) and pass it as `children`:\n *\n * ```tsx\n * import AnimationSvg from './animation.svg?react'; // SVGR\n *\n * <PixodeskSvgCssAnimator startOn=\"mouseOver\" outAction=\"pause\">\n * <AnimationSvg />\n * </PixodeskSvgCssAnimator>\n * ```\n *\n * The wrapper div carries one of three animation states via CSS class names:\n * - *(no class)* — idle, animation not started\n * - `px-anim-enabled` — started but paused\n * - `px-anim-enabled px-anim-playing` — actively playing\n *\n * @param children - The SVGR-imported SVG component to animate.\n * @param startOn - What triggers the animation to start:\n * - `'load'` — plays immediately on mount (default)\n * - `'mouseOver'` — plays on hover\n * - `'click'` — plays on click, toggles on second click\n * - `'scrollIntoView'` — plays when the element enters the viewport\n * @param outAction - What happens when the trigger ends (hover/scroll out, second click):\n * - `'continue'` — keeps playing (default)\n * - `'pause'` — pauses at the current frame\n * - `'reset'` — resets to the beginning\n * @param className - Additional CSS class names to apply to the wrapper div.\n * @param style - Inline styles for the wrapper div (e.g. `{ width: 400, height: 400 }`).\n */\nconst PixodeskSvgCssAnimator: FC<{\n className?: string;\n style?: CSSProperties;\n children: ReactNode;\n startOn?: StartOn;\n outAction?: OutAction;\n}> = ({ className, style, children, startOn = 'load', outAction = 'continue' }) => {\n\n const [state, setState] = useState<AnimState>(startOn === 'load' ? 'playing' : 'idle');\n\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (startOn !== 'scrollIntoView') return;\n const el = ref.current;\n if (!el) return;\n const outState: AnimState = (\n outAction === 'reset' ? 'idle' :\n outAction === 'pause' ? 'paused' : 'playing'\n );\n const observer = new IntersectionObserver(\n ([entry]) => setState(entry.isIntersecting ? 'playing' : outState),\n { threshold: 0.1 }\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [startOn, outAction]);\n\n const goOut = () => setState(\n outAction === 'reset' ? 'idle' :\n outAction === 'pause' ? 'paused' : 'playing'\n );\n\n const handlers =\n startOn === 'mouseOver' ? { onMouseEnter: () => setState('playing'), onMouseLeave: goOut } :\n startOn === 'click' ? { onClick: () => state === 'playing' ? goOut() : setState('playing') } :\n {};\n\n return (\n <div\n ref={ref}\n className={[\n className,\n state === 'playing' ? 'px-anim-enabled px-anim-playing' :\n state === 'paused' ? 'px-anim-enabled' : ''\n ].filter(Boolean).join(' ')}\n style={style}\n {...handlers}\n >\n {children}\n </div>\n );\n};\nexport default PixodeskSvgCssAnimator;"],"mappings":"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","names":["import_react","React","startOn","time","import_react","import_jsx_runtime"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -12,11 +12,22 @@ interface ReactAnimatorApi {
|
|
|
12
12
|
cancel(): void;
|
|
13
13
|
/** Jumps to the end of the animation and holds the final state. */
|
|
14
14
|
finish(): void;
|
|
15
|
+
/** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */
|
|
16
|
+
setPlaybackRate(rate: number): void;
|
|
15
17
|
/** Returns the current playback time in milliseconds. */
|
|
16
18
|
getCurrentTime(): number | null;
|
|
17
19
|
/** Jumps to a specific time (in milliseconds) in the animation. */
|
|
18
20
|
setCurrentTime(time: number): void;
|
|
19
21
|
}
|
|
22
|
+
/** Lifecycle callback props (subset of {@link PixodeskSvgAnimatorProps}). */
|
|
23
|
+
interface PixodeskSvgAnimatorCallbacks {
|
|
24
|
+
onPlay?: () => void;
|
|
25
|
+
onStop?: () => void;
|
|
26
|
+
onPause?: () => void;
|
|
27
|
+
onCancel?: () => void;
|
|
28
|
+
onFinish?: () => void;
|
|
29
|
+
onRemove?: () => void;
|
|
30
|
+
}
|
|
20
31
|
interface PixodeskSvgAnimatorProps {
|
|
21
32
|
className?: string;
|
|
22
33
|
style?: CSSProperties;
|
|
@@ -27,7 +38,6 @@ interface PixodeskSvgAnimatorProps {
|
|
|
27
38
|
* <PixodeskSvgAnimator doc="/animation.json" />
|
|
28
39
|
*/
|
|
29
40
|
doc: PxAnimatedSvgDocument;
|
|
30
|
-
timeline?: 'time' | 'scroll';
|
|
31
41
|
/** Forces a specific rendering engine. Defaults to 'auto'. */
|
|
32
42
|
mode?: JsMode;
|
|
33
43
|
/** Delay before the animation starts, in milliseconds. */
|
|
@@ -59,7 +69,7 @@ interface PixodeskSvgAnimatorProps {
|
|
|
59
69
|
pause?: boolean;
|
|
60
70
|
/** Ref populated with the imperative playback API. */
|
|
61
71
|
apiRef?: React.RefObject<ReactAnimatorApi | null>;
|
|
62
|
-
/** Seek to a specific point in the animation (
|
|
72
|
+
/** Seek to a specific point in the animation, as a fraction (0–1) of the whole timeline (duration × iterations). */
|
|
63
73
|
time?: number;
|
|
64
74
|
/** Seek to a specific point in the animation (milliseconds). */
|
|
65
75
|
timeMs?: number;
|
|
@@ -75,8 +85,6 @@ interface PixodeskSvgAnimatorProps {
|
|
|
75
85
|
onFinish?: () => void;
|
|
76
86
|
/** Called when the animation is removed. */
|
|
77
87
|
onRemove?: () => void;
|
|
78
|
-
onWarning?: (msg: string) => void;
|
|
79
|
-
onError?: (msg: string) => void;
|
|
80
88
|
}
|
|
81
89
|
/**
|
|
82
90
|
* React component for rendering and controlling Pixodesk SVG animations.
|
|
@@ -149,4 +157,4 @@ declare const PixodeskSvgCssAnimator: FC<{
|
|
|
149
157
|
outAction?: OutAction;
|
|
150
158
|
}>;
|
|
151
159
|
|
|
152
|
-
export { PixodeskSvgAnimator, PixodeskSvgCssAnimator, type ReactAnimatorApi };
|
|
160
|
+
export { PixodeskSvgAnimator, type PixodeskSvgAnimatorCallbacks, type PixodeskSvgAnimatorProps, PixodeskSvgCssAnimator, type ReactAnimatorApi };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,11 +12,22 @@ interface ReactAnimatorApi {
|
|
|
12
12
|
cancel(): void;
|
|
13
13
|
/** Jumps to the end of the animation and holds the final state. */
|
|
14
14
|
finish(): void;
|
|
15
|
+
/** Changes the speed of the animation. 1 is normal, 2 is double, -1 is reverse. */
|
|
16
|
+
setPlaybackRate(rate: number): void;
|
|
15
17
|
/** Returns the current playback time in milliseconds. */
|
|
16
18
|
getCurrentTime(): number | null;
|
|
17
19
|
/** Jumps to a specific time (in milliseconds) in the animation. */
|
|
18
20
|
setCurrentTime(time: number): void;
|
|
19
21
|
}
|
|
22
|
+
/** Lifecycle callback props (subset of {@link PixodeskSvgAnimatorProps}). */
|
|
23
|
+
interface PixodeskSvgAnimatorCallbacks {
|
|
24
|
+
onPlay?: () => void;
|
|
25
|
+
onStop?: () => void;
|
|
26
|
+
onPause?: () => void;
|
|
27
|
+
onCancel?: () => void;
|
|
28
|
+
onFinish?: () => void;
|
|
29
|
+
onRemove?: () => void;
|
|
30
|
+
}
|
|
20
31
|
interface PixodeskSvgAnimatorProps {
|
|
21
32
|
className?: string;
|
|
22
33
|
style?: CSSProperties;
|
|
@@ -27,7 +38,6 @@ interface PixodeskSvgAnimatorProps {
|
|
|
27
38
|
* <PixodeskSvgAnimator doc="/animation.json" />
|
|
28
39
|
*/
|
|
29
40
|
doc: PxAnimatedSvgDocument;
|
|
30
|
-
timeline?: 'time' | 'scroll';
|
|
31
41
|
/** Forces a specific rendering engine. Defaults to 'auto'. */
|
|
32
42
|
mode?: JsMode;
|
|
33
43
|
/** Delay before the animation starts, in milliseconds. */
|
|
@@ -59,7 +69,7 @@ interface PixodeskSvgAnimatorProps {
|
|
|
59
69
|
pause?: boolean;
|
|
60
70
|
/** Ref populated with the imperative playback API. */
|
|
61
71
|
apiRef?: React.RefObject<ReactAnimatorApi | null>;
|
|
62
|
-
/** Seek to a specific point in the animation (
|
|
72
|
+
/** Seek to a specific point in the animation, as a fraction (0–1) of the whole timeline (duration × iterations). */
|
|
63
73
|
time?: number;
|
|
64
74
|
/** Seek to a specific point in the animation (milliseconds). */
|
|
65
75
|
timeMs?: number;
|
|
@@ -75,8 +85,6 @@ interface PixodeskSvgAnimatorProps {
|
|
|
75
85
|
onFinish?: () => void;
|
|
76
86
|
/** Called when the animation is removed. */
|
|
77
87
|
onRemove?: () => void;
|
|
78
|
-
onWarning?: (msg: string) => void;
|
|
79
|
-
onError?: (msg: string) => void;
|
|
80
88
|
}
|
|
81
89
|
/**
|
|
82
90
|
* React component for rendering and controlling Pixodesk SVG animations.
|
|
@@ -149,4 +157,4 @@ declare const PixodeskSvgCssAnimator: FC<{
|
|
|
149
157
|
outAction?: OutAction;
|
|
150
158
|
}>;
|
|
151
159
|
|
|
152
|
-
export { PixodeskSvgAnimator, PixodeskSvgCssAnimator, type ReactAnimatorApi };
|
|
160
|
+
export { PixodeskSvgAnimator, type PixodeskSvgAnimatorCallbacks, type PixodeskSvgAnimatorProps, PixodeskSvgCssAnimator, type ReactAnimatorApi };
|
package/dist/index.js
CHANGED
|
@@ -99,22 +99,40 @@ var PixodeskSvgAnimatorImpl = ({
|
|
|
99
99
|
style,
|
|
100
100
|
doc,
|
|
101
101
|
compMode,
|
|
102
|
-
apiHolderRef
|
|
102
|
+
apiHolderRef,
|
|
103
|
+
callbacksRef
|
|
103
104
|
}) => {
|
|
104
105
|
doc = generateNewIds(doc);
|
|
105
106
|
const elementRefs = useRef2(/* @__PURE__ */ new Map());
|
|
106
|
-
const renderNode = (node) => {
|
|
107
|
+
const renderNode = (node, isRoot = false) => {
|
|
107
108
|
if (!node) return null;
|
|
108
109
|
const { type, animate, meta, children, ...props } = node;
|
|
109
110
|
const normProps = getNormalizedProps(props);
|
|
110
111
|
normProps["ref"] = (domEl) => {
|
|
111
112
|
if (node["id"]) elementRefs.current.set(node["id"], domEl);
|
|
112
113
|
};
|
|
114
|
+
if (isRoot) {
|
|
115
|
+
if (className) {
|
|
116
|
+
normProps["className"] = normProps["className"] ? normProps["className"] + " " + className : className;
|
|
117
|
+
}
|
|
118
|
+
if (style) normProps["style"] = style;
|
|
119
|
+
}
|
|
113
120
|
return createElement(type, normProps, children?.map((child) => renderNode(child)));
|
|
114
121
|
};
|
|
115
|
-
const root = doc ? renderNode(doc) : null;
|
|
122
|
+
const root = doc ? renderNode(doc, true) : null;
|
|
116
123
|
useEffect(() => {
|
|
117
|
-
|
|
124
|
+
const cb = (name, alsoStop = false) => () => {
|
|
125
|
+
callbacksRef.current?.[name]?.();
|
|
126
|
+
if (alsoStop) callbacksRef.current?.onStop?.();
|
|
127
|
+
};
|
|
128
|
+
const callbacks = {
|
|
129
|
+
onPlay: cb("onPlay"),
|
|
130
|
+
onPause: cb("onPause", true),
|
|
131
|
+
onCancel: cb("onCancel", true),
|
|
132
|
+
onFinish: cb("onFinish", true),
|
|
133
|
+
onRemove: cb("onRemove", true)
|
|
134
|
+
};
|
|
135
|
+
let api = createAnimator({ data: doc, adapter: createReactAdapter(elementRefs), callbacks });
|
|
118
136
|
apiHolderRef.current = api;
|
|
119
137
|
return () => {
|
|
120
138
|
api?.destroy();
|
|
@@ -138,7 +156,6 @@ var PixodeskSvgAnimator = ({
|
|
|
138
156
|
time,
|
|
139
157
|
timeMs,
|
|
140
158
|
apiRef,
|
|
141
|
-
timeline,
|
|
142
159
|
// Overrides
|
|
143
160
|
mode,
|
|
144
161
|
delay,
|
|
@@ -149,7 +166,13 @@ var PixodeskSvgAnimator = ({
|
|
|
149
166
|
frameRate,
|
|
150
167
|
startOn,
|
|
151
168
|
outAction,
|
|
152
|
-
scrollIntoViewThreshold
|
|
169
|
+
scrollIntoViewThreshold,
|
|
170
|
+
onPlay,
|
|
171
|
+
onStop,
|
|
172
|
+
onPause,
|
|
173
|
+
onCancel,
|
|
174
|
+
onFinish,
|
|
175
|
+
onRemove
|
|
153
176
|
}) => {
|
|
154
177
|
let compMode = "static" /* static */;
|
|
155
178
|
if (apiRef) {
|
|
@@ -158,7 +181,7 @@ var PixodeskSvgAnimator = ({
|
|
|
158
181
|
compMode = "autoplay" /* autoplay */;
|
|
159
182
|
} else if (time !== void 0 || timeMs !== void 0) {
|
|
160
183
|
compMode = "fixedTime" /* fixedTime */;
|
|
161
|
-
} else {
|
|
184
|
+
} else if (play !== void 0 || pause !== void 0) {
|
|
162
185
|
compMode = "play" /* play */;
|
|
163
186
|
}
|
|
164
187
|
if (compMode !== "autoplay" /* autoplay */) {
|
|
@@ -208,20 +231,20 @@ var PixodeskSvgAnimator = ({
|
|
|
208
231
|
}
|
|
209
232
|
};
|
|
210
233
|
}
|
|
234
|
+
let seekMs;
|
|
211
235
|
if (compMode === "fixedTime" /* fixedTime */) {
|
|
212
|
-
let delay2 = 0;
|
|
213
|
-
if (time !== void 0) delay2 = -time;
|
|
214
|
-
if (timeMs !== void 0) delay2 = -timeMs;
|
|
215
236
|
const animator = doc.animator || {};
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
237
|
+
if (time !== void 0) {
|
|
238
|
+
const iterationsValue = iterations ?? animator.iterations;
|
|
239
|
+
const iterationsCount = typeof iterationsValue === "number" && iterationsValue >= 1 ? iterationsValue : 1;
|
|
240
|
+
const singleDuration = duration ?? animator.duration ?? 1e3;
|
|
241
|
+
seekMs = time * singleDuration * iterationsCount;
|
|
242
|
+
}
|
|
243
|
+
if (timeMs !== void 0) seekMs = timeMs;
|
|
223
244
|
}
|
|
224
245
|
const apiHolderRef = useRef2(null);
|
|
246
|
+
const callbacksRef = useRef2({});
|
|
247
|
+
callbacksRef.current = { onPlay, onStop, onPause, onCancel, onFinish, onRemove };
|
|
225
248
|
useImperativeHandle(apiRef, () => {
|
|
226
249
|
return {
|
|
227
250
|
isPlaying: () => apiHolderRef.current?.isPlaying() || false,
|
|
@@ -229,18 +252,22 @@ var PixodeskSvgAnimator = ({
|
|
|
229
252
|
pause: () => apiHolderRef.current?.pause(),
|
|
230
253
|
cancel: () => apiHolderRef.current?.cancel(),
|
|
231
254
|
finish: () => apiHolderRef.current?.finish(),
|
|
232
|
-
|
|
255
|
+
setPlaybackRate: (rate) => apiHolderRef.current?.setPlaybackRate(rate),
|
|
256
|
+
getCurrentTime: () => apiHolderRef.current?.getCurrentTime() ?? null,
|
|
233
257
|
setCurrentTime: (time2) => apiHolderRef.current?.setCurrentTime(time2)
|
|
234
258
|
};
|
|
235
259
|
}, []);
|
|
260
|
+
const key = useDepsVersion(compMode, doc, className, style);
|
|
236
261
|
useEffect(() => {
|
|
237
262
|
if (compMode === "play" /* play */) {
|
|
238
263
|
if (play && !pause) {
|
|
239
264
|
apiHolderRef.current?.play();
|
|
240
265
|
} else if (pause) {
|
|
241
266
|
apiHolderRef.current?.pause();
|
|
242
|
-
} else {
|
|
267
|
+
} else if (play === false) {
|
|
243
268
|
apiHolderRef.current?.finish();
|
|
269
|
+
} else {
|
|
270
|
+
apiHolderRef.current?.play();
|
|
244
271
|
}
|
|
245
272
|
}
|
|
246
273
|
return () => {
|
|
@@ -248,14 +275,22 @@ var PixodeskSvgAnimator = ({
|
|
|
248
275
|
apiHolderRef.current?.pause();
|
|
249
276
|
}
|
|
250
277
|
};
|
|
251
|
-
}, [compMode, play, pause]);
|
|
252
|
-
|
|
278
|
+
}, [compMode, play, pause, key]);
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
if (compMode === "fixedTime" /* fixedTime */ && seekMs !== void 0) {
|
|
281
|
+
apiHolderRef.current?.setCurrentTime(seekMs);
|
|
282
|
+
apiHolderRef.current?.pause();
|
|
283
|
+
}
|
|
284
|
+
}, [compMode, seekMs, key]);
|
|
253
285
|
return /* @__PURE__ */ jsx(
|
|
254
286
|
PixodeskSvgAnimatorImplOnce,
|
|
255
287
|
{
|
|
288
|
+
className,
|
|
289
|
+
style,
|
|
256
290
|
compMode,
|
|
257
291
|
doc,
|
|
258
|
-
apiHolderRef
|
|
292
|
+
apiHolderRef,
|
|
293
|
+
callbacksRef
|
|
259
294
|
},
|
|
260
295
|
key
|
|
261
296
|
);
|
|
@@ -288,7 +323,10 @@ var PixodeskSvgCssAnimator = ({ className, style, children, startOn = "load", ou
|
|
|
288
323
|
"div",
|
|
289
324
|
{
|
|
290
325
|
ref,
|
|
291
|
-
className:
|
|
326
|
+
className: [
|
|
327
|
+
className,
|
|
328
|
+
state === "playing" ? "px-anim-enabled px-anim-playing" : state === "paused" ? "px-anim-enabled" : ""
|
|
329
|
+
].filter(Boolean).join(" "),
|
|
292
330
|
style,
|
|
293
331
|
...handlers,
|
|
294
332
|
children
|