@rootnative/inertia 0.0.3 → 0.0.5
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 +92 -5
- package/README.md +9 -3
- package/dist/{chunk-OQV66TBQ.mjs → chunk-27MKBTSG.mjs} +1 -1
- package/dist/{chunk-3XTVY34H.js → chunk-27U6766G.js} +2 -2
- package/dist/{chunk-4PEHWDAZ.js → chunk-4NAMD62I.js} +7 -7
- package/dist/chunk-67GHRCF6.js +8 -0
- package/dist/{chunk-SGUHE5CX.mjs → chunk-COEJVWRZ.mjs} +1 -1
- package/dist/chunk-GPOMFIIU.js +8 -0
- package/dist/{chunk-BQQTHG2V.mjs → chunk-GTJ6VAH5.mjs} +1 -1
- package/dist/chunk-K63LXGKS.js +8 -0
- package/dist/{chunk-46P57VMY.mjs → chunk-OAUWLPQH.mjs} +1 -1
- package/dist/{chunk-7AOERN53.js → chunk-OBRGJAST.js} +3 -3
- package/dist/{chunk-RGNX6UZN.mjs → chunk-OW5XTGVN.mjs} +2 -2
- package/dist/{chunk-PTRF47DA.js → chunk-PM6CVGXJ.js} +11 -3
- package/dist/{chunk-W5MC3P4N.js → chunk-QQVDZKSD.js} +2 -2
- package/dist/{chunk-CY7Y64C3.mjs → chunk-REYL77RE.mjs} +11 -4
- package/dist/{chunk-CSODMRJ7.mjs → chunk-RIVVBABB.mjs} +597 -134
- package/dist/{chunk-BP3Y2SHQ.js → chunk-VQ5D35UA.js} +617 -152
- package/dist/{chunk-O22NXXCZ.mjs → chunk-XSK5MNUH.mjs} +1 -1
- package/dist/{chunk-R63GIUNU.mjs → chunk-Z3HCJ43H.mjs} +1 -1
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/gestureLayer/index.js +10 -10
- package/dist/gestureLayer/index.mjs +3 -3
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +48 -169
- package/dist/index.mjs +17 -137
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +5 -5
- package/dist/motion/Image.mjs +4 -4
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +5 -5
- package/dist/motion/Pressable.mjs +4 -4
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +5 -5
- package/dist/motion/ScrollView.mjs +4 -4
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +5 -5
- package/dist/motion/Text.mjs +4 -4
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +5 -5
- package/dist/motion/View.mjs +4 -4
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/touch/index.js +3 -3
- package/dist/touch/index.mjs +1 -1
- package/dist/{types-G1dBU2IQ.d.mts → types-BQgLJeQG.d.mts} +85 -14
- package/dist/{types-G1dBU2IQ.d.ts → types-BQgLJeQG.d.ts} +85 -14
- package/dist/{useGesture-D1e4ixJo.d.ts → useGesture-B0_CzOUz.d.ts} +1 -1
- package/dist/{useGesture-RFY6kTL3.d.mts → useGesture-DfaTx-3t.d.mts} +1 -1
- package/llms.txt +3 -1
- package/package.json +1 -1
- package/src/index.ts +2 -1
- package/src/internal/boxShadow.ts +177 -6
- package/src/internal/nonWorkletWarning.ts +4 -6
- package/src/internal/warnOnce.ts +28 -0
- package/src/layout/index.ts +10 -0
- package/src/layout/measureWindow.ts +135 -0
- package/src/layout/sharedRegistry.ts +107 -18
- package/src/layout/useSharedLayout.ts +256 -91
- package/src/motion/createMotionComponent.tsx +497 -74
- package/src/motion/installCheck.ts +1 -1
- package/src/transitions/index.ts +1 -1
- package/src/transitions/resolveSequence.ts +12 -0
- package/src/types.ts +155 -12
- package/src/values/useColorTransition.ts +1 -1
- package/dist/chunk-FNVFV4EY.js +0 -8
- package/dist/chunk-FWQOXA43.js +0 -8
- package/dist/chunk-KBP4LR75.js +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,93 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to `@rootnative/inertia` 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.
|
|
3
|
+
All notable changes to `@rootnative/inertia` 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.0`, breaking changes may land in minor versions and are called out under their release.
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.0.5] - 2026-07-31
|
|
8
|
+
|
|
9
|
+
**Correctness release for the `animate` type surface.** The 40 layout and text-metric style keys that typechecked but were silently dropped at runtime now either animate or fail to compile. No API removals; the type narrowing is technically breaking for code that passed a never-driven key, but that code was already a no-op.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Layout numerics are animatable.** Forty keys join the `animate` surface, all riding the existing generic numeric path — one shared value each, resolved on the JS thread, emitted through the same branch as `opacity`:
|
|
14
|
+
|
|
15
|
+
| Group | Keys |
|
|
16
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| Per-corner radius | `borderTopLeftRadius`, `borderTopRightRadius`, `borderBottomLeftRadius`, `borderBottomRightRadius` |
|
|
18
|
+
| Border width | `borderWidth`, `borderTopWidth`, `borderRightWidth`, `borderBottomWidth`, `borderLeftWidth` |
|
|
19
|
+
| Absolute inset | `top`, `right`, `bottom`, `left` |
|
|
20
|
+
| Padding | `padding`, `paddingTop`, `paddingRight`, `paddingBottom`, `paddingLeft`, `paddingHorizontal`, `paddingVertical` |
|
|
21
|
+
| Margin | `margin`, `marginTop`, `marginRight`, `marginBottom`, `marginLeft`, `marginHorizontal`, `marginVertical` |
|
|
22
|
+
| Flex sizing | `flex`, `flexGrow`, `flexShrink` |
|
|
23
|
+
| Gap | `gap`, `rowGap`, `columnGap` |
|
|
24
|
+
| Stacking | `zIndex` |
|
|
25
|
+
| Text metrics | `fontSize`, `letterSpacing`, `lineHeight` — `Motion.Text` only, since they live on `TextStyle` |
|
|
26
|
+
|
|
27
|
+
Every one of these previously **typechecked and then did nothing**: `AnimateStyle<C>` mapped over the component's entire inferred style, so `animate={{ paddingTop: 40 }}` compiled cleanly, allocated nothing, and never appeared in the rendered style. The `Motion.Text` case was the sharpest — the docs told consumers to hand-roll `useAnimatedStyle` for `fontSize` while the type-test asserted `fontSize` was accepted, so the two halves of the contract actively disagreed. Sequences, `{ to }` step objects, per-property transitions, `gesture` sub-states, `exit`, variants, and the `layoutId` resting logic all work on the new keys with no special-casing.
|
|
28
|
+
|
|
29
|
+
**These drive real layout, so they reflow every frame.** Prefer `scale` / `translate*` for pure motion — those composite without touching layout. Reach for these when the layout genuinely changes: a drawer sliding via `left`, a card squaring off one corner as it expands, a pane resize via `flex`. The Fabric jitter caveat that has always applied to `width` / `height` on non-`flex: 1` containers applies here too.
|
|
30
|
+
|
|
31
|
+
**Resting values behave as they have since `0.0.3`.** A key declared only in a `gesture` sub-state, an `exit` target, or a non-active variant joins the active set, so the worklet emits it every frame including at rest — and since the animated style merges _after_ `style`, a non-identity resting default would silently stomp the consumer's layout. The existing style-scan handles this: such a key rests at whatever `StyleSheet.flatten(style)` says, falling back to the type default only when the style is silent. All 40 defaults are `0`, which is RN's own unset value for each, so a key that does fall back lands where the element already was. Guarded by four dedicated cases in `animatable-keys.test.tsx` alongside the existing `style-resting.test.tsx`.
|
|
32
|
+
|
|
33
|
+
**Bundle cost: +0.11 kB (+1.3%) per primitive subpath**, 8.80 → 8.91 kB brotlied, +0.08 kB on the root entry. No `size-limit` cap moved. Nearly free because the factory's per-key machinery was already generic: the only structural change was replacing 23 hand-written `useSharedValue` calls in `useAnimatableSharedValues` with a loop over `ALL_KEYS`, which offset almost the entire cost of the 40 new table entries. Hook order stays stable because `ALL_KEYS` is a module-level `as const` whose length is fixed at module evaluation.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- **`animate` now rejects style keys Inertia doesn't drive, at compile time.** `AnimateStyle<C>` is narrowed to an intersection of the component's style keys and the set the runtime actually animates, so `animate={{ alignItems: 'center' }}` is a type error instead of a silent no-op. This restores the library's headline differentiator — the first row of the sharp-edges table promises that wrong props error rather than going unnoticed — which the previous whole-style mapping had quietly broken for every non-animatable key.
|
|
38
|
+
|
|
39
|
+
**Technically breaking, practically not:** code that passed one of these keys stops compiling, but it was already doing nothing at runtime, so nothing that worked before stops working. Fixing a break means either deleting the key or moving it to the static `style` prop, which is where it belonged.
|
|
40
|
+
|
|
41
|
+
Two categories are rejected on purpose. **Enum-valued keys** (`position`, `overflow`, `alignItems`, `flexDirection`, `display`) have no interpolable midpoint. **`minWidth` / `maxWidth` / `minHeight` / `maxHeight` / `aspectRatio`** are excluded for a subtler reason worth recording: their unset state isn't a number, so there is no value they could rest at when declared only in a `gesture` sub-state or a non-active variant — any numeric default would change the layout the instant the key activated, which is exactly the `0.0.3` resting-value regression. Animate `width` / `height` instead, or drop to the value-layer hooks. Per-primitive gating is unchanged and still enforced: `tintColor` stays Image-only, and the text metrics are rejected on `Motion.View` and `Motion.Image`.
|
|
42
|
+
|
|
43
|
+
`AnimatableStyleKey` (the new type) and `ALL_KEYS` (the runtime array) are necessarily separate declarations — one is a type, the other a value in a module that imports it — so the pairing is pinned by tests on both sides: `__type-tests__/animate-keys.test-d.tsx` (23 compile-time assertions) proves the type accepts and rejects the right keys, and `__tests__/animatable-keys.test.tsx` (17 cases) proves every accepted key reaches the rendered style. A key added to one but not the other fails one of the two.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **Reduced motion is no longer bypassed by a sequence step that declares its own `type`.** `<MotionConfig reducedMotion="always">` (and the `'user'` default under an OS reduce-motion setting) swaps every per-key transition for `{ type: 'no-animation' }`, but `mergeTransition` in `resolveSequence.ts` let a step-declared `type` win outright over the base whenever the two differed — so `animate={{ translateX: [0, { to: 100, type: 'timing', duration: 200 }, 0] }}` still called `withTiming` for a user who had asked the OS for no motion. Both sequence arrays and the single `{ to, ...override }` form were affected, for every step type.
|
|
48
|
+
|
|
49
|
+
A `no-animation` base is now treated as a **ceiling rather than a default**: it short-circuits the merge before the step-type rule runs. That rule is unchanged and still correct for ordinary bases — mixing a spring base's `tension` into a timing override produces garbage, which is why it exists.
|
|
50
|
+
|
|
51
|
+
This contradicted the contract stated in `createMotionComponent.tsx`, which had promised since the gate was written that reduced motion "overrides every per-key transition (and any nested sequence-step transition)". The code was the half that was wrong.
|
|
52
|
+
|
|
53
|
+
**Why it went unnoticed:** `reduced-motion.test.tsx` asserted only on per-key transitions, where the base reaches Reanimated unmodified — sequence steps were the one path that could talk its way past the gate, and nothing covered them. Three cases now do, including a `reducedMotion="never"` positive control so a future regression can't pass by asserting nothing. Dropping a step `delay` alongside the type matches how the rest of the resolver already treats this transition type (`delayOf` and `repeatOf` both return `undefined` for `no-animation`), so a snap is never deferred or repeated anywhere in the library.
|
|
54
|
+
|
|
55
|
+
Surfaced by the `@rootnative/ui` validation consumer, whose `LinearProgress` / `CircularProgress` both use an inline-typed snap-back step inside an infinite keyframe loop. Their local workaround — not mounting the `Motion.View` at all under reduced motion — remains the better render and is unaffected. No bundle-size change (one early-return branch; primitives stay at 8.9 kB against the 10.3 kB cap).
|
|
56
|
+
|
|
57
|
+
## [0.0.4] - 2026-07-29
|
|
58
|
+
|
|
59
|
+
**Feature release.** The three deferred items the `0.0.3` audit left on the roadmap land together: `boxShadow` joins the declarative `animate` surface, and `layoutId` shared-element transitions gain window-coordinate measurement and a style carry. No breaking changes; the three adapters are lockstep-bumped with no runtime changes of their own.
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- **`boxShadow` is now an animatable property on the `animate` surface.** The cross-platform CSS shadow form joins the declarative surface alongside the native `shadow*` keys, accepting either a CSS string (`'0px 4px 8px rgba(0,0,0,0.3)'` — the shape design systems store elevation tokens in) or React Native's own `BoxShadowValue[]`, whose lengths may be numbers or px strings. The key was already accepted at compile time and silently ignored at runtime, because `AnimateStyle<C>` maps over every key of the inferred style and RN's `ViewStyle` has carried `boxShadow` since 0.76 — so this makes an accepted key work rather than widening the type surface. Endpoints are normalized on the JS thread once per change and padded to a common layer count, so **layer counts may differ between `initial` and `animate`**: the short side gains transparent zero layers and the surplus layer fades rather than popping, matching CSS transition semantics. Every length and color interpolates per layer. `inset` is carried as a **static** per-layer flag rather than interpolated (there is no meaningful midpoint between an inner and an outer shadow, and a boolean driven down Reanimated's numeric path yields `0` mid-flight — a number where native expects a boolean); both endpoints may use it freely, but a layer that is `inset` on one side only throws, as it already did in `useShadow`. Only px and unitless lengths are accepted; `em` / `%` / `rem` throw rather than animating from a `NaN`. New `BoxShadowInput` type exported from the root barrel. Guarded by `boxShadow.test.tsx` (22 cases) and seven compile-time assertions in `animate.test-d.tsx`.
|
|
64
|
+
|
|
65
|
+
Worth knowing if you go looking at the implementation: the target has to reach Reanimated as the **structured array**, not the CSS string. `withSpring` / `withTiming` dispatch on the runtime shape of the value, and a box-shadow string is not a color, so it lands in the prefix-number-suffix branch built for values like `'100%'` and would pull a single number out of a four-value shadow. The array form instead recurses into each layer and animates every leaf. All string parsing therefore happens on the JS thread, and the worklet only emits what the slot already holds — no frame-time string or structural work.
|
|
66
|
+
|
|
67
|
+
Two deliberate limits, both matching the single-value contract `shadowOffset` has carried since `0.0.1`. **Sequences are unsupported on this key**: `boxShadow: [a, b]` means one two-layer shadow, not a two-step keyframe sequence, because nothing distinguishes the two shapes structurally and the array form is the one RN itself uses. Per-property transitions are unaffected. **`boxShadow` is not accepted inside `gesture` sub-states**: compositing a layer stack through the priority cascade would put per-layer, per-field interpolation on the UI thread for every primitive whether or not it animates a shadow. It dev-warns and is ignored — drive it from `animate` (optionally via a variant keyed off the same state), or interpolate it yourself with `useShadow`. Animating `boxShadow` alongside the native `shadow*` keys on one element also dev-warns: that applies two shadow systems at once and whichever the view resolves last wins.
|
|
68
|
+
|
|
69
|
+
**Bundle cost, measured:** +1.61 kB (+24%) per primitive subpath — 6.63 kB → 8.24 kB brotlied — and +0.82 kB on the root entry, which was already carrying the shadow parser via `useShadow`. The `size-limit` caps were raised deliberately to keep the ~25% band the config has always claimed; the full accounting, including the alternatives that were measured and rejected, is in `.size-limit.cjs`.
|
|
70
|
+
|
|
71
|
+
- **`layoutId` shared-element transitions now carry style across, not just the rect.** A hero card that changes background colour, corner radius, or opacity between screens used to snap on those props while its frame animated — the most visible half of the transition arriving instantly. The source element's values for `opacity`, `borderRadius`, `backgroundColor`, `borderColor`, `color`, and `tintColor` are now snapshotted alongside its rect and crossfaded out over the same transition that drives the FLIP, so the arriving element starts wearing its counterpart's style and ends wearing its own. Nothing to configure: it rides the existing `layoutId` + `transition` props.
|
|
72
|
+
|
|
73
|
+
**Which keys carry, and why not more.** Transform keys are deliberately excluded — they are the FLIP's job, and carrying them too would apply the same displacement twice. So is `shadowColor`, despite being a colour key: crossfading one of the four native shadow props over geometry that snapped looks worse than letting the whole shadow snap together. There is no configuration surface for the list and no `layoutStyles` prop; if you need a key that isn't carried, drive it from `animate` on both sides.
|
|
74
|
+
|
|
75
|
+
**A key only participates when the element already has a value for it** — from `animate` / `initial` / a variant / `gesture`, or from the static `style`, read through `StyleSheet.flatten` the same way undriven resting values are. Values are never invented: activating a key the element says nothing about would rest it at the generic type default, and for `color` on a `Motion.Text` that inherits its colour from a parent, that default is `'transparent'` — invisible text on an element the consumer only asked to move. This is the same failure mode as the `0.0.3` resting-value regression, approached from the other side. A key the source carried but the target has no value for is ignored, and vice versa.
|
|
76
|
+
|
|
77
|
+
**A still-mounted source is read live**, for the same reason its rect is re-measured: values move without a layout pass (an animation settling, a theme swap), so the stored snapshot is a floor rather than the truth. Once the source has unmounted, the snapshot taken at release is all that remains. Reduced motion and `transition={{ type: 'no-animation' }}` snap, matching the rect path — and a source and target in mismatched coordinate spaces skip the style carry along with the FLIP, since half a shared-element transition reads as a glitch rather than as graceful degradation. On the mount that consumes a source, the carry composites _above_ the base value, so it overrides `initial` for the carried keys on that mount.
|
|
78
|
+
|
|
79
|
+
Cheap by construction: one progress shared value drives however many keys are carried, and the blend reuses the worklet's existing lerp / `interpolateColor` branches — the same ones the `gesture` cascade uses — sitting one priority above every gesture layer. At rest the pair is `(null, 0)`, so a primitive that isn't mid-transition pays a single comparison. **Bundle cost: +0.56 kB (+6.8%) per primitive subpath**, 8.24 → 8.80 kB brotlied, +0.59 kB root; the `size-limit` caps did not move. Workspace-internal API changes (none of it is exported from the package root): `consumeLayout` returns `{ rect, remeasure?, styles?, readStyles? }`, `registerLayout` takes an optional style reader, `releaseLayout` takes an optional snapshot, and `useSharedLayout` returns a `carry` binding alongside `flip`. Guarded by 16 new cases in `sharedLayout.test.tsx`.
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
|
|
83
|
+
- **`layoutId` shared-element rects are now measured in window coordinates.** Rects came from `onLayout`, which reports **parent-relative** coordinates, so a source and target sitting under containers at different screen offsets produced a FLIP short by exactly that offset — the element flew in from the wrong place. Rects are now measured with `measureInWindow` on the host node, which is what makes nested-parent setups line up. Where a synchronous measurement isn't available the parent-relative rect is used instead, so behavior is unchanged rather than broken; each entry records which space it is in, and a source and target that ended up in _different_ spaces skip the animation rather than play a wrong one.
|
|
84
|
+
|
|
85
|
+
**Synchronous or not at all**, and this is a design decision rather than a limitation. `measureInWindow` resolves synchronously on Fabric (a JSI call), asynchronously on the legacy architecture (over the bridge), and **never** on a detached node — `ReactFabricHostComponent.measureInWindow` looks the node up and simply returns when it's missing, and the Jest host mock behaves the same way. Awaiting the callback would put the same element in window space on one platform and parent space on another, and since the two aren't comparable, a source stored in one and a target measured in the other would silently cancel the transition. Reading the result synchronously or treating it as unavailable keeps the space coherent: fixed on Fabric, unchanged on legacy, never intermittent. A late callback is deliberately dropped. A measurement that is zero-sized or non-finite is also rejected — trusting it would fling the element in from the top-left corner, which is worse than not animating.
|
|
86
|
+
|
|
87
|
+
**A still-mounted source is re-measured when the target lays out.** This is the other half of the change, and without it window coordinates would have been a net regression. `onLayout` does not fire when an _ancestor_ scrolls, so a stored window rect drifts as the user scrolls a list while a parent-relative rect would have stayed valid — meaning the most common shared-element case (scroll a list of photos, tap one) would have been offset by the scroll distance. A registry entry now carries a re-measure hook while its owner is mounted, which a stack navigator's outgoing screen still is at the moment the incoming one lays out. `releaseLayout` drops the hook, since a detached node measures to nothing. Remaining caveat: if the navigator has already begun translating the outgoing screen, the re-measurement catches it mid-transition — bounded by how far the transition has progressed, far smaller than an unbounded scroll offset.
|
|
88
|
+
|
|
89
|
+
Also fixed while here: **the four FLIP shared values now cancel on unmount.** The `0.0.2` unmount-cancel pass covered the value-layer hooks and the factory's per-key values but missed these. Workspace-internal API changes (none of it is exported from the package root): `SharedRect` gains a required `space` field, `consumeLayout` returns a source object instead of a bare rect, `registerLayout` takes an optional re-measure hook, and a new `__setSharedLayoutMeasurer` test hook joins `__setSharedLayoutClock`. Guarded by 12 new cases in `sharedLayout.test.tsx` (49 in total for this release, counting the style carry below).
|
|
90
|
+
|
|
7
91
|
## [0.0.3] - 2026-07-25
|
|
8
92
|
|
|
9
93
|
### Fixed
|
|
@@ -80,9 +164,11 @@ All notable changes to `@rootnative/inertia` are documented here. The format fol
|
|
|
80
164
|
|
|
81
165
|
- **Nested `<MotionConfig>` now inherits `reducedMotion`** from its ancestor when the prop is omitted (previously an inner provider silently reset the subtree to the `'user'` default). A transitions-only inner provider no longer clobbers an outer `reducedMotion="never"` / `"always"`.
|
|
82
166
|
|
|
83
|
-
##
|
|
167
|
+
## 0.0.0-alpha.0
|
|
168
|
+
|
|
169
|
+
_No git tag was cut for this release; the published artifact is on npm as [`@rootnative/inertia@0.0.0-alpha.0`](https://www.npmjs.com/package/@rootnative/inertia/v/0.0.0-alpha.0). Unlinked here for that reason — every other heading resolves to a real tag._
|
|
84
170
|
|
|
85
|
-
Initial alpha publish. The full
|
|
171
|
+
Initial alpha publish. The full initial surface is in place; APIs are still subject to change before the stability lock at `1.0.0`.
|
|
86
172
|
|
|
87
173
|
### Added
|
|
88
174
|
|
|
@@ -105,7 +191,9 @@ Initial alpha publish. The full v0.1 surface is in place; APIs are still subject
|
|
|
105
191
|
- SVG path morphing, gradient interpolation, and shared-element transitions across screens are out of scope until `0.2.x` / `1.x` per the roadmap.
|
|
106
192
|
- `react-native-gesture-handler` integration (drag, pan, swipe sub-states) lands in `0.2` via the optional `@rootnative/inertia-gestures` adapter.
|
|
107
193
|
|
|
108
|
-
[unreleased]: https://github.com/rootnative/inertia/compare/core+gestures+gradients+svg@0.0.
|
|
194
|
+
[unreleased]: https://github.com/rootnative/inertia/compare/core+gestures+gradients+svg@0.0.5...HEAD
|
|
195
|
+
[0.0.5]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.5
|
|
196
|
+
[0.0.4]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.4
|
|
109
197
|
[0.0.3]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.3
|
|
110
198
|
[0.0.2]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.2
|
|
111
199
|
[0.0.1]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.1
|
|
@@ -114,4 +202,3 @@ Initial alpha publish. The full v0.1 surface is in place; APIs are still subject
|
|
|
114
202
|
[0.0.0-alpha.3]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.0-alpha.3
|
|
115
203
|
[0.0.0-alpha.2]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.0-alpha.2
|
|
116
204
|
[0.0.0-alpha.1]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.0-alpha.1
|
|
117
|
-
[0.0.0-alpha.0]: https://github.com/rootnative/inertia/releases/tag/core+gestures+gradients+svg@0.0.0-alpha.0
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Declarative animation primitives for React Native, built as a thin wrapper around [`react-native-reanimated`](https://docs.swmansion.com/react-native-reanimated/). Inspired by Framer Motion (web) and react-spring (cross-platform).
|
|
8
8
|
|
|
9
|
-
> **Status:** `0.0.
|
|
9
|
+
> **Status:** `0.0.5` — stable. Pre-`1.0.0` minor versions may break — see the root [README](https://github.com/rootnative/inertia#versioning--release).
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -86,9 +86,15 @@ Plus, on any transition: `delay`, `repeat`. Per-property transitions take preced
|
|
|
86
86
|
|
|
87
87
|
## Animatable properties
|
|
88
88
|
|
|
89
|
-
Numeric: `opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `width`, `height`, `borderRadius`. Color: `backgroundColor`, `borderColor`, `color`, `tintColor` (Image only — `Motion.View` rejects it at compile time). Layout transforms via `transform: [...]`. Color targets are forwarded straight through `withSpring` / `withTiming`; Reanimated's value setter packs the string to RGBA and interpolates on the UI thread.
|
|
89
|
+
Numeric: `opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `width`, `height`, `borderRadius`, `shadowOpacity`, `shadowRadius`, `elevation`. Color: `backgroundColor`, `borderColor`, `color`, `shadowColor`, `tintColor` (Image only — `Motion.View` rejects it at compile time). Layout transforms via `transform: [...]`. Color targets are forwarded straight through `withSpring` / `withTiming`; Reanimated's value setter packs the string to RGBA and interpolates on the UI thread.
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
Layout numerics (since `0.0.5`): per-corner radii (`borderTopLeftRadius` …), border widths (`borderWidth`, `borderTopWidth` …), absolute insets (`top` / `right` / `bottom` / `left`), padding and margin including the `*Horizontal` / `*Vertical` shorthands, `flex` / `flexGrow` / `flexShrink`, `gap` / `rowGap` / `columnGap`, `zIndex`, and the `Motion.Text`-only metrics `fontSize` / `letterSpacing` / `lineHeight`. These drive real layout, so they reflow each frame — prefer `scale` / `translate*` for pure motion.
|
|
92
|
+
|
|
93
|
+
`animate` is narrowed to the keys Inertia actually drives, so an unsupported style key (`alignItems`, `position`, `minWidth`, …) is a compile error instead of a silent no-op.
|
|
94
|
+
|
|
95
|
+
Nested object: `shadowOffset: { width, height }` — single-value form only (no sequences, no array keyframes). Structured: `boxShadow` — the cross-platform CSS shadow, as a string (`'0px 4px 8px rgba(0,0,0,0.3)'`) or RN's `BoxShadowValue[]`. Endpoints are padded to a common layer count, so layer counts may differ between `initial` and `animate`; sequences and `gesture` sub-states are not supported on this key.
|
|
96
|
+
|
|
97
|
+
SVG path morphing ships in the [`@rootnative/inertia-svg`](../svg) adapter (`MotionPath`). Shared-element transitions across screens are wired through the `layoutId` prop — pair the same id on a source and target `Motion.*` and Inertia FLIPs between them on mount, carrying `opacity`, `borderRadius`, and the color keys across alongside the rect.
|
|
92
98
|
|
|
93
99
|
## When not to use the core package alone
|
|
94
100
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkVQ5D35UA_js = require('./chunk-VQ5D35UA.js');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
5
|
|
|
6
|
-
var MotionPressable =
|
|
6
|
+
var MotionPressable = chunkVQ5D35UA_js.createMotionComponent(reactNative.Pressable);
|
|
7
7
|
|
|
8
8
|
exports.MotionPressable = MotionPressable;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkOBRGJAST_js = require('./chunk-OBRGJAST.js');
|
|
4
|
+
var chunkPM6CVGXJ_js = require('./chunk-PM6CVGXJ.js');
|
|
5
5
|
var react = require('react');
|
|
6
6
|
var reactNativeReanimated = require('react-native-reanimated');
|
|
7
7
|
|
|
@@ -10,12 +10,12 @@ function useGesture(transition) {
|
|
|
10
10
|
const focused = reactNativeReanimated.useSharedValue(0);
|
|
11
11
|
const focusVisible = reactNativeReanimated.useSharedValue(0);
|
|
12
12
|
const hovered = reactNativeReanimated.useSharedValue(0);
|
|
13
|
-
const shouldReduceMotion =
|
|
14
|
-
const resolved =
|
|
13
|
+
const shouldReduceMotion = chunkOBRGJAST_js.useShouldReduceMotion();
|
|
14
|
+
const resolved = chunkOBRGJAST_js.resolveNamedTransitionProp(transition, chunkOBRGJAST_js.useNamedTransitions());
|
|
15
15
|
const setLayer = react.useCallback(
|
|
16
16
|
(sv, layer, target) => {
|
|
17
17
|
const cfg = shouldReduceMotion ? { type: "no-animation" } : layerTransition(layer, resolved) ?? { type: "spring" };
|
|
18
|
-
sv.value =
|
|
18
|
+
sv.value = chunkPM6CVGXJ_js.resolveTransition(cfg, target);
|
|
19
19
|
},
|
|
20
20
|
// The transition is intentionally read on every call rather than cooked
|
|
21
21
|
// into the dep array — a fresh literal each render would otherwise
|
|
@@ -34,7 +34,7 @@ function useGesture(transition) {
|
|
|
34
34
|
onHoverOut: () => setLayer(hovered, "hovered", 0),
|
|
35
35
|
onFocus: () => {
|
|
36
36
|
setLayer(focused, "focused", 1);
|
|
37
|
-
if (
|
|
37
|
+
if (chunkOBRGJAST_js.isFocusVisible()) setLayer(focusVisible, "focusVisible", 1);
|
|
38
38
|
},
|
|
39
39
|
onBlur: () => {
|
|
40
40
|
setLayer(focused, "focused", 0);
|
|
@@ -47,7 +47,7 @@ function useGesture(transition) {
|
|
|
47
47
|
}
|
|
48
48
|
function layerTransition(layer, transition) {
|
|
49
49
|
if (!transition) return void 0;
|
|
50
|
-
if (
|
|
50
|
+
if (chunkPM6CVGXJ_js.isTopLevelTransition(transition)) return transition;
|
|
51
51
|
return transition[layer];
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkPM6CVGXJ_js = require('./chunk-PM6CVGXJ.js');
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var reactNativeReanimated = require('react-native-reanimated');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -32,7 +32,7 @@ function MotionConfig({
|
|
|
32
32
|
children
|
|
33
33
|
}) {
|
|
34
34
|
const parent = useMotionConfig();
|
|
35
|
-
const transitionsSig =
|
|
35
|
+
const transitionsSig = chunkPM6CVGXJ_js.stableSig(transitions);
|
|
36
36
|
const value = react.useMemo(
|
|
37
37
|
() => ({
|
|
38
38
|
reducedMotion: reducedMotion ?? parent.reducedMotion,
|
|
@@ -66,7 +66,7 @@ function resolveNamedTransitionProp(transition, registry) {
|
|
|
66
66
|
if (typeof transition === "string") {
|
|
67
67
|
return lookupNamedTransition(transition, registry);
|
|
68
68
|
}
|
|
69
|
-
if (
|
|
69
|
+
if (chunkPM6CVGXJ_js.isTopLevelTransition(transition)) return transition;
|
|
70
70
|
const map = transition;
|
|
71
71
|
let out = null;
|
|
72
72
|
for (const key in map) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useShouldReduceMotion, resolveNamedTransitionProp, useNamedTransitions, isFocusVisible } from './chunk-
|
|
2
|
-
import { resolveTransition, isTopLevelTransition } from './chunk-
|
|
1
|
+
import { useShouldReduceMotion, resolveNamedTransitionProp, useNamedTransitions, isFocusVisible } from './chunk-Z3HCJ43H.mjs';
|
|
2
|
+
import { resolveTransition, isTopLevelTransition } from './chunk-REYL77RE.mjs';
|
|
3
3
|
import { useCallback, useMemo } from 'react';
|
|
4
4
|
import { useSharedValue } from 'react-native-reanimated';
|
|
5
5
|
|
|
@@ -5,16 +5,22 @@ var reactNativeReanimated = require('react-native-reanimated');
|
|
|
5
5
|
|
|
6
6
|
// src/transitions/easing.ts
|
|
7
7
|
|
|
8
|
-
// src/internal/
|
|
8
|
+
// src/internal/warnOnce.ts
|
|
9
9
|
var warned = /* @__PURE__ */ new Set();
|
|
10
|
-
function
|
|
10
|
+
function warnOnce(key, message) {
|
|
11
11
|
if (!__DEV__) return;
|
|
12
|
-
if (typeof process !== "undefined" && process.env?.JEST_WORKER_ID) return;
|
|
13
12
|
if (warned.has(key)) return;
|
|
14
13
|
warned.add(key);
|
|
15
14
|
console.warn(message);
|
|
16
15
|
}
|
|
17
16
|
|
|
17
|
+
// src/internal/nonWorkletWarning.ts
|
|
18
|
+
function warnNonWorkletOnce(key, message) {
|
|
19
|
+
if (!__DEV__) return;
|
|
20
|
+
if (typeof process !== "undefined" && process.env?.JEST_WORKER_ID) return;
|
|
21
|
+
warnOnce(key, message);
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
// src/transitions/easing.ts
|
|
19
25
|
function ensureWorkletEasing(easing) {
|
|
20
26
|
if (!easing) return void 0;
|
|
@@ -153,6 +159,7 @@ function resolveStep(step, base, cb) {
|
|
|
153
159
|
return resolveTransition(base, step, cb);
|
|
154
160
|
}
|
|
155
161
|
function mergeTransition(base, override) {
|
|
162
|
+
if (base?.type === "no-animation") return base;
|
|
156
163
|
if (override.type && base && override.type !== base.type) {
|
|
157
164
|
return override;
|
|
158
165
|
}
|
|
@@ -282,3 +289,4 @@ exports.resolveTransition = resolveTransition;
|
|
|
282
289
|
exports.springToReanimated = springToReanimated;
|
|
283
290
|
exports.stableSig = stableSig;
|
|
284
291
|
exports.warnNonWorkletOnce = warnNonWorkletOnce;
|
|
292
|
+
exports.warnOnce = warnOnce;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkVQ5D35UA_js = require('./chunk-VQ5D35UA.js');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
5
|
|
|
6
|
-
var MotionScrollView =
|
|
6
|
+
var MotionScrollView = chunkVQ5D35UA_js.createMotionComponent(reactNative.ScrollView);
|
|
7
7
|
|
|
8
8
|
exports.MotionScrollView = MotionScrollView;
|
|
@@ -3,16 +3,22 @@ import { withSequence, Easing, withDecay, withTiming, withSpring, withRepeat, wi
|
|
|
3
3
|
|
|
4
4
|
// src/transitions/easing.ts
|
|
5
5
|
|
|
6
|
-
// src/internal/
|
|
6
|
+
// src/internal/warnOnce.ts
|
|
7
7
|
var warned = /* @__PURE__ */ new Set();
|
|
8
|
-
function
|
|
8
|
+
function warnOnce(key, message) {
|
|
9
9
|
if (!__DEV__) return;
|
|
10
|
-
if (typeof process !== "undefined" && process.env?.JEST_WORKER_ID) return;
|
|
11
10
|
if (warned.has(key)) return;
|
|
12
11
|
warned.add(key);
|
|
13
12
|
console.warn(message);
|
|
14
13
|
}
|
|
15
14
|
|
|
15
|
+
// src/internal/nonWorkletWarning.ts
|
|
16
|
+
function warnNonWorkletOnce(key, message) {
|
|
17
|
+
if (!__DEV__) return;
|
|
18
|
+
if (typeof process !== "undefined" && process.env?.JEST_WORKER_ID) return;
|
|
19
|
+
warnOnce(key, message);
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
// src/transitions/easing.ts
|
|
17
23
|
function ensureWorkletEasing(easing) {
|
|
18
24
|
if (!easing) return void 0;
|
|
@@ -151,6 +157,7 @@ function resolveStep(step, base, cb) {
|
|
|
151
157
|
return resolveTransition(base, step, cb);
|
|
152
158
|
}
|
|
153
159
|
function mergeTransition(base, override) {
|
|
160
|
+
if (base?.type === "no-animation") return base;
|
|
154
161
|
if (override.type && base && override.type !== base.type) {
|
|
155
162
|
return override;
|
|
156
163
|
}
|
|
@@ -270,4 +277,4 @@ function stableStringify(v) {
|
|
|
270
277
|
return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
|
|
271
278
|
}
|
|
272
279
|
|
|
273
|
-
export { DEFAULT_SPRING, buildReleaseAnimation, cubicBezier, ensureWorkletEasing, isTopLevelTransition, resolveAnimatableValue, resolveTransition, springToReanimated, stableSig, warnNonWorkletOnce };
|
|
280
|
+
export { DEFAULT_SPRING, buildReleaseAnimation, cubicBezier, ensureWorkletEasing, isTopLevelTransition, resolveAnimatableValue, resolveTransition, springToReanimated, stableSig, warnNonWorkletOnce, warnOnce };
|