@pixodesk/svg-animator-rn 1.0.21
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/LICENSE +21 -0
- package/dist/index.cjs +459 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +158 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +470 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/src/PixodeskSvgAnimator.tsx +386 -0
- package/src/PxRnPropNames.ts +55 -0
- package/src/PxRnRender.tsx +94 -0
- package/src/PxRnTracks.test.ts +185 -0
- package/src/PxRnTracks.ts +150 -0
- package/src/PxRnTypeMap.ts +64 -0
- package/src/index.ts +15 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Pixodesk LTD.
|
|
3
|
+
* Licensed under the MIT License. See the LICENSE file in the project root for details.
|
|
4
|
+
*---------------------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, it } from 'vitest';
|
|
7
|
+
import { generateNewIds, materialiseAllInTree, PxAnimatorEngine, type PxAnimatedSvgDocument } from '@pixodesk/svg-animator-core';
|
|
8
|
+
import { compileTracks, sampleProps } from './PxRnTracks';
|
|
9
|
+
import { toRnPropName } from './PxRnPropNames';
|
|
10
|
+
|
|
11
|
+
function makeDoc(): PxAnimatedSvgDocument {
|
|
12
|
+
return {
|
|
13
|
+
type: 'svg',
|
|
14
|
+
viewBox: '0 0 200 200',
|
|
15
|
+
animator: { mode: 'frames', duration: 1000, iterations: 2, direction: 'alternate' },
|
|
16
|
+
children: [
|
|
17
|
+
{
|
|
18
|
+
type: 'rect',
|
|
19
|
+
id: 'r1',
|
|
20
|
+
x: 0, y: 0, width: 50, height: 50, fill: '#3b82f6',
|
|
21
|
+
animate: {
|
|
22
|
+
opacity: { keyframes: [{ time: 0, value: 1 }, { time: 1000, value: 0 }] },
|
|
23
|
+
fill: { keyframes: [{ time: 0, value: '#3b82f6' }, { time: 1000, value: '#ec4899' }] },
|
|
24
|
+
'stroke-width': { keyframes: [{ time: 0, value: 1 }, { time: 1000, value: 5 }] },
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'g',
|
|
29
|
+
id: 'g1',
|
|
30
|
+
animate: {
|
|
31
|
+
translate: { keyframes: [{ time: 0, value: [0, 0] }, { time: 1000, value: [100, 100] }] },
|
|
32
|
+
},
|
|
33
|
+
children: [{ type: 'circle', cx: 0, cy: 0, r: 10, fill: '#000' }],
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function compile(doc = makeDoc(), opts?: Parameters<typeof compileTracks>[1]) {
|
|
40
|
+
const materialised = generateNewIds(materialiseAllInTree(doc, PxAnimatorEngine.frames));
|
|
41
|
+
return compileTracks(materialised, opts);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('compileTracks', () => {
|
|
45
|
+
it('captures animator config (duration, iterations, direction, fill default)', () => {
|
|
46
|
+
const tracks = compile();
|
|
47
|
+
expect(tracks.duration).toBe(1000);
|
|
48
|
+
expect(tracks.iterations).toBe(2);
|
|
49
|
+
expect(tracks.direction).toBe('alternate');
|
|
50
|
+
expect(tracks.fill).toBe('forwards');
|
|
51
|
+
expect(tracks.sampleCount).toBeGreaterThanOrEqual(2);
|
|
52
|
+
expect(tracks.stepMs * (tracks.sampleCount - 1)).toBeCloseTo(1000, 6);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('produces one track set per animated element', () => {
|
|
56
|
+
const tracks = compile();
|
|
57
|
+
expect(tracks.elements.length).toBe(2);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('samples numeric props with endpoint accuracy (opacity 1 → 0)', () => {
|
|
61
|
+
const tracks = compile();
|
|
62
|
+
const rect = tracks.elements.find(e => 'opacity' in e.props)!;
|
|
63
|
+
const op = rect.props.opacity;
|
|
64
|
+
expect(op[0]).toBe(1);
|
|
65
|
+
expect(op[op.length - 1]).toBe(0);
|
|
66
|
+
// midpoint ≈ 0.5 (linear)
|
|
67
|
+
expect(+op[Math.floor(op.length / 2)]).toBeCloseTo(0.5, 1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('converts attr names to react-native-svg prop names (stroke-width → strokeWidth)', () => {
|
|
71
|
+
const tracks = compile();
|
|
72
|
+
const rect = tracks.elements.find(e => 'opacity' in e.props)!;
|
|
73
|
+
expect(rect.props.strokeWidth).toBeDefined();
|
|
74
|
+
expect(rect.props['stroke-width']).toBeUndefined();
|
|
75
|
+
expect(+rect.props.strokeWidth[0]).toBe(1);
|
|
76
|
+
expect(+rect.props.strokeWidth[rect.props.strokeWidth.length - 1]).toBe(5);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('samples colour props as rgba strings', () => {
|
|
80
|
+
const tracks = compile();
|
|
81
|
+
const rect = tracks.elements.find(e => 'fill' in e.props)!;
|
|
82
|
+
expect(String(rect.props.fill[0])).toMatch(/^rgba\(/);
|
|
83
|
+
expect(String(rect.props.fill[rect.props.fill.length - 1])).toMatch(/^rgba\(/);
|
|
84
|
+
expect(rect.props.fill[0]).not.toBe(rect.props.fill[rect.props.fill.length - 1]);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('samples transforms as composed transform strings', () => {
|
|
88
|
+
const tracks = compile();
|
|
89
|
+
const g = tracks.elements.find(e => 'transform' in e.props)!;
|
|
90
|
+
expect(String(g.props.transform[0])).toContain('translate(0');
|
|
91
|
+
expect(String(g.props.transform[g.props.transform.length - 1])).toContain('translate(100');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('respects sampleRate and maxSamples options', () => {
|
|
95
|
+
const coarse = compile(makeDoc(), { sampleRate: 10 });
|
|
96
|
+
expect(coarse.sampleCount).toBe(11); // 1s at 10/s + endpoint
|
|
97
|
+
const capped = compile(makeDoc(), { sampleRate: 1000, maxSamples: 50 });
|
|
98
|
+
expect(capped.sampleCount).toBe(50);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('every track array is fully populated (no holes)', () => {
|
|
102
|
+
const tracks = compile();
|
|
103
|
+
for (const el of tracks.elements) {
|
|
104
|
+
for (const arr of Object.values(el.props)) {
|
|
105
|
+
expect(arr.length).toBe(tracks.sampleCount);
|
|
106
|
+
expect(arr.every(v => v !== undefined)).toBe(true);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('sampleProps', () => {
|
|
113
|
+
it('indexes the nearest sample and clamps at both ends', () => {
|
|
114
|
+
const tracks = compile();
|
|
115
|
+
const rect = tracks.elements.find(e => 'opacity' in e.props)!;
|
|
116
|
+
const { stepMs, sampleCount } = tracks;
|
|
117
|
+
|
|
118
|
+
expect(sampleProps(rect, 0, stepMs, sampleCount).opacity).toBe(1);
|
|
119
|
+
expect(sampleProps(rect, 1000, stepMs, sampleCount).opacity).toBe(0);
|
|
120
|
+
// out-of-range clamps
|
|
121
|
+
expect(sampleProps(rect, -50, stepMs, sampleCount).opacity).toBe(1);
|
|
122
|
+
expect(sampleProps(rect, 5000, stepMs, sampleCount).opacity).toBe(0);
|
|
123
|
+
// midpoint
|
|
124
|
+
expect(+sampleProps(rect, 500, stepMs, sampleCount).opacity).toBeCloseTo(0.5, 1);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('toRnPropName', () => {
|
|
129
|
+
it('camelCases kebab attrs and maps known overrides', () => {
|
|
130
|
+
expect(toRnPropName('stroke-width')).toBe('strokeWidth');
|
|
131
|
+
expect(toRnPropName('fill')).toBe('fill');
|
|
132
|
+
expect(toRnPropName('xlink:href')).toBe('href');
|
|
133
|
+
});
|
|
134
|
+
it('drops web-only props', () => {
|
|
135
|
+
expect(toRnPropName('class')).toBeUndefined();
|
|
136
|
+
expect(toRnPropName('style')).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('length-list props (stroke-dasharray)', () => {
|
|
141
|
+
it('compiles stroke-dasharray into number arrays (rn-svg native shape)', () => {
|
|
142
|
+
const doc: PxAnimatedSvgDocument = {
|
|
143
|
+
type: 'svg', viewBox: '0 0 100 100',
|
|
144
|
+
animator: { mode: 'frames', duration: 1000 },
|
|
145
|
+
children: [{
|
|
146
|
+
type: 'path', id: 'p', d: 'M 0 50 L 100 50', stroke: '#000', fill: 'none',
|
|
147
|
+
effects: { trimPath: { range: { keyframes: [{ time: 0, value: [0, 0.1] }, { time: 1000, value: [0, 1] }] } } },
|
|
148
|
+
}],
|
|
149
|
+
};
|
|
150
|
+
const materialised = generateNewIds(materialiseAllInTree(doc, PxAnimatorEngine.webapi));
|
|
151
|
+
const tracks = compileTracks(materialised);
|
|
152
|
+
const el = tracks.elements.find(e => 'strokeDasharray' in e.props)!;
|
|
153
|
+
expect(el).toBeDefined();
|
|
154
|
+
const first = el.props.strokeDasharray[0];
|
|
155
|
+
expect(Array.isArray(first)).toBe(true);
|
|
156
|
+
expect((first as number[]).every(n => typeof n === 'number' && Number.isFinite(n))).toBe(true);
|
|
157
|
+
expect((first as number[]).length % 2).toBe(0);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('animated <use> flattening (webapi materialisation)', () => {
|
|
162
|
+
it('inlines animated <use> clones so no live references remain', () => {
|
|
163
|
+
const doc: PxAnimatedSvgDocument = {
|
|
164
|
+
type: 'svg', viewBox: '0 0 300 200',
|
|
165
|
+
animator: { mode: 'frames', duration: 2000 },
|
|
166
|
+
children: [
|
|
167
|
+
{ type: 'defs', children: [{ type: 'g', id: 'sym', children: [{
|
|
168
|
+
type: 'circle', id: 'c', cx: 30, cy: 40, r: 16, fill: '#f59e0b',
|
|
169
|
+
animate: { cy: { keyframes: [{ time: 0, value: 40 }, { time: 2000, value: 160 }] } },
|
|
170
|
+
}] }] },
|
|
171
|
+
{ type: 'use', id: 'u1', href: '#sym' },
|
|
172
|
+
{ type: 'use', id: 'u2', href: '#sym', x: 80, effects: { clone: { baseId: 'sym', retime: { start: -600 } } } },
|
|
173
|
+
],
|
|
174
|
+
};
|
|
175
|
+
const materialised = generateNewIds(materialiseAllInTree(doc, PxAnimatorEngine.webapi));
|
|
176
|
+
const countUse = (n: any): number =>
|
|
177
|
+
(n.type === 'use' ? 1 : 0) + (n.children || []).reduce((s: number, c: any) => s + countUse(c), 0);
|
|
178
|
+
expect(countUse(materialised)).toBe(0);
|
|
179
|
+
|
|
180
|
+
const tracks = compileTracks(materialised);
|
|
181
|
+
const cyTracks = tracks.elements.filter(e => 'cy' in e.props);
|
|
182
|
+
expect(cyTracks.length).toBe(2);
|
|
183
|
+
expect(cyTracks[0].props.cy[0]).not.toBe(cyTracks[1].props.cy[0]);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Pixodesk LTD.
|
|
3
|
+
* Licensed under the MIT License. See the LICENSE file in the project root for details.
|
|
4
|
+
*---------------------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
calcAnimationValues,
|
|
8
|
+
getAnimatorConfig,
|
|
9
|
+
getNormalisedBindings,
|
|
10
|
+
DEFAULT_DURATION_MS,
|
|
11
|
+
PxAnimatorEngine,
|
|
12
|
+
type PxAnimatedSvgDocument,
|
|
13
|
+
type PxAnimationDefinition,
|
|
14
|
+
} from '@pixodesk/svg-animator-core';
|
|
15
|
+
import { toRnPropName, toRnPropValue } from './PxRnPropNames';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Sampled animation tracks for ONE element: prop name → per-sample values.
|
|
19
|
+
*
|
|
20
|
+
* The compiler densely samples every animated property through core's
|
|
21
|
+
* `calcAnimationValues` — the exact function the web frames engine renders
|
|
22
|
+
* with — so RN playback is value-identical to the web player. Easing, loops,
|
|
23
|
+
* transform composition, colour interpolation and path morphing are all baked
|
|
24
|
+
* into the samples at compile time; the UI-thread worklet only indexes arrays.
|
|
25
|
+
*/
|
|
26
|
+
export interface PxElementTracks {
|
|
27
|
+
/** Element id (after id regeneration). */
|
|
28
|
+
id: string;
|
|
29
|
+
/** react-native-svg prop name → one value per sample. */
|
|
30
|
+
props: Record<string, Array<string | number | Array<number>>>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface PxCompiledTracks {
|
|
34
|
+
/** Per-iteration duration, ms. */
|
|
35
|
+
duration: number;
|
|
36
|
+
/** Iteration count (Infinity for 'infinite'). */
|
|
37
|
+
iterations: number;
|
|
38
|
+
/** 'normal' | 'reverse' | 'alternate' | 'alternate-reverse' */
|
|
39
|
+
direction: string;
|
|
40
|
+
/** Delay before start, ms (positive = wait). */
|
|
41
|
+
delay: number;
|
|
42
|
+
/** WAAPI-style fill mode (default 'forwards'). */
|
|
43
|
+
fill: string;
|
|
44
|
+
/** Sample step, ms. */
|
|
45
|
+
stepMs: number;
|
|
46
|
+
/** Number of samples per iteration (>= 2; sample i is at time i*stepMs). */
|
|
47
|
+
sampleCount: number;
|
|
48
|
+
/** Tracks for every animated element. */
|
|
49
|
+
elements: Array<PxElementTracks>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface CompileTracksOptions {
|
|
53
|
+
/** Target sample rate, samples/second. Default 60 (one per frame). */
|
|
54
|
+
sampleRate?: number;
|
|
55
|
+
/** Hard cap on samples per iteration (memory guard). Default 600. */
|
|
56
|
+
maxSamples?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Compiles a MATERIALISED document (run `materialiseAllInTree(doc, 'frames')`
|
|
63
|
+
* + `generateNewIds` first) into densely sampled per-element tracks.
|
|
64
|
+
*/
|
|
65
|
+
export function compileTracks(doc: PxAnimatedSvgDocument, opts?: CompileTracksOptions): PxCompiledTracks {
|
|
66
|
+
const config = getAnimatorConfig(doc) || {};
|
|
67
|
+
|
|
68
|
+
const duration = +(config.duration || DEFAULT_DURATION_MS);
|
|
69
|
+
const _iterations = config.iterations;
|
|
70
|
+
let iterations = 1;
|
|
71
|
+
if (typeof _iterations === 'number') iterations = _iterations || 1;
|
|
72
|
+
if (_iterations === 'infinite') iterations = Infinity;
|
|
73
|
+
if (iterations < 1) iterations = 1;
|
|
74
|
+
|
|
75
|
+
const sampleRate = opts?.sampleRate ?? 60;
|
|
76
|
+
const maxSamples = opts?.maxSamples ?? 600;
|
|
77
|
+
let sampleCount = Math.max(2, Math.round((duration / 1000) * sampleRate) + 1);
|
|
78
|
+
if (sampleCount > maxSamples) sampleCount = maxSamples;
|
|
79
|
+
const stepMs = duration / (sampleCount - 1);
|
|
80
|
+
|
|
81
|
+
const bindings = getNormalisedBindings(doc, PxAnimatorEngine.frames) || [];
|
|
82
|
+
|
|
83
|
+
const elements: Array<PxElementTracks> = [];
|
|
84
|
+
for (const binding of bindings) {
|
|
85
|
+
const animDef = binding.animate;
|
|
86
|
+
if (!animDef || typeof animDef !== 'object' || Array.isArray(animDef)) continue;
|
|
87
|
+
|
|
88
|
+
const props: Record<string, Array<string | number | Array<number>>> = {};
|
|
89
|
+
for (let i = 0; i < sampleCount; i++) {
|
|
90
|
+
const t = i === sampleCount - 1 ? duration : i * stepMs;
|
|
91
|
+
const values = calcAnimationValues(animDef as PxAnimationDefinition, t);
|
|
92
|
+
for (const [attr, value] of Object.entries(values)) {
|
|
93
|
+
const rnProp = toRnPropName(attr);
|
|
94
|
+
if (!rnProp) continue;
|
|
95
|
+
let arr = props[rnProp];
|
|
96
|
+
if (!arr) {
|
|
97
|
+
arr = props[rnProp] = new Array(sampleCount);
|
|
98
|
+
// A prop can appear late (e.g. attrs whose first kf is
|
|
99
|
+
// beyond t=0) — backfill earlier samples with the first
|
|
100
|
+
// computed value so the array is always fully populated.
|
|
101
|
+
for (let j = 0; j < i; j++) arr[j] = toRnPropValue(rnProp, value);
|
|
102
|
+
}
|
|
103
|
+
arr[i] = toRnPropValue(rnProp, value);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Forward-fill any holes (attr disappeared from a later sample).
|
|
107
|
+
for (const arr of Object.values(props)) {
|
|
108
|
+
for (let i = 1; i < sampleCount; i++) {
|
|
109
|
+
if (arr[i] === undefined) arr[i] = arr[i - 1];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (Object.keys(props).length > 0) {
|
|
114
|
+
elements.push({ id: binding.id, props });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
duration,
|
|
120
|
+
iterations,
|
|
121
|
+
direction: config.direction || 'normal',
|
|
122
|
+
delay: config.delay || 0,
|
|
123
|
+
fill: config.fill ?? 'forwards',
|
|
124
|
+
stepMs,
|
|
125
|
+
sampleCount,
|
|
126
|
+
elements,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Worklet-safe sample lookup: returns the per-prop values at time `tMs`
|
|
132
|
+
* (already mapped into a single iteration by the caller). Kept deliberately
|
|
133
|
+
* trivial — runs on the UI thread every frame.
|
|
134
|
+
*/
|
|
135
|
+
export function sampleProps(
|
|
136
|
+
tracks: PxElementTracks,
|
|
137
|
+
tMs: number,
|
|
138
|
+
stepMs: number,
|
|
139
|
+
sampleCount: number
|
|
140
|
+
): Record<string, string | number | Array<number>> {
|
|
141
|
+
'worklet';
|
|
142
|
+
let idx = Math.round(tMs / stepMs);
|
|
143
|
+
if (idx < 0) idx = 0;
|
|
144
|
+
if (idx >= sampleCount) idx = sampleCount - 1;
|
|
145
|
+
const out: Record<string, string | number | Array<number>> = {};
|
|
146
|
+
for (const key in tracks.props) {
|
|
147
|
+
out[key] = tracks.props[key][idx];
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Pixodesk LTD.
|
|
3
|
+
* Licensed under the MIT License. See the LICENSE file in the project root for details.
|
|
4
|
+
*---------------------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Circle,
|
|
8
|
+
ClipPath,
|
|
9
|
+
Defs,
|
|
10
|
+
Ellipse,
|
|
11
|
+
G,
|
|
12
|
+
Image,
|
|
13
|
+
Line,
|
|
14
|
+
LinearGradient,
|
|
15
|
+
Marker,
|
|
16
|
+
Mask,
|
|
17
|
+
Path,
|
|
18
|
+
Pattern,
|
|
19
|
+
Polygon,
|
|
20
|
+
Polyline,
|
|
21
|
+
RadialGradient,
|
|
22
|
+
Rect,
|
|
23
|
+
Stop,
|
|
24
|
+
Svg,
|
|
25
|
+
Symbol as SvgSymbol,
|
|
26
|
+
Text as SvgText,
|
|
27
|
+
TextPath,
|
|
28
|
+
TSpan,
|
|
29
|
+
Use,
|
|
30
|
+
} from 'react-native-svg';
|
|
31
|
+
import type { ComponentType } from 'react';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* SVG tag → react-native-svg component. Tags not in this map are skipped at
|
|
35
|
+
* render time (with a warning collected by the renderer) — they go on the
|
|
36
|
+
* feature-gap list rather than crashing the tree.
|
|
37
|
+
*/
|
|
38
|
+
export const RN_SVG_COMPONENTS: Record<string, ComponentType<any>> = {
|
|
39
|
+
svg: Svg,
|
|
40
|
+
g: G,
|
|
41
|
+
rect: Rect,
|
|
42
|
+
circle: Circle,
|
|
43
|
+
ellipse: Ellipse,
|
|
44
|
+
line: Line,
|
|
45
|
+
path: Path,
|
|
46
|
+
polygon: Polygon,
|
|
47
|
+
polyline: Polyline,
|
|
48
|
+
text: SvgText,
|
|
49
|
+
tspan: TSpan,
|
|
50
|
+
textPath: TextPath,
|
|
51
|
+
defs: Defs,
|
|
52
|
+
linearGradient: LinearGradient,
|
|
53
|
+
radialGradient: RadialGradient,
|
|
54
|
+
stop: Stop,
|
|
55
|
+
use: Use,
|
|
56
|
+
symbol: SvgSymbol,
|
|
57
|
+
mask: Mask,
|
|
58
|
+
clipPath: ClipPath,
|
|
59
|
+
pattern: Pattern,
|
|
60
|
+
marker: Marker,
|
|
61
|
+
image: Image,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export { toRnPropName } from './PxRnPropNames';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*---------------------------------------------------------------------------------------
|
|
2
|
+
* Copyright (c) Pixodesk LTD.
|
|
3
|
+
* Licensed under the MIT License. See the LICENSE file in the project root for details.
|
|
4
|
+
*---------------------------------------------------------------------------------------*/
|
|
5
|
+
|
|
6
|
+
export { PixodeskSvgAnimator, default } from './PixodeskSvgAnimator';
|
|
7
|
+
export type { PixodeskSvgAnimatorProps, RnAnimatorApi } from './PixodeskSvgAnimator';
|
|
8
|
+
|
|
9
|
+
export { renderRnNode, toRnProps } from './PxRnRender';
|
|
10
|
+
export type { RenderRnNodeOptions } from './PxRnRender';
|
|
11
|
+
|
|
12
|
+
export { compileTracks, sampleProps } from './PxRnTracks';
|
|
13
|
+
export type { CompileTracksOptions, PxCompiledTracks, PxElementTracks } from './PxRnTracks';
|
|
14
|
+
|
|
15
|
+
export { RN_SVG_COMPONENTS, toRnPropName } from './PxRnTypeMap';
|