@rootnative/inertia-svg 0.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,358 @@
1
+ import { useRef, useMemo, useEffect } from 'react';
2
+ import { Path } from 'react-native-svg';
3
+ import Animated, { useSharedValue, useAnimatedProps } from 'react-native-reanimated';
4
+ import { useShouldReduceMotion, resolveTransition } from '@rootnative/inertia';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ // src/MotionPath.tsx
8
+
9
+ // src/path.ts
10
+ var CMD_ARGS = {
11
+ M: 2,
12
+ m: 2,
13
+ L: 2,
14
+ l: 2,
15
+ H: 1,
16
+ h: 1,
17
+ V: 1,
18
+ v: 1,
19
+ C: 6,
20
+ c: 6,
21
+ S: 4,
22
+ s: 4,
23
+ Q: 4,
24
+ q: 4,
25
+ T: 2,
26
+ t: 2,
27
+ A: 7,
28
+ a: 7,
29
+ Z: 0,
30
+ z: 0
31
+ };
32
+ var CMD_REPEAT = {
33
+ M: "L",
34
+ m: "l"
35
+ };
36
+ var isDigit = (c) => c >= "0" && c <= "9";
37
+ function tokenize(d) {
38
+ const out = [];
39
+ const len = d.length;
40
+ let i = 0;
41
+ while (i < len) {
42
+ const c = d[i];
43
+ if (c === " " || c === "," || c === " " || c === "\n" || c === "\r") {
44
+ i++;
45
+ continue;
46
+ }
47
+ if (c >= "A" && c <= "Z" || c >= "a" && c <= "z") {
48
+ if (!(c in CMD_ARGS)) {
49
+ throw new Error(
50
+ `[inertia-svg] unknown path command '${c}' at position ${i}`
51
+ );
52
+ }
53
+ out.push(c);
54
+ i++;
55
+ continue;
56
+ }
57
+ const start = i;
58
+ let hasDigit = false;
59
+ let hasDot = false;
60
+ if (c === "+" || c === "-") i++;
61
+ while (i < len) {
62
+ const ch = d[i];
63
+ if (isDigit(ch)) {
64
+ hasDigit = true;
65
+ i++;
66
+ } else if (ch === "." && !hasDot) {
67
+ hasDot = true;
68
+ i++;
69
+ } else {
70
+ break;
71
+ }
72
+ }
73
+ if (hasDigit && (d[i] === "e" || d[i] === "E")) {
74
+ i++;
75
+ if (d[i] === "+" || d[i] === "-") i++;
76
+ while (i < len && isDigit(d[i])) i++;
77
+ }
78
+ if (!hasDigit) {
79
+ throw new Error(
80
+ `[inertia-svg] expected number at position ${start} in path '${d}', got '${c}'`
81
+ );
82
+ }
83
+ out.push(Number(d.substring(start, i)));
84
+ }
85
+ return out;
86
+ }
87
+ function parsePathD(d) {
88
+ const tokens = tokenize(d);
89
+ const segments = [];
90
+ let i = 0;
91
+ while (i < tokens.length) {
92
+ const t = tokens[i];
93
+ if (typeof t !== "string") {
94
+ throw new Error(
95
+ `[inertia-svg] expected command letter at token ${i}, got number ${t} \u2014 paths must start with a command`
96
+ );
97
+ }
98
+ const cmd = t;
99
+ const argCount = CMD_ARGS[cmd];
100
+ i++;
101
+ if (argCount === 0) {
102
+ segments.push({ cmd, args: [] });
103
+ continue;
104
+ }
105
+ const first = [];
106
+ for (let j = 0; j < argCount; j++) {
107
+ const v = tokens[i++];
108
+ if (typeof v !== "number") {
109
+ throw new Error(
110
+ `[inertia-svg] command '${cmd}' expected ${argCount} numbers, got '${v}' at token ${i - 1}`
111
+ );
112
+ }
113
+ first.push(v);
114
+ }
115
+ segments.push({ cmd, args: first });
116
+ const repeatCmd = CMD_REPEAT[cmd] ?? cmd;
117
+ while (i < tokens.length && typeof tokens[i] === "number") {
118
+ const batch = [];
119
+ for (let j = 0; j < argCount; j++) {
120
+ const v = tokens[i++];
121
+ if (typeof v !== "number") {
122
+ throw new Error(
123
+ `[inertia-svg] command '${cmd}' (implicit repeat as '${repeatCmd}') expected ${argCount} numbers`
124
+ );
125
+ }
126
+ batch.push(v);
127
+ }
128
+ segments.push({ cmd: repeatCmd, args: batch });
129
+ }
130
+ }
131
+ return segments;
132
+ }
133
+ function templateOf(segments) {
134
+ const cmds = segments.map((s) => s.cmd);
135
+ const widths = segments.map((s) => s.args.length);
136
+ let size = 0;
137
+ for (let i = 0; i < widths.length; i++) size += widths[i];
138
+ return { cmds, widths, size };
139
+ }
140
+ function flattenParams(segments) {
141
+ const out = [];
142
+ for (let i = 0; i < segments.length; i++) {
143
+ const args = segments[i].args;
144
+ for (let j = 0; j < args.length; j++) out.push(args[j]);
145
+ }
146
+ return out;
147
+ }
148
+ function diffTemplate(source, target) {
149
+ if (source.cmds.length !== target.cmds.length) {
150
+ return `command count differs: source has ${source.cmds.length} segments, target has ${target.cmds.length}. Paths must produce the same command sequence after implicit-repeat expansion.`;
151
+ }
152
+ for (let i = 0; i < source.cmds.length; i++) {
153
+ if (source.cmds[i] !== target.cmds[i]) {
154
+ return `command at segment ${i} differs: source '${source.cmds[i]}' vs target '${target.cmds[i]}'. Command letters (including case \u2014 absolute vs relative) must match.`;
155
+ }
156
+ }
157
+ return null;
158
+ }
159
+ function serializePath(template, params) {
160
+ "worklet";
161
+ let out = "";
162
+ let p = 0;
163
+ for (let i = 0; i < template.cmds.length; i++) {
164
+ out += template.cmds[i];
165
+ const w = template.widths[i];
166
+ for (let j = 0; j < w; j++) {
167
+ out += " ";
168
+ out += params[p++];
169
+ }
170
+ }
171
+ return out;
172
+ }
173
+ var AnimatedPath = Animated.createAnimatedComponent(Path);
174
+ var NO_ANIMATION = { type: "no-animation" };
175
+ function pickTransition(per, key) {
176
+ if (!per) return void 0;
177
+ if ("type" in per) return per;
178
+ return per[key];
179
+ }
180
+ function MotionPath(props) {
181
+ const {
182
+ d,
183
+ fill,
184
+ stroke,
185
+ strokeWidth,
186
+ strokeOpacity,
187
+ fillOpacity,
188
+ opacity,
189
+ strokeDashoffset,
190
+ initial,
191
+ animate,
192
+ transition,
193
+ ...rest
194
+ } = props;
195
+ const sourceRef = useRef(null);
196
+ if (sourceRef.current === null) {
197
+ const segments = parsePathD(d);
198
+ sourceRef.current = {
199
+ template: templateOf(segments),
200
+ params: flattenParams(segments)
201
+ };
202
+ }
203
+ const template = sourceRef.current.template;
204
+ if (__DEV__) {
205
+ const segments = parsePathD(d);
206
+ const live = templateOf(segments);
207
+ const err = diffTemplate(template, live);
208
+ if (err) {
209
+ throw new Error(
210
+ `[inertia-svg] d prop template changed after mount: ${err}
211
+ If you need to swap to a structurally different path, remount with key={...}.`
212
+ );
213
+ }
214
+ }
215
+ const seedSource = initial === false ? animate : initial ?? void 0;
216
+ const seedParams = useMemo(() => {
217
+ if (!seedSource?.d) return sourceRef.current.params;
218
+ const segs = parsePathD(seedSource.d);
219
+ const t = templateOf(segs);
220
+ const err = diffTemplate(template, t);
221
+ if (err) {
222
+ if (__DEV__) {
223
+ throw new Error(`[inertia-svg] initial.d template mismatch: ${err}`);
224
+ }
225
+ return sourceRef.current.params;
226
+ }
227
+ return flattenParams(segs);
228
+ }, [seedSource?.d]);
229
+ const paramSvs = [];
230
+ for (let i = 0; i < template.size; i++) {
231
+ paramSvs.push(useSharedValue(seedParams[i] ?? 0));
232
+ }
233
+ const fillSv = useSharedValue(
234
+ seedSource?.fill ?? fill ?? "transparent"
235
+ );
236
+ const strokeSv = useSharedValue(
237
+ seedSource?.stroke ?? stroke ?? "transparent"
238
+ );
239
+ const strokeWidthSv = useSharedValue(
240
+ seedSource?.strokeWidth ?? strokeWidth ?? 1
241
+ );
242
+ const strokeOpacitySv = useSharedValue(
243
+ seedSource?.strokeOpacity ?? strokeOpacity ?? 1
244
+ );
245
+ const fillOpacitySv = useSharedValue(
246
+ seedSource?.fillOpacity ?? fillOpacity ?? 1
247
+ );
248
+ const opacitySv = useSharedValue(seedSource?.opacity ?? opacity ?? 1);
249
+ const strokeDashoffsetSv = useSharedValue(
250
+ seedSource?.strokeDashoffset ?? strokeDashoffset ?? 0
251
+ );
252
+ const reduce = useShouldReduceMotion();
253
+ const animateD = animate?.d;
254
+ const animateFill = animate?.fill;
255
+ const animateStroke = animate?.stroke;
256
+ const animateStrokeWidth = animate?.strokeWidth;
257
+ const animateStrokeOpacity = animate?.strokeOpacity;
258
+ const animateFillOpacity = animate?.fillOpacity;
259
+ const animateOpacity = animate?.opacity;
260
+ const animateStrokeDashoffset = animate?.strokeDashoffset;
261
+ useEffect(() => {
262
+ if (animateD === void 0) return;
263
+ const segments = parsePathD(animateD);
264
+ const t = templateOf(segments);
265
+ const err = diffTemplate(template, t);
266
+ if (err) {
267
+ if (__DEV__) {
268
+ throw new Error(`[inertia-svg] animate.d template mismatch: ${err}`);
269
+ }
270
+ return;
271
+ }
272
+ const target = flattenParams(segments);
273
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "d");
274
+ for (let i = 0; i < paramSvs.length; i++) {
275
+ paramSvs[i].value = resolveTransition(cfg, target[i] ?? 0);
276
+ }
277
+ }, [animateD, reduce, transition]);
278
+ useEffect(() => {
279
+ if (animateFill === void 0) return;
280
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "fill");
281
+ fillSv.value = resolveTransition(cfg, animateFill);
282
+ }, [animateFill, reduce, transition]);
283
+ useEffect(() => {
284
+ if (animateStroke === void 0) return;
285
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "stroke");
286
+ strokeSv.value = resolveTransition(cfg, animateStroke);
287
+ }, [animateStroke, reduce, transition]);
288
+ useEffect(() => {
289
+ if (animateStrokeWidth === void 0) return;
290
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "strokeWidth");
291
+ strokeWidthSv.value = resolveTransition(cfg, animateStrokeWidth);
292
+ }, [animateStrokeWidth, reduce, transition]);
293
+ useEffect(() => {
294
+ if (animateStrokeOpacity === void 0) return;
295
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "strokeOpacity");
296
+ strokeOpacitySv.value = resolveTransition(
297
+ cfg,
298
+ animateStrokeOpacity
299
+ );
300
+ }, [animateStrokeOpacity, reduce, transition]);
301
+ useEffect(() => {
302
+ if (animateFillOpacity === void 0) return;
303
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "fillOpacity");
304
+ fillOpacitySv.value = resolveTransition(cfg, animateFillOpacity);
305
+ }, [animateFillOpacity, reduce, transition]);
306
+ useEffect(() => {
307
+ if (animateOpacity === void 0) return;
308
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "opacity");
309
+ opacitySv.value = resolveTransition(cfg, animateOpacity);
310
+ }, [animateOpacity, reduce, transition]);
311
+ useEffect(() => {
312
+ if (animateStrokeDashoffset === void 0) return;
313
+ const cfg = reduce ? NO_ANIMATION : pickTransition(transition, "strokeDashoffset");
314
+ strokeDashoffsetSv.value = resolveTransition(
315
+ cfg,
316
+ animateStrokeDashoffset
317
+ );
318
+ }, [animateStrokeDashoffset, reduce, transition]);
319
+ const animatedProps = useAnimatedProps(() => {
320
+ "worklet";
321
+ const params = new Array(paramSvs.length);
322
+ for (let i = 0; i < paramSvs.length; i++) params[i] = paramSvs[i].value;
323
+ return {
324
+ d: serializePath(template, params),
325
+ fill: fillSv.value,
326
+ stroke: strokeSv.value,
327
+ strokeWidth: strokeWidthSv.value,
328
+ strokeOpacity: strokeOpacitySv.value,
329
+ fillOpacity: fillOpacitySv.value,
330
+ opacity: opacitySv.value,
331
+ strokeDashoffset: strokeDashoffsetSv.value
332
+ };
333
+ });
334
+ return /* @__PURE__ */ jsx(
335
+ AnimatedPath,
336
+ {
337
+ animatedProps,
338
+ d,
339
+ fill,
340
+ stroke,
341
+ strokeWidth,
342
+ strokeOpacity,
343
+ fillOpacity,
344
+ opacity,
345
+ strokeDashoffset,
346
+ ...rest
347
+ }
348
+ );
349
+ }
350
+
351
+ // src/index.ts
352
+ var MotionSvg = {
353
+ Path: MotionPath
354
+ };
355
+
356
+ export { MotionPath, MotionSvg, diffTemplate, flattenParams, parsePathD, serializePath, templateOf };
357
+ //# sourceMappingURL=index.mjs.map
358
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/path.ts","../src/MotionPath.tsx","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * SVG path-string utilities used by `MotionSvg.Path`. Everything here runs on\n * the JS thread — paths are tokenized into a normalized command list at mount\n * and when `animate.d` changes; the worklet only ever consumes flat number\n * arrays + a frozen command template.\n *\n * Path morphing in v0.2 requires **structural compatibility**: the source and\n * every target `d` must produce the same command sequence (same command\n * letters, in the same order, after implicit-repeat expansion). Element-wise\n * numeric interpolation is the entire morphing model — we do not resample\n * paths or insert/remove commands. Same-shape morphs (e.g. a heart breathing,\n * a chevron flipping, a check mark tracing in) are the supported use case.\n */\n\n/** Arg count per SVG path command. `Z`/`z` close the subpath and take none. */\nconst CMD_ARGS: Readonly<Record<string, number>> = {\n M: 2,\n m: 2,\n L: 2,\n l: 2,\n H: 1,\n h: 1,\n V: 1,\n v: 1,\n C: 6,\n c: 6,\n S: 4,\n s: 4,\n Q: 4,\n q: 4,\n T: 2,\n t: 2,\n A: 7,\n a: 7,\n Z: 0,\n z: 0,\n}\n\n/**\n * After an explicit `M`/`m` the SVG spec says additional coordinate pairs are\n * implicit `L`/`l` commands. Every other command repeats itself.\n */\nconst CMD_REPEAT: Readonly<Record<string, string>> = {\n M: 'L',\n m: 'l',\n}\n\n/**\n * A single normalized path command after implicit-repeat expansion. The cmd\n * letter is preserved (absolute vs relative — case is meaningful to the SVG\n * renderer). `args` always has exactly `CMD_ARGS[cmd]` entries.\n */\nexport interface PathSegment {\n cmd: string\n args: number[]\n}\n\nconst isDigit = (c: string): boolean => c >= '0' && c <= '9'\n\n/**\n * Tokenize a path `d` string into a stream of (command-letter | number)\n * tokens. Handles SVG's \"compact\" number forms — adjacent numbers separated\n * only by sign (`1-2`) or decimal point (`.5.6`) — so author-written paths\n * with mixed spacing all parse to the same tokens.\n */\nfunction tokenize(d: string): Array<string | number> {\n const out: Array<string | number> = []\n const len = d.length\n let i = 0\n while (i < len) {\n const c = d[i]!\n // SVG path whitespace + comma separators.\n if (c === ' ' || c === ',' || c === '\\t' || c === '\\n' || c === '\\r') {\n i++\n continue\n }\n // Command letter — any ASCII letter not adjacent to a number context.\n if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {\n if (!(c in CMD_ARGS)) {\n throw new Error(\n `[inertia-svg] unknown path command '${c}' at position ${i}`,\n )\n }\n out.push(c)\n i++\n continue\n }\n // Number. Reaches here for digits, `.`, `+`, `-`.\n const start = i\n let hasDigit = false\n let hasDot = false\n if (c === '+' || c === '-') i++\n while (i < len) {\n const ch = d[i]!\n if (isDigit(ch)) {\n hasDigit = true\n i++\n } else if (ch === '.' && !hasDot) {\n hasDot = true\n i++\n } else {\n break\n }\n }\n if (hasDigit && (d[i] === 'e' || d[i] === 'E')) {\n i++\n if (d[i] === '+' || d[i] === '-') i++\n while (i < len && isDigit(d[i]!)) i++\n }\n if (!hasDigit) {\n throw new Error(\n `[inertia-svg] expected number at position ${start} in path '${d}', got '${c}'`,\n )\n }\n out.push(Number(d.substring(start, i)))\n }\n return out\n}\n\n/**\n * Parse a path `d` string into a flat list of normalized segments. Implicit\n * repeats are expanded — `M 0 0 10 10 20 20` becomes three segments\n * (`M 0 0`, `L 10 10`, `L 20 20`) so the segment list can be compared and\n * interpolated 1:1 against another path.\n */\nexport function parsePathD(d: string): PathSegment[] {\n const tokens = tokenize(d)\n const segments: PathSegment[] = []\n let i = 0\n while (i < tokens.length) {\n const t = tokens[i]\n if (typeof t !== 'string') {\n throw new Error(\n `[inertia-svg] expected command letter at token ${i}, got number ${t} — paths must start with a command`,\n )\n }\n const cmd = t\n const argCount = CMD_ARGS[cmd]!\n i++\n if (argCount === 0) {\n segments.push({ cmd, args: [] })\n continue\n }\n // First explicit batch for this command.\n const first: number[] = []\n for (let j = 0; j < argCount; j++) {\n const v = tokens[i++]\n if (typeof v !== 'number') {\n throw new Error(\n `[inertia-svg] command '${cmd}' expected ${argCount} numbers, got '${v}' at token ${i - 1}`,\n )\n }\n first.push(v)\n }\n segments.push({ cmd, args: first })\n // Repeated batches consume numbers up to the next command letter, applying\n // the implicit-repeat command (M → L, m → l, everything else → itself).\n // `argCount === 0` is handled above with an early continue, so the loop\n // body here always makes forward progress.\n const repeatCmd = CMD_REPEAT[cmd] ?? cmd\n while (i < tokens.length && typeof tokens[i] === 'number') {\n const batch: number[] = []\n for (let j = 0; j < argCount; j++) {\n const v = tokens[i++]\n if (typeof v !== 'number') {\n throw new Error(\n `[inertia-svg] command '${cmd}' (implicit repeat as '${repeatCmd}') expected ${argCount} numbers`,\n )\n }\n batch.push(v)\n }\n segments.push({ cmd: repeatCmd, args: batch })\n }\n }\n return segments\n}\n\n/**\n * The frozen \"shape\" of a path — just command letters and arg widths. Two\n * paths are morphable iff their templates are equal.\n */\nexport interface PathTemplate {\n cmds: ReadonlyArray<string>\n /** Flat width per segment, indexed parallel to `cmds`. */\n widths: ReadonlyArray<number>\n /** Total scalar count across all segments — `widths.reduce((a,b)=>a+b,0)`. */\n size: number\n}\n\nexport function templateOf(segments: ReadonlyArray<PathSegment>): PathTemplate {\n const cmds = segments.map((s) => s.cmd)\n const widths = segments.map((s) => s.args.length)\n let size = 0\n for (let i = 0; i < widths.length; i++) size += widths[i]!\n return { cmds, widths, size }\n}\n\n/** Flatten a parsed segment list into a single number array (length === size). */\nexport function flattenParams(segments: ReadonlyArray<PathSegment>): number[] {\n const out: number[] = []\n for (let i = 0; i < segments.length; i++) {\n const args = segments[i]!.args\n for (let j = 0; j < args.length; j++) out.push(args[j]!)\n }\n return out\n}\n\n/**\n * Verify a target template matches the source. Returns `null` on match or a\n * descriptive error string on mismatch — callers throw in `__DEV__` and\n * skip the bad target in production (the path keeps its current `d`).\n */\nexport function diffTemplate(\n source: PathTemplate,\n target: PathTemplate,\n): string | null {\n if (source.cmds.length !== target.cmds.length) {\n return `command count differs: source has ${source.cmds.length} segments, target has ${target.cmds.length}. Paths must produce the same command sequence after implicit-repeat expansion.`\n }\n for (let i = 0; i < source.cmds.length; i++) {\n if (source.cmds[i] !== target.cmds[i]) {\n return `command at segment ${i} differs: source '${source.cmds[i]}' vs target '${target.cmds[i]}'. Command letters (including case — absolute vs relative) must match.`\n }\n }\n return null\n}\n\n/**\n * Build a path `d` string from a template + flat param array. Runs inside the\n * worklet on the UI thread, so it must not capture any JS-thread closures or\n * use Array.prototype helpers that allocate intermediates the Hermes runtime\n * boxes into JS objects. Manual loops + `+=` string concat keep the worklet\n * cheap.\n *\n * MUST be a worklet — call sites in `MotionPath` wrap it with `'worklet'` via\n * `useAnimatedProps`.\n */\nexport function serializePath(\n template: PathTemplate,\n params: ReadonlyArray<number>,\n): string {\n 'worklet'\n let out = ''\n let p = 0\n for (let i = 0; i < template.cmds.length; i++) {\n out += template.cmds[i]\n const w = template.widths[i]!\n for (let j = 0; j < w; j++) {\n out += ' '\n out += params[p++]\n }\n }\n return out\n}\n","import { useEffect, useMemo, useRef } from 'react'\nimport { Path, type PathProps } from 'react-native-svg'\nimport Animated, {\n useAnimatedProps,\n useSharedValue,\n type SharedValue,\n} from 'react-native-reanimated'\nimport {\n resolveTransition,\n useShouldReduceMotion,\n type TransitionConfig,\n} from '@rootnative/inertia'\nimport {\n diffTemplate,\n flattenParams,\n parsePathD,\n serializePath,\n templateOf,\n type PathTemplate,\n} from './path'\nimport type {\n PathAnimate,\n PathPerPropertyTransition,\n PathTransition,\n} from './types'\n\nconst AnimatedPath = Animated.createAnimatedComponent(Path)\n\nconst NO_ANIMATION: TransitionConfig = { type: 'no-animation' }\n\nfunction pickTransition(\n per: PathTransition | undefined,\n key: keyof PathPerPropertyTransition,\n): TransitionConfig | undefined {\n if (!per) return undefined\n if ('type' in per) return per as TransitionConfig\n return (per as PathPerPropertyTransition)[key]\n}\n\nexport interface MotionPathProps extends Omit<\n PathProps,\n | 'd'\n | 'fill'\n | 'stroke'\n | 'strokeWidth'\n | 'strokeOpacity'\n | 'fillOpacity'\n | 'opacity'\n | 'strokeDashoffset'\n> {\n /**\n * Initial path data. **The command sequence is locked at first render** —\n * every target `d` passed via `animate` / `initial` must produce the same\n * command letters in the same order after implicit-repeat expansion. To\n * morph between structurally different paths, remount with a new `key`.\n */\n d: string\n fill?: string\n stroke?: string\n strokeWidth?: number\n strokeOpacity?: number\n fillOpacity?: number\n opacity?: number\n strokeDashoffset?: number\n /**\n * Initial frame override. When present, the component mounts displaying\n * these values, then animates to `animate` on the next effect. Pass `false`\n * to skip the initial-mount animation entirely.\n */\n initial?: PathAnimate | false\n /** Target animation state. */\n animate?: PathAnimate\n /**\n * Transition config — either a single `TransitionConfig` applied to every\n * animated dimension, or a per-property map. Per-property entries win over\n * the top-level transition.\n */\n transition?: PathTransition\n}\n\n/**\n * Animatable `<Path>` from `react-native-svg`. Wraps `Path` with declarative\n * `initial` / `animate` / `transition` props.\n *\n * Animatable dimensions:\n * - `d` — path morph via element-wise scalar interpolation. Source and target\n * must share the same command sequence (e.g. both `M L L L Z`).\n * - `fill`, `stroke` — color strings, interpolated via Reanimated's native\n * color animation.\n * - `strokeWidth`, `strokeOpacity`, `fillOpacity`, `opacity`,\n * `strokeDashoffset` — numeric, spring or timing-driven.\n *\n * Example:\n * ```tsx\n * <Svg viewBox=\"0 0 100 100\">\n * <MotionPath\n * d=\"M 50 20 L 80 80 L 20 80 Z\"\n * animate={{ d: \"M 50 80 L 80 20 L 20 20 Z\", fill: '#7c3aed' }}\n * transition={{ type: 'spring', tension: 140, friction: 12 }}\n * fill=\"#0ea5e9\"\n * />\n * </Svg>\n * ```\n */\nexport function MotionPath(props: MotionPathProps) {\n const {\n d,\n fill,\n stroke,\n strokeWidth,\n strokeOpacity,\n fillOpacity,\n opacity,\n strokeDashoffset,\n initial,\n animate,\n transition,\n ...rest\n } = props\n\n // Parse + freeze the source template at mount. The number of scalar params\n // is locked here so the shared-value array allocated below has a stable\n // length across renders.\n const sourceRef = useRef<{\n template: PathTemplate\n params: number[]\n } | null>(null)\n if (sourceRef.current === null) {\n const segments = parsePathD(d)\n sourceRef.current = {\n template: templateOf(segments),\n params: flattenParams(segments),\n }\n }\n const template = sourceRef.current.template\n\n if (__DEV__) {\n // Re-parse the current `d` prop and verify the template hasn't shifted.\n // Catches the easy mistake of swapping a star for a hexagon without\n // remounting via `key`.\n const segments = parsePathD(d)\n const live = templateOf(segments)\n const err = diffTemplate(template, live)\n if (err) {\n throw new Error(\n `[inertia-svg] d prop template changed after mount: ${err}\\n` +\n `If you need to swap to a structurally different path, remount with key={...}.`,\n )\n }\n }\n\n // `initial: false` → start at the animate target (no mount animation).\n // `initial: {...}` → explicit seed values.\n // `initial: undefined` → seed from the static props.\n const seedSource = initial === false ? animate : (initial ?? undefined)\n\n // Seed the path params. If `initial.d` is provided, parse it and verify\n // it's template-compatible before seeding.\n const seedParams: number[] = useMemo(() => {\n if (!seedSource?.d) return sourceRef.current!.params\n const segs = parsePathD(seedSource.d)\n const t = templateOf(segs)\n const err = diffTemplate(template, t)\n if (err) {\n if (__DEV__) {\n throw new Error(`[inertia-svg] initial.d template mismatch: ${err}`)\n }\n return sourceRef.current!.params\n }\n return flattenParams(segs)\n // template is stable for the component's lifetime; seedSource is the\n // only meaningful input. We intentionally ignore `template` in deps.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [seedSource?.d])\n\n // Loop-of-hooks per scalar param — safe because `template.size` is locked\n // at mount via the source ref above.\n const paramSvs: SharedValue<number>[] = []\n for (let i = 0; i < template.size; i++) {\n // eslint-disable-next-line react-hooks/rules-of-hooks\n paramSvs.push(useSharedValue<number>(seedParams[i] ?? 0))\n }\n\n // Scalar property SVs. Strings (`fill`, `stroke`) use color seeds so\n // Reanimated recognizes them as colors from frame 1.\n const fillSv = useSharedValue<string>(\n seedSource?.fill ?? fill ?? 'transparent',\n )\n const strokeSv = useSharedValue<string>(\n seedSource?.stroke ?? stroke ?? 'transparent',\n )\n const strokeWidthSv = useSharedValue<number>(\n seedSource?.strokeWidth ?? strokeWidth ?? 1,\n )\n const strokeOpacitySv = useSharedValue<number>(\n seedSource?.strokeOpacity ?? strokeOpacity ?? 1,\n )\n const fillOpacitySv = useSharedValue<number>(\n seedSource?.fillOpacity ?? fillOpacity ?? 1,\n )\n const opacitySv = useSharedValue<number>(seedSource?.opacity ?? opacity ?? 1)\n const strokeDashoffsetSv = useSharedValue<number>(\n seedSource?.strokeDashoffset ?? strokeDashoffset ?? 0,\n )\n\n const reduce = useShouldReduceMotion()\n\n // Serialize scalar targets into stable keys so effects re-run on value\n // change, not on every parent re-render (a fresh `animate` literal each\n // render is the common case).\n const animateD = animate?.d\n const animateFill = animate?.fill\n const animateStroke = animate?.stroke\n const animateStrokeWidth = animate?.strokeWidth\n const animateStrokeOpacity = animate?.strokeOpacity\n const animateFillOpacity = animate?.fillOpacity\n const animateOpacity = animate?.opacity\n const animateStrokeDashoffset = animate?.strokeDashoffset\n\n useEffect(() => {\n if (animateD === undefined) return\n const segments = parsePathD(animateD)\n const t = templateOf(segments)\n const err = diffTemplate(template, t)\n if (err) {\n if (__DEV__) {\n throw new Error(`[inertia-svg] animate.d template mismatch: ${err}`)\n }\n return\n }\n const target = flattenParams(segments)\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'd')\n for (let i = 0; i < paramSvs.length; i++) {\n paramSvs[i]!.value = resolveTransition(cfg, target[i] ?? 0) as number\n }\n // paramSvs / template are stable across renders by the locks above.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateD, reduce, transition])\n\n useEffect(() => {\n if (animateFill === undefined) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'fill')\n fillSv.value = resolveTransition(cfg, animateFill) as string\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateFill, reduce, transition])\n\n useEffect(() => {\n if (animateStroke === undefined) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'stroke')\n strokeSv.value = resolveTransition(cfg, animateStroke) as string\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateStroke, reduce, transition])\n\n useEffect(() => {\n if (animateStrokeWidth === undefined) return\n const cfg = reduce\n ? NO_ANIMATION\n : pickTransition(transition, 'strokeWidth')\n strokeWidthSv.value = resolveTransition(cfg, animateStrokeWidth) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateStrokeWidth, reduce, transition])\n\n useEffect(() => {\n if (animateStrokeOpacity === undefined) return\n const cfg = reduce\n ? NO_ANIMATION\n : pickTransition(transition, 'strokeOpacity')\n strokeOpacitySv.value = resolveTransition(\n cfg,\n animateStrokeOpacity,\n ) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateStrokeOpacity, reduce, transition])\n\n useEffect(() => {\n if (animateFillOpacity === undefined) return\n const cfg = reduce\n ? NO_ANIMATION\n : pickTransition(transition, 'fillOpacity')\n fillOpacitySv.value = resolveTransition(cfg, animateFillOpacity) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateFillOpacity, reduce, transition])\n\n useEffect(() => {\n if (animateOpacity === undefined) return\n const cfg = reduce ? NO_ANIMATION : pickTransition(transition, 'opacity')\n opacitySv.value = resolveTransition(cfg, animateOpacity) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateOpacity, reduce, transition])\n\n useEffect(() => {\n if (animateStrokeDashoffset === undefined) return\n const cfg = reduce\n ? NO_ANIMATION\n : pickTransition(transition, 'strokeDashoffset')\n strokeDashoffsetSv.value = resolveTransition(\n cfg,\n animateStrokeDashoffset,\n ) as number\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [animateStrokeDashoffset, reduce, transition])\n\n const animatedProps = useAnimatedProps(() => {\n 'worklet'\n const params = new Array<number>(paramSvs.length)\n for (let i = 0; i < paramSvs.length; i++) params[i] = paramSvs[i]!.value\n return {\n d: serializePath(template, params),\n fill: fillSv.value,\n stroke: strokeSv.value,\n strokeWidth: strokeWidthSv.value,\n strokeOpacity: strokeOpacitySv.value,\n fillOpacity: fillOpacitySv.value,\n opacity: opacitySv.value,\n strokeDashoffset: strokeDashoffsetSv.value,\n }\n })\n\n return (\n <AnimatedPath\n // `animatedProps` overrides every animated key each frame; the static\n // props below are the first-render seeds so the path renders before the\n // first effect tick. The cast sheds Reanimated's strict-prop constraint\n // that the worklet's return type can't express — the runtime shape is\n // the same.\n animatedProps={animatedProps as never}\n d={d}\n fill={fill}\n stroke={stroke}\n strokeWidth={strokeWidth}\n strokeOpacity={strokeOpacity}\n fillOpacity={fillOpacity}\n opacity={opacity}\n strokeDashoffset={strokeDashoffset}\n {...rest}\n />\n )\n}\n\ndeclare const __DEV__: boolean\n","/**\n * `@rootnative/inertia-svg` — animatable SVG primitives for\n * `@rootnative/inertia`.\n *\n * v0.2 surface:\n * - `MotionPath` / `MotionSvg.Path` — animatable `<Path>` over\n * `react-native-svg`. Supports path morphing on the `d` attribute (source\n * and target must share the same command sequence) plus animatable\n * `fill`, `stroke`, `strokeWidth`, `strokeOpacity`, `fillOpacity`,\n * `opacity`, and `strokeDashoffset` with the same `initial` /\n * `animate` / `transition` shape as the core `Motion.*` primitives.\n *\n * Additional shape primitives (`Circle`, `Rect`, `Line`, `Ellipse`) land in\n * a follow-up once the path morphing API is validated. Path normalization\n * (resampling between structurally different paths) is out of scope for\n * v0.2 — use structurally-compatible source/target paths and remount with\n * `key={...}` to switch shape.\n */\nexport { MotionPath } from './MotionPath'\nexport type { MotionPathProps } from './MotionPath'\nexport type {\n PathAnimate,\n PathPerPropertyTransition,\n PathStateShape,\n PathTransition,\n} from './types'\n\nexport {\n parsePathD,\n templateOf,\n diffTemplate,\n flattenParams,\n serializePath,\n type PathSegment,\n type PathTemplate,\n} from './path'\n\nimport { MotionPath } from './MotionPath'\n\n/**\n * Namespace bundling every animatable SVG primitive. Use `MotionSvg.Path` for\n * autocomplete-friendly grouping or import `MotionPath` directly — both\n * point at the same component.\n */\nexport const MotionSvg = {\n Path: MotionPath,\n} as const\n"]}
package/llms.txt ADDED
@@ -0,0 +1,156 @@
1
+ > @rootnative/inertia-svg — adapter package for @rootnative/inertia.
2
+ > This file is generated from the matching docs page by scripts/build-llms.mjs — do not edit by hand.
3
+
4
+ > Full docs: https://rootnative.github.io/inertia/
5
+ > Core overview: see @rootnative/inertia/llms.txt (or docs/static/llms.txt in the repo)
6
+ > Source: https://github.com/rootnative/inertia
7
+
8
+ ---
9
+ # SVG
10
+
11
+ `@rootnative/inertia-svg` adds animatable SVG primitives built on [`react-native-svg`](https://github.com/software-mansion/react-native-svg). It is an **optional** sibling package — install it only when you need to morph paths or animate `fill` / `stroke`. The core library has no required `react-native-svg` dependency.
12
+
13
+ `MotionPath` wraps `<Path>` and accepts the same `initial` / `animate` / `transition` shape as the core `Motion.*` primitives, with animatable keys for the path data (`d`) plus color and numeric paint properties.
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ yarn add @rootnative/inertia-svg react-native-svg
19
+ ```
20
+
21
+ `react-native-svg` works in bare React Native projects as well as Expo.
22
+
23
+ ## Usage
24
+
25
+ ```tsx
26
+ import Svg from 'react-native-svg'
27
+ import { MotionPath } from '@rootnative/inertia-svg'
28
+
29
+ function Toggle({ open }) {
30
+ return (
31
+ <Svg viewBox="0 0 100 100" width={120} height={120}>
32
+ <MotionPath
33
+ d="M 20 30 L 50 60 L 80 30 L 80 30 L 50 60 L 20 30"
34
+ animate={{
35
+ d: open
36
+ ? 'M 20 30 L 50 60 L 80 30 L 80 30 L 50 60 L 20 30'
37
+ : 'M 20 50 L 50 20 L 80 50 L 80 50 L 50 80 L 20 50',
38
+ fill: open ? '#0ea5e9' : '#1f2937',
39
+ }}
40
+ transition={{ type: 'spring', tension: 140, friction: 12 }}
41
+ fill="#1f2937"
42
+ />
43
+ </Svg>
44
+ )
45
+ }
46
+ ```
47
+
48
+ The static `d` prop is required. Its **command sequence is locked at first render** — every target `d` you pass via `animate` or `initial` must produce the same command letters in the same order after implicit-repeat expansion. Element-wise scalar interpolation is the entire morphing model.
49
+
50
+ ## Structural compatibility
51
+
52
+ Two paths are morphable iff their normalized template (command letters, in order, with case preserved) is equal. Examples:
53
+
54
+ ```
55
+ ✅ M 0 0 L 10 10 Z ↔ M 50 50 L 80 80 Z same: M L Z
56
+ ✅ M 0 0 L 10 10 L 20 20 ↔ M 0 0 50 50 60 60 same: M L L
57
+ (implicit repeats after M expand to L)
58
+ ❌ M 0 0 L 10 10 Z ↔ M 0 0 L 10 10 differs: count
59
+ ❌ M 0 0 L 10 10 ↔ M 0 0 l 10 10 differs: absolute L vs relative l
60
+ ❌ M 0 0 L 10 10 ↔ M 0 0 C 1 1 2 2 3 3 differs: L vs C
61
+ ```
62
+
63
+ The component throws in dev when the templates diverge — either at mount (if `initial.d` mismatches the static `d`), when `animate.d` changes shape, or when the static `d` prop itself changes shape between renders. In production the bad target is skipped instead — the path simply keeps its current `d` (a mismatched `initial.d` falls back to the static `d`) so a single bad value doesn't crash the screen — but you should treat dev errors as bugs.
64
+
65
+ To switch between structurally different shapes, **remount with a new `key`**:
66
+
67
+ ```tsx
68
+ <MotionPath
69
+ key={open ? 'hexagon' : 'circle'}
70
+ d={open ? HEXAGON_D : CIRCLE_AS_QUADS_D}
71
+ />
72
+ ```
73
+
74
+ Path normalization that resamples between arbitrary shapes (the flubber-style approach) is out of scope for v0.2.
75
+
76
+ ## Animatable props
77
+
78
+ | Key | Shape | Notes |
79
+ | ------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------- |
80
+ | `d` | `string` | Path data. Source and target must share the same template — see above. Each scalar param springs / times independently. |
81
+ | `fill` | `string` | Color, interpolated via Reanimated's color setter. Defaults to `'transparent'` if neither static nor `initial` is supplied. |
82
+ | `stroke` | `string` | Same as `fill`. |
83
+ | `strokeWidth` | `number` | Numeric. Default seed `1`. |
84
+ | `strokeOpacity` | `number` | Numeric, 0–1. |
85
+ | `fillOpacity` | `number` | Numeric, 0–1. |
86
+ | `opacity` | `number` | Numeric, 0–1. |
87
+ | `strokeDashoffset` | `number` | Useful for "draw" animations on a dashed stroke. |
88
+
89
+ Per-property transitions work just like the core primitives:
90
+
91
+ ```tsx
92
+ <MotionPath
93
+ d={SOURCE_D}
94
+ fill="#000"
95
+ animate={{ d: TARGET_D, fill: '#7c3aed' }}
96
+ transition={{
97
+ d: { type: 'spring', tension: 160, friction: 14 },
98
+ fill: { type: 'timing', duration: 300 },
99
+ }}
100
+ />
101
+ ```
102
+
103
+ ## `initial`
104
+
105
+ Pass `initial` to override the mount-frame values (so the component starts somewhere other than the static props), or `initial={false}` to start at the `animate` target with no mount animation.
106
+
107
+ ```tsx
108
+ <MotionPath
109
+ d={STAR_D}
110
+ initial={{ d: TINY_STAR_D, opacity: 0 }} // hatch from a smaller star, fading in
111
+ animate={{ d: STAR_D, opacity: 1 }}
112
+ />
113
+
114
+ <MotionPath
115
+ d={STAR_D}
116
+ initial={false} // skip the mount animation
117
+ animate={{ d: HEART_D }}
118
+ />
119
+ ```
120
+
121
+ If `initial.d` is provided, it must be template-compatible with the static `d` — same rule as `animate.d`.
122
+
123
+ ## Reduced motion
124
+
125
+ `MotionPath` participates in [`<MotionConfig reducedMotion>`](./motion-config.md) the same way the core primitives do — when the OS reduce-motion setting is on (or you pass `reducedMotion="always"`), transitions resolve as direct assignment instead of `withSpring` / `withTiming`.
126
+
127
+ ## What this primitive doesn't do (v0.2)
128
+
129
+ - **Path resampling** between structurally different shapes. Same-template morphs only — the rest is your `key` to remount.
130
+ - **Other SVG shapes** (`Circle`, `Rect`, `Line`, `Ellipse`). They land in a follow-up release; pencil them in if you need them.
131
+ - **Gradient fills inside the SVG**. For gradient fills use `<Defs>` + `<LinearGradient>` from `react-native-svg` and animate the stops via [`MotionLinearGradient`](./gradients.mdx)'s patterns; the path itself just references the gradient by `url(#id)`.
132
+ - **Path command interpolation** (e.g. morphing an `L` into a `C`). Element-wise scalar interpolation is intentional — it's predictable, cheap, and matches what designers reach for 95% of the time.
133
+
134
+ ## Path utilities
135
+
136
+ The tokenizer and template helpers are exported for downstream tooling:
137
+
138
+ ```ts
139
+ import {
140
+ parsePathD,
141
+ templateOf,
142
+ diffTemplate,
143
+ flattenParams,
144
+ serializePath,
145
+ } from '@rootnative/inertia-svg'
146
+
147
+ const segs = parsePathD('M 0 0 L 10 10 Z') // [{ cmd: 'M', args: [0, 0] }, …]
148
+ const t = templateOf(segs) // { cmds: ['M','L','Z'], widths: [2,2,0], size: 4 }
149
+ const params = flattenParams(segs) // [0, 0, 10, 10]
150
+ const out = serializePath(t, [5, 5, 20, 20]) // 'M 5 5L 20 20Z'
151
+
152
+ const err = diffTemplate(t, templateOf(parsePathD('M 0 0 L 1 1')))
153
+ // → 'command count differs: …'
154
+ ```
155
+
156
+ `serializePath` is a worklet — call it inside `useAnimatedProps` if you build your own SVG primitives on top of this layer.
package/package.json ADDED
@@ -0,0 +1,84 @@
1
+ {
2
+ "name": "@rootnative/inertia-svg",
3
+ "version": "0.0.0-alpha.0",
4
+ "description": "Animatable SVG primitives (path morphing, fill/stroke) for @rootnative/inertia, built on react-native-svg.",
5
+ "license": "MIT",
6
+ "author": "RootNative",
7
+ "homepage": "https://github.com/rootnative/inertia",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/rootnative/inertia.git",
11
+ "directory": "packages/svg"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/rootnative/inertia/issues"
15
+ },
16
+ "keywords": [
17
+ "react-native",
18
+ "reanimated",
19
+ "svg",
20
+ "path",
21
+ "morph",
22
+ "animation",
23
+ "inertia"
24
+ ],
25
+ "sideEffects": false,
26
+ "main": "./dist/index.js",
27
+ "module": "./dist/index.mjs",
28
+ "types": "./dist/index.d.ts",
29
+ "react-native": "./src/index.ts",
30
+ "source": "./src/index.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "react-native": "./src/index.ts",
35
+ "source": "./src/index.ts",
36
+ "import": "./dist/index.mjs",
37
+ "require": "./dist/index.js"
38
+ },
39
+ "./package.json": "./package.json"
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "src",
44
+ "llms.txt",
45
+ "README.md",
46
+ "LICENSE",
47
+ "CHANGELOG.md",
48
+ "!**/__tests__",
49
+ "!**/*.test.*"
50
+ ],
51
+ "peerDependencies": {
52
+ "@rootnative/inertia": ">=0.0.0-alpha.0",
53
+ "react": ">=19.0.0",
54
+ "react-native": ">=0.81.0",
55
+ "react-native-reanimated": ">=4.0.0",
56
+ "react-native-svg": ">=15.0.0"
57
+ },
58
+ "devDependencies": {
59
+ "@react-native/babel-preset": "^0.81.5",
60
+ "@testing-library/react-native": "^13.3.3",
61
+ "@types/jest": "^29.5.14",
62
+ "@types/react": "^19.1.0",
63
+ "jest": "^29.7.0",
64
+ "react": "19.1.0",
65
+ "react-native": "0.81.5",
66
+ "react-native-reanimated": "~4.1.1",
67
+ "react-native-svg": "~15.13.0",
68
+ "react-test-renderer": "19.1.0",
69
+ "tsup": "^8.3.5",
70
+ "typescript": "^5.7.3",
71
+ "@rootnative/inertia": "0.0.0-alpha.0"
72
+ },
73
+ "publishConfig": {
74
+ "access": "public"
75
+ },
76
+ "scripts": {
77
+ "build": "tsup",
78
+ "dev": "tsup --watch",
79
+ "typecheck": "tsc --noEmit",
80
+ "test": "jest",
81
+ "lint": "eslint .",
82
+ "clean": "rm -rf dist .turbo *.tsbuildinfo"
83
+ }
84
+ }