@pixodesk/svg-animator-rn 1.0.29 โ 1.0.34
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 +24 -22
- package/dist/index.cjs +5 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/PixodeskSvgAnimator.tsx +7 -6
- package/src/PxRnTracks.test.ts +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# animator-rn
|
|
2
2
|
|
|
3
|
+
> ๐ Full user guide: [docs/library/react-native.md](../../docs/library/react-native.md) ยท [all docs](../../README.md#documentation)
|
|
4
|
+
|
|
3
5
|
[](https://github.com/pixodesk/pixodesk-svg-animator/actions/workflows/ci.yml)
|
|
4
6
|
[](https://opensource.org/licenses/MIT)
|
|
5
7
|
|
|
@@ -21,8 +23,8 @@ native SVG, driven on the UI thread.
|
|
|
21
23
|
- **One prop to render:** put the `.json` next to your component, import it, pass
|
|
22
24
|
it as `doc`.
|
|
23
25
|
- **Playback control:** declarative props (`autoplay`, `play`, `pause`,
|
|
24
|
-
`
|
|
25
|
-
- **
|
|
26
|
+
`time`) or an imperative ref (`play()`, `pause()`, `setCurrentTime()`, โฆ).
|
|
27
|
+
- **No size of its own:** it fills whatever `View` you put it in โ give that `View` a `width` and `height`.
|
|
26
28
|
|
|
27
29
|
## Quick start
|
|
28
30
|
|
|
@@ -153,13 +155,13 @@ const api = useRef<RnAnimatorApi>(null);
|
|
|
153
155
|
|
|
154
156
|
### Controlled time
|
|
155
157
|
|
|
156
|
-
|
|
158
|
+
Move through the animation with a slider, or show one fixed frame:
|
|
157
159
|
|
|
158
160
|
```tsx
|
|
159
|
-
const [
|
|
161
|
+
const [time, setTime] = useState(0);
|
|
160
162
|
|
|
161
|
-
<PixodeskSvgAnimator doc={doc}
|
|
162
|
-
<Slider minimumValue={0} maximumValue={2000} value={
|
|
163
|
+
<PixodeskSvgAnimator doc={doc} time={time} />
|
|
164
|
+
<Slider minimumValue={0} maximumValue={2000} value={time} onValueChange={setTime} />
|
|
163
165
|
```
|
|
164
166
|
|
|
165
167
|
## Props
|
|
@@ -171,8 +173,8 @@ const [timeMs, setTimeMs] = useState(0);
|
|
|
171
173
|
| `play` | `boolean` | Start playback, ignoring document triggers |
|
|
172
174
|
| `pause` | `boolean` | Pause current playback |
|
|
173
175
|
| `apiRef` | `RefObject<RnAnimatorApi>` | Ref for imperative control |
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
+
| `progress` | `number` | show the frame at this position in the whole timeline (duration ร iterations): `0` is the first frame, `0.5` the middle, `1` the last |
|
|
177
|
+
| `time` | `number` | show the frame at that time, in milliseconds from the start |
|
|
176
178
|
| `duration` | `number` | Duration override (ms) |
|
|
177
179
|
| `delay` | `number` | Delay before start (ms) |
|
|
178
180
|
| `iterations` | `number \| 'infinite'` | Loop count |
|
|
@@ -188,7 +190,7 @@ const [timeMs, setTimeMs] = useState(0);
|
|
|
188
190
|
| `onError` | `(error, componentStack?) => void` | Called when a document cannot be compiled or rendered |
|
|
189
191
|
| `fallback` | `(error) => ReactElement \| null` | Rendered in place of a failed animation (default: nothing) |
|
|
190
192
|
|
|
191
|
-
With none of `autoplay` / `play` / `pause` / `
|
|
193
|
+
With none of `autoplay` / `play` / `pause` / `progress` / `time` set, the component
|
|
192
194
|
renders the animation statically (initial state, no playback).
|
|
193
195
|
|
|
194
196
|
### Failure handling
|
|
@@ -215,11 +217,11 @@ renderer never reaches JavaScript and cannot be caught โ see
|
|
|
215
217
|
|
|
216
218
|
| Prop | Why it differs |
|
|
217
219
|
|---|---|
|
|
218
|
-
| `mode` | Not accepted. There is no Web Animations API on
|
|
219
|
-
| `frameRate` | Not accepted.
|
|
220
|
+
| `mode` | Not accepted. There is no Web Animations API on React Native; playback is always native-driven. |
|
|
221
|
+
| `frameRate` | Not accepted. The screen's own refresh rate is used. The player does not compute values frame by frame: when the document loads it works out the animated values in advance, as a list of snapshots (60 per second of animation), and each screen refresh shows the nearest one. The closest thing to a frame rate is how many snapshots per second are prepared โ `compileTracks({ sampleRate })`, only available when you use the lower-level API instead of the component. |
|
|
220
222
|
| `startOn` | Not accepted as a prop โ the document's trigger is honoured via `autoplay` (`load`, `click`, `scrollIntoView`, `programmatic`). `mouseOver` has no touch equivalent. |
|
|
221
|
-
| `className` / `style` | Not accepted
|
|
222
|
-
| `onRemove` |
|
|
223
|
+
| `className` / `style` | Not accepted โ you cannot style the component itself. It fills whatever `View` you put it in, so to set its size, give that `View` a `width` and `height`. Styling *inside* the document (`style` on an element in the JSON) is supported. |
|
|
224
|
+
| `onRemove` | Never called. On the web it tells you the animator was thrown away; here there is nothing to tell โ when the component leaves the screen, React removes it and everything it created. To run code at that moment, use a `useEffect` cleanup function in your own component. |
|
|
223
225
|
|
|
224
226
|
## How playback works
|
|
225
227
|
|
|
@@ -255,11 +257,11 @@ properties actually change over time.
|
|
|
255
257
|
| `text`, `tspan` | โ
| content via the `text` attribute |
|
|
256
258
|
| `textPath` | โ
| see *Text along a path* below |
|
|
257
259
|
| `image` | โ
| `href` accepts `data:` URIs; remote URLs are blocked by the sanitiser |
|
|
258
|
-
| `use`, `symbol` | โ
| animated targets are **inlined into real clones** before render โ `<use>` does not propagate animation natively in
|
|
260
|
+
| `use`, `symbol` | โ
| animated targets are **inlined into real clones** before render โ `<use>` does not propagate animation natively in React Native |
|
|
259
261
|
| `linearGradient`, `radialGradient`, `stop` | โ
| |
|
|
260
262
|
| `pattern`, `marker` | โ
| static geometry verified; complex cases unverified on device |
|
|
261
263
|
| `mask`, `clipPath` | โ
| |
|
|
262
|
-
| `filter` + all 22 `fe*` primitives | โ
| `feGaussianBlur`, `feDropShadow`, `feColorMatrix`, `feMerge`, `feComponentTransfer` + `feFunc*`, โฆ
|
|
264
|
+
| `filter` + all 22 `fe*` primitives | โ
| `feGaussianBlur`, `feDropShadow`, `feColorMatrix`, `feMerge`, `feComponentTransfer` + `feFunc*`, โฆ **The visual result has not yet been checked on a real device** |
|
|
263
265
|
| `foreignObject` | โ | blocked by the shared sanitiser (embeds arbitrary host content) |
|
|
264
266
|
| `script` | โ | blocked by the shared sanitiser |
|
|
265
267
|
|
|
@@ -269,7 +271,7 @@ properties actually change over time.
|
|
|
269
271
|
|---|---|---|
|
|
270
272
|
| `opacity`, `fill-opacity`, `stroke-opacity` | โ
| |
|
|
271
273
|
| `fill`, `stroke`, `stop-color` | โ
| interpolated as RGBA |
|
|
272
|
-
| `stroke-width`, `stroke-dasharray`, `stroke-dashoffset` | โ
| dash arrays are converted to the numeric form
|
|
274
|
+
| `stroke-width`, `stroke-dasharray`, `stroke-dashoffset` | โ
| dash arrays are converted to the numeric form React Native expects |
|
|
273
275
|
| `x`, `y`, `width`, `height`, `cx`, `cy`, `r`, `rx`, `ry` | โ
| |
|
|
274
276
|
| `d` (**path morphing**) | โ
| keyframes must share command structure |
|
|
275
277
|
| `transform` (unified parts record) | โ
| `translate`, `rotate`, `skew`, `scale`, `origin` |
|
|
@@ -281,7 +283,7 @@ properties actually change over time.
|
|
|
281
283
|
|
|
282
284
|
### Effects (`node.effects`)
|
|
283
285
|
|
|
284
|
-
All effects are materialised by the shared core before rendering, so the
|
|
286
|
+
All effects are materialised by the shared core before rendering, so the React Native
|
|
285
287
|
player sees plain nodes. **All are supported:**
|
|
286
288
|
|
|
287
289
|
| Effect | Status | Notes |
|
|
@@ -290,7 +292,7 @@ player sees plain nodes. **All are supported:**
|
|
|
290
292
|
| `repeater` | โ
| copies materialised as real elements; per-copy params animatable |
|
|
291
293
|
| `maskedBy` | โ
| including an animated mask source |
|
|
292
294
|
| `clipPath` | โ
| including animated clip geometry |
|
|
293
|
-
| `
|
|
295
|
+
| `strokeTrim` | โ
| incl. `offset` and `subPaths: 'combined'` |
|
|
294
296
|
| `clone` + `retime` | โ
| each clone keeps its own time shift, incl. `retime.timeCrop` (a visibility window on the document timeline) |
|
|
295
297
|
| `fillGradient` / `strokeGradient` | โ
| animated stops **and animated geometry** (`animate.gradientX1`/`Cx`/`R`, โฆ); `gradientTransform` is static (core-wide) |
|
|
296
298
|
| `textPath` | โ
| incl. animated `startOffset` |
|
|
@@ -306,7 +308,7 @@ player sees plain nodes. **All are supported:**
|
|
|
306
308
|
| Per-property `loop` (incl. `alternate` pingpong) | โ
| expanded before playback |
|
|
307
309
|
| Easing (cubic-bezier and named refs) | โ
| baked into the sampled tracks |
|
|
308
310
|
| `definitions.animations` / `easings` / `styles` / `glyphs` | โ
| named refs resolved; `style` presets applied as props |
|
|
309
|
-
| `node.style` (inline or named) | โ
| resolved to props โ
|
|
311
|
+
| `node.style` (inline or named) | โ
| resolved to props โ React Native has no CSS, so explicit attributes win |
|
|
310
312
|
|
|
311
313
|
### Playback and triggers
|
|
312
314
|
|
|
@@ -317,14 +319,14 @@ player sees plain nodes. **All are supported:**
|
|
|
317
319
|
| `fill` โ `forwards` / `backwards` / `both` / `none` | โ
| |
|
|
318
320
|
| `resetOnFinish` | โ
| |
|
|
319
321
|
| `play` / `pause` / `cancel` / `finish` | โ
| |
|
|
320
|
-
| `setCurrentTime` โ
|
|
322
|
+
| `setCurrentTime` โ jump to a time, including **while playing** | โ
| playback continues from the new point |
|
|
321
323
|
| `setPlaybackRate` โ faster, slower and **reverse** (negative) | โ
| composes with `direction` |
|
|
322
324
|
| Trigger `load` / `programmatic` | โ
| |
|
|
323
325
|
| Trigger `click` | โ
| wrapped in a `Pressable`; a second tap applies `outAction` |
|
|
324
|
-
| Trigger `scrollIntoView` | โ
| visibility sampled by measuring against the window (
|
|
326
|
+
| Trigger `scrollIntoView` | โ
| visibility sampled by measuring against the window (React Native has no `IntersectionObserver`); honours `scrollIntoViewThreshold` and `outAction` |
|
|
325
327
|
| Trigger `mouseOver` | โ | no touch equivalent โ use `click`, or drive `play` yourself |
|
|
326
328
|
| `frameRate` | n/a | reanimated runs at the display refresh rate; use `compileTracks({sampleRate})` to trade memory for temporal precision |
|
|
327
|
-
| `mode` (`waapi` / `frames`) | n/a | there is no Web Animations API on
|
|
329
|
+
| `mode` (`waapi` / `frames`) | n/a | there is no Web Animations API on React Native โ playback is always native-driven |
|
|
328
330
|
|
|
329
331
|
### Known limitations
|
|
330
332
|
|
package/dist/index.cjs
CHANGED
|
@@ -593,12 +593,13 @@ function PixodeskSvgAnimator({
|
|
|
593
593
|
direction,
|
|
594
594
|
resetOnFinish,
|
|
595
595
|
outAction: outActionProp,
|
|
596
|
+
// (`progress` prop aliased โ the name is taken by the internal reanimated SharedValue)
|
|
596
597
|
autoplay,
|
|
597
598
|
play,
|
|
598
599
|
pause,
|
|
599
600
|
apiRef,
|
|
601
|
+
progress: progressProp,
|
|
600
602
|
time,
|
|
601
|
-
timeMs,
|
|
602
603
|
onPlay,
|
|
603
604
|
onStop,
|
|
604
605
|
onPause,
|
|
@@ -716,8 +717,8 @@ function PixodeskSvgAnimator({
|
|
|
716
717
|
const startOn = (_b = trigger == null ? void 0 : trigger.startOn) != null ? _b : "load";
|
|
717
718
|
const outAction = (_c = outActionProp != null ? outActionProp : trigger == null ? void 0 : trigger.outAction) != null ? _c : "pause";
|
|
718
719
|
(0, import_react3.useEffect)(() => {
|
|
719
|
-
if (
|
|
720
|
-
const seekMs =
|
|
720
|
+
if (progressProp !== void 0 || time !== void 0) {
|
|
721
|
+
const seekMs = time !== void 0 ? time : (progressProp != null ? progressProp : 0) * totalDuration;
|
|
721
722
|
api.setCurrentTime(seekMs);
|
|
722
723
|
return;
|
|
723
724
|
}
|
|
@@ -731,7 +732,7 @@ function PixodeskSvgAnimator({
|
|
|
731
732
|
if (autoplay && startOn === "load") {
|
|
732
733
|
api.play();
|
|
733
734
|
}
|
|
734
|
-
}, [compiled, autoplay, play, pause,
|
|
735
|
+
}, [compiled, autoplay, play, pause, progressProp, time]);
|
|
735
736
|
const scrollRef = (0, import_react3.useRef)(null);
|
|
736
737
|
const inViewRef = (0, import_react3.useRef)(false);
|
|
737
738
|
(0, import_react3.useEffect)(() => {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/PixodeskSvgAnimator.tsx","../src/PxRnTracks.ts","../src/PxRnPropNames.ts","../src/PxRnMatrix.ts","../src/PxRnRender.tsx","../src/PxRnTypeMap.ts","../src/PxRnErrorBoundary.tsx","../src/PxRnSafety.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nexport { PixodeskSvgAnimator, default } from './PixodeskSvgAnimator';\nexport type { PixodeskSvgAnimatorProps, RnAnimatorApi } from './PixodeskSvgAnimator';\n\nexport { renderRnNode, toRnProps } from './PxRnRender';\nexport { PxRnErrorBoundary, type PxRnErrorBoundaryProps } from './PxRnErrorBoundary';\nexport { openClosedTextPathTargets } from './PxRnSafety';\nexport type { RenderRnNodeOptions } from './PxRnRender';\n\nexport { compileTracks, sampleProps } from './PxRnTracks';\nexport type { CompileTracksOptions, PxCompiledTracks, PxElementTracks } from './PxRnTracks';\n\nexport { RN_SVG_COMPONENTS, toRnPropName } from './PxRnTypeMap';\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 {\n generateNewIds,\n getAnimatorConfig,\n getDefs,\n materialiseAllInTree,\n validateNodeEffects,\n PxAnimatorEngine,\n type FillMode,\n type OutAction,\n type PlaybackDirection,\n type PxAnimatedSvgDocument,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport React, { createElement, useEffect, useImperativeHandle, useMemo, useRef, useState, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { Dimensions, Platform, Pressable, View } from 'react-native';\nimport Animated, {\n cancelAnimation,\n useAnimatedReaction,\n Easing,\n runOnJS,\n useAnimatedProps,\n useSharedValue,\n withDelay,\n withRepeat,\n withTiming,\n type SharedValue,\n} from 'react-native-reanimated';\nimport { compileTracks, sampleProps, type PxCompiledTracks, type PxElementTracks } from './PxRnTracks';\nimport { renderRnNode, type RenderRnNodeOptions } from './PxRnRender';\nimport { PxRnErrorBoundary } from './PxRnErrorBoundary';\nimport { openClosedTextPathTargets } from './PxRnSafety';\n\n\n// -- Public types -----------------------------------------------------------\n\n/** Imperative playback API โ mirrors ReactAnimatorApi from svg-animator-react. */\nexport interface RnAnimatorApi {\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. */\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 PixodeskSvgAnimatorProps {\n\n // -- Source ---------------------------------------------------------------\n\n /** The animation document to render. */\n doc: PxAnimatedSvgDocument;\n\n // -- Timing overrides -----------------------------------------------------\n\n /** Duration of a single iteration in milliseconds. */\n duration?: number;\n\n /** Delay before the animation starts, in milliseconds. */\n delay?: number;\n\n /** Number of iterations, or 'infinite' for endless looping. */\n iterations?: number | 'infinite';\n\n /** Defines the element's state when the animation is not active. */\n fill?: FillMode;\n\n /** Playback direction. */\n direction?: PlaybackDirection;\n\n /** Snap back to the start state after a natural finish. */\n resetOnFinish?: boolean;\n\n /**\n * What a second tap does when `startOn: 'click'` is active.\n * Defaults to the document's `trigger.outAction`, else `'pause'`.\n */\n outAction?: OutAction;\n\n // -- Declarative control --------------------------------------------------\n\n /** When true, honours the document trigger (`startOn: 'load'` plays on mount). */\n autoplay?: boolean;\n\n /** Starts playback unconditionally. */\n play?: boolean;\n\n /** Pauses current playback. */\n pause?: boolean;\n\n // -- Imperative control ---------------------------------------------------\n\n /** Ref populated with the imperative playback API. */\n apiRef?: React.RefObject<RnAnimatorApi | null>;\n\n // -- Controlled (external) time -------------------------------------------\n\n /** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */\n time?: number;\n\n /** Seek to a specific time in milliseconds. */\n timeMs?: number;\n\n // -- Callbacks ------------------------------------------------------------\n\n onPlay?: () => void;\n onStop?: () => void;\n onPause?: () => void;\n onCancel?: () => void;\n onFinish?: () => void;\n\n\n // -- Failure handling -----------------------------------------------------\n\n /**\n * Called when a document cannot be compiled or rendered. The component\n * renders {@link fallback} instead of throwing, so a single broken\n * animation never takes down the screen around it.\n *\n * Only JavaScript failures reach this โ a crash inside react-native-svg's\n * native renderer bypasses JavaScript entirely.\n */\n onError?: (error: Error, componentStack?: string) => void;\n\n /** Rendered in place of the animation after a failure. Default: nothing. */\n fallback?: (error: Error) => ReactElement | null;\n}\n\n\n// -- Animated element wrapper ------------------------------------------------\n\n/**\n * Whether react-native-svg is backed by NATIVE views here, rather than by the\n * DOM through react-native-web.\n *\n * The two want different things from an animated `transform`: a native view\n * declares a `matrix` prop taking six numbers, while the DOM wants a\n * `transform` attribute holding an SVG string. Getting it wrong is silent โ\n * the value is dropped and the element simply never moves โ so this single\n * constant decides it once and feeds both the track compiler (value form) and\n * the sampler (prop name). Everything else in the package defaults to the\n * DOM-compatible form.\n */\nconst NATIVE_SVG_VIEWS = Platform.OS !== 'web';\n\nconst animatedComponentCache = new Map<ComponentType<any>, ComponentType<any>>();\n\nfunction getAnimatedComponent(Component: ComponentType<any>): ComponentType<any> {\n let cached = animatedComponentCache.get(Component);\n if (!cached) {\n cached = Animated.createAnimatedComponent(Component as any);\n animatedComponentCache.set(Component, cached);\n }\n return cached;\n}\n\n/** One animated element: static props + UI-thread sampled animated props. */\nfunction AnimatedPxElement({\n Component, staticProps, children, tracks, progress, stepMs, sampleCount,\n}: {\n Component: ComponentType<any>;\n staticProps: Record<string, any>;\n children: ReactNode;\n tracks: PxElementTracks;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n}) {\n const AnimatedComponent = useMemo(() => getAnimatedComponent(Component), [Component]);\n\n // Runs on the UI thread every frame; `sampleProps` is a trivial indexed\n // lookup into the precompiled tracks โ no interpolation logic on the hot path.\n const animatedProps = useAnimatedProps(() => {\n // On iOS/Android these values bypass react-native-svg's JS prop layer\n // and land on the native view, which declares `matrix`, not\n // `transform`. The web build keeps the DOM-facing `transform` name.\n return sampleProps(tracks, progress.value, stepMs, sampleCount, NATIVE_SVG_VIEWS);\n }, [tracks, stepMs, sampleCount]);\n\n return (\n <AnimatedComponent {...staticProps} animatedProps={animatedProps}>\n {children}\n </AnimatedComponent>\n );\n}\n\n\n/**\n * react-native-svg elements whose `render()` returns `null`. They carry data for\n * their PARENT (a `<Stop>` is read by the gradient that owns it) rather than\n * producing a native view, so reanimated has nothing to attach to โ wrapping one\n * in `Animated.createAnimatedComponent` throws\n * \"Cannot find host instance for this component\".\n */\nconst NON_HOST_TAGS = new Set(['stop', 'feMergeNode']);\n\n/**\n * Definition elements โ they describe paint/geometry for something else rather\n * than drawing themselves. Their animated attributes (a gradient's `y1`, a\n * stop's `stop-color`) do not reliably flow through reanimated's animated-props\n * path, so an animated def is rendered by re-sampling from JS instead. There\n * are only ever a handful per document and they change slowly, so the cost is\n * negligible โ visual elements still animate entirely on the UI thread.\n */\nconst SAMPLED_DEF_TAGS = new Set(['linearGradient', 'radialGradient', ...NON_HOST_TAGS]);\n\n/** True when this subtree must be driven from JS rather than the UI thread:\n * either the node itself is an animated def, or it owns an animated non-host\n * child (an animated `<Stop>` only re-renders via its parent gradient). */\nfunction needsJsSampling(node: PxNode, trackById: Map<string, PxElementTracks>): boolean {\n const id = (node as any).id;\n if (SAMPLED_DEF_TAGS.has(String(node.type)) && id && trackById.has(id)) return true;\n return (node.children ?? []).some(c => needsJsSampling(c, trackById));\n}\n\n/**\n * Renders a subtree whose animation cannot run on the UI thread (see\n * {@link NON_HOST_TAGS}) by re-rendering it from JS with sampled values.\n *\n * Changing a `<Stop>`'s props does not re-render its parent gradient, so the\n * whole subtree is rebuilt โ which is why this wraps the gradient rather than\n * the stop. The reaction itself runs on the UI thread and only crosses to JS\n * when the QUANTISED sample index changes, capping these few elements at\n * ~30fps instead of a JS call every frame.\n */\nfunction SampledSubtree({\n node, trackById, progress, stepMs, sampleCount, renderOpts,\n}: {\n node: PxNode;\n trackById: Map<string, PxElementTracks>;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n renderOpts: RenderRnNodeOptions;\n}) {\n const [idx, setIdx] = useState(0);\n\n useAnimatedReaction(\n () => Math.floor(Math.round(progress.value / stepMs) / 2) * 2, // half-rate\n (next, prev) => {\n if (next !== prev) runOnJS(setIdx)(next);\n },\n [stepMs]\n );\n\n const tMs = Math.min(Math.max(idx, 0), sampleCount - 1) * stepMs;\n\n return renderRnNode(node, {\n ...renderOpts,\n // Sampled values are baked in as PLAIN props โ nothing reanimated-driven.\n decorate: (n, Component, staticProps, children, key) => {\n const id = (n as any).id;\n const tracks = id ? trackById.get(id) : undefined;\n if (!tracks) return undefined;\n // Wire prop names, NOT the native ones: these go back through\n // react-native-svg's JS prop layer, which does the renaming itself.\n const sampled = sampleProps(tracks, tMs, stepMs, sampleCount);\n return createElement(Component, { ...staticProps, ...sampled, key }, children);\n },\n });\n}\n\n\n\n/** Overrides that shadow the document's own `animator` config. */\ninterface ConfigOverrides {\n duration?: number;\n delay?: number;\n iterations?: number | 'infinite';\n fill?: FillMode;\n direction?: PlaybackDirection;\n resetOnFinish?: boolean;\n}\n\ninterface Compiled {\n /** Materialised document, or null when compilation failed. */\n doc: PxAnimatedSvgDocument | null;\n tracks: PxCompiledTracks;\n error: Error | null;\n}\n\n/** Playable-but-empty tracks, so a failed compile still satisfies every hook\n * below it โ React forbids skipping hooks on an error path. */\nconst EMPTY_TRACKS: PxCompiledTracks = {\n duration: 1, iterations: 1, direction: 'normal', delay: 0,\n fill: 'forwards', resetOnFinish: false, stepMs: 1, sampleCount: 2, elements: [],\n};\n\n/**\n * Materialises + compiles a document. Extracted from the component so the\n * whole thing sits behind one try/catch, and so it can be tested directly.\n */\nfunction compileDocument(doc: PxAnimatedSvgDocument, overrides: ConfigOverrides): Compiled {\n const { duration, delay, iterations, fill, direction, resetOnFinish } = overrides;\n const warnings = validateNodeEffects(doc as PxNode);\n for (const w of warnings) console.warn('[PixodeskSvgAnimator] effects shape warning:', w);\n\n // `waapi` = the FULLY-FLATTENED materialisation: effects + loops +\n // sampled motion paths + animated `<use>` inlined into real `<g>`\n // clones + orphaned defs pruned. That last part is why RN must not use\n // the `frames` flavour: frames keeps `<use href=\"#animatedTarget\">`\n // live references, which only work because the DOM propagates\n // attribute writes through `<use>` shadow trees. react-native-svg has\n // no such live propagation, so an animated `<use>` would render frozen.\n let prepared = materialiseAllInTree(doc, PxAnimatorEngine.waapi);\n\n // Sidestep a react-native-svg NATIVE crash (see PxRnSafety). Guarded on\n // the platform because the DOM renders this case correctly and the web\n // document must stay exactly as the core pipeline produced it.\n if (NATIVE_SVG_VIEWS) {\n prepared = openClosedTextPathTargets(prepared as PxNode) as PxAnimatedSvgDocument;\n }\n\n // Apply prop overrides onto the animator config (mirrors the react wrapper).\n const animator = getAnimatorConfig(prepared) || {};\n prepared = {\n ...prepared,\n animator: {\n ...animator,\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 resetOnFinish: resetOnFinish !== undefined ? resetOnFinish : animator.resetOnFinish,\n },\n };\n\n prepared = generateNewIds(prepared);\n const tracks = compileTracks(prepared, { native: NATIVE_SVG_VIEWS });\n return { doc: prepared, tracks, error: null };\n}\n\n\n// -- Main component ----------------------------------------------------------\n\n/**\n * React Native component for rendering and controlling Pixodesk SVG animations.\n *\n * The document is materialised once through the shared core pipeline (effects,\n * loops, motion-path sampling, animated-`<use>` inlining โ identical to the\n * web frames engine), compiled into densely sampled per-element tracks, and\n * played back natively: a single reanimated progress value driven by\n * `withTiming`/`withRepeat` on the UI thread, with per-element worklets\n * indexing the precompiled tracks. No JS-thread frame loop.\n */\nexport function PixodeskSvgAnimator({\n doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp,\n autoplay, play, pause, apiRef, time, timeMs,\n onPlay, onStop, onPause, onCancel, onFinish, onError, fallback,\n}: PixodeskSvgAnimatorProps): ReactElement | null {\n\n // -- Compile the document (once per doc/override change) ------------------\n\n const compiled = useMemo((): Compiled => {\n try {\n return compileDocument(\n doc,\n { duration, delay, iterations, fill, direction, resetOnFinish }\n );\n } catch (e) {\n // A malformed document must not take the host screen down with it.\n const error = e instanceof Error ? e : new Error(String(e));\n console.warn('[PixodeskSvgAnimator] could not compile the document:', error.message);\n return { doc: null, tracks: EMPTY_TRACKS, error };\n }\n }, [doc, duration, delay, iterations, fill, direction, resetOnFinish]);\n\n const tracks: PxCompiledTracks = compiled.tracks;\n const totalDuration = tracks.duration * (tracks.iterations === Infinity ? 1 : tracks.iterations);\n\n // -- Playback state -------------------------------------------------------\n\n // Progress in ms within ONE iteration; iteration repetition/alternation is\n // expressed through withRepeat, so worklets only ever see [0, duration].\n const progress = useSharedValue(0);\n const playingRef = useRef(false);\n const rateRef = useRef(1);\n\n /** True when the current rate plays the timeline backwards. */\n const reversePlayback = () => rateRef.current < 0;\n\n /** Where the playhead rests once playback ends. `resetOnFinish` snaps back\n * to the start; otherwise `fill` decides whether the final frame is held. */\n const restingPosition = () => {\n if (tracks.resetOnFinish) return 0;\n if (tracks.fill === 'none' || tracks.fill === 'backwards') return 0;\n return reversePlayback() ? 0 : tracks.duration;\n };\n\n const notifyFinish = () => {\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n };\n\n const startFrom = (fromMs: number) => {\n const dur = tracks.duration;\n const rate = rateRef.current || 1;\n const backwards = rate < 0;\n const speed = Math.abs(rate);\n // `direction` decides which end a leg runs toward; a negative playback\n // rate flips it again (the two compose, as in the Web Animations API).\n const directionReversed = tracks.direction === 'reverse' || tracks.direction === 'alternate-reverse';\n const reversedStart = backwards ? !directionReversed : directionReversed;\n const alternates = tracks.direction === 'alternate' || tracks.direction === 'alternate-reverse';\n const from = Math.max(0, Math.min(fromMs, dur));\n\n const legTarget = reversedStart ? 0 : dur;\n const legRemaining = Math.abs(legTarget - from) / speed;\n const repeats = tracks.iterations === Infinity ? -1 : tracks.iterations;\n\n cancelAnimation(progress);\n progress.value = reversedStart ? (from <= 0 ? dur : from) : (from >= dur ? 0 : from);\n\n const animation = repeats === 1\n ? withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }, (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n })\n : withRepeat(\n withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }),\n repeats, alternates,\n (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n }\n );\n\n progress.value = tracks.delay > 0 && from === 0\n ? withDelay(tracks.delay / speed, animation)\n : animation;\n\n playingRef.current = true;\n };\n\n const api: RnAnimatorApi = {\n isPlaying: () => playingRef.current,\n play: () => {\n // `startFrom` rewinds to the opposite end when the playhead is\n // already resting at a boundary (mirrors WAAPI, where play() on a\n // finished animation auto-rewinds).\n startFrom(progress.value);\n onPlay?.();\n },\n pause: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n onPause?.();\n onStop?.();\n },\n cancel: () => {\n cancelAnimation(progress);\n progress.value = 0;\n playingRef.current = false;\n onCancel?.();\n onStop?.();\n },\n finish: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n },\n setPlaybackRate: (rate: number) => {\n if (!isFinite(rate) || rate === 0) {\n console.warn('setPlaybackRate: rate must be finite and non-zero');\n return;\n }\n rateRef.current = rate;\n if (playingRef.current) startFrom(progress.value);\n },\n getCurrentTime: () => progress.value,\n setCurrentTime: (t: number) => {\n const wasPlaying = playingRef.current;\n cancelAnimation(progress);\n playingRef.current = false;\n const clamped = Math.max(0, Math.min(t, totalDuration));\n const withinIteration = tracks.duration > 0\n ? (clamped % tracks.duration) || (clamped === 0 ? 0 : tracks.duration)\n : 0;\n progress.value = withinIteration;\n // Seeking mid-playback continues from the new position rather than\n // silently pausing.\n if (wasPlaying) startFrom(withinIteration);\n },\n };\n\n useImperativeHandle(apiRef, () => api, [compiled]);\n\n // -- Declarative control --------------------------------------------------\n\n const trigger = compiled.doc ? getAnimatorConfig(compiled.doc)?.trigger : undefined;\n const startOn = trigger?.startOn ?? 'load';\n const outAction = outActionProp ?? trigger?.outAction ?? 'pause';\n\n useEffect(() => {\n if (time !== undefined || timeMs !== undefined) {\n const seekMs = timeMs !== undefined ? timeMs : (time ?? 0) * totalDuration;\n api.setCurrentTime(seekMs);\n return;\n }\n if (play !== undefined || pause !== undefined) {\n if (play && !pause) api.play();\n else if (pause) api.pause();\n else if (play === false) api.finish();\n else api.play();\n return;\n }\n // 'click' and 'scrollIntoView' start from their own handlers below.\n if (autoplay && startOn === 'load') {\n api.play();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, play, pause, time, timeMs]);\n\n // `startOn: 'scrollIntoView'` โ react-native has no IntersectionObserver, so\n // visibility is sampled by measuring the view against the window box. The\n // poll is cheap (a native measure every 200ms) and only runs while this\n // trigger is active; `outAction` decides what leaving the viewport does.\n const scrollRef = useRef<View | null>(null);\n const inViewRef = useRef(false);\n useEffect(() => {\n if (!autoplay || startOn !== 'scrollIntoView') return;\n const threshold = trigger?.scrollIntoViewThreshold ?? 0;\n inViewRef.current = false;\n\n const check = () => {\n const node = scrollRef.current;\n if (!node) return;\n node.measureInWindow((_x, y, _w, h) => {\n if (!h) return;\n const screen = Dimensions.get('window').height;\n const visible = Math.max(0, Math.min(y + h, screen) - Math.max(y, 0));\n const ratio = visible / h;\n const isIn = ratio > 0 && ratio >= threshold;\n if (isIn === inViewRef.current) return;\n inViewRef.current = isIn;\n if (isIn) {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n } else if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n });\n };\n\n check();\n const id = setInterval(check, 200);\n return () => clearInterval(id);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, startOn, outAction]);\n\n // Stop cleanly on unmount / doc swap.\n useEffect(() => {\n return () => {\n cancelAnimation(progress);\n playingRef.current = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled]);\n\n // -- Render ---------------------------------------------------------------\n\n const trackById = useMemo(() => {\n const map = new Map<string, PxElementTracks>();\n for (const el of tracks.elements) map.set(el.id, el);\n return map;\n }, [tracks]);\n\n const warningsRef = useRef<Array<string>>([]);\n const renderErrorRef = useRef<Error | null>(null);\n const root = useMemo(() => {\n warningsRef.current = [];\n renderErrorRef.current = null;\n if (!compiled.doc) return null;\n\n const renderOpts: RenderRnNodeOptions = {\n warnings: warningsRef.current,\n defs: getDefs(compiled.doc),\n };\n try {\n return renderRnNode(compiled.doc as PxNode, {\n ...renderOpts,\n decorate: (node, Component, staticProps, children, key) => {\n // An animated definition subtree (gradient / its stops) cannot be\n // driven on the UI thread โ hand the WHOLE subtree to the\n // JS-sampled renderer and stop descending here.\n if (needsJsSampling(node, trackById)) {\n return (\n <SampledSubtree\n key={key}\n node={node}\n trackById={trackById}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n renderOpts={renderOpts}\n />\n );\n }\n\n const id = (node as any).id;\n const elTracks = id ? trackById.get(id) : undefined;\n if (!elTracks) return undefined;\n return (\n <AnimatedPxElement\n key={key}\n Component={Component}\n staticProps={staticProps}\n tracks={elTracks}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n >\n {children}\n </AnimatedPxElement>\n );\n },\n });\n } catch (e) {\n // Building the element tree threw โ report it and render nothing\n // rather than propagating and unmounting the host screen.\n const error = e instanceof Error ? e : new Error(String(e));\n renderErrorRef.current = error;\n console.warn('[PixodeskSvgAnimator] could not render the document:', error.message);\n return null;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, trackById]);\n\n useEffect(() => {\n for (const w of warningsRef.current) console.warn('[PixodeskSvgAnimator]', w);\n }, [root]);\n\n // Surface compile/render failures to the host exactly once per occurrence.\n const failure = compiled.error ?? renderErrorRef.current;\n useEffect(() => {\n if (failure) onError?.(failure);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [failure]);\n\n if (failure) return fallback ? fallback(failure) : null;\n\n // `startOn: 'click'` โ the touch analogue of the web player's click trigger:\n // tap to start, tap again to apply `outAction`. Hover (`mouseOver`) has no\n // touch equivalent and `scrollIntoView` needs the surrounding scroll view,\n // so both are left to the host app.\n let content: ReactElement | null = root;\n\n if (autoplay && startOn === 'scrollIntoView' && root) {\n // `collapsable={false}` keeps the view in the native tree so it can be measured.\n content = <View ref={scrollRef} collapsable={false}>{root}</View>;\n } else if (autoplay && startOn === 'click' && root) {\n content = (\n <Pressable\n onPress={() => {\n if (playingRef.current) {\n if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n } else {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n }\n }}\n >\n {root}\n </Pressable>\n );\n }\n\n // Catches what the try/catch above cannot: throws during React's own render\n // and commit of the tree โ react-native-svg internals, reanimated failing\n // to attach to a component that turns out not to be a host view, and so on.\n return (\n <PxRnErrorBoundary onError={onError} fallback={fallback}>\n {content}\n </PxRnErrorBoundary>\n );\n}\n\nexport default PixodeskSvgAnimator;\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 {\n calcAnimationValues,\n getAnimatorConfig,\n getNormalisedBindings,\n DEFAULT_DURATION_MS,\n PxAnimatorEngine,\n type PxAnimatedSvgDocument,\n type PxAnimationDefinition,\n} from '@pixodesk/svg-animator-core';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\n/**\n * Sampled animation tracks for ONE element: prop name โ per-sample values.\n *\n * The compiler densely samples every animated property through core's\n * `calcAnimationValues` โ the exact function the web frames engine renders\n * with โ so RN playback is value-identical to the web player. Easing, loops,\n * transform composition, colour interpolation and path morphing are all baked\n * into the samples at compile time; the UI-thread worklet only indexes arrays.\n */\nexport interface PxElementTracks {\n /** Element id (after id regeneration). */\n id: string;\n /** react-native-svg prop name โ one value per sample. */\n props: Record<string, Array<string | number | Array<number>>>;\n}\n\nexport interface PxCompiledTracks {\n /** Per-iteration duration, ms. */\n duration: number;\n /** Iteration count (Infinity for 'infinite'). */\n iterations: number;\n /** 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' */\n direction: string;\n /** Delay before start, ms (positive = wait). */\n delay: number;\n /** WAAPI-style fill mode (default 'forwards'). */\n fill: string;\n /** When true, snap back to the start after a natural finish. */\n resetOnFinish: boolean;\n /** Sample step, ms. */\n stepMs: number;\n /** Number of samples per iteration (>= 2; sample i is at time i*stepMs). */\n sampleCount: number;\n /** Tracks for every animated element. */\n elements: Array<PxElementTracks>;\n}\n\nexport interface CompileTracksOptions {\n /** Target sample rate, samples/second. Default 60 (one per frame). */\n sampleRate?: number;\n /** Hard cap on samples per iteration (memory guard). Default 600. */\n maxSamples?: number;\n /**\n * Sample values in the form the NATIVE react-native-svg views expect\n * (currently: `transform` as a 6-number matrix rather than an SVG string).\n *\n * Defaults to `false` โ the plain SVG form, which is what react-native-web\n * hands straight to the DOM. Only the component knows the platform, so it\n * decides; every consumer that does not opt in keeps DOM-compatible values.\n */\n native?: boolean;\n}\n\n\n\n/**\n * Compiles a MATERIALISED document (run `materialiseAllInTree(doc, 'frames')`\n * + `generateNewIds` first) into densely sampled per-element tracks.\n */\nexport function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksOptions): PxCompiledTracks {\n const config = getAnimatorConfig(doc) || {};\n\n const duration = +(config.duration || DEFAULT_DURATION_MS);\n const _iterations = config.iterations;\n let iterations = 1;\n if (typeof _iterations === 'number') iterations = _iterations || 1;\n if (_iterations === 'infinite') iterations = Infinity;\n if (iterations < 1) iterations = 1;\n\n const native = opts?.native ?? false;\n const sampleRate = opts?.sampleRate ?? 60;\n const maxSamples = opts?.maxSamples ?? 600;\n let sampleCount = Math.max(2, Math.round((duration / 1000) * sampleRate) + 1);\n if (sampleCount > maxSamples) sampleCount = maxSamples;\n const stepMs = duration / (sampleCount - 1);\n\n // Element tag per id โ `toRnPropValue` needs it to leave the root `<Svg>`'s\n // transform as a string (see its `tag` parameter).\n const tagById = new Map<string, string>();\n const indexTags = (n: any): void => {\n if (n && typeof n.id === 'string') tagById.set(n.id, String(n.type));\n (n?.children ?? []).forEach(indexTags);\n };\n indexTags(doc);\n\n const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames) || [];\n\n const elements: Array<PxElementTracks> = [];\n for (const binding of bindings) {\n const animDef = binding.animate;\n if (!animDef || typeof animDef !== 'object' || Array.isArray(animDef)) continue;\n\n const props: Record<string, Array<string | number | Array<number>>> = {};\n for (let i = 0; i < sampleCount; i++) {\n const t = i === sampleCount - 1 ? duration : i * stepMs;\n const values = calcAnimationValues(animDef as PxAnimationDefinition, t);\n for (const [attr, value] of Object.entries(values)) {\n const rnProp = toRnPropName(attr);\n if (!rnProp) continue;\n let arr = props[rnProp];\n if (!arr) {\n arr = props[rnProp] = new Array(sampleCount);\n // A prop can appear late (e.g. attrs whose first kf is\n // beyond t=0) โ backfill earlier samples with the first\n // computed value so the array is always fully populated.\n for (let j = 0; j < i; j++) arr[j] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n arr[i] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n }\n // Forward-fill any holes (attr disappeared from a later sample).\n for (const arr of Object.values(props)) {\n for (let i = 1; i < sampleCount; i++) {\n if (arr[i] === undefined) arr[i] = arr[i - 1];\n }\n }\n\n if (Object.keys(props).length > 0) {\n elements.push({ id: binding.id, props });\n }\n }\n\n return {\n duration,\n iterations,\n direction: config.direction || 'normal',\n delay: config.delay || 0,\n fill: config.fill ?? 'forwards',\n resetOnFinish: !!config.resetOnFinish,\n stepMs,\n sampleCount,\n elements,\n };\n}\n\n/**\n * Wire prop โ the prop name the NATIVE view actually declares.\n *\n * react-native-svg's JS layer renames some props on the way down: a\n * `transform` (string or matrix) is parsed by `extractProps` and handed to the\n * native component as `matrix` โ the Fabric spec has no `transform` prop at\n * all. Values sent through reanimated's animated-props path skip that JS\n * rename, so they must already use the native name or the native view drops\n * them silently. This is ONLY for the animated path; plain React renders still\n * go through the JS layer and must keep the wire name.\n */\nexport const NATIVE_PROP_NAME: Record<string, string> = {\n transform: 'matrix',\n};\n\n/**\n * Worklet-safe sample lookup: returns the per-prop values at time `tMs`\n * (already mapped into a single iteration by the caller). Kept deliberately\n * trivial โ runs on the UI thread every frame.\n *\n * `native = true` applies {@link NATIVE_PROP_NAME} โ pass it only on the\n * reanimated animated-props path of a real device. Props that are applied by\n * re-rendering through React (and therefore still pass through react-native-svg's\n * JS layer), and every value on the web, must keep the wire name.\n */\nexport function sampleProps(\n tracks: PxElementTracks,\n tMs: number,\n stepMs: number,\n sampleCount: number,\n native = false\n): Record<string, string | number | Array<number>> {\n 'worklet';\n const out: Record<string, string | number | Array<number>> = {};\n // Defensive: this runs on the UI thread, where a throw is a hard crash\n // with no React boundary to catch it.\n if (!tracks || !tracks.props || !(stepMs > 0)) return out;\n\n let idx = Math.round(tMs / stepMs);\n if (idx < 0) idx = 0;\n if (idx >= sampleCount) idx = sampleCount - 1;\n for (const key in tracks.props) {\n const values = tracks.props[key];\n if (!values) continue;\n const value = values[idx];\n if (value === undefined) continue;\n const name = native && key === 'transform' ? 'matrix' : key;\n out[name] = value;\n }\n return out;\n}\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 { kebabToCamelCaseWord } from '@pixodesk/svg-animator-core';\nimport { svgTransformToMatrix } from './PxRnMatrix';\n\n/** Attribute names with a react-native-svg prop equivalent under a\n * different name (not just a casing change). */\nconst ATTR_NAME_OVERRIDES: Record<string, string> = {\n 'xlink:href': 'href',\n};\n\n/** Props react-native-svg does not understand / must not receive. */\nconst DROPPED_ATTRS = new Set(['class', 'className', 'style', 'xmlns', 'xmlns:xlink', 'data-px-meta']);\n\n/**\n * Converts one normalised wire attribute name (camelCase after core's\n * `getNormalizedProps`, or kebab-case raw) to a react-native-svg prop name.\n * Returns undefined for props that must be dropped.\n *\n * Pure (no react-native-svg import) so the track compiler and its tests\n * don't need a React Native environment.\n */\nexport function toRnPropName(attrName: string): string | undefined {\n if (DROPPED_ATTRS.has(attrName)) return undefined;\n const override = ATTR_NAME_OVERRIDES[attrName];\n if (override) return override;\n // react-native-svg uses camelCase props (strokeWidth, fillOpacity, โฆ);\n // core's kebabToCamelCaseWord is a no-op for already-camelCase input.\n return kebabToCamelCaseWord(attrName);\n}\n\n/** Props whose value is a LIST of lengths. react-native-svg's native side\n * expects a number array here (its JS `extractLengthList` splits strings, but\n * values delivered through reanimated's animated-props path bypass that JS\n * extraction and reach the native view directly). */\nconst LENGTH_LIST_PROPS = new Set(['strokeDasharray']);\n\n/**\n * Converts one already-renamed prop value into the shape react-native-svg\n * expects: length-list props become number arrays; numeric strings become\n * numbers; everything else passes through.\n */\nexport function toRnPropValue(\n rnPropName: string,\n value: string | number,\n /** The owning element's tag. The ROOT `<Svg>` handles `transform` through a\n * different code path (`extractTransformSvgView`, which wants a string or\n * an RN style) โ a matrix there would be dropped, so leave it alone. */\n tag?: string,\n /** Opt in to the NATIVE representation of a value (see below). Defaults to\n * off, so web keeps the plain SVG/DOM form it has always been given. */\n native = false,\n): string | number | Array<number> {\n // On a device `transform` must arrive as a matrix, not a string: the\n // stringโmatrix parse happens in JS during render, which reanimated's\n // animated-props path skips entirely. See PxRnMatrix for the full why.\n // On the web the DOM parses the string itself and an array would serialise\n // to a meaningless `transform=\"1,0,0,1,3,4\"`, so it must stay a string.\n if (native && rnPropName === 'transform' && typeof value === 'string' && tag !== 'svg') {\n const m = svgTransformToMatrix(value);\n if (m) return m;\n }\n if (LENGTH_LIST_PROPS.has(rnPropName)) {\n const parts = String(value).trim().replace(/,/g, ' ').split(/\\s+/).map(Number).filter(n => Number.isFinite(n));\n // An odd-length dasharray repeats to become even (SVG spec); rn-svg\n // does this itself for the static path โ mirror it so both paths agree.\n return parts.length % 2 === 1 ? parts.concat(parts) : parts;\n }\n if (typeof value === 'number') return value;\n const num = +value;\n return Number.isFinite(num) && String(num) === value ? num : value;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * SVG transform string โ 2D affine matrix, in the order react-native-svg's\n * native side expects: `[a, b, c, d, e, f]`, i.e. SVG's own `matrix(โฆ)` order\n *\n * ```\n * | a c e |\n * | b d f |\n * | 0 0 1 |\n * ```\n *\n * WHY THIS EXISTS: react-native-svg parses a `transform` STRING into this matrix\n * in JavaScript, inside `extractTransform`, during render. Values delivered\n * through reanimated's `animatedProps` bypass that JS step and reach the native\n * view directly, where a raw string is meaningless โ an animated transform\n * simply does nothing. Feeding the matrix instead makes the animated and static\n * paths agree. (On the web the DOM parses the string itself, which is why this\n * only shows up on a device.)\n */\nexport type Mat2D = [number, number, number, number, number, number];\n\nexport const IDENTITY: Mat2D = [1, 0, 0, 1, 0, 0];\n\nconst DEG = Math.PI / 180;\n\n/** `m1 ยท m2` โ apply m2 first, then m1 (same convention as SVG's left-to-right list). */\nfunction multiply(m1: Mat2D, m2: Mat2D): Mat2D {\n const [a1, b1, c1, d1, e1, f1] = m1;\n const [a2, b2, c2, d2, e2, f2] = m2;\n return [\n a1 * a2 + c1 * b2,\n b1 * a2 + d1 * b2,\n a1 * c2 + c1 * d2,\n b1 * c2 + d1 * d2,\n a1 * e2 + c1 * f2 + e1,\n b1 * e2 + d1 * f2 + f1,\n ];\n}\n\n/** Splits `translate(1,2)rotate(45)` into `[['translate',[1,2]], ['rotate',[45]]]`. */\nconst FN_RE = /([a-zA-Z]+)\\s*\\(([^)]*)\\)/g;\n\nfunction numbers(raw: string): Array<number> {\n return raw\n .split(/[\\s,]+/)\n .filter(s => s.length > 0)\n .map(Number)\n .filter(n => Number.isFinite(n));\n}\n\n/**\n * Parses an SVG transform list. Returns `undefined` when the string contains no\n * recognisable function, so callers can leave the original value untouched\n * rather than silently replacing it with an identity matrix.\n */\nexport function svgTransformToMatrix(value: string): Mat2D | undefined {\n let m: Mat2D | undefined;\n FN_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = FN_RE.exec(value)) !== null) {\n const fn = match[1].toLowerCase();\n const n = numbers(match[2]);\n let step: Mat2D | undefined;\n\n switch (fn) {\n case 'translate':\n step = [1, 0, 0, 1, n[0] || 0, n[1] || 0];\n break;\n case 'scale': {\n const sx = n[0] ?? 1;\n const sy = n.length > 1 ? n[1] : sx;\n step = [sx, 0, 0, sy, 0, 0];\n break;\n }\n case 'rotate': {\n const rad = (n[0] || 0) * DEG;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n const rot: Mat2D = [cos, sin, -sin, cos, 0, 0];\n if (n.length >= 3) {\n // rotate(a, cx, cy) == translate(cx,cy) rotate(a) translate(-cx,-cy)\n const cx = n[1], cy = n[2];\n step = multiply(multiply([1, 0, 0, 1, cx, cy], rot), [1, 0, 0, 1, -cx, -cy]);\n } else {\n step = rot;\n }\n break;\n }\n case 'skewx':\n step = [1, 0, Math.tan((n[0] || 0) * DEG), 1, 0, 0];\n break;\n case 'skewy':\n step = [1, Math.tan((n[0] || 0) * DEG), 0, 1, 0, 0];\n break;\n case 'matrix':\n if (n.length >= 6) step = [n[0], n[1], n[2], n[3], n[4], n[5]];\n break;\n default:\n step = undefined; // unknown function โ ignore it\n }\n\n if (step) m = m ? multiply(m, step) : step;\n }\n\n return m;\n}\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 {\n getNormalizedProps,\n resolveStyle,\n sanitiseAttributeValue,\n DISALLOWED_SVG_TAGS_LOWER,\n TEXT_ATTR,\n TEXT_CONTENT_ATTR,\n type PxDefs,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport { createElement, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { RN_SVG_COMPONENTS } from './PxRnTypeMap';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\nexport interface RenderRnNodeOptions {\n /** Collects non-fatal issues (unsupported tags, dropped attrs). */\n warnings?: Array<string>;\n /** `definitions` from the document, used to resolve named `style` presets. */\n defs?: PxDefs;\n /**\n * Wraps the created element for animated nodes: receives the resolved\n * component + static props and returns the element to mount (the animator\n * substitutes an Animated component wired to its tracks). Return undefined\n * to keep the plain static element.\n *\n * `key` is handed over SEPARATELY and is deliberately absent from `props`:\n * React 19 warns when a props object containing `key` is spread into JSX,\n * and implementations of this hook do exactly that.\n */\n decorate?: (\n node: PxNode,\n Component: ComponentType<any>,\n props: Record<string, any>,\n children: ReactNode,\n key: string | number | undefined\n ) => ReactElement | undefined;\n}\n\n/**\n * Converts core-normalised wire props into react-native-svg props: RN prop\n * naming, sanitisation (same security rules as the web renderer), numeric\n * coercion where possible.\n */\nexport function toRnProps(props: Record<string, any>, warnings?: Array<string>, tag?: string): Record<string, any> {\n const normalised = getNormalizedProps(props);\n const out: Record<string, any> = {};\n for (const key of Object.keys(normalised)) {\n const sanitised = sanitiseAttributeValue(key, normalised[key]);\n if (sanitised === undefined) continue;\n const rnKey = toRnPropName(key);\n if (!rnKey) continue;\n out[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n return out;\n}\n\n/**\n * Renders a (materialised) PxNode tree to react-native-svg elements.\n * Mirrors the web `renderNode` contract: unsupported/dangerous tags are\n * skipped with a warning, never a crash.\n */\nexport function renderRnNode(node: PxNode, opts: RenderRnNodeOptions = {}, key?: string | number): ReactElement | null {\n if (!node) return null;\n\n const { type, children, style, animate, meta, effects, ...props } = node as any;\n const tag = String(type || 'g');\n\n // ESCAPE KEY (S2): elements whose SVG `type` ATTRIBUTE collides with the reserved\n // `type` node-tag key carry it under `domType` โ `feColorMatrix` (matrix/saturate/โฆ),\n // `feTurbulence` (fractalNoise/turbulence), `feFunc*` (identity/table/โฆ).\n // Restore it as a real prop, mirroring the web renderer.\n const domType: string | undefined = props.domType;\n if (domType !== undefined) delete props.domType;\n\n if (DISALLOWED_SVG_TAGS_LOWER.has(tag.toLowerCase())) {\n opts.warnings?.push('tag blocked (dangerous): ' + tag);\n return null;\n }\n\n const Component = RN_SVG_COMPONENTS[tag];\n if (!Component) {\n opts.warnings?.push('tag not supported in react-native-svg mapping: ' + tag);\n return null;\n }\n\n // NB: `key` is never written into this object โ see `decorate` above.\n const rnProps = toRnProps(props, opts.warnings, tag);\n if (domType !== undefined) rnProps.type = domType;\n\n // `node.style` โ a named preset from `definitions.styles`, or an inline\n // record. react-native-svg has no CSS, so the resolved declarations are\n // applied as ordinary props (the same names, e.g. `fill`, `strokeWidth`).\n // Explicit attributes on the node win over the style block.\n const resolved = resolveStyle(style, opts.defs);\n if (resolved) {\n for (const [k, v] of Object.entries(resolved)) {\n const rnKey = toRnPropName(k);\n if (!rnKey || rnKey in rnProps) continue;\n const sanitised = sanitiseAttributeValue(rnKey, v);\n if (sanitised === undefined) continue;\n rnProps[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n }\n\n // Text content: wire nodes carry it as `text` / `textContent` attr.\n const textContent: string | undefined = props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR];\n\n let childElements: ReactNode = undefined;\n if (Array.isArray(children) && children.length > 0) {\n childElements = children\n .map((ch: PxNode, i: number) => {\n // One malformed child should cost that child, not the whole tree.\n try {\n return renderRnNode(ch, opts, i);\n } catch (e) {\n opts.warnings?.push('child failed to render: ' + (e instanceof Error ? e.message : String(e)));\n return null;\n }\n })\n .filter(Boolean);\n } else if (textContent !== undefined) {\n childElements = String(textContent);\n }\n\n const decorated = opts.decorate?.(node, Component, rnProps, childElements, key);\n if (decorated !== undefined) return decorated;\n\n // `createElement` takes `key` in its config object โ that path does NOT\n // trigger React's JSX-spread warning.\n return createElement(\n Component,\n key !== undefined ? { ...rnProps, key } : rnProps,\n childElements\n );\n}\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 {\n Circle,\n ClipPath,\n Defs,\n Ellipse,\n FeBlend,\n FeColorMatrix,\n FeComponentTransfer,\n FeComposite,\n FeConvolveMatrix,\n FeDiffuseLighting,\n FeDisplacementMap,\n FeDistantLight,\n FeDropShadow,\n FeFlood,\n FeFuncA,\n FeFuncB,\n FeFuncG,\n FeFuncR,\n FeGaussianBlur,\n FeImage,\n FeMerge,\n FeMergeNode,\n FeMorphology,\n FeOffset,\n FePointLight,\n FeSpecularLighting,\n FeSpotLight,\n FeTile,\n FeTurbulence,\n Filter,\n G,\n Image,\n Line,\n LinearGradient,\n Marker,\n Mask,\n Path,\n Pattern,\n Polygon,\n Polyline,\n RadialGradient,\n Rect,\n Stop,\n Svg,\n Symbol as SvgSymbol,\n Text as SvgText,\n TextPath,\n TSpan,\n Use,\n} from 'react-native-svg';\nimport type { ComponentType } from 'react';\n\n/**\n * SVG tag โ react-native-svg component. Tags not in this map are skipped at\n * render time (with a warning collected by the renderer) โ they go on the\n * feature-gap list rather than crashing the tree.\n *\n * Keys are the wire-format `node.type` values, which follow SVG's own casing\n * (`clipPath`, `feGaussianBlur`, `linearGradient`, โฆ).\n */\nexport const RN_SVG_COMPONENTS: Record<string, ComponentType<any>> = {\n // Root & containers\n svg: Svg,\n g: G,\n defs: Defs,\n symbol: SvgSymbol,\n use: Use,\n\n // Shapes\n rect: Rect,\n circle: Circle,\n ellipse: Ellipse,\n line: Line,\n path: Path,\n polygon: Polygon,\n polyline: Polyline,\n image: Image,\n\n // Text\n text: SvgText,\n tspan: TSpan,\n textPath: TextPath,\n\n // Paint servers & clipping\n linearGradient: LinearGradient,\n radialGradient: RadialGradient,\n stop: Stop,\n pattern: Pattern,\n mask: Mask,\n clipPath: ClipPath,\n marker: Marker,\n\n // Filters โ react-native-svg implements the full primitive set.\n // NOTE: filter rendering requires the New Architecture (Fabric) and is\n // newer than the rest of react-native-svg; treat visual parity with the\n // web player as unverified until checked on a device.\n filter: Filter,\n feBlend: FeBlend,\n feColorMatrix: FeColorMatrix,\n feComponentTransfer: FeComponentTransfer,\n feComposite: FeComposite,\n feConvolveMatrix: FeConvolveMatrix,\n feDiffuseLighting: FeDiffuseLighting,\n feDisplacementMap: FeDisplacementMap,\n feDistantLight: FeDistantLight,\n feDropShadow: FeDropShadow,\n feFlood: FeFlood,\n feFuncA: FeFuncA,\n feFuncB: FeFuncB,\n feFuncG: FeFuncG,\n feFuncR: FeFuncR,\n feGaussianBlur: FeGaussianBlur,\n feImage: FeImage,\n feMerge: FeMerge,\n feMergeNode: FeMergeNode,\n feMorphology: FeMorphology,\n feOffset: FeOffset,\n fePointLight: FePointLight,\n feSpecularLighting: FeSpecularLighting,\n feSpotLight: FeSpotLight,\n feTile: FeTile,\n feTurbulence: FeTurbulence,\n};\n\nexport { toRnPropName } from './PxRnPropNames';\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 { Component, type ErrorInfo, type ReactNode } from 'react';\n\nexport interface PxRnErrorBoundaryProps {\n children: ReactNode;\n /** Rendered instead of the children once something has thrown. */\n fallback?: (error: Error) => ReactNode;\n onError?: (error: Error, info?: string) => void;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Keeps one bad animation from taking down the screen around it.\n *\n * A throw anywhere in the rendered SVG tree โ an unsupported prop shape, a\n * react-native-svg internal, a reanimated attachment failure โ otherwise\n * unmounts the whole React tree above it. Here it is contained to this one\n * animation, reported through `onError`, and replaced by `fallback`.\n *\n * NOTE the limit: this catches JavaScript errors only. A crash INSIDE the\n * native renderer (see `openClosedTextPathTargets` for a real example) never\n * reaches JavaScript and cannot be caught here โ those have to be avoided\n * rather than handled.\n */\nexport class PxRnErrorBoundary extends Component<PxRnErrorBoundaryProps, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n this.props.onError?.(error, info?.componentStack ?? undefined);\n console.warn('[PixodeskSvgAnimator] render failed:', error?.message ?? error);\n }\n\n override componentDidUpdate(prev: PxRnErrorBoundaryProps): void {\n // A new document deserves a fresh attempt โ otherwise the boundary\n // would stay latched on the failure for the rest of its life.\n if (this.state.error && prev.children !== this.props.children) {\n this.setState({ error: null });\n }\n }\n\n override render(): ReactNode {\n const { error } = this.state;\n if (error) return this.props.fallback ? this.props.fallback(error) : null;\n return this.props.children;\n }\n}\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 { deepClone, generateUniqueId, type PxNode } from '@pixodesk/svg-animator-core';\n\n/**\n * Workarounds for defects in react-native-svg's NATIVE renderer that would\n * otherwise take the whole app down.\n *\n * These are applied only when the native views are in use โ never on the web,\n * where the DOM handles all of this correctly and the document must be left\n * exactly as the core pipeline produced it.\n */\n\n/** True when a path's `d` contains a close-subpath command. */\nfunction isClosedPath(d: unknown): boolean {\n return typeof d === 'string' && /[zZ]/.test(d);\n}\n\n/** Drops close-subpath commands, turning a closed outline into an open one. */\nfunction openPath(d: string): string {\n return d.replace(/[zZ]/g, '').trimEnd();\n}\n\n/** `#foo` โ `foo`. Returns undefined for anything that is not a local ref. */\nfunction localRef(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.startsWith('#') ? trimmed.slice(1) : undefined;\n}\n\nfunction forEachNode(node: PxNode | undefined, visit: (n: PxNode, parent?: PxNode) => void, parent?: PxNode): void {\n if (!node) return;\n visit(node, parent);\n for (const child of (node.children ?? [])) forEachNode(child, visit, node);\n}\n\n/**\n * Gives every `<textPath>` that follows a CLOSED path its own OPEN copy of it.\n *\n * WHY: react-native-svg's native text-on-path layout crashes the app โ\n * an uncatchable `NSRangeException` on iOS โ for this combination.\n * `RNSVGTSpan.mm` skips glyphs outside `[startOfRendering, endOfRendering]`,\n * but for a closed path it sets those bounds to `startOffset โฆ startOffset +\n * pathLength` instead of `0 โฆ pathLength`. Any glyph past the end of the path\n * therefore survives the bounds check and reaches `getPosAndTan`, whose\n * `indexOfObjectPassingTest` returns `NSNotFound` โ and indexing the lengths\n * array with `NSNotFound` throws. A non-zero `startOffset` on a closed path is\n * all it takes, and animating `startOffset` guarantees hitting it.\n *\n * Opening the path restores the `0 โฆ pathLength` bounds, so out-of-range\n * glyphs are skipped as intended. The copy is private to the `<textPath>`, so\n * anything else drawing the same path still gets the closed original. For a\n * shape whose ends already meet (a circle, the usual case) the removed segment\n * has zero length and nothing changes visually at all.\n *\n * Returns the document unchanged โ the same object โ when nothing matches.\n */\nexport function openClosedTextPathTargets(doc: PxNode, warnings?: Array<string>): PxNode {\n // Cheap pre-check: the overwhelming majority of documents have no textPath.\n let hasTextPath = false;\n forEachNode(doc, n => { if (String(n.type) === 'textPath') hasTextPath = true; });\n if (!hasTextPath) return doc;\n\n const result = deepClone(doc);\n\n const byId = new Map<string, PxNode>();\n forEachNode(result, n => {\n const id = (n as any).id;\n if (typeof id === 'string') byId.set(id, n);\n });\n\n /** The copy is a geometry reference, never something to draw โ so it goes\n * in `<defs>`, alongside the paths textPath targets normally live in. */\n let defs = (result.children ?? []).find(c => String(c.type) === 'defs');\n const ensureDefs = (): PxNode => {\n if (!defs) {\n defs = { type: 'defs', children: [] } as unknown as PxNode;\n (result.children ??= []).unshift(defs);\n }\n return defs;\n };\n\n /** Original path id โ id of the open copy, so N textPaths share one copy. */\n const openCopies = new Map<string, string>();\n\n forEachNode(result, node => {\n if (String(node.type) !== 'textPath') return;\n\n const anyNode = node as any;\n const attr = anyNode.href !== undefined ? 'href' : 'xlink:href';\n const targetId = localRef(anyNode[attr]);\n if (!targetId) return;\n\n const target = byId.get(targetId);\n if (!target || !isClosedPath((target as any).d)) return;\n\n let copyId = openCopies.get(targetId);\n if (!copyId) {\n const copy = deepClone(target) as any;\n copyId = 'px_open_' + generateUniqueId();\n copy.id = copyId;\n copy.d = openPath(String(copy.d));\n // A copy that also carried animation would animate twice; the copy\n // exists purely as a geometry reference for the text.\n delete copy.animate;\n delete copy.effects;\n\n (ensureDefs().children ??= []).push(copy);\n openCopies.set(targetId, copyId);\n warnings?.push(\n 'textPath follows a closed path (#' + targetId + '); using an open copy to ' +\n 'avoid a react-native-svg native crash'\n );\n }\n\n anyNode[attr] = '#' + copyId;\n });\n\n return result;\n}\n"],"mappings":"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","names":["import_svg_animator_core","import_react","import_svg_animator_core","_a","import_svg_animator_core","SvgSymbol","SvgText","Component","_a","import_react","import_svg_animator_core","_a","Component","Animated","_a"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/PixodeskSvgAnimator.tsx","../src/PxRnTracks.ts","../src/PxRnPropNames.ts","../src/PxRnMatrix.ts","../src/PxRnRender.tsx","../src/PxRnTypeMap.ts","../src/PxRnErrorBoundary.tsx","../src/PxRnSafety.ts"],"sourcesContent":["/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\nexport { PixodeskSvgAnimator, default } from './PixodeskSvgAnimator';\nexport type { PixodeskSvgAnimatorProps, RnAnimatorApi } from './PixodeskSvgAnimator';\n\nexport { renderRnNode, toRnProps } from './PxRnRender';\nexport { PxRnErrorBoundary, type PxRnErrorBoundaryProps } from './PxRnErrorBoundary';\nexport { openClosedTextPathTargets } from './PxRnSafety';\nexport type { RenderRnNodeOptions } from './PxRnRender';\n\nexport { compileTracks, sampleProps } from './PxRnTracks';\nexport type { CompileTracksOptions, PxCompiledTracks, PxElementTracks } from './PxRnTracks';\n\nexport { RN_SVG_COMPONENTS, toRnPropName } from './PxRnTypeMap';\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 {\n generateNewIds,\n getAnimatorConfig,\n getDefs,\n materialiseAllInTree,\n validateNodeEffects,\n PxAnimatorEngine,\n type FillMode,\n type OutAction,\n type PlaybackDirection,\n type PxAnimatedSvgDocument,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport React, { createElement, useEffect, useImperativeHandle, useMemo, useRef, useState, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { Dimensions, Platform, Pressable, View } from 'react-native';\nimport Animated, {\n cancelAnimation,\n useAnimatedReaction,\n Easing,\n runOnJS,\n useAnimatedProps,\n useSharedValue,\n withDelay,\n withRepeat,\n withTiming,\n type SharedValue,\n} from 'react-native-reanimated';\nimport { compileTracks, sampleProps, type PxCompiledTracks, type PxElementTracks } from './PxRnTracks';\nimport { renderRnNode, type RenderRnNodeOptions } from './PxRnRender';\nimport { PxRnErrorBoundary } from './PxRnErrorBoundary';\nimport { openClosedTextPathTargets } from './PxRnSafety';\n\n\n// -- Public types -----------------------------------------------------------\n\n/** Imperative playback API โ mirrors ReactAnimatorApi from svg-animator-react. */\nexport interface RnAnimatorApi {\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. */\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 PixodeskSvgAnimatorProps {\n\n // -- Source ---------------------------------------------------------------\n\n /** The animation document to render. */\n doc: PxAnimatedSvgDocument;\n\n // -- Timing overrides -----------------------------------------------------\n\n /** Duration of a single iteration in milliseconds. */\n duration?: number;\n\n /** Delay before the animation starts, in milliseconds. */\n delay?: number;\n\n /** Number of iterations, or 'infinite' for endless looping. */\n iterations?: number | 'infinite';\n\n /** Defines the element's state when the animation is not active. */\n fill?: FillMode;\n\n /** Playback direction. */\n direction?: PlaybackDirection;\n\n /** Snap back to the start state after a natural finish. */\n resetOnFinish?: boolean;\n\n /**\n * What a second tap does when `startOn: 'click'` is active.\n * Defaults to the document's `trigger.outAction`, else `'pause'`.\n */\n outAction?: OutAction;\n\n // -- Declarative control --------------------------------------------------\n\n /** When true, honours the document trigger (`startOn: 'load'` plays on mount). */\n autoplay?: boolean;\n\n /** Starts playback unconditionally. */\n play?: boolean;\n\n /** Pauses current playback. */\n pause?: boolean;\n\n // -- Imperative control ---------------------------------------------------\n\n /** Ref populated with the imperative playback API. */\n apiRef?: React.RefObject<RnAnimatorApi | null>;\n\n // -- Controlled (external) time -------------------------------------------\n\n /** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */\n progress?: number;\n\n /** Seek to a specific time in milliseconds. */\n time?: number;\n\n // -- Callbacks ------------------------------------------------------------\n\n onPlay?: () => void;\n onStop?: () => void;\n onPause?: () => void;\n onCancel?: () => void;\n onFinish?: () => void;\n\n\n // -- Failure handling -----------------------------------------------------\n\n /**\n * Called when a document cannot be compiled or rendered. The component\n * renders {@link fallback} instead of throwing, so a single broken\n * animation never takes down the screen around it.\n *\n * Only JavaScript failures reach this โ a crash inside react-native-svg's\n * native renderer bypasses JavaScript entirely.\n */\n onError?: (error: Error, componentStack?: string) => void;\n\n /** Rendered in place of the animation after a failure. Default: nothing. */\n fallback?: (error: Error) => ReactElement | null;\n}\n\n\n// -- Animated element wrapper ------------------------------------------------\n\n/**\n * Whether react-native-svg is backed by NATIVE views here, rather than by the\n * DOM through react-native-web.\n *\n * The two want different things from an animated `transform`: a native view\n * declares a `matrix` prop taking six numbers, while the DOM wants a\n * `transform` attribute holding an SVG string. Getting it wrong is silent โ\n * the value is dropped and the element simply never moves โ so this single\n * constant decides it once and feeds both the track compiler (value form) and\n * the sampler (prop name). Everything else in the package defaults to the\n * DOM-compatible form.\n */\nconst NATIVE_SVG_VIEWS = Platform.OS !== 'web';\n\nconst animatedComponentCache = new Map<ComponentType<any>, ComponentType<any>>();\n\nfunction getAnimatedComponent(Component: ComponentType<any>): ComponentType<any> {\n let cached = animatedComponentCache.get(Component);\n if (!cached) {\n cached = Animated.createAnimatedComponent(Component as any);\n animatedComponentCache.set(Component, cached);\n }\n return cached;\n}\n\n/** One animated element: static props + UI-thread sampled animated props. */\nfunction AnimatedPxElement({\n Component, staticProps, children, tracks, progress, stepMs, sampleCount,\n}: {\n Component: ComponentType<any>;\n staticProps: Record<string, any>;\n children: ReactNode;\n tracks: PxElementTracks;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n}) {\n const AnimatedComponent = useMemo(() => getAnimatedComponent(Component), [Component]);\n\n // Runs on the UI thread every frame; `sampleProps` is a trivial indexed\n // lookup into the precompiled tracks โ no interpolation logic on the hot path.\n const animatedProps = useAnimatedProps(() => {\n // On iOS/Android these values bypass react-native-svg's JS prop layer\n // and land on the native view, which declares `matrix`, not\n // `transform`. The web build keeps the DOM-facing `transform` name.\n return sampleProps(tracks, progress.value, stepMs, sampleCount, NATIVE_SVG_VIEWS);\n }, [tracks, stepMs, sampleCount]);\n\n return (\n <AnimatedComponent {...staticProps} animatedProps={animatedProps}>\n {children}\n </AnimatedComponent>\n );\n}\n\n\n/**\n * react-native-svg elements whose `render()` returns `null`. They carry data for\n * their PARENT (a `<Stop>` is read by the gradient that owns it) rather than\n * producing a native view, so reanimated has nothing to attach to โ wrapping one\n * in `Animated.createAnimatedComponent` throws\n * \"Cannot find host instance for this component\".\n */\nconst NON_HOST_TAGS = new Set(['stop', 'feMergeNode']);\n\n/**\n * Definition elements โ they describe paint/geometry for something else rather\n * than drawing themselves. Their animated attributes (a gradient's `y1`, a\n * stop's `stop-color`) do not reliably flow through reanimated's animated-props\n * path, so an animated def is rendered by re-sampling from JS instead. There\n * are only ever a handful per document and they change slowly, so the cost is\n * negligible โ visual elements still animate entirely on the UI thread.\n */\nconst SAMPLED_DEF_TAGS = new Set(['linearGradient', 'radialGradient', ...NON_HOST_TAGS]);\n\n/** True when this subtree must be driven from JS rather than the UI thread:\n * either the node itself is an animated def, or it owns an animated non-host\n * child (an animated `<Stop>` only re-renders via its parent gradient). */\nfunction needsJsSampling(node: PxNode, trackById: Map<string, PxElementTracks>): boolean {\n const id = (node as any).id;\n if (SAMPLED_DEF_TAGS.has(String(node.type)) && id && trackById.has(id)) return true;\n return (node.children ?? []).some(c => needsJsSampling(c, trackById));\n}\n\n/**\n * Renders a subtree whose animation cannot run on the UI thread (see\n * {@link NON_HOST_TAGS}) by re-rendering it from JS with sampled values.\n *\n * Changing a `<Stop>`'s props does not re-render its parent gradient, so the\n * whole subtree is rebuilt โ which is why this wraps the gradient rather than\n * the stop. The reaction itself runs on the UI thread and only crosses to JS\n * when the QUANTISED sample index changes, capping these few elements at\n * ~30fps instead of a JS call every frame.\n */\nfunction SampledSubtree({\n node, trackById, progress, stepMs, sampleCount, renderOpts,\n}: {\n node: PxNode;\n trackById: Map<string, PxElementTracks>;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n renderOpts: RenderRnNodeOptions;\n}) {\n const [idx, setIdx] = useState(0);\n\n useAnimatedReaction(\n () => Math.floor(Math.round(progress.value / stepMs) / 2) * 2, // half-rate\n (next, prev) => {\n if (next !== prev) runOnJS(setIdx)(next);\n },\n [stepMs]\n );\n\n const tMs = Math.min(Math.max(idx, 0), sampleCount - 1) * stepMs;\n\n return renderRnNode(node, {\n ...renderOpts,\n // Sampled values are baked in as PLAIN props โ nothing reanimated-driven.\n decorate: (n, Component, staticProps, children, key) => {\n const id = (n as any).id;\n const tracks = id ? trackById.get(id) : undefined;\n if (!tracks) return undefined;\n // Wire prop names, NOT the native ones: these go back through\n // react-native-svg's JS prop layer, which does the renaming itself.\n const sampled = sampleProps(tracks, tMs, stepMs, sampleCount);\n return createElement(Component, { ...staticProps, ...sampled, key }, children);\n },\n });\n}\n\n\n\n/** Overrides that shadow the document's own `animator` config. */\ninterface ConfigOverrides {\n duration?: number;\n delay?: number;\n iterations?: number | 'infinite';\n fill?: FillMode;\n direction?: PlaybackDirection;\n resetOnFinish?: boolean;\n}\n\ninterface Compiled {\n /** Materialised document, or null when compilation failed. */\n doc: PxAnimatedSvgDocument | null;\n tracks: PxCompiledTracks;\n error: Error | null;\n}\n\n/** Playable-but-empty tracks, so a failed compile still satisfies every hook\n * below it โ React forbids skipping hooks on an error path. */\nconst EMPTY_TRACKS: PxCompiledTracks = {\n duration: 1, iterations: 1, direction: 'normal', delay: 0,\n fill: 'forwards', resetOnFinish: false, stepMs: 1, sampleCount: 2, elements: [],\n};\n\n/**\n * Materialises + compiles a document. Extracted from the component so the\n * whole thing sits behind one try/catch, and so it can be tested directly.\n */\nfunction compileDocument(doc: PxAnimatedSvgDocument, overrides: ConfigOverrides): Compiled {\n const { duration, delay, iterations, fill, direction, resetOnFinish } = overrides;\n const warnings = validateNodeEffects(doc as PxNode);\n for (const w of warnings) console.warn('[PixodeskSvgAnimator] effects shape warning:', w);\n\n // `waapi` = the FULLY-FLATTENED materialisation: effects + loops +\n // sampled motion paths + animated `<use>` inlined into real `<g>`\n // clones + orphaned defs pruned. That last part is why RN must not use\n // the `frames` flavour: frames keeps `<use href=\"#animatedTarget\">`\n // live references, which only work because the DOM propagates\n // attribute writes through `<use>` shadow trees. react-native-svg has\n // no such live propagation, so an animated `<use>` would render frozen.\n let prepared = materialiseAllInTree(doc, PxAnimatorEngine.waapi);\n\n // Sidestep a react-native-svg NATIVE crash (see PxRnSafety). Guarded on\n // the platform because the DOM renders this case correctly and the web\n // document must stay exactly as the core pipeline produced it.\n if (NATIVE_SVG_VIEWS) {\n prepared = openClosedTextPathTargets(prepared as PxNode) as PxAnimatedSvgDocument;\n }\n\n // Apply prop overrides onto the animator config (mirrors the react wrapper).\n const animator = getAnimatorConfig(prepared) || {};\n prepared = {\n ...prepared,\n animator: {\n ...animator,\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 resetOnFinish: resetOnFinish !== undefined ? resetOnFinish : animator.resetOnFinish,\n },\n };\n\n prepared = generateNewIds(prepared);\n const tracks = compileTracks(prepared, { native: NATIVE_SVG_VIEWS });\n return { doc: prepared, tracks, error: null };\n}\n\n\n// -- Main component ----------------------------------------------------------\n\n/**\n * React Native component for rendering and controlling Pixodesk SVG animations.\n *\n * The document is materialised once through the shared core pipeline (effects,\n * loops, motion-path sampling, animated-`<use>` inlining โ identical to the\n * web frames engine), compiled into densely sampled per-element tracks, and\n * played back natively: a single reanimated progress value driven by\n * `withTiming`/`withRepeat` on the UI thread, with per-element worklets\n * indexing the precompiled tracks. No JS-thread frame loop.\n */\nexport function PixodeskSvgAnimator({\n doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp,\n // (`progress` prop aliased โ the name is taken by the internal reanimated SharedValue)\n autoplay, play, pause, apiRef, progress: progressProp, time,\n onPlay, onStop, onPause, onCancel, onFinish, onError, fallback,\n}: PixodeskSvgAnimatorProps): ReactElement | null {\n\n // -- Compile the document (once per doc/override change) ------------------\n\n const compiled = useMemo((): Compiled => {\n try {\n return compileDocument(\n doc,\n { duration, delay, iterations, fill, direction, resetOnFinish }\n );\n } catch (e) {\n // A malformed document must not take the host screen down with it.\n const error = e instanceof Error ? e : new Error(String(e));\n console.warn('[PixodeskSvgAnimator] could not compile the document:', error.message);\n return { doc: null, tracks: EMPTY_TRACKS, error };\n }\n }, [doc, duration, delay, iterations, fill, direction, resetOnFinish]);\n\n const tracks: PxCompiledTracks = compiled.tracks;\n const totalDuration = tracks.duration * (tracks.iterations === Infinity ? 1 : tracks.iterations);\n\n // -- Playback state -------------------------------------------------------\n\n // Progress in ms within ONE iteration; iteration repetition/alternation is\n // expressed through withRepeat, so worklets only ever see [0, duration].\n const progress = useSharedValue(0);\n const playingRef = useRef(false);\n const rateRef = useRef(1);\n\n /** True when the current rate plays the timeline backwards. */\n const reversePlayback = () => rateRef.current < 0;\n\n /** Where the playhead rests once playback ends. `resetOnFinish` snaps back\n * to the start; otherwise `fill` decides whether the final frame is held. */\n const restingPosition = () => {\n if (tracks.resetOnFinish) return 0;\n if (tracks.fill === 'none' || tracks.fill === 'backwards') return 0;\n return reversePlayback() ? 0 : tracks.duration;\n };\n\n const notifyFinish = () => {\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n };\n\n const startFrom = (fromMs: number) => {\n const dur = tracks.duration;\n const rate = rateRef.current || 1;\n const backwards = rate < 0;\n const speed = Math.abs(rate);\n // `direction` decides which end a leg runs toward; a negative playback\n // rate flips it again (the two compose, as in the Web Animations API).\n const directionReversed = tracks.direction === 'reverse' || tracks.direction === 'alternate-reverse';\n const reversedStart = backwards ? !directionReversed : directionReversed;\n const alternates = tracks.direction === 'alternate' || tracks.direction === 'alternate-reverse';\n const from = Math.max(0, Math.min(fromMs, dur));\n\n const legTarget = reversedStart ? 0 : dur;\n const legRemaining = Math.abs(legTarget - from) / speed;\n const repeats = tracks.iterations === Infinity ? -1 : tracks.iterations;\n\n cancelAnimation(progress);\n progress.value = reversedStart ? (from <= 0 ? dur : from) : (from >= dur ? 0 : from);\n\n const animation = repeats === 1\n ? withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }, (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n })\n : withRepeat(\n withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }),\n repeats, alternates,\n (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n }\n );\n\n progress.value = tracks.delay > 0 && from === 0\n ? withDelay(tracks.delay / speed, animation)\n : animation;\n\n playingRef.current = true;\n };\n\n const api: RnAnimatorApi = {\n isPlaying: () => playingRef.current,\n play: () => {\n // `startFrom` rewinds to the opposite end when the playhead is\n // already resting at a boundary (mirrors WAAPI, where play() on a\n // finished animation auto-rewinds).\n startFrom(progress.value);\n onPlay?.();\n },\n pause: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n onPause?.();\n onStop?.();\n },\n cancel: () => {\n cancelAnimation(progress);\n progress.value = 0;\n playingRef.current = false;\n onCancel?.();\n onStop?.();\n },\n finish: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n },\n setPlaybackRate: (rate: number) => {\n if (!isFinite(rate) || rate === 0) {\n console.warn('setPlaybackRate: rate must be finite and non-zero');\n return;\n }\n rateRef.current = rate;\n if (playingRef.current) startFrom(progress.value);\n },\n getCurrentTime: () => progress.value,\n setCurrentTime: (t: number) => {\n const wasPlaying = playingRef.current;\n cancelAnimation(progress);\n playingRef.current = false;\n const clamped = Math.max(0, Math.min(t, totalDuration));\n const withinIteration = tracks.duration > 0\n ? (clamped % tracks.duration) || (clamped === 0 ? 0 : tracks.duration)\n : 0;\n progress.value = withinIteration;\n // Seeking mid-playback continues from the new position rather than\n // silently pausing.\n if (wasPlaying) startFrom(withinIteration);\n },\n };\n\n useImperativeHandle(apiRef, () => api, [compiled]);\n\n // -- Declarative control --------------------------------------------------\n\n const trigger = compiled.doc ? getAnimatorConfig(compiled.doc)?.trigger : undefined;\n const startOn = trigger?.startOn ?? 'load';\n const outAction = outActionProp ?? trigger?.outAction ?? 'pause';\n\n useEffect(() => {\n if (progressProp !== undefined || time !== undefined) {\n const seekMs = time !== undefined ? time : (progressProp ?? 0) * totalDuration;\n api.setCurrentTime(seekMs);\n return;\n }\n if (play !== undefined || pause !== undefined) {\n if (play && !pause) api.play();\n else if (pause) api.pause();\n else if (play === false) api.finish();\n else api.play();\n return;\n }\n // 'click' and 'scrollIntoView' start from their own handlers below.\n if (autoplay && startOn === 'load') {\n api.play();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, play, pause, progressProp, time]);\n\n // `startOn: 'scrollIntoView'` โ react-native has no IntersectionObserver, so\n // visibility is sampled by measuring the view against the window box. The\n // poll is cheap (a native measure every 200ms) and only runs while this\n // trigger is active; `outAction` decides what leaving the viewport does.\n const scrollRef = useRef<View | null>(null);\n const inViewRef = useRef(false);\n useEffect(() => {\n if (!autoplay || startOn !== 'scrollIntoView') return;\n const threshold = trigger?.scrollIntoViewThreshold ?? 0;\n inViewRef.current = false;\n\n const check = () => {\n const node = scrollRef.current;\n if (!node) return;\n node.measureInWindow((_x, y, _w, h) => {\n if (!h) return;\n const screen = Dimensions.get('window').height;\n const visible = Math.max(0, Math.min(y + h, screen) - Math.max(y, 0));\n const ratio = visible / h;\n const isIn = ratio > 0 && ratio >= threshold;\n if (isIn === inViewRef.current) return;\n inViewRef.current = isIn;\n if (isIn) {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n } else if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n });\n };\n\n check();\n const id = setInterval(check, 200);\n return () => clearInterval(id);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, startOn, outAction]);\n\n // Stop cleanly on unmount / doc swap.\n useEffect(() => {\n return () => {\n cancelAnimation(progress);\n playingRef.current = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled]);\n\n // -- Render ---------------------------------------------------------------\n\n const trackById = useMemo(() => {\n const map = new Map<string, PxElementTracks>();\n for (const el of tracks.elements) map.set(el.id, el);\n return map;\n }, [tracks]);\n\n const warningsRef = useRef<Array<string>>([]);\n const renderErrorRef = useRef<Error | null>(null);\n const root = useMemo(() => {\n warningsRef.current = [];\n renderErrorRef.current = null;\n if (!compiled.doc) return null;\n\n const renderOpts: RenderRnNodeOptions = {\n warnings: warningsRef.current,\n defs: getDefs(compiled.doc),\n };\n try {\n return renderRnNode(compiled.doc as PxNode, {\n ...renderOpts,\n decorate: (node, Component, staticProps, children, key) => {\n // An animated definition subtree (gradient / its stops) cannot be\n // driven on the UI thread โ hand the WHOLE subtree to the\n // JS-sampled renderer and stop descending here.\n if (needsJsSampling(node, trackById)) {\n return (\n <SampledSubtree\n key={key}\n node={node}\n trackById={trackById}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n renderOpts={renderOpts}\n />\n );\n }\n\n const id = (node as any).id;\n const elTracks = id ? trackById.get(id) : undefined;\n if (!elTracks) return undefined;\n return (\n <AnimatedPxElement\n key={key}\n Component={Component}\n staticProps={staticProps}\n tracks={elTracks}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n >\n {children}\n </AnimatedPxElement>\n );\n },\n });\n } catch (e) {\n // Building the element tree threw โ report it and render nothing\n // rather than propagating and unmounting the host screen.\n const error = e instanceof Error ? e : new Error(String(e));\n renderErrorRef.current = error;\n console.warn('[PixodeskSvgAnimator] could not render the document:', error.message);\n return null;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, trackById]);\n\n useEffect(() => {\n for (const w of warningsRef.current) console.warn('[PixodeskSvgAnimator]', w);\n }, [root]);\n\n // Surface compile/render failures to the host exactly once per occurrence.\n const failure = compiled.error ?? renderErrorRef.current;\n useEffect(() => {\n if (failure) onError?.(failure);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [failure]);\n\n if (failure) return fallback ? fallback(failure) : null;\n\n // `startOn: 'click'` โ the touch analogue of the web player's click trigger:\n // tap to start, tap again to apply `outAction`. Hover (`mouseOver`) has no\n // touch equivalent and `scrollIntoView` needs the surrounding scroll view,\n // so both are left to the host app.\n let content: ReactElement | null = root;\n\n if (autoplay && startOn === 'scrollIntoView' && root) {\n // `collapsable={false}` keeps the view in the native tree so it can be measured.\n content = <View ref={scrollRef} collapsable={false}>{root}</View>;\n } else if (autoplay && startOn === 'click' && root) {\n content = (\n <Pressable\n onPress={() => {\n if (playingRef.current) {\n if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n } else {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n }\n }}\n >\n {root}\n </Pressable>\n );\n }\n\n // Catches what the try/catch above cannot: throws during React's own render\n // and commit of the tree โ react-native-svg internals, reanimated failing\n // to attach to a component that turns out not to be a host view, and so on.\n return (\n <PxRnErrorBoundary onError={onError} fallback={fallback}>\n {content}\n </PxRnErrorBoundary>\n );\n}\n\nexport default PixodeskSvgAnimator;\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 {\n calcAnimationValues,\n getAnimatorConfig,\n getNormalisedBindings,\n DEFAULT_DURATION_MS,\n PxAnimatorEngine,\n type PxAnimatedSvgDocument,\n type PxAnimationDefinition,\n} from '@pixodesk/svg-animator-core';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\n/**\n * Sampled animation tracks for ONE element: prop name โ per-sample values.\n *\n * The compiler densely samples every animated property through core's\n * `calcAnimationValues` โ the exact function the web frames engine renders\n * with โ so RN playback is value-identical to the web player. Easing, loops,\n * transform composition, colour interpolation and path morphing are all baked\n * into the samples at compile time; the UI-thread worklet only indexes arrays.\n */\nexport interface PxElementTracks {\n /** Element id (after id regeneration). */\n id: string;\n /** react-native-svg prop name โ one value per sample. */\n props: Record<string, Array<string | number | Array<number>>>;\n}\n\nexport interface PxCompiledTracks {\n /** Per-iteration duration, ms. */\n duration: number;\n /** Iteration count (Infinity for 'infinite'). */\n iterations: number;\n /** 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' */\n direction: string;\n /** Delay before start, ms (positive = wait). */\n delay: number;\n /** WAAPI-style fill mode (default 'forwards'). */\n fill: string;\n /** When true, snap back to the start after a natural finish. */\n resetOnFinish: boolean;\n /** Sample step, ms. */\n stepMs: number;\n /** Number of samples per iteration (>= 2; sample i is at time i*stepMs). */\n sampleCount: number;\n /** Tracks for every animated element. */\n elements: Array<PxElementTracks>;\n}\n\nexport interface CompileTracksOptions {\n /** Target sample rate, samples/second. Default 60 (one per frame). */\n sampleRate?: number;\n /** Hard cap on samples per iteration (memory guard). Default 600. */\n maxSamples?: number;\n /**\n * Sample values in the form the NATIVE react-native-svg views expect\n * (currently: `transform` as a 6-number matrix rather than an SVG string).\n *\n * Defaults to `false` โ the plain SVG form, which is what react-native-web\n * hands straight to the DOM. Only the component knows the platform, so it\n * decides; every consumer that does not opt in keeps DOM-compatible values.\n */\n native?: boolean;\n}\n\n\n\n/**\n * Compiles a MATERIALISED document (run `materialiseAllInTree(doc, 'frames')`\n * + `generateNewIds` first) into densely sampled per-element tracks.\n */\nexport function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksOptions): PxCompiledTracks {\n const config = getAnimatorConfig(doc) || {};\n\n const duration = +(config.duration || DEFAULT_DURATION_MS);\n const _iterations = config.iterations;\n let iterations = 1;\n if (typeof _iterations === 'number') iterations = _iterations || 1;\n if (_iterations === 'infinite') iterations = Infinity;\n if (iterations < 1) iterations = 1;\n\n const native = opts?.native ?? false;\n const sampleRate = opts?.sampleRate ?? 60;\n const maxSamples = opts?.maxSamples ?? 600;\n let sampleCount = Math.max(2, Math.round((duration / 1000) * sampleRate) + 1);\n if (sampleCount > maxSamples) sampleCount = maxSamples;\n const stepMs = duration / (sampleCount - 1);\n\n // Element tag per id โ `toRnPropValue` needs it to leave the root `<Svg>`'s\n // transform as a string (see its `tag` parameter).\n const tagById = new Map<string, string>();\n const indexTags = (n: any): void => {\n if (n && typeof n.id === 'string') tagById.set(n.id, String(n.type));\n (n?.children ?? []).forEach(indexTags);\n };\n indexTags(doc);\n\n const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames) || [];\n\n const elements: Array<PxElementTracks> = [];\n for (const binding of bindings) {\n const animDef = binding.animate;\n if (!animDef || typeof animDef !== 'object' || Array.isArray(animDef)) continue;\n\n const props: Record<string, Array<string | number | Array<number>>> = {};\n for (let i = 0; i < sampleCount; i++) {\n const t = i === sampleCount - 1 ? duration : i * stepMs;\n const values = calcAnimationValues(animDef as PxAnimationDefinition, t);\n for (const [attr, value] of Object.entries(values)) {\n const rnProp = toRnPropName(attr);\n if (!rnProp) continue;\n let arr = props[rnProp];\n if (!arr) {\n arr = props[rnProp] = new Array(sampleCount);\n // A prop can appear late (e.g. attrs whose first kf is\n // beyond t=0) โ backfill earlier samples with the first\n // computed value so the array is always fully populated.\n for (let j = 0; j < i; j++) arr[j] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n arr[i] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n }\n // Forward-fill any holes (attr disappeared from a later sample).\n for (const arr of Object.values(props)) {\n for (let i = 1; i < sampleCount; i++) {\n if (arr[i] === undefined) arr[i] = arr[i - 1];\n }\n }\n\n if (Object.keys(props).length > 0) {\n elements.push({ id: binding.id, props });\n }\n }\n\n return {\n duration,\n iterations,\n direction: config.direction || 'normal',\n delay: config.delay || 0,\n fill: config.fill ?? 'forwards',\n resetOnFinish: !!config.resetOnFinish,\n stepMs,\n sampleCount,\n elements,\n };\n}\n\n/**\n * Wire prop โ the prop name the NATIVE view actually declares.\n *\n * react-native-svg's JS layer renames some props on the way down: a\n * `transform` (string or matrix) is parsed by `extractProps` and handed to the\n * native component as `matrix` โ the Fabric spec has no `transform` prop at\n * all. Values sent through reanimated's animated-props path skip that JS\n * rename, so they must already use the native name or the native view drops\n * them silently. This is ONLY for the animated path; plain React renders still\n * go through the JS layer and must keep the wire name.\n */\nexport const NATIVE_PROP_NAME: Record<string, string> = {\n transform: 'matrix',\n};\n\n/**\n * Worklet-safe sample lookup: returns the per-prop values at time `tMs`\n * (already mapped into a single iteration by the caller). Kept deliberately\n * trivial โ runs on the UI thread every frame.\n *\n * `native = true` applies {@link NATIVE_PROP_NAME} โ pass it only on the\n * reanimated animated-props path of a real device. Props that are applied by\n * re-rendering through React (and therefore still pass through react-native-svg's\n * JS layer), and every value on the web, must keep the wire name.\n */\nexport function sampleProps(\n tracks: PxElementTracks,\n tMs: number,\n stepMs: number,\n sampleCount: number,\n native = false\n): Record<string, string | number | Array<number>> {\n 'worklet';\n const out: Record<string, string | number | Array<number>> = {};\n // Defensive: this runs on the UI thread, where a throw is a hard crash\n // with no React boundary to catch it.\n if (!tracks || !tracks.props || !(stepMs > 0)) return out;\n\n let idx = Math.round(tMs / stepMs);\n if (idx < 0) idx = 0;\n if (idx >= sampleCount) idx = sampleCount - 1;\n for (const key in tracks.props) {\n const values = tracks.props[key];\n if (!values) continue;\n const value = values[idx];\n if (value === undefined) continue;\n const name = native && key === 'transform' ? 'matrix' : key;\n out[name] = value;\n }\n return out;\n}\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 { kebabToCamelCaseWord } from '@pixodesk/svg-animator-core';\nimport { svgTransformToMatrix } from './PxRnMatrix';\n\n/** Attribute names with a react-native-svg prop equivalent under a\n * different name (not just a casing change). */\nconst ATTR_NAME_OVERRIDES: Record<string, string> = {\n 'xlink:href': 'href',\n};\n\n/** Props react-native-svg does not understand / must not receive. */\nconst DROPPED_ATTRS = new Set(['class', 'className', 'style', 'xmlns', 'xmlns:xlink', 'data-px-meta']);\n\n/**\n * Converts one normalised wire attribute name (camelCase after core's\n * `getNormalizedProps`, or kebab-case raw) to a react-native-svg prop name.\n * Returns undefined for props that must be dropped.\n *\n * Pure (no react-native-svg import) so the track compiler and its tests\n * don't need a React Native environment.\n */\nexport function toRnPropName(attrName: string): string | undefined {\n if (DROPPED_ATTRS.has(attrName)) return undefined;\n const override = ATTR_NAME_OVERRIDES[attrName];\n if (override) return override;\n // react-native-svg uses camelCase props (strokeWidth, fillOpacity, โฆ);\n // core's kebabToCamelCaseWord is a no-op for already-camelCase input.\n return kebabToCamelCaseWord(attrName);\n}\n\n/** Props whose value is a LIST of lengths. react-native-svg's native side\n * expects a number array here (its JS `extractLengthList` splits strings, but\n * values delivered through reanimated's animated-props path bypass that JS\n * extraction and reach the native view directly). */\nconst LENGTH_LIST_PROPS = new Set(['strokeDasharray']);\n\n/**\n * Converts one already-renamed prop value into the shape react-native-svg\n * expects: length-list props become number arrays; numeric strings become\n * numbers; everything else passes through.\n */\nexport function toRnPropValue(\n rnPropName: string,\n value: string | number,\n /** The owning element's tag. The ROOT `<Svg>` handles `transform` through a\n * different code path (`extractTransformSvgView`, which wants a string or\n * an RN style) โ a matrix there would be dropped, so leave it alone. */\n tag?: string,\n /** Opt in to the NATIVE representation of a value (see below). Defaults to\n * off, so web keeps the plain SVG/DOM form it has always been given. */\n native = false,\n): string | number | Array<number> {\n // On a device `transform` must arrive as a matrix, not a string: the\n // stringโmatrix parse happens in JS during render, which reanimated's\n // animated-props path skips entirely. See PxRnMatrix for the full why.\n // On the web the DOM parses the string itself and an array would serialise\n // to a meaningless `transform=\"1,0,0,1,3,4\"`, so it must stay a string.\n if (native && rnPropName === 'transform' && typeof value === 'string' && tag !== 'svg') {\n const m = svgTransformToMatrix(value);\n if (m) return m;\n }\n if (LENGTH_LIST_PROPS.has(rnPropName)) {\n const parts = String(value).trim().replace(/,/g, ' ').split(/\\s+/).map(Number).filter(n => Number.isFinite(n));\n // An odd-length dasharray repeats to become even (SVG spec); rn-svg\n // does this itself for the static path โ mirror it so both paths agree.\n return parts.length % 2 === 1 ? parts.concat(parts) : parts;\n }\n if (typeof value === 'number') return value;\n const num = +value;\n return Number.isFinite(num) && String(num) === value ? num : value;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * SVG transform string โ 2D affine matrix, in the order react-native-svg's\n * native side expects: `[a, b, c, d, e, f]`, i.e. SVG's own `matrix(โฆ)` order\n *\n * ```\n * | a c e |\n * | b d f |\n * | 0 0 1 |\n * ```\n *\n * WHY THIS EXISTS: react-native-svg parses a `transform` STRING into this matrix\n * in JavaScript, inside `extractTransform`, during render. Values delivered\n * through reanimated's `animatedProps` bypass that JS step and reach the native\n * view directly, where a raw string is meaningless โ an animated transform\n * simply does nothing. Feeding the matrix instead makes the animated and static\n * paths agree. (On the web the DOM parses the string itself, which is why this\n * only shows up on a device.)\n */\nexport type Mat2D = [number, number, number, number, number, number];\n\nexport const IDENTITY: Mat2D = [1, 0, 0, 1, 0, 0];\n\nconst DEG = Math.PI / 180;\n\n/** `m1 ยท m2` โ apply m2 first, then m1 (same convention as SVG's left-to-right list). */\nfunction multiply(m1: Mat2D, m2: Mat2D): Mat2D {\n const [a1, b1, c1, d1, e1, f1] = m1;\n const [a2, b2, c2, d2, e2, f2] = m2;\n return [\n a1 * a2 + c1 * b2,\n b1 * a2 + d1 * b2,\n a1 * c2 + c1 * d2,\n b1 * c2 + d1 * d2,\n a1 * e2 + c1 * f2 + e1,\n b1 * e2 + d1 * f2 + f1,\n ];\n}\n\n/** Splits `translate(1,2)rotate(45)` into `[['translate',[1,2]], ['rotate',[45]]]`. */\nconst FN_RE = /([a-zA-Z]+)\\s*\\(([^)]*)\\)/g;\n\nfunction numbers(raw: string): Array<number> {\n return raw\n .split(/[\\s,]+/)\n .filter(s => s.length > 0)\n .map(Number)\n .filter(n => Number.isFinite(n));\n}\n\n/**\n * Parses an SVG transform list. Returns `undefined` when the string contains no\n * recognisable function, so callers can leave the original value untouched\n * rather than silently replacing it with an identity matrix.\n */\nexport function svgTransformToMatrix(value: string): Mat2D | undefined {\n let m: Mat2D | undefined;\n FN_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = FN_RE.exec(value)) !== null) {\n const fn = match[1].toLowerCase();\n const n = numbers(match[2]);\n let step: Mat2D | undefined;\n\n switch (fn) {\n case 'translate':\n step = [1, 0, 0, 1, n[0] || 0, n[1] || 0];\n break;\n case 'scale': {\n const sx = n[0] ?? 1;\n const sy = n.length > 1 ? n[1] : sx;\n step = [sx, 0, 0, sy, 0, 0];\n break;\n }\n case 'rotate': {\n const rad = (n[0] || 0) * DEG;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n const rot: Mat2D = [cos, sin, -sin, cos, 0, 0];\n if (n.length >= 3) {\n // rotate(a, cx, cy) == translate(cx,cy) rotate(a) translate(-cx,-cy)\n const cx = n[1], cy = n[2];\n step = multiply(multiply([1, 0, 0, 1, cx, cy], rot), [1, 0, 0, 1, -cx, -cy]);\n } else {\n step = rot;\n }\n break;\n }\n case 'skewx':\n step = [1, 0, Math.tan((n[0] || 0) * DEG), 1, 0, 0];\n break;\n case 'skewy':\n step = [1, Math.tan((n[0] || 0) * DEG), 0, 1, 0, 0];\n break;\n case 'matrix':\n if (n.length >= 6) step = [n[0], n[1], n[2], n[3], n[4], n[5]];\n break;\n default:\n step = undefined; // unknown function โ ignore it\n }\n\n if (step) m = m ? multiply(m, step) : step;\n }\n\n return m;\n}\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 {\n getNormalizedProps,\n resolveStyle,\n sanitiseAttributeValue,\n DISALLOWED_SVG_TAGS_LOWER,\n TEXT_ATTR,\n TEXT_CONTENT_ATTR,\n type PxDefs,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport { createElement, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { RN_SVG_COMPONENTS } from './PxRnTypeMap';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\nexport interface RenderRnNodeOptions {\n /** Collects non-fatal issues (unsupported tags, dropped attrs). */\n warnings?: Array<string>;\n /** `definitions` from the document, used to resolve named `style` presets. */\n defs?: PxDefs;\n /**\n * Wraps the created element for animated nodes: receives the resolved\n * component + static props and returns the element to mount (the animator\n * substitutes an Animated component wired to its tracks). Return undefined\n * to keep the plain static element.\n *\n * `key` is handed over SEPARATELY and is deliberately absent from `props`:\n * React 19 warns when a props object containing `key` is spread into JSX,\n * and implementations of this hook do exactly that.\n */\n decorate?: (\n node: PxNode,\n Component: ComponentType<any>,\n props: Record<string, any>,\n children: ReactNode,\n key: string | number | undefined\n ) => ReactElement | undefined;\n}\n\n/**\n * Converts core-normalised wire props into react-native-svg props: RN prop\n * naming, sanitisation (same security rules as the web renderer), numeric\n * coercion where possible.\n */\nexport function toRnProps(props: Record<string, any>, warnings?: Array<string>, tag?: string): Record<string, any> {\n const normalised = getNormalizedProps(props);\n const out: Record<string, any> = {};\n for (const key of Object.keys(normalised)) {\n const sanitised = sanitiseAttributeValue(key, normalised[key]);\n if (sanitised === undefined) continue;\n const rnKey = toRnPropName(key);\n if (!rnKey) continue;\n out[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n return out;\n}\n\n/**\n * Renders a (materialised) PxNode tree to react-native-svg elements.\n * Mirrors the web `renderNode` contract: unsupported/dangerous tags are\n * skipped with a warning, never a crash.\n */\nexport function renderRnNode(node: PxNode, opts: RenderRnNodeOptions = {}, key?: string | number): ReactElement | null {\n if (!node) return null;\n\n const { type, children, style, animate, meta, effects, ...props } = node as any;\n const tag = String(type || 'g');\n\n // ESCAPE KEY (S2): elements whose SVG `type` ATTRIBUTE collides with the reserved\n // `type` node-tag key carry it under `domType` โ `feColorMatrix` (matrix/saturate/โฆ),\n // `feTurbulence` (fractalNoise/turbulence), `feFunc*` (identity/table/โฆ).\n // Restore it as a real prop, mirroring the web renderer.\n const domType: string | undefined = props.domType;\n if (domType !== undefined) delete props.domType;\n\n if (DISALLOWED_SVG_TAGS_LOWER.has(tag.toLowerCase())) {\n opts.warnings?.push('tag blocked (dangerous): ' + tag);\n return null;\n }\n\n const Component = RN_SVG_COMPONENTS[tag];\n if (!Component) {\n opts.warnings?.push('tag not supported in react-native-svg mapping: ' + tag);\n return null;\n }\n\n // NB: `key` is never written into this object โ see `decorate` above.\n const rnProps = toRnProps(props, opts.warnings, tag);\n if (domType !== undefined) rnProps.type = domType;\n\n // `node.style` โ a named preset from `definitions.styles`, or an inline\n // record. react-native-svg has no CSS, so the resolved declarations are\n // applied as ordinary props (the same names, e.g. `fill`, `strokeWidth`).\n // Explicit attributes on the node win over the style block.\n const resolved = resolveStyle(style, opts.defs);\n if (resolved) {\n for (const [k, v] of Object.entries(resolved)) {\n const rnKey = toRnPropName(k);\n if (!rnKey || rnKey in rnProps) continue;\n const sanitised = sanitiseAttributeValue(rnKey, v);\n if (sanitised === undefined) continue;\n rnProps[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n }\n\n // Text content: wire nodes carry it as `text` / `textContent` attr.\n const textContent: string | undefined = props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR];\n\n let childElements: ReactNode = undefined;\n if (Array.isArray(children) && children.length > 0) {\n childElements = children\n .map((ch: PxNode, i: number) => {\n // One malformed child should cost that child, not the whole tree.\n try {\n return renderRnNode(ch, opts, i);\n } catch (e) {\n opts.warnings?.push('child failed to render: ' + (e instanceof Error ? e.message : String(e)));\n return null;\n }\n })\n .filter(Boolean);\n } else if (textContent !== undefined) {\n childElements = String(textContent);\n }\n\n const decorated = opts.decorate?.(node, Component, rnProps, childElements, key);\n if (decorated !== undefined) return decorated;\n\n // `createElement` takes `key` in its config object โ that path does NOT\n // trigger React's JSX-spread warning.\n return createElement(\n Component,\n key !== undefined ? { ...rnProps, key } : rnProps,\n childElements\n );\n}\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 {\n Circle,\n ClipPath,\n Defs,\n Ellipse,\n FeBlend,\n FeColorMatrix,\n FeComponentTransfer,\n FeComposite,\n FeConvolveMatrix,\n FeDiffuseLighting,\n FeDisplacementMap,\n FeDistantLight,\n FeDropShadow,\n FeFlood,\n FeFuncA,\n FeFuncB,\n FeFuncG,\n FeFuncR,\n FeGaussianBlur,\n FeImage,\n FeMerge,\n FeMergeNode,\n FeMorphology,\n FeOffset,\n FePointLight,\n FeSpecularLighting,\n FeSpotLight,\n FeTile,\n FeTurbulence,\n Filter,\n G,\n Image,\n Line,\n LinearGradient,\n Marker,\n Mask,\n Path,\n Pattern,\n Polygon,\n Polyline,\n RadialGradient,\n Rect,\n Stop,\n Svg,\n Symbol as SvgSymbol,\n Text as SvgText,\n TextPath,\n TSpan,\n Use,\n} from 'react-native-svg';\nimport type { ComponentType } from 'react';\n\n/**\n * SVG tag โ react-native-svg component. Tags not in this map are skipped at\n * render time (with a warning collected by the renderer) โ they go on the\n * feature-gap list rather than crashing the tree.\n *\n * Keys are the wire-format `node.type` values, which follow SVG's own casing\n * (`clipPath`, `feGaussianBlur`, `linearGradient`, โฆ).\n */\nexport const RN_SVG_COMPONENTS: Record<string, ComponentType<any>> = {\n // Root & containers\n svg: Svg,\n g: G,\n defs: Defs,\n symbol: SvgSymbol,\n use: Use,\n\n // Shapes\n rect: Rect,\n circle: Circle,\n ellipse: Ellipse,\n line: Line,\n path: Path,\n polygon: Polygon,\n polyline: Polyline,\n image: Image,\n\n // Text\n text: SvgText,\n tspan: TSpan,\n textPath: TextPath,\n\n // Paint servers & clipping\n linearGradient: LinearGradient,\n radialGradient: RadialGradient,\n stop: Stop,\n pattern: Pattern,\n mask: Mask,\n clipPath: ClipPath,\n marker: Marker,\n\n // Filters โ react-native-svg implements the full primitive set.\n // NOTE: filter rendering requires the New Architecture (Fabric) and is\n // newer than the rest of react-native-svg; treat visual parity with the\n // web player as unverified until checked on a device.\n filter: Filter,\n feBlend: FeBlend,\n feColorMatrix: FeColorMatrix,\n feComponentTransfer: FeComponentTransfer,\n feComposite: FeComposite,\n feConvolveMatrix: FeConvolveMatrix,\n feDiffuseLighting: FeDiffuseLighting,\n feDisplacementMap: FeDisplacementMap,\n feDistantLight: FeDistantLight,\n feDropShadow: FeDropShadow,\n feFlood: FeFlood,\n feFuncA: FeFuncA,\n feFuncB: FeFuncB,\n feFuncG: FeFuncG,\n feFuncR: FeFuncR,\n feGaussianBlur: FeGaussianBlur,\n feImage: FeImage,\n feMerge: FeMerge,\n feMergeNode: FeMergeNode,\n feMorphology: FeMorphology,\n feOffset: FeOffset,\n fePointLight: FePointLight,\n feSpecularLighting: FeSpecularLighting,\n feSpotLight: FeSpotLight,\n feTile: FeTile,\n feTurbulence: FeTurbulence,\n};\n\nexport { toRnPropName } from './PxRnPropNames';\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 { Component, type ErrorInfo, type ReactNode } from 'react';\n\nexport interface PxRnErrorBoundaryProps {\n children: ReactNode;\n /** Rendered instead of the children once something has thrown. */\n fallback?: (error: Error) => ReactNode;\n onError?: (error: Error, info?: string) => void;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Keeps one bad animation from taking down the screen around it.\n *\n * A throw anywhere in the rendered SVG tree โ an unsupported prop shape, a\n * react-native-svg internal, a reanimated attachment failure โ otherwise\n * unmounts the whole React tree above it. Here it is contained to this one\n * animation, reported through `onError`, and replaced by `fallback`.\n *\n * NOTE the limit: this catches JavaScript errors only. A crash INSIDE the\n * native renderer (see `openClosedTextPathTargets` for a real example) never\n * reaches JavaScript and cannot be caught here โ those have to be avoided\n * rather than handled.\n */\nexport class PxRnErrorBoundary extends Component<PxRnErrorBoundaryProps, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n this.props.onError?.(error, info?.componentStack ?? undefined);\n console.warn('[PixodeskSvgAnimator] render failed:', error?.message ?? error);\n }\n\n override componentDidUpdate(prev: PxRnErrorBoundaryProps): void {\n // A new document deserves a fresh attempt โ otherwise the boundary\n // would stay latched on the failure for the rest of its life.\n if (this.state.error && prev.children !== this.props.children) {\n this.setState({ error: null });\n }\n }\n\n override render(): ReactNode {\n const { error } = this.state;\n if (error) return this.props.fallback ? this.props.fallback(error) : null;\n return this.props.children;\n }\n}\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 { deepClone, generateUniqueId, type PxNode } from '@pixodesk/svg-animator-core';\n\n/**\n * Workarounds for defects in react-native-svg's NATIVE renderer that would\n * otherwise take the whole app down.\n *\n * These are applied only when the native views are in use โ never on the web,\n * where the DOM handles all of this correctly and the document must be left\n * exactly as the core pipeline produced it.\n */\n\n/** True when a path's `d` contains a close-subpath command. */\nfunction isClosedPath(d: unknown): boolean {\n return typeof d === 'string' && /[zZ]/.test(d);\n}\n\n/** Drops close-subpath commands, turning a closed outline into an open one. */\nfunction openPath(d: string): string {\n return d.replace(/[zZ]/g, '').trimEnd();\n}\n\n/** `#foo` โ `foo`. Returns undefined for anything that is not a local ref. */\nfunction localRef(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.startsWith('#') ? trimmed.slice(1) : undefined;\n}\n\nfunction forEachNode(node: PxNode | undefined, visit: (n: PxNode, parent?: PxNode) => void, parent?: PxNode): void {\n if (!node) return;\n visit(node, parent);\n for (const child of (node.children ?? [])) forEachNode(child, visit, node);\n}\n\n/**\n * Gives every `<textPath>` that follows a CLOSED path its own OPEN copy of it.\n *\n * WHY: react-native-svg's native text-on-path layout crashes the app โ\n * an uncatchable `NSRangeException` on iOS โ for this combination.\n * `RNSVGTSpan.mm` skips glyphs outside `[startOfRendering, endOfRendering]`,\n * but for a closed path it sets those bounds to `startOffset โฆ startOffset +\n * pathLength` instead of `0 โฆ pathLength`. Any glyph past the end of the path\n * therefore survives the bounds check and reaches `getPosAndTan`, whose\n * `indexOfObjectPassingTest` returns `NSNotFound` โ and indexing the lengths\n * array with `NSNotFound` throws. A non-zero `startOffset` on a closed path is\n * all it takes, and animating `startOffset` guarantees hitting it.\n *\n * Opening the path restores the `0 โฆ pathLength` bounds, so out-of-range\n * glyphs are skipped as intended. The copy is private to the `<textPath>`, so\n * anything else drawing the same path still gets the closed original. For a\n * shape whose ends already meet (a circle, the usual case) the removed segment\n * has zero length and nothing changes visually at all.\n *\n * Returns the document unchanged โ the same object โ when nothing matches.\n */\nexport function openClosedTextPathTargets(doc: PxNode, warnings?: Array<string>): PxNode {\n // Cheap pre-check: the overwhelming majority of documents have no textPath.\n let hasTextPath = false;\n forEachNode(doc, n => { if (String(n.type) === 'textPath') hasTextPath = true; });\n if (!hasTextPath) return doc;\n\n const result = deepClone(doc);\n\n const byId = new Map<string, PxNode>();\n forEachNode(result, n => {\n const id = (n as any).id;\n if (typeof id === 'string') byId.set(id, n);\n });\n\n /** The copy is a geometry reference, never something to draw โ so it goes\n * in `<defs>`, alongside the paths textPath targets normally live in. */\n let defs = (result.children ?? []).find(c => String(c.type) === 'defs');\n const ensureDefs = (): PxNode => {\n if (!defs) {\n defs = { type: 'defs', children: [] } as unknown as PxNode;\n (result.children ??= []).unshift(defs);\n }\n return defs;\n };\n\n /** Original path id โ id of the open copy, so N textPaths share one copy. */\n const openCopies = new Map<string, string>();\n\n forEachNode(result, node => {\n if (String(node.type) !== 'textPath') return;\n\n const anyNode = node as any;\n const attr = anyNode.href !== undefined ? 'href' : 'xlink:href';\n const targetId = localRef(anyNode[attr]);\n if (!targetId) return;\n\n const target = byId.get(targetId);\n if (!target || !isClosedPath((target as any).d)) return;\n\n let copyId = openCopies.get(targetId);\n if (!copyId) {\n const copy = deepClone(target) as any;\n copyId = 'px_open_' + generateUniqueId();\n copy.id = copyId;\n copy.d = openPath(String(copy.d));\n // A copy that also carried animation would animate twice; the copy\n // exists purely as a geometry reference for the text.\n delete copy.animate;\n delete copy.effects;\n\n (ensureDefs().children ??= []).push(copy);\n openCopies.set(targetId, copyId);\n warnings?.push(\n 'textPath follows a closed path (#' + targetId + '); using an open copy to ' +\n 'avoid a react-native-svg native crash'\n );\n }\n\n anyNode[attr] = '#' + copyId;\n });\n\n return result;\n}\n"],"mappings":"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","names":["import_svg_animator_core","import_react","import_svg_animator_core","_a","import_svg_animator_core","SvgSymbol","SvgText","Component","_a","import_react","import_svg_animator_core","_a","Component","Animated","_a"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -49,9 +49,9 @@ interface PixodeskSvgAnimatorProps {
|
|
|
49
49
|
/** Ref populated with the imperative playback API. */
|
|
50
50
|
apiRef?: React.RefObject<RnAnimatorApi | null>;
|
|
51
51
|
/** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */
|
|
52
|
-
|
|
52
|
+
progress?: number;
|
|
53
53
|
/** Seek to a specific time in milliseconds. */
|
|
54
|
-
|
|
54
|
+
time?: number;
|
|
55
55
|
onPlay?: () => void;
|
|
56
56
|
onStop?: () => void;
|
|
57
57
|
onPause?: () => void;
|
|
@@ -79,7 +79,7 @@ interface PixodeskSvgAnimatorProps {
|
|
|
79
79
|
* `withTiming`/`withRepeat` on the UI thread, with per-element worklets
|
|
80
80
|
* indexing the precompiled tracks. No JS-thread frame loop.
|
|
81
81
|
*/
|
|
82
|
-
declare function PixodeskSvgAnimator({ doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp, autoplay, play, pause, apiRef,
|
|
82
|
+
declare function PixodeskSvgAnimator({ doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp, autoplay, play, pause, apiRef, progress: progressProp, time, onPlay, onStop, onPause, onCancel, onFinish, onError, fallback, }: PixodeskSvgAnimatorProps): ReactElement | null;
|
|
83
83
|
|
|
84
84
|
interface RenderRnNodeOptions {
|
|
85
85
|
/** Collects non-fatal issues (unsupported tags, dropped attrs). */
|
package/dist/index.d.ts
CHANGED
|
@@ -49,9 +49,9 @@ interface PixodeskSvgAnimatorProps {
|
|
|
49
49
|
/** Ref populated with the imperative playback API. */
|
|
50
50
|
apiRef?: React.RefObject<RnAnimatorApi | null>;
|
|
51
51
|
/** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */
|
|
52
|
-
|
|
52
|
+
progress?: number;
|
|
53
53
|
/** Seek to a specific time in milliseconds. */
|
|
54
|
-
|
|
54
|
+
time?: number;
|
|
55
55
|
onPlay?: () => void;
|
|
56
56
|
onStop?: () => void;
|
|
57
57
|
onPause?: () => void;
|
|
@@ -79,7 +79,7 @@ interface PixodeskSvgAnimatorProps {
|
|
|
79
79
|
* `withTiming`/`withRepeat` on the UI thread, with per-element worklets
|
|
80
80
|
* indexing the precompiled tracks. No JS-thread frame loop.
|
|
81
81
|
*/
|
|
82
|
-
declare function PixodeskSvgAnimator({ doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp, autoplay, play, pause, apiRef,
|
|
82
|
+
declare function PixodeskSvgAnimator({ doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp, autoplay, play, pause, apiRef, progress: progressProp, time, onPlay, onStop, onPause, onCancel, onFinish, onError, fallback, }: PixodeskSvgAnimatorProps): ReactElement | null;
|
|
83
83
|
|
|
84
84
|
interface RenderRnNodeOptions {
|
|
85
85
|
/** Collects non-fatal issues (unsupported tags, dropped attrs). */
|
package/dist/index.js
CHANGED
|
@@ -631,12 +631,13 @@ function PixodeskSvgAnimator({
|
|
|
631
631
|
direction,
|
|
632
632
|
resetOnFinish,
|
|
633
633
|
outAction: outActionProp,
|
|
634
|
+
// (`progress` prop aliased โ the name is taken by the internal reanimated SharedValue)
|
|
634
635
|
autoplay,
|
|
635
636
|
play,
|
|
636
637
|
pause,
|
|
637
638
|
apiRef,
|
|
639
|
+
progress: progressProp,
|
|
638
640
|
time,
|
|
639
|
-
timeMs,
|
|
640
641
|
onPlay,
|
|
641
642
|
onStop,
|
|
642
643
|
onPause,
|
|
@@ -754,8 +755,8 @@ function PixodeskSvgAnimator({
|
|
|
754
755
|
const startOn = (_b = trigger == null ? void 0 : trigger.startOn) != null ? _b : "load";
|
|
755
756
|
const outAction = (_c = outActionProp != null ? outActionProp : trigger == null ? void 0 : trigger.outAction) != null ? _c : "pause";
|
|
756
757
|
useEffect(() => {
|
|
757
|
-
if (
|
|
758
|
-
const seekMs =
|
|
758
|
+
if (progressProp !== void 0 || time !== void 0) {
|
|
759
|
+
const seekMs = time !== void 0 ? time : (progressProp != null ? progressProp : 0) * totalDuration;
|
|
759
760
|
api.setCurrentTime(seekMs);
|
|
760
761
|
return;
|
|
761
762
|
}
|
|
@@ -769,7 +770,7 @@ function PixodeskSvgAnimator({
|
|
|
769
770
|
if (autoplay && startOn === "load") {
|
|
770
771
|
api.play();
|
|
771
772
|
}
|
|
772
|
-
}, [compiled, autoplay, play, pause,
|
|
773
|
+
}, [compiled, autoplay, play, pause, progressProp, time]);
|
|
773
774
|
const scrollRef = useRef(null);
|
|
774
775
|
const inViewRef = useRef(false);
|
|
775
776
|
useEffect(() => {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/PixodeskSvgAnimator.tsx","../src/PxRnTracks.ts","../src/PxRnPropNames.ts","../src/PxRnMatrix.ts","../src/PxRnRender.tsx","../src/PxRnTypeMap.ts","../src/PxRnErrorBoundary.tsx","../src/PxRnSafety.ts"],"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 {\n generateNewIds,\n getAnimatorConfig,\n getDefs,\n materialiseAllInTree,\n validateNodeEffects,\n PxAnimatorEngine,\n type FillMode,\n type OutAction,\n type PlaybackDirection,\n type PxAnimatedSvgDocument,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport React, { createElement, useEffect, useImperativeHandle, useMemo, useRef, useState, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { Dimensions, Platform, Pressable, View } from 'react-native';\nimport Animated, {\n cancelAnimation,\n useAnimatedReaction,\n Easing,\n runOnJS,\n useAnimatedProps,\n useSharedValue,\n withDelay,\n withRepeat,\n withTiming,\n type SharedValue,\n} from 'react-native-reanimated';\nimport { compileTracks, sampleProps, type PxCompiledTracks, type PxElementTracks } from './PxRnTracks';\nimport { renderRnNode, type RenderRnNodeOptions } from './PxRnRender';\nimport { PxRnErrorBoundary } from './PxRnErrorBoundary';\nimport { openClosedTextPathTargets } from './PxRnSafety';\n\n\n// -- Public types -----------------------------------------------------------\n\n/** Imperative playback API โ mirrors ReactAnimatorApi from svg-animator-react. */\nexport interface RnAnimatorApi {\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. */\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 PixodeskSvgAnimatorProps {\n\n // -- Source ---------------------------------------------------------------\n\n /** The animation document to render. */\n doc: PxAnimatedSvgDocument;\n\n // -- Timing overrides -----------------------------------------------------\n\n /** Duration of a single iteration in milliseconds. */\n duration?: number;\n\n /** Delay before the animation starts, in milliseconds. */\n delay?: number;\n\n /** Number of iterations, or 'infinite' for endless looping. */\n iterations?: number | 'infinite';\n\n /** Defines the element's state when the animation is not active. */\n fill?: FillMode;\n\n /** Playback direction. */\n direction?: PlaybackDirection;\n\n /** Snap back to the start state after a natural finish. */\n resetOnFinish?: boolean;\n\n /**\n * What a second tap does when `startOn: 'click'` is active.\n * Defaults to the document's `trigger.outAction`, else `'pause'`.\n */\n outAction?: OutAction;\n\n // -- Declarative control --------------------------------------------------\n\n /** When true, honours the document trigger (`startOn: 'load'` plays on mount). */\n autoplay?: boolean;\n\n /** Starts playback unconditionally. */\n play?: boolean;\n\n /** Pauses current playback. */\n pause?: boolean;\n\n // -- Imperative control ---------------------------------------------------\n\n /** Ref populated with the imperative playback API. */\n apiRef?: React.RefObject<RnAnimatorApi | null>;\n\n // -- Controlled (external) time -------------------------------------------\n\n /** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */\n time?: number;\n\n /** Seek to a specific time in milliseconds. */\n timeMs?: number;\n\n // -- Callbacks ------------------------------------------------------------\n\n onPlay?: () => void;\n onStop?: () => void;\n onPause?: () => void;\n onCancel?: () => void;\n onFinish?: () => void;\n\n\n // -- Failure handling -----------------------------------------------------\n\n /**\n * Called when a document cannot be compiled or rendered. The component\n * renders {@link fallback} instead of throwing, so a single broken\n * animation never takes down the screen around it.\n *\n * Only JavaScript failures reach this โ a crash inside react-native-svg's\n * native renderer bypasses JavaScript entirely.\n */\n onError?: (error: Error, componentStack?: string) => void;\n\n /** Rendered in place of the animation after a failure. Default: nothing. */\n fallback?: (error: Error) => ReactElement | null;\n}\n\n\n// -- Animated element wrapper ------------------------------------------------\n\n/**\n * Whether react-native-svg is backed by NATIVE views here, rather than by the\n * DOM through react-native-web.\n *\n * The two want different things from an animated `transform`: a native view\n * declares a `matrix` prop taking six numbers, while the DOM wants a\n * `transform` attribute holding an SVG string. Getting it wrong is silent โ\n * the value is dropped and the element simply never moves โ so this single\n * constant decides it once and feeds both the track compiler (value form) and\n * the sampler (prop name). Everything else in the package defaults to the\n * DOM-compatible form.\n */\nconst NATIVE_SVG_VIEWS = Platform.OS !== 'web';\n\nconst animatedComponentCache = new Map<ComponentType<any>, ComponentType<any>>();\n\nfunction getAnimatedComponent(Component: ComponentType<any>): ComponentType<any> {\n let cached = animatedComponentCache.get(Component);\n if (!cached) {\n cached = Animated.createAnimatedComponent(Component as any);\n animatedComponentCache.set(Component, cached);\n }\n return cached;\n}\n\n/** One animated element: static props + UI-thread sampled animated props. */\nfunction AnimatedPxElement({\n Component, staticProps, children, tracks, progress, stepMs, sampleCount,\n}: {\n Component: ComponentType<any>;\n staticProps: Record<string, any>;\n children: ReactNode;\n tracks: PxElementTracks;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n}) {\n const AnimatedComponent = useMemo(() => getAnimatedComponent(Component), [Component]);\n\n // Runs on the UI thread every frame; `sampleProps` is a trivial indexed\n // lookup into the precompiled tracks โ no interpolation logic on the hot path.\n const animatedProps = useAnimatedProps(() => {\n // On iOS/Android these values bypass react-native-svg's JS prop layer\n // and land on the native view, which declares `matrix`, not\n // `transform`. The web build keeps the DOM-facing `transform` name.\n return sampleProps(tracks, progress.value, stepMs, sampleCount, NATIVE_SVG_VIEWS);\n }, [tracks, stepMs, sampleCount]);\n\n return (\n <AnimatedComponent {...staticProps} animatedProps={animatedProps}>\n {children}\n </AnimatedComponent>\n );\n}\n\n\n/**\n * react-native-svg elements whose `render()` returns `null`. They carry data for\n * their PARENT (a `<Stop>` is read by the gradient that owns it) rather than\n * producing a native view, so reanimated has nothing to attach to โ wrapping one\n * in `Animated.createAnimatedComponent` throws\n * \"Cannot find host instance for this component\".\n */\nconst NON_HOST_TAGS = new Set(['stop', 'feMergeNode']);\n\n/**\n * Definition elements โ they describe paint/geometry for something else rather\n * than drawing themselves. Their animated attributes (a gradient's `y1`, a\n * stop's `stop-color`) do not reliably flow through reanimated's animated-props\n * path, so an animated def is rendered by re-sampling from JS instead. There\n * are only ever a handful per document and they change slowly, so the cost is\n * negligible โ visual elements still animate entirely on the UI thread.\n */\nconst SAMPLED_DEF_TAGS = new Set(['linearGradient', 'radialGradient', ...NON_HOST_TAGS]);\n\n/** True when this subtree must be driven from JS rather than the UI thread:\n * either the node itself is an animated def, or it owns an animated non-host\n * child (an animated `<Stop>` only re-renders via its parent gradient). */\nfunction needsJsSampling(node: PxNode, trackById: Map<string, PxElementTracks>): boolean {\n const id = (node as any).id;\n if (SAMPLED_DEF_TAGS.has(String(node.type)) && id && trackById.has(id)) return true;\n return (node.children ?? []).some(c => needsJsSampling(c, trackById));\n}\n\n/**\n * Renders a subtree whose animation cannot run on the UI thread (see\n * {@link NON_HOST_TAGS}) by re-rendering it from JS with sampled values.\n *\n * Changing a `<Stop>`'s props does not re-render its parent gradient, so the\n * whole subtree is rebuilt โ which is why this wraps the gradient rather than\n * the stop. The reaction itself runs on the UI thread and only crosses to JS\n * when the QUANTISED sample index changes, capping these few elements at\n * ~30fps instead of a JS call every frame.\n */\nfunction SampledSubtree({\n node, trackById, progress, stepMs, sampleCount, renderOpts,\n}: {\n node: PxNode;\n trackById: Map<string, PxElementTracks>;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n renderOpts: RenderRnNodeOptions;\n}) {\n const [idx, setIdx] = useState(0);\n\n useAnimatedReaction(\n () => Math.floor(Math.round(progress.value / stepMs) / 2) * 2, // half-rate\n (next, prev) => {\n if (next !== prev) runOnJS(setIdx)(next);\n },\n [stepMs]\n );\n\n const tMs = Math.min(Math.max(idx, 0), sampleCount - 1) * stepMs;\n\n return renderRnNode(node, {\n ...renderOpts,\n // Sampled values are baked in as PLAIN props โ nothing reanimated-driven.\n decorate: (n, Component, staticProps, children, key) => {\n const id = (n as any).id;\n const tracks = id ? trackById.get(id) : undefined;\n if (!tracks) return undefined;\n // Wire prop names, NOT the native ones: these go back through\n // react-native-svg's JS prop layer, which does the renaming itself.\n const sampled = sampleProps(tracks, tMs, stepMs, sampleCount);\n return createElement(Component, { ...staticProps, ...sampled, key }, children);\n },\n });\n}\n\n\n\n/** Overrides that shadow the document's own `animator` config. */\ninterface ConfigOverrides {\n duration?: number;\n delay?: number;\n iterations?: number | 'infinite';\n fill?: FillMode;\n direction?: PlaybackDirection;\n resetOnFinish?: boolean;\n}\n\ninterface Compiled {\n /** Materialised document, or null when compilation failed. */\n doc: PxAnimatedSvgDocument | null;\n tracks: PxCompiledTracks;\n error: Error | null;\n}\n\n/** Playable-but-empty tracks, so a failed compile still satisfies every hook\n * below it โ React forbids skipping hooks on an error path. */\nconst EMPTY_TRACKS: PxCompiledTracks = {\n duration: 1, iterations: 1, direction: 'normal', delay: 0,\n fill: 'forwards', resetOnFinish: false, stepMs: 1, sampleCount: 2, elements: [],\n};\n\n/**\n * Materialises + compiles a document. Extracted from the component so the\n * whole thing sits behind one try/catch, and so it can be tested directly.\n */\nfunction compileDocument(doc: PxAnimatedSvgDocument, overrides: ConfigOverrides): Compiled {\n const { duration, delay, iterations, fill, direction, resetOnFinish } = overrides;\n const warnings = validateNodeEffects(doc as PxNode);\n for (const w of warnings) console.warn('[PixodeskSvgAnimator] effects shape warning:', w);\n\n // `waapi` = the FULLY-FLATTENED materialisation: effects + loops +\n // sampled motion paths + animated `<use>` inlined into real `<g>`\n // clones + orphaned defs pruned. That last part is why RN must not use\n // the `frames` flavour: frames keeps `<use href=\"#animatedTarget\">`\n // live references, which only work because the DOM propagates\n // attribute writes through `<use>` shadow trees. react-native-svg has\n // no such live propagation, so an animated `<use>` would render frozen.\n let prepared = materialiseAllInTree(doc, PxAnimatorEngine.waapi);\n\n // Sidestep a react-native-svg NATIVE crash (see PxRnSafety). Guarded on\n // the platform because the DOM renders this case correctly and the web\n // document must stay exactly as the core pipeline produced it.\n if (NATIVE_SVG_VIEWS) {\n prepared = openClosedTextPathTargets(prepared as PxNode) as PxAnimatedSvgDocument;\n }\n\n // Apply prop overrides onto the animator config (mirrors the react wrapper).\n const animator = getAnimatorConfig(prepared) || {};\n prepared = {\n ...prepared,\n animator: {\n ...animator,\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 resetOnFinish: resetOnFinish !== undefined ? resetOnFinish : animator.resetOnFinish,\n },\n };\n\n prepared = generateNewIds(prepared);\n const tracks = compileTracks(prepared, { native: NATIVE_SVG_VIEWS });\n return { doc: prepared, tracks, error: null };\n}\n\n\n// -- Main component ----------------------------------------------------------\n\n/**\n * React Native component for rendering and controlling Pixodesk SVG animations.\n *\n * The document is materialised once through the shared core pipeline (effects,\n * loops, motion-path sampling, animated-`<use>` inlining โ identical to the\n * web frames engine), compiled into densely sampled per-element tracks, and\n * played back natively: a single reanimated progress value driven by\n * `withTiming`/`withRepeat` on the UI thread, with per-element worklets\n * indexing the precompiled tracks. No JS-thread frame loop.\n */\nexport function PixodeskSvgAnimator({\n doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp,\n autoplay, play, pause, apiRef, time, timeMs,\n onPlay, onStop, onPause, onCancel, onFinish, onError, fallback,\n}: PixodeskSvgAnimatorProps): ReactElement | null {\n\n // -- Compile the document (once per doc/override change) ------------------\n\n const compiled = useMemo((): Compiled => {\n try {\n return compileDocument(\n doc,\n { duration, delay, iterations, fill, direction, resetOnFinish }\n );\n } catch (e) {\n // A malformed document must not take the host screen down with it.\n const error = e instanceof Error ? e : new Error(String(e));\n console.warn('[PixodeskSvgAnimator] could not compile the document:', error.message);\n return { doc: null, tracks: EMPTY_TRACKS, error };\n }\n }, [doc, duration, delay, iterations, fill, direction, resetOnFinish]);\n\n const tracks: PxCompiledTracks = compiled.tracks;\n const totalDuration = tracks.duration * (tracks.iterations === Infinity ? 1 : tracks.iterations);\n\n // -- Playback state -------------------------------------------------------\n\n // Progress in ms within ONE iteration; iteration repetition/alternation is\n // expressed through withRepeat, so worklets only ever see [0, duration].\n const progress = useSharedValue(0);\n const playingRef = useRef(false);\n const rateRef = useRef(1);\n\n /** True when the current rate plays the timeline backwards. */\n const reversePlayback = () => rateRef.current < 0;\n\n /** Where the playhead rests once playback ends. `resetOnFinish` snaps back\n * to the start; otherwise `fill` decides whether the final frame is held. */\n const restingPosition = () => {\n if (tracks.resetOnFinish) return 0;\n if (tracks.fill === 'none' || tracks.fill === 'backwards') return 0;\n return reversePlayback() ? 0 : tracks.duration;\n };\n\n const notifyFinish = () => {\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n };\n\n const startFrom = (fromMs: number) => {\n const dur = tracks.duration;\n const rate = rateRef.current || 1;\n const backwards = rate < 0;\n const speed = Math.abs(rate);\n // `direction` decides which end a leg runs toward; a negative playback\n // rate flips it again (the two compose, as in the Web Animations API).\n const directionReversed = tracks.direction === 'reverse' || tracks.direction === 'alternate-reverse';\n const reversedStart = backwards ? !directionReversed : directionReversed;\n const alternates = tracks.direction === 'alternate' || tracks.direction === 'alternate-reverse';\n const from = Math.max(0, Math.min(fromMs, dur));\n\n const legTarget = reversedStart ? 0 : dur;\n const legRemaining = Math.abs(legTarget - from) / speed;\n const repeats = tracks.iterations === Infinity ? -1 : tracks.iterations;\n\n cancelAnimation(progress);\n progress.value = reversedStart ? (from <= 0 ? dur : from) : (from >= dur ? 0 : from);\n\n const animation = repeats === 1\n ? withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }, (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n })\n : withRepeat(\n withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }),\n repeats, alternates,\n (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n }\n );\n\n progress.value = tracks.delay > 0 && from === 0\n ? withDelay(tracks.delay / speed, animation)\n : animation;\n\n playingRef.current = true;\n };\n\n const api: RnAnimatorApi = {\n isPlaying: () => playingRef.current,\n play: () => {\n // `startFrom` rewinds to the opposite end when the playhead is\n // already resting at a boundary (mirrors WAAPI, where play() on a\n // finished animation auto-rewinds).\n startFrom(progress.value);\n onPlay?.();\n },\n pause: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n onPause?.();\n onStop?.();\n },\n cancel: () => {\n cancelAnimation(progress);\n progress.value = 0;\n playingRef.current = false;\n onCancel?.();\n onStop?.();\n },\n finish: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n },\n setPlaybackRate: (rate: number) => {\n if (!isFinite(rate) || rate === 0) {\n console.warn('setPlaybackRate: rate must be finite and non-zero');\n return;\n }\n rateRef.current = rate;\n if (playingRef.current) startFrom(progress.value);\n },\n getCurrentTime: () => progress.value,\n setCurrentTime: (t: number) => {\n const wasPlaying = playingRef.current;\n cancelAnimation(progress);\n playingRef.current = false;\n const clamped = Math.max(0, Math.min(t, totalDuration));\n const withinIteration = tracks.duration > 0\n ? (clamped % tracks.duration) || (clamped === 0 ? 0 : tracks.duration)\n : 0;\n progress.value = withinIteration;\n // Seeking mid-playback continues from the new position rather than\n // silently pausing.\n if (wasPlaying) startFrom(withinIteration);\n },\n };\n\n useImperativeHandle(apiRef, () => api, [compiled]);\n\n // -- Declarative control --------------------------------------------------\n\n const trigger = compiled.doc ? getAnimatorConfig(compiled.doc)?.trigger : undefined;\n const startOn = trigger?.startOn ?? 'load';\n const outAction = outActionProp ?? trigger?.outAction ?? 'pause';\n\n useEffect(() => {\n if (time !== undefined || timeMs !== undefined) {\n const seekMs = timeMs !== undefined ? timeMs : (time ?? 0) * totalDuration;\n api.setCurrentTime(seekMs);\n return;\n }\n if (play !== undefined || pause !== undefined) {\n if (play && !pause) api.play();\n else if (pause) api.pause();\n else if (play === false) api.finish();\n else api.play();\n return;\n }\n // 'click' and 'scrollIntoView' start from their own handlers below.\n if (autoplay && startOn === 'load') {\n api.play();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, play, pause, time, timeMs]);\n\n // `startOn: 'scrollIntoView'` โ react-native has no IntersectionObserver, so\n // visibility is sampled by measuring the view against the window box. The\n // poll is cheap (a native measure every 200ms) and only runs while this\n // trigger is active; `outAction` decides what leaving the viewport does.\n const scrollRef = useRef<View | null>(null);\n const inViewRef = useRef(false);\n useEffect(() => {\n if (!autoplay || startOn !== 'scrollIntoView') return;\n const threshold = trigger?.scrollIntoViewThreshold ?? 0;\n inViewRef.current = false;\n\n const check = () => {\n const node = scrollRef.current;\n if (!node) return;\n node.measureInWindow((_x, y, _w, h) => {\n if (!h) return;\n const screen = Dimensions.get('window').height;\n const visible = Math.max(0, Math.min(y + h, screen) - Math.max(y, 0));\n const ratio = visible / h;\n const isIn = ratio > 0 && ratio >= threshold;\n if (isIn === inViewRef.current) return;\n inViewRef.current = isIn;\n if (isIn) {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n } else if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n });\n };\n\n check();\n const id = setInterval(check, 200);\n return () => clearInterval(id);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, startOn, outAction]);\n\n // Stop cleanly on unmount / doc swap.\n useEffect(() => {\n return () => {\n cancelAnimation(progress);\n playingRef.current = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled]);\n\n // -- Render ---------------------------------------------------------------\n\n const trackById = useMemo(() => {\n const map = new Map<string, PxElementTracks>();\n for (const el of tracks.elements) map.set(el.id, el);\n return map;\n }, [tracks]);\n\n const warningsRef = useRef<Array<string>>([]);\n const renderErrorRef = useRef<Error | null>(null);\n const root = useMemo(() => {\n warningsRef.current = [];\n renderErrorRef.current = null;\n if (!compiled.doc) return null;\n\n const renderOpts: RenderRnNodeOptions = {\n warnings: warningsRef.current,\n defs: getDefs(compiled.doc),\n };\n try {\n return renderRnNode(compiled.doc as PxNode, {\n ...renderOpts,\n decorate: (node, Component, staticProps, children, key) => {\n // An animated definition subtree (gradient / its stops) cannot be\n // driven on the UI thread โ hand the WHOLE subtree to the\n // JS-sampled renderer and stop descending here.\n if (needsJsSampling(node, trackById)) {\n return (\n <SampledSubtree\n key={key}\n node={node}\n trackById={trackById}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n renderOpts={renderOpts}\n />\n );\n }\n\n const id = (node as any).id;\n const elTracks = id ? trackById.get(id) : undefined;\n if (!elTracks) return undefined;\n return (\n <AnimatedPxElement\n key={key}\n Component={Component}\n staticProps={staticProps}\n tracks={elTracks}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n >\n {children}\n </AnimatedPxElement>\n );\n },\n });\n } catch (e) {\n // Building the element tree threw โ report it and render nothing\n // rather than propagating and unmounting the host screen.\n const error = e instanceof Error ? e : new Error(String(e));\n renderErrorRef.current = error;\n console.warn('[PixodeskSvgAnimator] could not render the document:', error.message);\n return null;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, trackById]);\n\n useEffect(() => {\n for (const w of warningsRef.current) console.warn('[PixodeskSvgAnimator]', w);\n }, [root]);\n\n // Surface compile/render failures to the host exactly once per occurrence.\n const failure = compiled.error ?? renderErrorRef.current;\n useEffect(() => {\n if (failure) onError?.(failure);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [failure]);\n\n if (failure) return fallback ? fallback(failure) : null;\n\n // `startOn: 'click'` โ the touch analogue of the web player's click trigger:\n // tap to start, tap again to apply `outAction`. Hover (`mouseOver`) has no\n // touch equivalent and `scrollIntoView` needs the surrounding scroll view,\n // so both are left to the host app.\n let content: ReactElement | null = root;\n\n if (autoplay && startOn === 'scrollIntoView' && root) {\n // `collapsable={false}` keeps the view in the native tree so it can be measured.\n content = <View ref={scrollRef} collapsable={false}>{root}</View>;\n } else if (autoplay && startOn === 'click' && root) {\n content = (\n <Pressable\n onPress={() => {\n if (playingRef.current) {\n if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n } else {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n }\n }}\n >\n {root}\n </Pressable>\n );\n }\n\n // Catches what the try/catch above cannot: throws during React's own render\n // and commit of the tree โ react-native-svg internals, reanimated failing\n // to attach to a component that turns out not to be a host view, and so on.\n return (\n <PxRnErrorBoundary onError={onError} fallback={fallback}>\n {content}\n </PxRnErrorBoundary>\n );\n}\n\nexport default PixodeskSvgAnimator;\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 {\n calcAnimationValues,\n getAnimatorConfig,\n getNormalisedBindings,\n DEFAULT_DURATION_MS,\n PxAnimatorEngine,\n type PxAnimatedSvgDocument,\n type PxAnimationDefinition,\n} from '@pixodesk/svg-animator-core';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\n/**\n * Sampled animation tracks for ONE element: prop name โ per-sample values.\n *\n * The compiler densely samples every animated property through core's\n * `calcAnimationValues` โ the exact function the web frames engine renders\n * with โ so RN playback is value-identical to the web player. Easing, loops,\n * transform composition, colour interpolation and path morphing are all baked\n * into the samples at compile time; the UI-thread worklet only indexes arrays.\n */\nexport interface PxElementTracks {\n /** Element id (after id regeneration). */\n id: string;\n /** react-native-svg prop name โ one value per sample. */\n props: Record<string, Array<string | number | Array<number>>>;\n}\n\nexport interface PxCompiledTracks {\n /** Per-iteration duration, ms. */\n duration: number;\n /** Iteration count (Infinity for 'infinite'). */\n iterations: number;\n /** 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' */\n direction: string;\n /** Delay before start, ms (positive = wait). */\n delay: number;\n /** WAAPI-style fill mode (default 'forwards'). */\n fill: string;\n /** When true, snap back to the start after a natural finish. */\n resetOnFinish: boolean;\n /** Sample step, ms. */\n stepMs: number;\n /** Number of samples per iteration (>= 2; sample i is at time i*stepMs). */\n sampleCount: number;\n /** Tracks for every animated element. */\n elements: Array<PxElementTracks>;\n}\n\nexport interface CompileTracksOptions {\n /** Target sample rate, samples/second. Default 60 (one per frame). */\n sampleRate?: number;\n /** Hard cap on samples per iteration (memory guard). Default 600. */\n maxSamples?: number;\n /**\n * Sample values in the form the NATIVE react-native-svg views expect\n * (currently: `transform` as a 6-number matrix rather than an SVG string).\n *\n * Defaults to `false` โ the plain SVG form, which is what react-native-web\n * hands straight to the DOM. Only the component knows the platform, so it\n * decides; every consumer that does not opt in keeps DOM-compatible values.\n */\n native?: boolean;\n}\n\n\n\n/**\n * Compiles a MATERIALISED document (run `materialiseAllInTree(doc, 'frames')`\n * + `generateNewIds` first) into densely sampled per-element tracks.\n */\nexport function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksOptions): PxCompiledTracks {\n const config = getAnimatorConfig(doc) || {};\n\n const duration = +(config.duration || DEFAULT_DURATION_MS);\n const _iterations = config.iterations;\n let iterations = 1;\n if (typeof _iterations === 'number') iterations = _iterations || 1;\n if (_iterations === 'infinite') iterations = Infinity;\n if (iterations < 1) iterations = 1;\n\n const native = opts?.native ?? false;\n const sampleRate = opts?.sampleRate ?? 60;\n const maxSamples = opts?.maxSamples ?? 600;\n let sampleCount = Math.max(2, Math.round((duration / 1000) * sampleRate) + 1);\n if (sampleCount > maxSamples) sampleCount = maxSamples;\n const stepMs = duration / (sampleCount - 1);\n\n // Element tag per id โ `toRnPropValue` needs it to leave the root `<Svg>`'s\n // transform as a string (see its `tag` parameter).\n const tagById = new Map<string, string>();\n const indexTags = (n: any): void => {\n if (n && typeof n.id === 'string') tagById.set(n.id, String(n.type));\n (n?.children ?? []).forEach(indexTags);\n };\n indexTags(doc);\n\n const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames) || [];\n\n const elements: Array<PxElementTracks> = [];\n for (const binding of bindings) {\n const animDef = binding.animate;\n if (!animDef || typeof animDef !== 'object' || Array.isArray(animDef)) continue;\n\n const props: Record<string, Array<string | number | Array<number>>> = {};\n for (let i = 0; i < sampleCount; i++) {\n const t = i === sampleCount - 1 ? duration : i * stepMs;\n const values = calcAnimationValues(animDef as PxAnimationDefinition, t);\n for (const [attr, value] of Object.entries(values)) {\n const rnProp = toRnPropName(attr);\n if (!rnProp) continue;\n let arr = props[rnProp];\n if (!arr) {\n arr = props[rnProp] = new Array(sampleCount);\n // A prop can appear late (e.g. attrs whose first kf is\n // beyond t=0) โ backfill earlier samples with the first\n // computed value so the array is always fully populated.\n for (let j = 0; j < i; j++) arr[j] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n arr[i] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n }\n // Forward-fill any holes (attr disappeared from a later sample).\n for (const arr of Object.values(props)) {\n for (let i = 1; i < sampleCount; i++) {\n if (arr[i] === undefined) arr[i] = arr[i - 1];\n }\n }\n\n if (Object.keys(props).length > 0) {\n elements.push({ id: binding.id, props });\n }\n }\n\n return {\n duration,\n iterations,\n direction: config.direction || 'normal',\n delay: config.delay || 0,\n fill: config.fill ?? 'forwards',\n resetOnFinish: !!config.resetOnFinish,\n stepMs,\n sampleCount,\n elements,\n };\n}\n\n/**\n * Wire prop โ the prop name the NATIVE view actually declares.\n *\n * react-native-svg's JS layer renames some props on the way down: a\n * `transform` (string or matrix) is parsed by `extractProps` and handed to the\n * native component as `matrix` โ the Fabric spec has no `transform` prop at\n * all. Values sent through reanimated's animated-props path skip that JS\n * rename, so they must already use the native name or the native view drops\n * them silently. This is ONLY for the animated path; plain React renders still\n * go through the JS layer and must keep the wire name.\n */\nexport const NATIVE_PROP_NAME: Record<string, string> = {\n transform: 'matrix',\n};\n\n/**\n * Worklet-safe sample lookup: returns the per-prop values at time `tMs`\n * (already mapped into a single iteration by the caller). Kept deliberately\n * trivial โ runs on the UI thread every frame.\n *\n * `native = true` applies {@link NATIVE_PROP_NAME} โ pass it only on the\n * reanimated animated-props path of a real device. Props that are applied by\n * re-rendering through React (and therefore still pass through react-native-svg's\n * JS layer), and every value on the web, must keep the wire name.\n */\nexport function sampleProps(\n tracks: PxElementTracks,\n tMs: number,\n stepMs: number,\n sampleCount: number,\n native = false\n): Record<string, string | number | Array<number>> {\n 'worklet';\n const out: Record<string, string | number | Array<number>> = {};\n // Defensive: this runs on the UI thread, where a throw is a hard crash\n // with no React boundary to catch it.\n if (!tracks || !tracks.props || !(stepMs > 0)) return out;\n\n let idx = Math.round(tMs / stepMs);\n if (idx < 0) idx = 0;\n if (idx >= sampleCount) idx = sampleCount - 1;\n for (const key in tracks.props) {\n const values = tracks.props[key];\n if (!values) continue;\n const value = values[idx];\n if (value === undefined) continue;\n const name = native && key === 'transform' ? 'matrix' : key;\n out[name] = value;\n }\n return out;\n}\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 { kebabToCamelCaseWord } from '@pixodesk/svg-animator-core';\nimport { svgTransformToMatrix } from './PxRnMatrix';\n\n/** Attribute names with a react-native-svg prop equivalent under a\n * different name (not just a casing change). */\nconst ATTR_NAME_OVERRIDES: Record<string, string> = {\n 'xlink:href': 'href',\n};\n\n/** Props react-native-svg does not understand / must not receive. */\nconst DROPPED_ATTRS = new Set(['class', 'className', 'style', 'xmlns', 'xmlns:xlink', 'data-px-meta']);\n\n/**\n * Converts one normalised wire attribute name (camelCase after core's\n * `getNormalizedProps`, or kebab-case raw) to a react-native-svg prop name.\n * Returns undefined for props that must be dropped.\n *\n * Pure (no react-native-svg import) so the track compiler and its tests\n * don't need a React Native environment.\n */\nexport function toRnPropName(attrName: string): string | undefined {\n if (DROPPED_ATTRS.has(attrName)) return undefined;\n const override = ATTR_NAME_OVERRIDES[attrName];\n if (override) return override;\n // react-native-svg uses camelCase props (strokeWidth, fillOpacity, โฆ);\n // core's kebabToCamelCaseWord is a no-op for already-camelCase input.\n return kebabToCamelCaseWord(attrName);\n}\n\n/** Props whose value is a LIST of lengths. react-native-svg's native side\n * expects a number array here (its JS `extractLengthList` splits strings, but\n * values delivered through reanimated's animated-props path bypass that JS\n * extraction and reach the native view directly). */\nconst LENGTH_LIST_PROPS = new Set(['strokeDasharray']);\n\n/**\n * Converts one already-renamed prop value into the shape react-native-svg\n * expects: length-list props become number arrays; numeric strings become\n * numbers; everything else passes through.\n */\nexport function toRnPropValue(\n rnPropName: string,\n value: string | number,\n /** The owning element's tag. The ROOT `<Svg>` handles `transform` through a\n * different code path (`extractTransformSvgView`, which wants a string or\n * an RN style) โ a matrix there would be dropped, so leave it alone. */\n tag?: string,\n /** Opt in to the NATIVE representation of a value (see below). Defaults to\n * off, so web keeps the plain SVG/DOM form it has always been given. */\n native = false,\n): string | number | Array<number> {\n // On a device `transform` must arrive as a matrix, not a string: the\n // stringโmatrix parse happens in JS during render, which reanimated's\n // animated-props path skips entirely. See PxRnMatrix for the full why.\n // On the web the DOM parses the string itself and an array would serialise\n // to a meaningless `transform=\"1,0,0,1,3,4\"`, so it must stay a string.\n if (native && rnPropName === 'transform' && typeof value === 'string' && tag !== 'svg') {\n const m = svgTransformToMatrix(value);\n if (m) return m;\n }\n if (LENGTH_LIST_PROPS.has(rnPropName)) {\n const parts = String(value).trim().replace(/,/g, ' ').split(/\\s+/).map(Number).filter(n => Number.isFinite(n));\n // An odd-length dasharray repeats to become even (SVG spec); rn-svg\n // does this itself for the static path โ mirror it so both paths agree.\n return parts.length % 2 === 1 ? parts.concat(parts) : parts;\n }\n if (typeof value === 'number') return value;\n const num = +value;\n return Number.isFinite(num) && String(num) === value ? num : value;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * SVG transform string โ 2D affine matrix, in the order react-native-svg's\n * native side expects: `[a, b, c, d, e, f]`, i.e. SVG's own `matrix(โฆ)` order\n *\n * ```\n * | a c e |\n * | b d f |\n * | 0 0 1 |\n * ```\n *\n * WHY THIS EXISTS: react-native-svg parses a `transform` STRING into this matrix\n * in JavaScript, inside `extractTransform`, during render. Values delivered\n * through reanimated's `animatedProps` bypass that JS step and reach the native\n * view directly, where a raw string is meaningless โ an animated transform\n * simply does nothing. Feeding the matrix instead makes the animated and static\n * paths agree. (On the web the DOM parses the string itself, which is why this\n * only shows up on a device.)\n */\nexport type Mat2D = [number, number, number, number, number, number];\n\nexport const IDENTITY: Mat2D = [1, 0, 0, 1, 0, 0];\n\nconst DEG = Math.PI / 180;\n\n/** `m1 ยท m2` โ apply m2 first, then m1 (same convention as SVG's left-to-right list). */\nfunction multiply(m1: Mat2D, m2: Mat2D): Mat2D {\n const [a1, b1, c1, d1, e1, f1] = m1;\n const [a2, b2, c2, d2, e2, f2] = m2;\n return [\n a1 * a2 + c1 * b2,\n b1 * a2 + d1 * b2,\n a1 * c2 + c1 * d2,\n b1 * c2 + d1 * d2,\n a1 * e2 + c1 * f2 + e1,\n b1 * e2 + d1 * f2 + f1,\n ];\n}\n\n/** Splits `translate(1,2)rotate(45)` into `[['translate',[1,2]], ['rotate',[45]]]`. */\nconst FN_RE = /([a-zA-Z]+)\\s*\\(([^)]*)\\)/g;\n\nfunction numbers(raw: string): Array<number> {\n return raw\n .split(/[\\s,]+/)\n .filter(s => s.length > 0)\n .map(Number)\n .filter(n => Number.isFinite(n));\n}\n\n/**\n * Parses an SVG transform list. Returns `undefined` when the string contains no\n * recognisable function, so callers can leave the original value untouched\n * rather than silently replacing it with an identity matrix.\n */\nexport function svgTransformToMatrix(value: string): Mat2D | undefined {\n let m: Mat2D | undefined;\n FN_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = FN_RE.exec(value)) !== null) {\n const fn = match[1].toLowerCase();\n const n = numbers(match[2]);\n let step: Mat2D | undefined;\n\n switch (fn) {\n case 'translate':\n step = [1, 0, 0, 1, n[0] || 0, n[1] || 0];\n break;\n case 'scale': {\n const sx = n[0] ?? 1;\n const sy = n.length > 1 ? n[1] : sx;\n step = [sx, 0, 0, sy, 0, 0];\n break;\n }\n case 'rotate': {\n const rad = (n[0] || 0) * DEG;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n const rot: Mat2D = [cos, sin, -sin, cos, 0, 0];\n if (n.length >= 3) {\n // rotate(a, cx, cy) == translate(cx,cy) rotate(a) translate(-cx,-cy)\n const cx = n[1], cy = n[2];\n step = multiply(multiply([1, 0, 0, 1, cx, cy], rot), [1, 0, 0, 1, -cx, -cy]);\n } else {\n step = rot;\n }\n break;\n }\n case 'skewx':\n step = [1, 0, Math.tan((n[0] || 0) * DEG), 1, 0, 0];\n break;\n case 'skewy':\n step = [1, Math.tan((n[0] || 0) * DEG), 0, 1, 0, 0];\n break;\n case 'matrix':\n if (n.length >= 6) step = [n[0], n[1], n[2], n[3], n[4], n[5]];\n break;\n default:\n step = undefined; // unknown function โ ignore it\n }\n\n if (step) m = m ? multiply(m, step) : step;\n }\n\n return m;\n}\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 {\n getNormalizedProps,\n resolveStyle,\n sanitiseAttributeValue,\n DISALLOWED_SVG_TAGS_LOWER,\n TEXT_ATTR,\n TEXT_CONTENT_ATTR,\n type PxDefs,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport { createElement, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { RN_SVG_COMPONENTS } from './PxRnTypeMap';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\nexport interface RenderRnNodeOptions {\n /** Collects non-fatal issues (unsupported tags, dropped attrs). */\n warnings?: Array<string>;\n /** `definitions` from the document, used to resolve named `style` presets. */\n defs?: PxDefs;\n /**\n * Wraps the created element for animated nodes: receives the resolved\n * component + static props and returns the element to mount (the animator\n * substitutes an Animated component wired to its tracks). Return undefined\n * to keep the plain static element.\n *\n * `key` is handed over SEPARATELY and is deliberately absent from `props`:\n * React 19 warns when a props object containing `key` is spread into JSX,\n * and implementations of this hook do exactly that.\n */\n decorate?: (\n node: PxNode,\n Component: ComponentType<any>,\n props: Record<string, any>,\n children: ReactNode,\n key: string | number | undefined\n ) => ReactElement | undefined;\n}\n\n/**\n * Converts core-normalised wire props into react-native-svg props: RN prop\n * naming, sanitisation (same security rules as the web renderer), numeric\n * coercion where possible.\n */\nexport function toRnProps(props: Record<string, any>, warnings?: Array<string>, tag?: string): Record<string, any> {\n const normalised = getNormalizedProps(props);\n const out: Record<string, any> = {};\n for (const key of Object.keys(normalised)) {\n const sanitised = sanitiseAttributeValue(key, normalised[key]);\n if (sanitised === undefined) continue;\n const rnKey = toRnPropName(key);\n if (!rnKey) continue;\n out[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n return out;\n}\n\n/**\n * Renders a (materialised) PxNode tree to react-native-svg elements.\n * Mirrors the web `renderNode` contract: unsupported/dangerous tags are\n * skipped with a warning, never a crash.\n */\nexport function renderRnNode(node: PxNode, opts: RenderRnNodeOptions = {}, key?: string | number): ReactElement | null {\n if (!node) return null;\n\n const { type, children, style, animate, meta, effects, ...props } = node as any;\n const tag = String(type || 'g');\n\n // ESCAPE KEY (S2): elements whose SVG `type` ATTRIBUTE collides with the reserved\n // `type` node-tag key carry it under `domType` โ `feColorMatrix` (matrix/saturate/โฆ),\n // `feTurbulence` (fractalNoise/turbulence), `feFunc*` (identity/table/โฆ).\n // Restore it as a real prop, mirroring the web renderer.\n const domType: string | undefined = props.domType;\n if (domType !== undefined) delete props.domType;\n\n if (DISALLOWED_SVG_TAGS_LOWER.has(tag.toLowerCase())) {\n opts.warnings?.push('tag blocked (dangerous): ' + tag);\n return null;\n }\n\n const Component = RN_SVG_COMPONENTS[tag];\n if (!Component) {\n opts.warnings?.push('tag not supported in react-native-svg mapping: ' + tag);\n return null;\n }\n\n // NB: `key` is never written into this object โ see `decorate` above.\n const rnProps = toRnProps(props, opts.warnings, tag);\n if (domType !== undefined) rnProps.type = domType;\n\n // `node.style` โ a named preset from `definitions.styles`, or an inline\n // record. react-native-svg has no CSS, so the resolved declarations are\n // applied as ordinary props (the same names, e.g. `fill`, `strokeWidth`).\n // Explicit attributes on the node win over the style block.\n const resolved = resolveStyle(style, opts.defs);\n if (resolved) {\n for (const [k, v] of Object.entries(resolved)) {\n const rnKey = toRnPropName(k);\n if (!rnKey || rnKey in rnProps) continue;\n const sanitised = sanitiseAttributeValue(rnKey, v);\n if (sanitised === undefined) continue;\n rnProps[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n }\n\n // Text content: wire nodes carry it as `text` / `textContent` attr.\n const textContent: string | undefined = props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR];\n\n let childElements: ReactNode = undefined;\n if (Array.isArray(children) && children.length > 0) {\n childElements = children\n .map((ch: PxNode, i: number) => {\n // One malformed child should cost that child, not the whole tree.\n try {\n return renderRnNode(ch, opts, i);\n } catch (e) {\n opts.warnings?.push('child failed to render: ' + (e instanceof Error ? e.message : String(e)));\n return null;\n }\n })\n .filter(Boolean);\n } else if (textContent !== undefined) {\n childElements = String(textContent);\n }\n\n const decorated = opts.decorate?.(node, Component, rnProps, childElements, key);\n if (decorated !== undefined) return decorated;\n\n // `createElement` takes `key` in its config object โ that path does NOT\n // trigger React's JSX-spread warning.\n return createElement(\n Component,\n key !== undefined ? { ...rnProps, key } : rnProps,\n childElements\n );\n}\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 {\n Circle,\n ClipPath,\n Defs,\n Ellipse,\n FeBlend,\n FeColorMatrix,\n FeComponentTransfer,\n FeComposite,\n FeConvolveMatrix,\n FeDiffuseLighting,\n FeDisplacementMap,\n FeDistantLight,\n FeDropShadow,\n FeFlood,\n FeFuncA,\n FeFuncB,\n FeFuncG,\n FeFuncR,\n FeGaussianBlur,\n FeImage,\n FeMerge,\n FeMergeNode,\n FeMorphology,\n FeOffset,\n FePointLight,\n FeSpecularLighting,\n FeSpotLight,\n FeTile,\n FeTurbulence,\n Filter,\n G,\n Image,\n Line,\n LinearGradient,\n Marker,\n Mask,\n Path,\n Pattern,\n Polygon,\n Polyline,\n RadialGradient,\n Rect,\n Stop,\n Svg,\n Symbol as SvgSymbol,\n Text as SvgText,\n TextPath,\n TSpan,\n Use,\n} from 'react-native-svg';\nimport type { ComponentType } from 'react';\n\n/**\n * SVG tag โ react-native-svg component. Tags not in this map are skipped at\n * render time (with a warning collected by the renderer) โ they go on the\n * feature-gap list rather than crashing the tree.\n *\n * Keys are the wire-format `node.type` values, which follow SVG's own casing\n * (`clipPath`, `feGaussianBlur`, `linearGradient`, โฆ).\n */\nexport const RN_SVG_COMPONENTS: Record<string, ComponentType<any>> = {\n // Root & containers\n svg: Svg,\n g: G,\n defs: Defs,\n symbol: SvgSymbol,\n use: Use,\n\n // Shapes\n rect: Rect,\n circle: Circle,\n ellipse: Ellipse,\n line: Line,\n path: Path,\n polygon: Polygon,\n polyline: Polyline,\n image: Image,\n\n // Text\n text: SvgText,\n tspan: TSpan,\n textPath: TextPath,\n\n // Paint servers & clipping\n linearGradient: LinearGradient,\n radialGradient: RadialGradient,\n stop: Stop,\n pattern: Pattern,\n mask: Mask,\n clipPath: ClipPath,\n marker: Marker,\n\n // Filters โ react-native-svg implements the full primitive set.\n // NOTE: filter rendering requires the New Architecture (Fabric) and is\n // newer than the rest of react-native-svg; treat visual parity with the\n // web player as unverified until checked on a device.\n filter: Filter,\n feBlend: FeBlend,\n feColorMatrix: FeColorMatrix,\n feComponentTransfer: FeComponentTransfer,\n feComposite: FeComposite,\n feConvolveMatrix: FeConvolveMatrix,\n feDiffuseLighting: FeDiffuseLighting,\n feDisplacementMap: FeDisplacementMap,\n feDistantLight: FeDistantLight,\n feDropShadow: FeDropShadow,\n feFlood: FeFlood,\n feFuncA: FeFuncA,\n feFuncB: FeFuncB,\n feFuncG: FeFuncG,\n feFuncR: FeFuncR,\n feGaussianBlur: FeGaussianBlur,\n feImage: FeImage,\n feMerge: FeMerge,\n feMergeNode: FeMergeNode,\n feMorphology: FeMorphology,\n feOffset: FeOffset,\n fePointLight: FePointLight,\n feSpecularLighting: FeSpecularLighting,\n feSpotLight: FeSpotLight,\n feTile: FeTile,\n feTurbulence: FeTurbulence,\n};\n\nexport { toRnPropName } from './PxRnPropNames';\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 { Component, type ErrorInfo, type ReactNode } from 'react';\n\nexport interface PxRnErrorBoundaryProps {\n children: ReactNode;\n /** Rendered instead of the children once something has thrown. */\n fallback?: (error: Error) => ReactNode;\n onError?: (error: Error, info?: string) => void;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Keeps one bad animation from taking down the screen around it.\n *\n * A throw anywhere in the rendered SVG tree โ an unsupported prop shape, a\n * react-native-svg internal, a reanimated attachment failure โ otherwise\n * unmounts the whole React tree above it. Here it is contained to this one\n * animation, reported through `onError`, and replaced by `fallback`.\n *\n * NOTE the limit: this catches JavaScript errors only. A crash INSIDE the\n * native renderer (see `openClosedTextPathTargets` for a real example) never\n * reaches JavaScript and cannot be caught here โ those have to be avoided\n * rather than handled.\n */\nexport class PxRnErrorBoundary extends Component<PxRnErrorBoundaryProps, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n this.props.onError?.(error, info?.componentStack ?? undefined);\n console.warn('[PixodeskSvgAnimator] render failed:', error?.message ?? error);\n }\n\n override componentDidUpdate(prev: PxRnErrorBoundaryProps): void {\n // A new document deserves a fresh attempt โ otherwise the boundary\n // would stay latched on the failure for the rest of its life.\n if (this.state.error && prev.children !== this.props.children) {\n this.setState({ error: null });\n }\n }\n\n override render(): ReactNode {\n const { error } = this.state;\n if (error) return this.props.fallback ? this.props.fallback(error) : null;\n return this.props.children;\n }\n}\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 { deepClone, generateUniqueId, type PxNode } from '@pixodesk/svg-animator-core';\n\n/**\n * Workarounds for defects in react-native-svg's NATIVE renderer that would\n * otherwise take the whole app down.\n *\n * These are applied only when the native views are in use โ never on the web,\n * where the DOM handles all of this correctly and the document must be left\n * exactly as the core pipeline produced it.\n */\n\n/** True when a path's `d` contains a close-subpath command. */\nfunction isClosedPath(d: unknown): boolean {\n return typeof d === 'string' && /[zZ]/.test(d);\n}\n\n/** Drops close-subpath commands, turning a closed outline into an open one. */\nfunction openPath(d: string): string {\n return d.replace(/[zZ]/g, '').trimEnd();\n}\n\n/** `#foo` โ `foo`. Returns undefined for anything that is not a local ref. */\nfunction localRef(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.startsWith('#') ? trimmed.slice(1) : undefined;\n}\n\nfunction forEachNode(node: PxNode | undefined, visit: (n: PxNode, parent?: PxNode) => void, parent?: PxNode): void {\n if (!node) return;\n visit(node, parent);\n for (const child of (node.children ?? [])) forEachNode(child, visit, node);\n}\n\n/**\n * Gives every `<textPath>` that follows a CLOSED path its own OPEN copy of it.\n *\n * WHY: react-native-svg's native text-on-path layout crashes the app โ\n * an uncatchable `NSRangeException` on iOS โ for this combination.\n * `RNSVGTSpan.mm` skips glyphs outside `[startOfRendering, endOfRendering]`,\n * but for a closed path it sets those bounds to `startOffset โฆ startOffset +\n * pathLength` instead of `0 โฆ pathLength`. Any glyph past the end of the path\n * therefore survives the bounds check and reaches `getPosAndTan`, whose\n * `indexOfObjectPassingTest` returns `NSNotFound` โ and indexing the lengths\n * array with `NSNotFound` throws. A non-zero `startOffset` on a closed path is\n * all it takes, and animating `startOffset` guarantees hitting it.\n *\n * Opening the path restores the `0 โฆ pathLength` bounds, so out-of-range\n * glyphs are skipped as intended. The copy is private to the `<textPath>`, so\n * anything else drawing the same path still gets the closed original. For a\n * shape whose ends already meet (a circle, the usual case) the removed segment\n * has zero length and nothing changes visually at all.\n *\n * Returns the document unchanged โ the same object โ when nothing matches.\n */\nexport function openClosedTextPathTargets(doc: PxNode, warnings?: Array<string>): PxNode {\n // Cheap pre-check: the overwhelming majority of documents have no textPath.\n let hasTextPath = false;\n forEachNode(doc, n => { if (String(n.type) === 'textPath') hasTextPath = true; });\n if (!hasTextPath) return doc;\n\n const result = deepClone(doc);\n\n const byId = new Map<string, PxNode>();\n forEachNode(result, n => {\n const id = (n as any).id;\n if (typeof id === 'string') byId.set(id, n);\n });\n\n /** The copy is a geometry reference, never something to draw โ so it goes\n * in `<defs>`, alongside the paths textPath targets normally live in. */\n let defs = (result.children ?? []).find(c => String(c.type) === 'defs');\n const ensureDefs = (): PxNode => {\n if (!defs) {\n defs = { type: 'defs', children: [] } as unknown as PxNode;\n (result.children ??= []).unshift(defs);\n }\n return defs;\n };\n\n /** Original path id โ id of the open copy, so N textPaths share one copy. */\n const openCopies = new Map<string, string>();\n\n forEachNode(result, node => {\n if (String(node.type) !== 'textPath') return;\n\n const anyNode = node as any;\n const attr = anyNode.href !== undefined ? 'href' : 'xlink:href';\n const targetId = localRef(anyNode[attr]);\n if (!targetId) return;\n\n const target = byId.get(targetId);\n if (!target || !isClosedPath((target as any).d)) return;\n\n let copyId = openCopies.get(targetId);\n if (!copyId) {\n const copy = deepClone(target) as any;\n copyId = 'px_open_' + generateUniqueId();\n copy.id = copyId;\n copy.d = openPath(String(copy.d));\n // A copy that also carried animation would animate twice; the copy\n // exists purely as a geometry reference for the text.\n delete copy.animate;\n delete copy.effects;\n\n (ensureDefs().children ??= []).push(copy);\n openCopies.set(targetId, copyId);\n warnings?.push(\n 'textPath follows a closed path (#' + targetId + '); using an open copy to ' +\n 'avoid a react-native-svg native crash'\n );\n }\n\n anyNode[attr] = '#' + copyId;\n });\n\n return result;\n}\n"],"mappings":"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","names":["getAnimatorConfig","PxAnimatorEngine","createElement","_a","Component","_a","_a","Component","createElement","PxAnimatorEngine","getAnimatorConfig","_a"]}
|
|
1
|
+
{"version":3,"sources":["../src/PixodeskSvgAnimator.tsx","../src/PxRnTracks.ts","../src/PxRnPropNames.ts","../src/PxRnMatrix.ts","../src/PxRnRender.tsx","../src/PxRnTypeMap.ts","../src/PxRnErrorBoundary.tsx","../src/PxRnSafety.ts"],"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 {\n generateNewIds,\n getAnimatorConfig,\n getDefs,\n materialiseAllInTree,\n validateNodeEffects,\n PxAnimatorEngine,\n type FillMode,\n type OutAction,\n type PlaybackDirection,\n type PxAnimatedSvgDocument,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport React, { createElement, useEffect, useImperativeHandle, useMemo, useRef, useState, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { Dimensions, Platform, Pressable, View } from 'react-native';\nimport Animated, {\n cancelAnimation,\n useAnimatedReaction,\n Easing,\n runOnJS,\n useAnimatedProps,\n useSharedValue,\n withDelay,\n withRepeat,\n withTiming,\n type SharedValue,\n} from 'react-native-reanimated';\nimport { compileTracks, sampleProps, type PxCompiledTracks, type PxElementTracks } from './PxRnTracks';\nimport { renderRnNode, type RenderRnNodeOptions } from './PxRnRender';\nimport { PxRnErrorBoundary } from './PxRnErrorBoundary';\nimport { openClosedTextPathTargets } from './PxRnSafety';\n\n\n// -- Public types -----------------------------------------------------------\n\n/** Imperative playback API โ mirrors ReactAnimatorApi from svg-animator-react. */\nexport interface RnAnimatorApi {\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. */\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 PixodeskSvgAnimatorProps {\n\n // -- Source ---------------------------------------------------------------\n\n /** The animation document to render. */\n doc: PxAnimatedSvgDocument;\n\n // -- Timing overrides -----------------------------------------------------\n\n /** Duration of a single iteration in milliseconds. */\n duration?: number;\n\n /** Delay before the animation starts, in milliseconds. */\n delay?: number;\n\n /** Number of iterations, or 'infinite' for endless looping. */\n iterations?: number | 'infinite';\n\n /** Defines the element's state when the animation is not active. */\n fill?: FillMode;\n\n /** Playback direction. */\n direction?: PlaybackDirection;\n\n /** Snap back to the start state after a natural finish. */\n resetOnFinish?: boolean;\n\n /**\n * What a second tap does when `startOn: 'click'` is active.\n * Defaults to the document's `trigger.outAction`, else `'pause'`.\n */\n outAction?: OutAction;\n\n // -- Declarative control --------------------------------------------------\n\n /** When true, honours the document trigger (`startOn: 'load'` plays on mount). */\n autoplay?: boolean;\n\n /** Starts playback unconditionally. */\n play?: boolean;\n\n /** Pauses current playback. */\n pause?: boolean;\n\n // -- Imperative control ---------------------------------------------------\n\n /** Ref populated with the imperative playback API. */\n apiRef?: React.RefObject<RnAnimatorApi | null>;\n\n // -- Controlled (external) time -------------------------------------------\n\n /** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */\n progress?: number;\n\n /** Seek to a specific time in milliseconds. */\n time?: number;\n\n // -- Callbacks ------------------------------------------------------------\n\n onPlay?: () => void;\n onStop?: () => void;\n onPause?: () => void;\n onCancel?: () => void;\n onFinish?: () => void;\n\n\n // -- Failure handling -----------------------------------------------------\n\n /**\n * Called when a document cannot be compiled or rendered. The component\n * renders {@link fallback} instead of throwing, so a single broken\n * animation never takes down the screen around it.\n *\n * Only JavaScript failures reach this โ a crash inside react-native-svg's\n * native renderer bypasses JavaScript entirely.\n */\n onError?: (error: Error, componentStack?: string) => void;\n\n /** Rendered in place of the animation after a failure. Default: nothing. */\n fallback?: (error: Error) => ReactElement | null;\n}\n\n\n// -- Animated element wrapper ------------------------------------------------\n\n/**\n * Whether react-native-svg is backed by NATIVE views here, rather than by the\n * DOM through react-native-web.\n *\n * The two want different things from an animated `transform`: a native view\n * declares a `matrix` prop taking six numbers, while the DOM wants a\n * `transform` attribute holding an SVG string. Getting it wrong is silent โ\n * the value is dropped and the element simply never moves โ so this single\n * constant decides it once and feeds both the track compiler (value form) and\n * the sampler (prop name). Everything else in the package defaults to the\n * DOM-compatible form.\n */\nconst NATIVE_SVG_VIEWS = Platform.OS !== 'web';\n\nconst animatedComponentCache = new Map<ComponentType<any>, ComponentType<any>>();\n\nfunction getAnimatedComponent(Component: ComponentType<any>): ComponentType<any> {\n let cached = animatedComponentCache.get(Component);\n if (!cached) {\n cached = Animated.createAnimatedComponent(Component as any);\n animatedComponentCache.set(Component, cached);\n }\n return cached;\n}\n\n/** One animated element: static props + UI-thread sampled animated props. */\nfunction AnimatedPxElement({\n Component, staticProps, children, tracks, progress, stepMs, sampleCount,\n}: {\n Component: ComponentType<any>;\n staticProps: Record<string, any>;\n children: ReactNode;\n tracks: PxElementTracks;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n}) {\n const AnimatedComponent = useMemo(() => getAnimatedComponent(Component), [Component]);\n\n // Runs on the UI thread every frame; `sampleProps` is a trivial indexed\n // lookup into the precompiled tracks โ no interpolation logic on the hot path.\n const animatedProps = useAnimatedProps(() => {\n // On iOS/Android these values bypass react-native-svg's JS prop layer\n // and land on the native view, which declares `matrix`, not\n // `transform`. The web build keeps the DOM-facing `transform` name.\n return sampleProps(tracks, progress.value, stepMs, sampleCount, NATIVE_SVG_VIEWS);\n }, [tracks, stepMs, sampleCount]);\n\n return (\n <AnimatedComponent {...staticProps} animatedProps={animatedProps}>\n {children}\n </AnimatedComponent>\n );\n}\n\n\n/**\n * react-native-svg elements whose `render()` returns `null`. They carry data for\n * their PARENT (a `<Stop>` is read by the gradient that owns it) rather than\n * producing a native view, so reanimated has nothing to attach to โ wrapping one\n * in `Animated.createAnimatedComponent` throws\n * \"Cannot find host instance for this component\".\n */\nconst NON_HOST_TAGS = new Set(['stop', 'feMergeNode']);\n\n/**\n * Definition elements โ they describe paint/geometry for something else rather\n * than drawing themselves. Their animated attributes (a gradient's `y1`, a\n * stop's `stop-color`) do not reliably flow through reanimated's animated-props\n * path, so an animated def is rendered by re-sampling from JS instead. There\n * are only ever a handful per document and they change slowly, so the cost is\n * negligible โ visual elements still animate entirely on the UI thread.\n */\nconst SAMPLED_DEF_TAGS = new Set(['linearGradient', 'radialGradient', ...NON_HOST_TAGS]);\n\n/** True when this subtree must be driven from JS rather than the UI thread:\n * either the node itself is an animated def, or it owns an animated non-host\n * child (an animated `<Stop>` only re-renders via its parent gradient). */\nfunction needsJsSampling(node: PxNode, trackById: Map<string, PxElementTracks>): boolean {\n const id = (node as any).id;\n if (SAMPLED_DEF_TAGS.has(String(node.type)) && id && trackById.has(id)) return true;\n return (node.children ?? []).some(c => needsJsSampling(c, trackById));\n}\n\n/**\n * Renders a subtree whose animation cannot run on the UI thread (see\n * {@link NON_HOST_TAGS}) by re-rendering it from JS with sampled values.\n *\n * Changing a `<Stop>`'s props does not re-render its parent gradient, so the\n * whole subtree is rebuilt โ which is why this wraps the gradient rather than\n * the stop. The reaction itself runs on the UI thread and only crosses to JS\n * when the QUANTISED sample index changes, capping these few elements at\n * ~30fps instead of a JS call every frame.\n */\nfunction SampledSubtree({\n node, trackById, progress, stepMs, sampleCount, renderOpts,\n}: {\n node: PxNode;\n trackById: Map<string, PxElementTracks>;\n progress: SharedValue<number>;\n stepMs: number;\n sampleCount: number;\n renderOpts: RenderRnNodeOptions;\n}) {\n const [idx, setIdx] = useState(0);\n\n useAnimatedReaction(\n () => Math.floor(Math.round(progress.value / stepMs) / 2) * 2, // half-rate\n (next, prev) => {\n if (next !== prev) runOnJS(setIdx)(next);\n },\n [stepMs]\n );\n\n const tMs = Math.min(Math.max(idx, 0), sampleCount - 1) * stepMs;\n\n return renderRnNode(node, {\n ...renderOpts,\n // Sampled values are baked in as PLAIN props โ nothing reanimated-driven.\n decorate: (n, Component, staticProps, children, key) => {\n const id = (n as any).id;\n const tracks = id ? trackById.get(id) : undefined;\n if (!tracks) return undefined;\n // Wire prop names, NOT the native ones: these go back through\n // react-native-svg's JS prop layer, which does the renaming itself.\n const sampled = sampleProps(tracks, tMs, stepMs, sampleCount);\n return createElement(Component, { ...staticProps, ...sampled, key }, children);\n },\n });\n}\n\n\n\n/** Overrides that shadow the document's own `animator` config. */\ninterface ConfigOverrides {\n duration?: number;\n delay?: number;\n iterations?: number | 'infinite';\n fill?: FillMode;\n direction?: PlaybackDirection;\n resetOnFinish?: boolean;\n}\n\ninterface Compiled {\n /** Materialised document, or null when compilation failed. */\n doc: PxAnimatedSvgDocument | null;\n tracks: PxCompiledTracks;\n error: Error | null;\n}\n\n/** Playable-but-empty tracks, so a failed compile still satisfies every hook\n * below it โ React forbids skipping hooks on an error path. */\nconst EMPTY_TRACKS: PxCompiledTracks = {\n duration: 1, iterations: 1, direction: 'normal', delay: 0,\n fill: 'forwards', resetOnFinish: false, stepMs: 1, sampleCount: 2, elements: [],\n};\n\n/**\n * Materialises + compiles a document. Extracted from the component so the\n * whole thing sits behind one try/catch, and so it can be tested directly.\n */\nfunction compileDocument(doc: PxAnimatedSvgDocument, overrides: ConfigOverrides): Compiled {\n const { duration, delay, iterations, fill, direction, resetOnFinish } = overrides;\n const warnings = validateNodeEffects(doc as PxNode);\n for (const w of warnings) console.warn('[PixodeskSvgAnimator] effects shape warning:', w);\n\n // `waapi` = the FULLY-FLATTENED materialisation: effects + loops +\n // sampled motion paths + animated `<use>` inlined into real `<g>`\n // clones + orphaned defs pruned. That last part is why RN must not use\n // the `frames` flavour: frames keeps `<use href=\"#animatedTarget\">`\n // live references, which only work because the DOM propagates\n // attribute writes through `<use>` shadow trees. react-native-svg has\n // no such live propagation, so an animated `<use>` would render frozen.\n let prepared = materialiseAllInTree(doc, PxAnimatorEngine.waapi);\n\n // Sidestep a react-native-svg NATIVE crash (see PxRnSafety). Guarded on\n // the platform because the DOM renders this case correctly and the web\n // document must stay exactly as the core pipeline produced it.\n if (NATIVE_SVG_VIEWS) {\n prepared = openClosedTextPathTargets(prepared as PxNode) as PxAnimatedSvgDocument;\n }\n\n // Apply prop overrides onto the animator config (mirrors the react wrapper).\n const animator = getAnimatorConfig(prepared) || {};\n prepared = {\n ...prepared,\n animator: {\n ...animator,\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 resetOnFinish: resetOnFinish !== undefined ? resetOnFinish : animator.resetOnFinish,\n },\n };\n\n prepared = generateNewIds(prepared);\n const tracks = compileTracks(prepared, { native: NATIVE_SVG_VIEWS });\n return { doc: prepared, tracks, error: null };\n}\n\n\n// -- Main component ----------------------------------------------------------\n\n/**\n * React Native component for rendering and controlling Pixodesk SVG animations.\n *\n * The document is materialised once through the shared core pipeline (effects,\n * loops, motion-path sampling, animated-`<use>` inlining โ identical to the\n * web frames engine), compiled into densely sampled per-element tracks, and\n * played back natively: a single reanimated progress value driven by\n * `withTiming`/`withRepeat` on the UI thread, with per-element worklets\n * indexing the precompiled tracks. No JS-thread frame loop.\n */\nexport function PixodeskSvgAnimator({\n doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp,\n // (`progress` prop aliased โ the name is taken by the internal reanimated SharedValue)\n autoplay, play, pause, apiRef, progress: progressProp, time,\n onPlay, onStop, onPause, onCancel, onFinish, onError, fallback,\n}: PixodeskSvgAnimatorProps): ReactElement | null {\n\n // -- Compile the document (once per doc/override change) ------------------\n\n const compiled = useMemo((): Compiled => {\n try {\n return compileDocument(\n doc,\n { duration, delay, iterations, fill, direction, resetOnFinish }\n );\n } catch (e) {\n // A malformed document must not take the host screen down with it.\n const error = e instanceof Error ? e : new Error(String(e));\n console.warn('[PixodeskSvgAnimator] could not compile the document:', error.message);\n return { doc: null, tracks: EMPTY_TRACKS, error };\n }\n }, [doc, duration, delay, iterations, fill, direction, resetOnFinish]);\n\n const tracks: PxCompiledTracks = compiled.tracks;\n const totalDuration = tracks.duration * (tracks.iterations === Infinity ? 1 : tracks.iterations);\n\n // -- Playback state -------------------------------------------------------\n\n // Progress in ms within ONE iteration; iteration repetition/alternation is\n // expressed through withRepeat, so worklets only ever see [0, duration].\n const progress = useSharedValue(0);\n const playingRef = useRef(false);\n const rateRef = useRef(1);\n\n /** True when the current rate plays the timeline backwards. */\n const reversePlayback = () => rateRef.current < 0;\n\n /** Where the playhead rests once playback ends. `resetOnFinish` snaps back\n * to the start; otherwise `fill` decides whether the final frame is held. */\n const restingPosition = () => {\n if (tracks.resetOnFinish) return 0;\n if (tracks.fill === 'none' || tracks.fill === 'backwards') return 0;\n return reversePlayback() ? 0 : tracks.duration;\n };\n\n const notifyFinish = () => {\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n };\n\n const startFrom = (fromMs: number) => {\n const dur = tracks.duration;\n const rate = rateRef.current || 1;\n const backwards = rate < 0;\n const speed = Math.abs(rate);\n // `direction` decides which end a leg runs toward; a negative playback\n // rate flips it again (the two compose, as in the Web Animations API).\n const directionReversed = tracks.direction === 'reverse' || tracks.direction === 'alternate-reverse';\n const reversedStart = backwards ? !directionReversed : directionReversed;\n const alternates = tracks.direction === 'alternate' || tracks.direction === 'alternate-reverse';\n const from = Math.max(0, Math.min(fromMs, dur));\n\n const legTarget = reversedStart ? 0 : dur;\n const legRemaining = Math.abs(legTarget - from) / speed;\n const repeats = tracks.iterations === Infinity ? -1 : tracks.iterations;\n\n cancelAnimation(progress);\n progress.value = reversedStart ? (from <= 0 ? dur : from) : (from >= dur ? 0 : from);\n\n const animation = repeats === 1\n ? withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }, (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n })\n : withRepeat(\n withTiming(legTarget, { duration: legRemaining, easing: Easing.linear }),\n repeats, alternates,\n (finished) => {\n 'worklet';\n if (finished) runOnJS(notifyFinish)();\n }\n );\n\n progress.value = tracks.delay > 0 && from === 0\n ? withDelay(tracks.delay / speed, animation)\n : animation;\n\n playingRef.current = true;\n };\n\n const api: RnAnimatorApi = {\n isPlaying: () => playingRef.current,\n play: () => {\n // `startFrom` rewinds to the opposite end when the playhead is\n // already resting at a boundary (mirrors WAAPI, where play() on a\n // finished animation auto-rewinds).\n startFrom(progress.value);\n onPlay?.();\n },\n pause: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n onPause?.();\n onStop?.();\n },\n cancel: () => {\n cancelAnimation(progress);\n progress.value = 0;\n playingRef.current = false;\n onCancel?.();\n onStop?.();\n },\n finish: () => {\n cancelAnimation(progress);\n playingRef.current = false;\n progress.value = restingPosition();\n onFinish?.();\n onStop?.();\n },\n setPlaybackRate: (rate: number) => {\n if (!isFinite(rate) || rate === 0) {\n console.warn('setPlaybackRate: rate must be finite and non-zero');\n return;\n }\n rateRef.current = rate;\n if (playingRef.current) startFrom(progress.value);\n },\n getCurrentTime: () => progress.value,\n setCurrentTime: (t: number) => {\n const wasPlaying = playingRef.current;\n cancelAnimation(progress);\n playingRef.current = false;\n const clamped = Math.max(0, Math.min(t, totalDuration));\n const withinIteration = tracks.duration > 0\n ? (clamped % tracks.duration) || (clamped === 0 ? 0 : tracks.duration)\n : 0;\n progress.value = withinIteration;\n // Seeking mid-playback continues from the new position rather than\n // silently pausing.\n if (wasPlaying) startFrom(withinIteration);\n },\n };\n\n useImperativeHandle(apiRef, () => api, [compiled]);\n\n // -- Declarative control --------------------------------------------------\n\n const trigger = compiled.doc ? getAnimatorConfig(compiled.doc)?.trigger : undefined;\n const startOn = trigger?.startOn ?? 'load';\n const outAction = outActionProp ?? trigger?.outAction ?? 'pause';\n\n useEffect(() => {\n if (progressProp !== undefined || time !== undefined) {\n const seekMs = time !== undefined ? time : (progressProp ?? 0) * totalDuration;\n api.setCurrentTime(seekMs);\n return;\n }\n if (play !== undefined || pause !== undefined) {\n if (play && !pause) api.play();\n else if (pause) api.pause();\n else if (play === false) api.finish();\n else api.play();\n return;\n }\n // 'click' and 'scrollIntoView' start from their own handlers below.\n if (autoplay && startOn === 'load') {\n api.play();\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, play, pause, progressProp, time]);\n\n // `startOn: 'scrollIntoView'` โ react-native has no IntersectionObserver, so\n // visibility is sampled by measuring the view against the window box. The\n // poll is cheap (a native measure every 200ms) and only runs while this\n // trigger is active; `outAction` decides what leaving the viewport does.\n const scrollRef = useRef<View | null>(null);\n const inViewRef = useRef(false);\n useEffect(() => {\n if (!autoplay || startOn !== 'scrollIntoView') return;\n const threshold = trigger?.scrollIntoViewThreshold ?? 0;\n inViewRef.current = false;\n\n const check = () => {\n const node = scrollRef.current;\n if (!node) return;\n node.measureInWindow((_x, y, _w, h) => {\n if (!h) return;\n const screen = Dimensions.get('window').height;\n const visible = Math.max(0, Math.min(y + h, screen) - Math.max(y, 0));\n const ratio = visible / h;\n const isIn = ratio > 0 && ratio >= threshold;\n if (isIn === inViewRef.current) return;\n inViewRef.current = isIn;\n if (isIn) {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n } else if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n });\n };\n\n check();\n const id = setInterval(check, 200);\n return () => clearInterval(id);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, autoplay, startOn, outAction]);\n\n // Stop cleanly on unmount / doc swap.\n useEffect(() => {\n return () => {\n cancelAnimation(progress);\n playingRef.current = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled]);\n\n // -- Render ---------------------------------------------------------------\n\n const trackById = useMemo(() => {\n const map = new Map<string, PxElementTracks>();\n for (const el of tracks.elements) map.set(el.id, el);\n return map;\n }, [tracks]);\n\n const warningsRef = useRef<Array<string>>([]);\n const renderErrorRef = useRef<Error | null>(null);\n const root = useMemo(() => {\n warningsRef.current = [];\n renderErrorRef.current = null;\n if (!compiled.doc) return null;\n\n const renderOpts: RenderRnNodeOptions = {\n warnings: warningsRef.current,\n defs: getDefs(compiled.doc),\n };\n try {\n return renderRnNode(compiled.doc as PxNode, {\n ...renderOpts,\n decorate: (node, Component, staticProps, children, key) => {\n // An animated definition subtree (gradient / its stops) cannot be\n // driven on the UI thread โ hand the WHOLE subtree to the\n // JS-sampled renderer and stop descending here.\n if (needsJsSampling(node, trackById)) {\n return (\n <SampledSubtree\n key={key}\n node={node}\n trackById={trackById}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n renderOpts={renderOpts}\n />\n );\n }\n\n const id = (node as any).id;\n const elTracks = id ? trackById.get(id) : undefined;\n if (!elTracks) return undefined;\n return (\n <AnimatedPxElement\n key={key}\n Component={Component}\n staticProps={staticProps}\n tracks={elTracks}\n progress={progress}\n stepMs={tracks.stepMs}\n sampleCount={tracks.sampleCount}\n >\n {children}\n </AnimatedPxElement>\n );\n },\n });\n } catch (e) {\n // Building the element tree threw โ report it and render nothing\n // rather than propagating and unmounting the host screen.\n const error = e instanceof Error ? e : new Error(String(e));\n renderErrorRef.current = error;\n console.warn('[PixodeskSvgAnimator] could not render the document:', error.message);\n return null;\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [compiled, trackById]);\n\n useEffect(() => {\n for (const w of warningsRef.current) console.warn('[PixodeskSvgAnimator]', w);\n }, [root]);\n\n // Surface compile/render failures to the host exactly once per occurrence.\n const failure = compiled.error ?? renderErrorRef.current;\n useEffect(() => {\n if (failure) onError?.(failure);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [failure]);\n\n if (failure) return fallback ? fallback(failure) : null;\n\n // `startOn: 'click'` โ the touch analogue of the web player's click trigger:\n // tap to start, tap again to apply `outAction`. Hover (`mouseOver`) has no\n // touch equivalent and `scrollIntoView` needs the surrounding scroll view,\n // so both are left to the host app.\n let content: ReactElement | null = root;\n\n if (autoplay && startOn === 'scrollIntoView' && root) {\n // `collapsable={false}` keeps the view in the native tree so it can be measured.\n content = <View ref={scrollRef} collapsable={false}>{root}</View>;\n } else if (autoplay && startOn === 'click' && root) {\n content = (\n <Pressable\n onPress={() => {\n if (playingRef.current) {\n if (outAction === 'reset') api.cancel();\n else if (outAction === 'reverse') { api.setPlaybackRate(-Math.abs(rateRef.current || 1)); api.play(); }\n else if (outAction !== 'continue') api.pause();\n } else {\n if (rateRef.current < 0) api.setPlaybackRate(Math.abs(rateRef.current));\n api.play();\n }\n }}\n >\n {root}\n </Pressable>\n );\n }\n\n // Catches what the try/catch above cannot: throws during React's own render\n // and commit of the tree โ react-native-svg internals, reanimated failing\n // to attach to a component that turns out not to be a host view, and so on.\n return (\n <PxRnErrorBoundary onError={onError} fallback={fallback}>\n {content}\n </PxRnErrorBoundary>\n );\n}\n\nexport default PixodeskSvgAnimator;\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 {\n calcAnimationValues,\n getAnimatorConfig,\n getNormalisedBindings,\n DEFAULT_DURATION_MS,\n PxAnimatorEngine,\n type PxAnimatedSvgDocument,\n type PxAnimationDefinition,\n} from '@pixodesk/svg-animator-core';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\n/**\n * Sampled animation tracks for ONE element: prop name โ per-sample values.\n *\n * The compiler densely samples every animated property through core's\n * `calcAnimationValues` โ the exact function the web frames engine renders\n * with โ so RN playback is value-identical to the web player. Easing, loops,\n * transform composition, colour interpolation and path morphing are all baked\n * into the samples at compile time; the UI-thread worklet only indexes arrays.\n */\nexport interface PxElementTracks {\n /** Element id (after id regeneration). */\n id: string;\n /** react-native-svg prop name โ one value per sample. */\n props: Record<string, Array<string | number | Array<number>>>;\n}\n\nexport interface PxCompiledTracks {\n /** Per-iteration duration, ms. */\n duration: number;\n /** Iteration count (Infinity for 'infinite'). */\n iterations: number;\n /** 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' */\n direction: string;\n /** Delay before start, ms (positive = wait). */\n delay: number;\n /** WAAPI-style fill mode (default 'forwards'). */\n fill: string;\n /** When true, snap back to the start after a natural finish. */\n resetOnFinish: boolean;\n /** Sample step, ms. */\n stepMs: number;\n /** Number of samples per iteration (>= 2; sample i is at time i*stepMs). */\n sampleCount: number;\n /** Tracks for every animated element. */\n elements: Array<PxElementTracks>;\n}\n\nexport interface CompileTracksOptions {\n /** Target sample rate, samples/second. Default 60 (one per frame). */\n sampleRate?: number;\n /** Hard cap on samples per iteration (memory guard). Default 600. */\n maxSamples?: number;\n /**\n * Sample values in the form the NATIVE react-native-svg views expect\n * (currently: `transform` as a 6-number matrix rather than an SVG string).\n *\n * Defaults to `false` โ the plain SVG form, which is what react-native-web\n * hands straight to the DOM. Only the component knows the platform, so it\n * decides; every consumer that does not opt in keeps DOM-compatible values.\n */\n native?: boolean;\n}\n\n\n\n/**\n * Compiles a MATERIALISED document (run `materialiseAllInTree(doc, 'frames')`\n * + `generateNewIds` first) into densely sampled per-element tracks.\n */\nexport function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksOptions): PxCompiledTracks {\n const config = getAnimatorConfig(doc) || {};\n\n const duration = +(config.duration || DEFAULT_DURATION_MS);\n const _iterations = config.iterations;\n let iterations = 1;\n if (typeof _iterations === 'number') iterations = _iterations || 1;\n if (_iterations === 'infinite') iterations = Infinity;\n if (iterations < 1) iterations = 1;\n\n const native = opts?.native ?? false;\n const sampleRate = opts?.sampleRate ?? 60;\n const maxSamples = opts?.maxSamples ?? 600;\n let sampleCount = Math.max(2, Math.round((duration / 1000) * sampleRate) + 1);\n if (sampleCount > maxSamples) sampleCount = maxSamples;\n const stepMs = duration / (sampleCount - 1);\n\n // Element tag per id โ `toRnPropValue` needs it to leave the root `<Svg>`'s\n // transform as a string (see its `tag` parameter).\n const tagById = new Map<string, string>();\n const indexTags = (n: any): void => {\n if (n && typeof n.id === 'string') tagById.set(n.id, String(n.type));\n (n?.children ?? []).forEach(indexTags);\n };\n indexTags(doc);\n\n const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames) || [];\n\n const elements: Array<PxElementTracks> = [];\n for (const binding of bindings) {\n const animDef = binding.animate;\n if (!animDef || typeof animDef !== 'object' || Array.isArray(animDef)) continue;\n\n const props: Record<string, Array<string | number | Array<number>>> = {};\n for (let i = 0; i < sampleCount; i++) {\n const t = i === sampleCount - 1 ? duration : i * stepMs;\n const values = calcAnimationValues(animDef as PxAnimationDefinition, t);\n for (const [attr, value] of Object.entries(values)) {\n const rnProp = toRnPropName(attr);\n if (!rnProp) continue;\n let arr = props[rnProp];\n if (!arr) {\n arr = props[rnProp] = new Array(sampleCount);\n // A prop can appear late (e.g. attrs whose first kf is\n // beyond t=0) โ backfill earlier samples with the first\n // computed value so the array is always fully populated.\n for (let j = 0; j < i; j++) arr[j] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n arr[i] = toRnPropValue(rnProp, value, tagById.get(binding.id), native);\n }\n }\n // Forward-fill any holes (attr disappeared from a later sample).\n for (const arr of Object.values(props)) {\n for (let i = 1; i < sampleCount; i++) {\n if (arr[i] === undefined) arr[i] = arr[i - 1];\n }\n }\n\n if (Object.keys(props).length > 0) {\n elements.push({ id: binding.id, props });\n }\n }\n\n return {\n duration,\n iterations,\n direction: config.direction || 'normal',\n delay: config.delay || 0,\n fill: config.fill ?? 'forwards',\n resetOnFinish: !!config.resetOnFinish,\n stepMs,\n sampleCount,\n elements,\n };\n}\n\n/**\n * Wire prop โ the prop name the NATIVE view actually declares.\n *\n * react-native-svg's JS layer renames some props on the way down: a\n * `transform` (string or matrix) is parsed by `extractProps` and handed to the\n * native component as `matrix` โ the Fabric spec has no `transform` prop at\n * all. Values sent through reanimated's animated-props path skip that JS\n * rename, so they must already use the native name or the native view drops\n * them silently. This is ONLY for the animated path; plain React renders still\n * go through the JS layer and must keep the wire name.\n */\nexport const NATIVE_PROP_NAME: Record<string, string> = {\n transform: 'matrix',\n};\n\n/**\n * Worklet-safe sample lookup: returns the per-prop values at time `tMs`\n * (already mapped into a single iteration by the caller). Kept deliberately\n * trivial โ runs on the UI thread every frame.\n *\n * `native = true` applies {@link NATIVE_PROP_NAME} โ pass it only on the\n * reanimated animated-props path of a real device. Props that are applied by\n * re-rendering through React (and therefore still pass through react-native-svg's\n * JS layer), and every value on the web, must keep the wire name.\n */\nexport function sampleProps(\n tracks: PxElementTracks,\n tMs: number,\n stepMs: number,\n sampleCount: number,\n native = false\n): Record<string, string | number | Array<number>> {\n 'worklet';\n const out: Record<string, string | number | Array<number>> = {};\n // Defensive: this runs on the UI thread, where a throw is a hard crash\n // with no React boundary to catch it.\n if (!tracks || !tracks.props || !(stepMs > 0)) return out;\n\n let idx = Math.round(tMs / stepMs);\n if (idx < 0) idx = 0;\n if (idx >= sampleCount) idx = sampleCount - 1;\n for (const key in tracks.props) {\n const values = tracks.props[key];\n if (!values) continue;\n const value = values[idx];\n if (value === undefined) continue;\n const name = native && key === 'transform' ? 'matrix' : key;\n out[name] = value;\n }\n return out;\n}\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 { kebabToCamelCaseWord } from '@pixodesk/svg-animator-core';\nimport { svgTransformToMatrix } from './PxRnMatrix';\n\n/** Attribute names with a react-native-svg prop equivalent under a\n * different name (not just a casing change). */\nconst ATTR_NAME_OVERRIDES: Record<string, string> = {\n 'xlink:href': 'href',\n};\n\n/** Props react-native-svg does not understand / must not receive. */\nconst DROPPED_ATTRS = new Set(['class', 'className', 'style', 'xmlns', 'xmlns:xlink', 'data-px-meta']);\n\n/**\n * Converts one normalised wire attribute name (camelCase after core's\n * `getNormalizedProps`, or kebab-case raw) to a react-native-svg prop name.\n * Returns undefined for props that must be dropped.\n *\n * Pure (no react-native-svg import) so the track compiler and its tests\n * don't need a React Native environment.\n */\nexport function toRnPropName(attrName: string): string | undefined {\n if (DROPPED_ATTRS.has(attrName)) return undefined;\n const override = ATTR_NAME_OVERRIDES[attrName];\n if (override) return override;\n // react-native-svg uses camelCase props (strokeWidth, fillOpacity, โฆ);\n // core's kebabToCamelCaseWord is a no-op for already-camelCase input.\n return kebabToCamelCaseWord(attrName);\n}\n\n/** Props whose value is a LIST of lengths. react-native-svg's native side\n * expects a number array here (its JS `extractLengthList` splits strings, but\n * values delivered through reanimated's animated-props path bypass that JS\n * extraction and reach the native view directly). */\nconst LENGTH_LIST_PROPS = new Set(['strokeDasharray']);\n\n/**\n * Converts one already-renamed prop value into the shape react-native-svg\n * expects: length-list props become number arrays; numeric strings become\n * numbers; everything else passes through.\n */\nexport function toRnPropValue(\n rnPropName: string,\n value: string | number,\n /** The owning element's tag. The ROOT `<Svg>` handles `transform` through a\n * different code path (`extractTransformSvgView`, which wants a string or\n * an RN style) โ a matrix there would be dropped, so leave it alone. */\n tag?: string,\n /** Opt in to the NATIVE representation of a value (see below). Defaults to\n * off, so web keeps the plain SVG/DOM form it has always been given. */\n native = false,\n): string | number | Array<number> {\n // On a device `transform` must arrive as a matrix, not a string: the\n // stringโmatrix parse happens in JS during render, which reanimated's\n // animated-props path skips entirely. See PxRnMatrix for the full why.\n // On the web the DOM parses the string itself and an array would serialise\n // to a meaningless `transform=\"1,0,0,1,3,4\"`, so it must stay a string.\n if (native && rnPropName === 'transform' && typeof value === 'string' && tag !== 'svg') {\n const m = svgTransformToMatrix(value);\n if (m) return m;\n }\n if (LENGTH_LIST_PROPS.has(rnPropName)) {\n const parts = String(value).trim().replace(/,/g, ' ').split(/\\s+/).map(Number).filter(n => Number.isFinite(n));\n // An odd-length dasharray repeats to become even (SVG spec); rn-svg\n // does this itself for the static path โ mirror it so both paths agree.\n return parts.length % 2 === 1 ? parts.concat(parts) : parts;\n }\n if (typeof value === 'number') return value;\n const num = +value;\n return Number.isFinite(num) && String(num) === value ? num : value;\n}\n","/*---------------------------------------------------------------------------------------\n * Copyright (c) Pixodesk LTD.\n * Licensed under the MIT License. See the LICENSE file in the project root for details.\n *---------------------------------------------------------------------------------------*/\n\n/**\n * SVG transform string โ 2D affine matrix, in the order react-native-svg's\n * native side expects: `[a, b, c, d, e, f]`, i.e. SVG's own `matrix(โฆ)` order\n *\n * ```\n * | a c e |\n * | b d f |\n * | 0 0 1 |\n * ```\n *\n * WHY THIS EXISTS: react-native-svg parses a `transform` STRING into this matrix\n * in JavaScript, inside `extractTransform`, during render. Values delivered\n * through reanimated's `animatedProps` bypass that JS step and reach the native\n * view directly, where a raw string is meaningless โ an animated transform\n * simply does nothing. Feeding the matrix instead makes the animated and static\n * paths agree. (On the web the DOM parses the string itself, which is why this\n * only shows up on a device.)\n */\nexport type Mat2D = [number, number, number, number, number, number];\n\nexport const IDENTITY: Mat2D = [1, 0, 0, 1, 0, 0];\n\nconst DEG = Math.PI / 180;\n\n/** `m1 ยท m2` โ apply m2 first, then m1 (same convention as SVG's left-to-right list). */\nfunction multiply(m1: Mat2D, m2: Mat2D): Mat2D {\n const [a1, b1, c1, d1, e1, f1] = m1;\n const [a2, b2, c2, d2, e2, f2] = m2;\n return [\n a1 * a2 + c1 * b2,\n b1 * a2 + d1 * b2,\n a1 * c2 + c1 * d2,\n b1 * c2 + d1 * d2,\n a1 * e2 + c1 * f2 + e1,\n b1 * e2 + d1 * f2 + f1,\n ];\n}\n\n/** Splits `translate(1,2)rotate(45)` into `[['translate',[1,2]], ['rotate',[45]]]`. */\nconst FN_RE = /([a-zA-Z]+)\\s*\\(([^)]*)\\)/g;\n\nfunction numbers(raw: string): Array<number> {\n return raw\n .split(/[\\s,]+/)\n .filter(s => s.length > 0)\n .map(Number)\n .filter(n => Number.isFinite(n));\n}\n\n/**\n * Parses an SVG transform list. Returns `undefined` when the string contains no\n * recognisable function, so callers can leave the original value untouched\n * rather than silently replacing it with an identity matrix.\n */\nexport function svgTransformToMatrix(value: string): Mat2D | undefined {\n let m: Mat2D | undefined;\n FN_RE.lastIndex = 0;\n\n let match: RegExpExecArray | null;\n while ((match = FN_RE.exec(value)) !== null) {\n const fn = match[1].toLowerCase();\n const n = numbers(match[2]);\n let step: Mat2D | undefined;\n\n switch (fn) {\n case 'translate':\n step = [1, 0, 0, 1, n[0] || 0, n[1] || 0];\n break;\n case 'scale': {\n const sx = n[0] ?? 1;\n const sy = n.length > 1 ? n[1] : sx;\n step = [sx, 0, 0, sy, 0, 0];\n break;\n }\n case 'rotate': {\n const rad = (n[0] || 0) * DEG;\n const cos = Math.cos(rad), sin = Math.sin(rad);\n const rot: Mat2D = [cos, sin, -sin, cos, 0, 0];\n if (n.length >= 3) {\n // rotate(a, cx, cy) == translate(cx,cy) rotate(a) translate(-cx,-cy)\n const cx = n[1], cy = n[2];\n step = multiply(multiply([1, 0, 0, 1, cx, cy], rot), [1, 0, 0, 1, -cx, -cy]);\n } else {\n step = rot;\n }\n break;\n }\n case 'skewx':\n step = [1, 0, Math.tan((n[0] || 0) * DEG), 1, 0, 0];\n break;\n case 'skewy':\n step = [1, Math.tan((n[0] || 0) * DEG), 0, 1, 0, 0];\n break;\n case 'matrix':\n if (n.length >= 6) step = [n[0], n[1], n[2], n[3], n[4], n[5]];\n break;\n default:\n step = undefined; // unknown function โ ignore it\n }\n\n if (step) m = m ? multiply(m, step) : step;\n }\n\n return m;\n}\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 {\n getNormalizedProps,\n resolveStyle,\n sanitiseAttributeValue,\n DISALLOWED_SVG_TAGS_LOWER,\n TEXT_ATTR,\n TEXT_CONTENT_ATTR,\n type PxDefs,\n type PxNode,\n} from '@pixodesk/svg-animator-core';\nimport { createElement, type ComponentType, type ReactElement, type ReactNode } from 'react';\nimport { RN_SVG_COMPONENTS } from './PxRnTypeMap';\nimport { toRnPropName, toRnPropValue } from './PxRnPropNames';\n\nexport interface RenderRnNodeOptions {\n /** Collects non-fatal issues (unsupported tags, dropped attrs). */\n warnings?: Array<string>;\n /** `definitions` from the document, used to resolve named `style` presets. */\n defs?: PxDefs;\n /**\n * Wraps the created element for animated nodes: receives the resolved\n * component + static props and returns the element to mount (the animator\n * substitutes an Animated component wired to its tracks). Return undefined\n * to keep the plain static element.\n *\n * `key` is handed over SEPARATELY and is deliberately absent from `props`:\n * React 19 warns when a props object containing `key` is spread into JSX,\n * and implementations of this hook do exactly that.\n */\n decorate?: (\n node: PxNode,\n Component: ComponentType<any>,\n props: Record<string, any>,\n children: ReactNode,\n key: string | number | undefined\n ) => ReactElement | undefined;\n}\n\n/**\n * Converts core-normalised wire props into react-native-svg props: RN prop\n * naming, sanitisation (same security rules as the web renderer), numeric\n * coercion where possible.\n */\nexport function toRnProps(props: Record<string, any>, warnings?: Array<string>, tag?: string): Record<string, any> {\n const normalised = getNormalizedProps(props);\n const out: Record<string, any> = {};\n for (const key of Object.keys(normalised)) {\n const sanitised = sanitiseAttributeValue(key, normalised[key]);\n if (sanitised === undefined) continue;\n const rnKey = toRnPropName(key);\n if (!rnKey) continue;\n out[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n return out;\n}\n\n/**\n * Renders a (materialised) PxNode tree to react-native-svg elements.\n * Mirrors the web `renderNode` contract: unsupported/dangerous tags are\n * skipped with a warning, never a crash.\n */\nexport function renderRnNode(node: PxNode, opts: RenderRnNodeOptions = {}, key?: string | number): ReactElement | null {\n if (!node) return null;\n\n const { type, children, style, animate, meta, effects, ...props } = node as any;\n const tag = String(type || 'g');\n\n // ESCAPE KEY (S2): elements whose SVG `type` ATTRIBUTE collides with the reserved\n // `type` node-tag key carry it under `domType` โ `feColorMatrix` (matrix/saturate/โฆ),\n // `feTurbulence` (fractalNoise/turbulence), `feFunc*` (identity/table/โฆ).\n // Restore it as a real prop, mirroring the web renderer.\n const domType: string | undefined = props.domType;\n if (domType !== undefined) delete props.domType;\n\n if (DISALLOWED_SVG_TAGS_LOWER.has(tag.toLowerCase())) {\n opts.warnings?.push('tag blocked (dangerous): ' + tag);\n return null;\n }\n\n const Component = RN_SVG_COMPONENTS[tag];\n if (!Component) {\n opts.warnings?.push('tag not supported in react-native-svg mapping: ' + tag);\n return null;\n }\n\n // NB: `key` is never written into this object โ see `decorate` above.\n const rnProps = toRnProps(props, opts.warnings, tag);\n if (domType !== undefined) rnProps.type = domType;\n\n // `node.style` โ a named preset from `definitions.styles`, or an inline\n // record. react-native-svg has no CSS, so the resolved declarations are\n // applied as ordinary props (the same names, e.g. `fill`, `strokeWidth`).\n // Explicit attributes on the node win over the style block.\n const resolved = resolveStyle(style, opts.defs);\n if (resolved) {\n for (const [k, v] of Object.entries(resolved)) {\n const rnKey = toRnPropName(k);\n if (!rnKey || rnKey in rnProps) continue;\n const sanitised = sanitiseAttributeValue(rnKey, v);\n if (sanitised === undefined) continue;\n rnProps[rnKey] = toRnPropValue(rnKey, String(sanitised), tag);\n }\n }\n\n // Text content: wire nodes carry it as `text` / `textContent` attr.\n const textContent: string | undefined = props[TEXT_ATTR] || props[TEXT_CONTENT_ATTR];\n\n let childElements: ReactNode = undefined;\n if (Array.isArray(children) && children.length > 0) {\n childElements = children\n .map((ch: PxNode, i: number) => {\n // One malformed child should cost that child, not the whole tree.\n try {\n return renderRnNode(ch, opts, i);\n } catch (e) {\n opts.warnings?.push('child failed to render: ' + (e instanceof Error ? e.message : String(e)));\n return null;\n }\n })\n .filter(Boolean);\n } else if (textContent !== undefined) {\n childElements = String(textContent);\n }\n\n const decorated = opts.decorate?.(node, Component, rnProps, childElements, key);\n if (decorated !== undefined) return decorated;\n\n // `createElement` takes `key` in its config object โ that path does NOT\n // trigger React's JSX-spread warning.\n return createElement(\n Component,\n key !== undefined ? { ...rnProps, key } : rnProps,\n childElements\n );\n}\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 {\n Circle,\n ClipPath,\n Defs,\n Ellipse,\n FeBlend,\n FeColorMatrix,\n FeComponentTransfer,\n FeComposite,\n FeConvolveMatrix,\n FeDiffuseLighting,\n FeDisplacementMap,\n FeDistantLight,\n FeDropShadow,\n FeFlood,\n FeFuncA,\n FeFuncB,\n FeFuncG,\n FeFuncR,\n FeGaussianBlur,\n FeImage,\n FeMerge,\n FeMergeNode,\n FeMorphology,\n FeOffset,\n FePointLight,\n FeSpecularLighting,\n FeSpotLight,\n FeTile,\n FeTurbulence,\n Filter,\n G,\n Image,\n Line,\n LinearGradient,\n Marker,\n Mask,\n Path,\n Pattern,\n Polygon,\n Polyline,\n RadialGradient,\n Rect,\n Stop,\n Svg,\n Symbol as SvgSymbol,\n Text as SvgText,\n TextPath,\n TSpan,\n Use,\n} from 'react-native-svg';\nimport type { ComponentType } from 'react';\n\n/**\n * SVG tag โ react-native-svg component. Tags not in this map are skipped at\n * render time (with a warning collected by the renderer) โ they go on the\n * feature-gap list rather than crashing the tree.\n *\n * Keys are the wire-format `node.type` values, which follow SVG's own casing\n * (`clipPath`, `feGaussianBlur`, `linearGradient`, โฆ).\n */\nexport const RN_SVG_COMPONENTS: Record<string, ComponentType<any>> = {\n // Root & containers\n svg: Svg,\n g: G,\n defs: Defs,\n symbol: SvgSymbol,\n use: Use,\n\n // Shapes\n rect: Rect,\n circle: Circle,\n ellipse: Ellipse,\n line: Line,\n path: Path,\n polygon: Polygon,\n polyline: Polyline,\n image: Image,\n\n // Text\n text: SvgText,\n tspan: TSpan,\n textPath: TextPath,\n\n // Paint servers & clipping\n linearGradient: LinearGradient,\n radialGradient: RadialGradient,\n stop: Stop,\n pattern: Pattern,\n mask: Mask,\n clipPath: ClipPath,\n marker: Marker,\n\n // Filters โ react-native-svg implements the full primitive set.\n // NOTE: filter rendering requires the New Architecture (Fabric) and is\n // newer than the rest of react-native-svg; treat visual parity with the\n // web player as unverified until checked on a device.\n filter: Filter,\n feBlend: FeBlend,\n feColorMatrix: FeColorMatrix,\n feComponentTransfer: FeComponentTransfer,\n feComposite: FeComposite,\n feConvolveMatrix: FeConvolveMatrix,\n feDiffuseLighting: FeDiffuseLighting,\n feDisplacementMap: FeDisplacementMap,\n feDistantLight: FeDistantLight,\n feDropShadow: FeDropShadow,\n feFlood: FeFlood,\n feFuncA: FeFuncA,\n feFuncB: FeFuncB,\n feFuncG: FeFuncG,\n feFuncR: FeFuncR,\n feGaussianBlur: FeGaussianBlur,\n feImage: FeImage,\n feMerge: FeMerge,\n feMergeNode: FeMergeNode,\n feMorphology: FeMorphology,\n feOffset: FeOffset,\n fePointLight: FePointLight,\n feSpecularLighting: FeSpecularLighting,\n feSpotLight: FeSpotLight,\n feTile: FeTile,\n feTurbulence: FeTurbulence,\n};\n\nexport { toRnPropName } from './PxRnPropNames';\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 { Component, type ErrorInfo, type ReactNode } from 'react';\n\nexport interface PxRnErrorBoundaryProps {\n children: ReactNode;\n /** Rendered instead of the children once something has thrown. */\n fallback?: (error: Error) => ReactNode;\n onError?: (error: Error, info?: string) => void;\n}\n\ninterface State {\n error: Error | null;\n}\n\n/**\n * Keeps one bad animation from taking down the screen around it.\n *\n * A throw anywhere in the rendered SVG tree โ an unsupported prop shape, a\n * react-native-svg internal, a reanimated attachment failure โ otherwise\n * unmounts the whole React tree above it. Here it is contained to this one\n * animation, reported through `onError`, and replaced by `fallback`.\n *\n * NOTE the limit: this catches JavaScript errors only. A crash INSIDE the\n * native renderer (see `openClosedTextPathTargets` for a real example) never\n * reaches JavaScript and cannot be caught here โ those have to be avoided\n * rather than handled.\n */\nexport class PxRnErrorBoundary extends Component<PxRnErrorBoundaryProps, State> {\n override state: State = { error: null };\n\n static getDerivedStateFromError(error: Error): State {\n return { error };\n }\n\n override componentDidCatch(error: Error, info: ErrorInfo): void {\n this.props.onError?.(error, info?.componentStack ?? undefined);\n console.warn('[PixodeskSvgAnimator] render failed:', error?.message ?? error);\n }\n\n override componentDidUpdate(prev: PxRnErrorBoundaryProps): void {\n // A new document deserves a fresh attempt โ otherwise the boundary\n // would stay latched on the failure for the rest of its life.\n if (this.state.error && prev.children !== this.props.children) {\n this.setState({ error: null });\n }\n }\n\n override render(): ReactNode {\n const { error } = this.state;\n if (error) return this.props.fallback ? this.props.fallback(error) : null;\n return this.props.children;\n }\n}\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 { deepClone, generateUniqueId, type PxNode } from '@pixodesk/svg-animator-core';\n\n/**\n * Workarounds for defects in react-native-svg's NATIVE renderer that would\n * otherwise take the whole app down.\n *\n * These are applied only when the native views are in use โ never on the web,\n * where the DOM handles all of this correctly and the document must be left\n * exactly as the core pipeline produced it.\n */\n\n/** True when a path's `d` contains a close-subpath command. */\nfunction isClosedPath(d: unknown): boolean {\n return typeof d === 'string' && /[zZ]/.test(d);\n}\n\n/** Drops close-subpath commands, turning a closed outline into an open one. */\nfunction openPath(d: string): string {\n return d.replace(/[zZ]/g, '').trimEnd();\n}\n\n/** `#foo` โ `foo`. Returns undefined for anything that is not a local ref. */\nfunction localRef(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n const trimmed = value.trim();\n return trimmed.startsWith('#') ? trimmed.slice(1) : undefined;\n}\n\nfunction forEachNode(node: PxNode | undefined, visit: (n: PxNode, parent?: PxNode) => void, parent?: PxNode): void {\n if (!node) return;\n visit(node, parent);\n for (const child of (node.children ?? [])) forEachNode(child, visit, node);\n}\n\n/**\n * Gives every `<textPath>` that follows a CLOSED path its own OPEN copy of it.\n *\n * WHY: react-native-svg's native text-on-path layout crashes the app โ\n * an uncatchable `NSRangeException` on iOS โ for this combination.\n * `RNSVGTSpan.mm` skips glyphs outside `[startOfRendering, endOfRendering]`,\n * but for a closed path it sets those bounds to `startOffset โฆ startOffset +\n * pathLength` instead of `0 โฆ pathLength`. Any glyph past the end of the path\n * therefore survives the bounds check and reaches `getPosAndTan`, whose\n * `indexOfObjectPassingTest` returns `NSNotFound` โ and indexing the lengths\n * array with `NSNotFound` throws. A non-zero `startOffset` on a closed path is\n * all it takes, and animating `startOffset` guarantees hitting it.\n *\n * Opening the path restores the `0 โฆ pathLength` bounds, so out-of-range\n * glyphs are skipped as intended. The copy is private to the `<textPath>`, so\n * anything else drawing the same path still gets the closed original. For a\n * shape whose ends already meet (a circle, the usual case) the removed segment\n * has zero length and nothing changes visually at all.\n *\n * Returns the document unchanged โ the same object โ when nothing matches.\n */\nexport function openClosedTextPathTargets(doc: PxNode, warnings?: Array<string>): PxNode {\n // Cheap pre-check: the overwhelming majority of documents have no textPath.\n let hasTextPath = false;\n forEachNode(doc, n => { if (String(n.type) === 'textPath') hasTextPath = true; });\n if (!hasTextPath) return doc;\n\n const result = deepClone(doc);\n\n const byId = new Map<string, PxNode>();\n forEachNode(result, n => {\n const id = (n as any).id;\n if (typeof id === 'string') byId.set(id, n);\n });\n\n /** The copy is a geometry reference, never something to draw โ so it goes\n * in `<defs>`, alongside the paths textPath targets normally live in. */\n let defs = (result.children ?? []).find(c => String(c.type) === 'defs');\n const ensureDefs = (): PxNode => {\n if (!defs) {\n defs = { type: 'defs', children: [] } as unknown as PxNode;\n (result.children ??= []).unshift(defs);\n }\n return defs;\n };\n\n /** Original path id โ id of the open copy, so N textPaths share one copy. */\n const openCopies = new Map<string, string>();\n\n forEachNode(result, node => {\n if (String(node.type) !== 'textPath') return;\n\n const anyNode = node as any;\n const attr = anyNode.href !== undefined ? 'href' : 'xlink:href';\n const targetId = localRef(anyNode[attr]);\n if (!targetId) return;\n\n const target = byId.get(targetId);\n if (!target || !isClosedPath((target as any).d)) return;\n\n let copyId = openCopies.get(targetId);\n if (!copyId) {\n const copy = deepClone(target) as any;\n copyId = 'px_open_' + generateUniqueId();\n copy.id = copyId;\n copy.d = openPath(String(copy.d));\n // A copy that also carried animation would animate twice; the copy\n // exists purely as a geometry reference for the text.\n delete copy.animate;\n delete copy.effects;\n\n (ensureDefs().children ??= []).push(copy);\n openCopies.set(targetId, copyId);\n warnings?.push(\n 'textPath follows a closed path (#' + targetId + '); using an open copy to ' +\n 'avoid a react-native-svg native crash'\n );\n }\n\n anyNode[attr] = '#' + copyId;\n });\n\n return result;\n}\n"],"mappings":"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","names":["getAnimatorConfig","PxAnimatorEngine","createElement","_a","Component","_a","_a","Component","createElement","PxAnimatorEngine","getAnimatorConfig","_a"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixodesk/svg-animator-rn",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.34",
|
|
4
4
|
"description": "Pixodesk SVG animator for React Native โ renders animator documents via react-native-svg, driven natively by react-native-reanimated",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"src"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@pixodesk/svg-animator-core": "^1.0.
|
|
29
|
+
"@pixodesk/svg-animator-core": "^1.0.34"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"react": ">=18",
|
|
@@ -117,10 +117,10 @@ export interface PixodeskSvgAnimatorProps {
|
|
|
117
117
|
// -- Controlled (external) time -------------------------------------------
|
|
118
118
|
|
|
119
119
|
/** Seek to a fraction (0โ1) of the whole timeline (duration ร iterations). */
|
|
120
|
-
|
|
120
|
+
progress?: number;
|
|
121
121
|
|
|
122
122
|
/** Seek to a specific time in milliseconds. */
|
|
123
|
-
|
|
123
|
+
time?: number;
|
|
124
124
|
|
|
125
125
|
// -- Callbacks ------------------------------------------------------------
|
|
126
126
|
|
|
@@ -367,7 +367,8 @@ function compileDocument(doc: PxAnimatedSvgDocument, overrides: ConfigOverrides)
|
|
|
367
367
|
*/
|
|
368
368
|
export function PixodeskSvgAnimator({
|
|
369
369
|
doc, duration, delay, iterations, fill, direction, resetOnFinish, outAction: outActionProp,
|
|
370
|
-
|
|
370
|
+
// (`progress` prop aliased โ the name is taken by the internal reanimated SharedValue)
|
|
371
|
+
autoplay, play, pause, apiRef, progress: progressProp, time,
|
|
371
372
|
onPlay, onStop, onPause, onCancel, onFinish, onError, fallback,
|
|
372
373
|
}: PixodeskSvgAnimatorProps): ReactElement | null {
|
|
373
374
|
|
|
@@ -518,8 +519,8 @@ export function PixodeskSvgAnimator({
|
|
|
518
519
|
const outAction = outActionProp ?? trigger?.outAction ?? 'pause';
|
|
519
520
|
|
|
520
521
|
useEffect(() => {
|
|
521
|
-
if (
|
|
522
|
-
const seekMs =
|
|
522
|
+
if (progressProp !== undefined || time !== undefined) {
|
|
523
|
+
const seekMs = time !== undefined ? time : (progressProp ?? 0) * totalDuration;
|
|
523
524
|
api.setCurrentTime(seekMs);
|
|
524
525
|
return;
|
|
525
526
|
}
|
|
@@ -535,7 +536,7 @@ export function PixodeskSvgAnimator({
|
|
|
535
536
|
api.play();
|
|
536
537
|
}
|
|
537
538
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
538
|
-
}, [compiled, autoplay, play, pause,
|
|
539
|
+
}, [compiled, autoplay, play, pause, progressProp, time]);
|
|
539
540
|
|
|
540
541
|
// `startOn: 'scrollIntoView'` โ react-native has no IntersectionObserver, so
|
|
541
542
|
// visibility is sampled by measuring the view against the window box. The
|
package/src/PxRnTracks.test.ts
CHANGED
|
@@ -153,7 +153,7 @@ describe('length-list props (stroke-dasharray)', () => {
|
|
|
153
153
|
animator: { mode: 'frames', duration: 1000 },
|
|
154
154
|
children: [{
|
|
155
155
|
type: 'path', id: 'p', d: 'M 0 50 L 100 50', stroke: '#000', fill: 'none',
|
|
156
|
-
effects: {
|
|
156
|
+
effects: { strokeTrim: { range: { keyframes: [{ time: 0, value: [0, 0.1] }, { time: 1000, value: [0, 1] }] } } },
|
|
157
157
|
}],
|
|
158
158
|
};
|
|
159
159
|
const materialised = generateNewIds(materialiseAllInTree(doc, PxAnimatorEngine.waapi));
|