@onlynative/inertia-svg 0.0.1-alpha.6 → 0.0.1-alpha.7
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/CHANGELOG.md +16 -0
- package/llms.txt +156 -0
- package/package.json +4 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@onlynative/inertia-svg` are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Pre-`1.0`, breaking changes may land in minor versions and are called out under their release.
|
|
4
|
+
|
|
5
|
+
This package ships in lockstep with `@onlynative/inertia` — version numbers track the core release that introduced or last touched the adapter.
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.0.1-alpha.6] — 2026-05-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `MotionPath` over `react-native-svg`. Animatable: `d` (element-wise scalar interpolation on structurally-compatible paths), `fill`, `stroke`, `strokeWidth`, opacities, `strokeDashoffset`. Source and target paths must share the same command sequence after implicit-repeat expansion; remount with `key` to switch shape.
|
|
14
|
+
|
|
15
|
+
[unreleased]: https://github.com/onlynative/inertia/compare/v0.0.1-alpha.6...HEAD
|
|
16
|
+
[0.0.1-alpha.6]: https://github.com/onlynative/inertia/releases/tag/v0.0.1-alpha.6
|
package/llms.txt
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
> @onlynative/inertia-svg — adapter package for @onlynative/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://onlynative.github.io/inertia/
|
|
5
|
+
> Core overview: see @onlynative/inertia/llms.txt (or docs/static/llms.txt in the repo)
|
|
6
|
+
> Source: https://github.com/onlynative/inertia
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
# SVG
|
|
10
|
+
|
|
11
|
+
`@onlynative/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 @onlynative/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 '@onlynative/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 those throws degrade to a no-op snap so a single bad target 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 '@onlynative/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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlynative/inertia-svg",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.7",
|
|
4
4
|
"description": "Animatable SVG primitives (path morphing, fill/stroke) for @onlynative/inertia, built on react-native-svg.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "OnlyNative",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"files": [
|
|
42
42
|
"dist",
|
|
43
43
|
"src",
|
|
44
|
+
"llms.txt",
|
|
44
45
|
"README.md",
|
|
45
46
|
"LICENSE",
|
|
46
47
|
"CHANGELOG.md",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"!**/*.test.*"
|
|
49
50
|
],
|
|
50
51
|
"peerDependencies": {
|
|
51
|
-
"@onlynative/inertia": ">=0.0.1-alpha.
|
|
52
|
+
"@onlynative/inertia": ">=0.0.1-alpha.7",
|
|
52
53
|
"react": ">=19.0.0",
|
|
53
54
|
"react-native": ">=0.81.0",
|
|
54
55
|
"react-native-reanimated": ">=4.0.0",
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
"react-test-renderer": "19.1.0",
|
|
68
69
|
"tsup": "^8.3.5",
|
|
69
70
|
"typescript": "^5.7.3",
|
|
70
|
-
"@onlynative/inertia": "0.0.1-alpha.
|
|
71
|
+
"@onlynative/inertia": "0.0.1-alpha.7"
|
|
71
72
|
},
|
|
72
73
|
"publishConfig": {
|
|
73
74
|
"access": "public"
|