@rootnative/inertia 0.0.4 → 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.
Files changed (63) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/README.md +5 -1
  3. package/dist/{chunk-NAOXQJ7U.mjs → chunk-27MKBTSG.mjs} +1 -1
  4. package/dist/{chunk-CENTULW6.js → chunk-27U6766G.js} +2 -2
  5. package/dist/{chunk-D5KAHWMC.js → chunk-4NAMD62I.js} +7 -7
  6. package/dist/chunk-67GHRCF6.js +8 -0
  7. package/dist/{chunk-4ASOELLA.mjs → chunk-COEJVWRZ.mjs} +1 -1
  8. package/dist/chunk-GPOMFIIU.js +8 -0
  9. package/dist/{chunk-YKGY22SB.mjs → chunk-GTJ6VAH5.mjs} +1 -1
  10. package/dist/chunk-K63LXGKS.js +8 -0
  11. package/dist/{chunk-RF7J5FRM.mjs → chunk-OAUWLPQH.mjs} +1 -1
  12. package/dist/{chunk-WVRCKOPO.js → chunk-OBRGJAST.js} +3 -3
  13. package/dist/{chunk-K3CLP74S.mjs → chunk-OW5XTGVN.mjs} +2 -2
  14. package/dist/{chunk-7A6WTXNK.js → chunk-PM6CVGXJ.js} +1 -0
  15. package/dist/{chunk-XMEVPEMH.js → chunk-QQVDZKSD.js} +2 -2
  16. package/dist/{chunk-TU2XFPAK.mjs → chunk-REYL77RE.mjs} +1 -0
  17. package/dist/{chunk-55W7BNO2.mjs → chunk-RIVVBABB.mjs} +130 -59
  18. package/dist/{chunk-MYE5NMXW.js → chunk-VQ5D35UA.js} +154 -83
  19. package/dist/{chunk-J5Q46OPW.mjs → chunk-XSK5MNUH.mjs} +1 -1
  20. package/dist/{chunk-QKC3APP4.mjs → chunk-Z3HCJ43H.mjs} +1 -1
  21. package/dist/gestureLayer/index.d.mts +2 -2
  22. package/dist/gestureLayer/index.d.ts +2 -2
  23. package/dist/gestureLayer/index.js +10 -10
  24. package/dist/gestureLayer/index.mjs +3 -3
  25. package/dist/index.d.mts +3 -3
  26. package/dist/index.d.ts +3 -3
  27. package/dist/index.js +48 -48
  28. package/dist/index.mjs +17 -17
  29. package/dist/motion/Image.d.mts +1 -1
  30. package/dist/motion/Image.d.ts +1 -1
  31. package/dist/motion/Image.js +5 -5
  32. package/dist/motion/Image.mjs +4 -4
  33. package/dist/motion/Pressable.d.mts +1 -1
  34. package/dist/motion/Pressable.d.ts +1 -1
  35. package/dist/motion/Pressable.js +5 -5
  36. package/dist/motion/Pressable.mjs +4 -4
  37. package/dist/motion/ScrollView.d.mts +1 -1
  38. package/dist/motion/ScrollView.d.ts +1 -1
  39. package/dist/motion/ScrollView.js +5 -5
  40. package/dist/motion/ScrollView.mjs +4 -4
  41. package/dist/motion/Text.d.mts +1 -1
  42. package/dist/motion/Text.d.ts +1 -1
  43. package/dist/motion/Text.js +5 -5
  44. package/dist/motion/Text.mjs +4 -4
  45. package/dist/motion/View.d.mts +1 -1
  46. package/dist/motion/View.d.ts +1 -1
  47. package/dist/motion/View.js +5 -5
  48. package/dist/motion/View.mjs +4 -4
  49. package/dist/touch/index.d.mts +1 -1
  50. package/dist/touch/index.d.ts +1 -1
  51. package/dist/touch/index.js +3 -3
  52. package/dist/touch/index.mjs +1 -1
  53. package/dist/{types-37pN82yh.d.mts → types-BQgLJeQG.d.mts} +39 -3
  54. package/dist/{types-37pN82yh.d.ts → types-BQgLJeQG.d.ts} +39 -3
  55. package/dist/{useGesture-Cl4uzZIr.d.ts → useGesture-B0_CzOUz.d.ts} +1 -1
  56. package/dist/{useGesture-_IKkS8Dv.d.mts → useGesture-DfaTx-3t.d.mts} +1 -1
  57. package/package.json +1 -1
  58. package/src/motion/createMotionComponent.tsx +145 -61
  59. package/src/transitions/resolveSequence.ts +12 -0
  60. package/src/types.ts +106 -3
  61. package/dist/chunk-5SRD2WCO.js +0 -8
  62. package/dist/chunk-TVFNJ25Z.js +0 -8
  63. package/dist/chunk-VLDIFL3F.js +0 -8
@@ -184,6 +184,20 @@ type BoxShadowInput = string | ReadonlyArray<BoxShadowValue>;
184
184
  type AnimatableStructuredExtras<S> = 'boxShadow' extends keyof S ? {
185
185
  boxShadow?: BoxShadowInput;
186
186
  } : {};
187
+ /**
188
+ * The `transform: [...]` array form, passed through as the underlying style
189
+ * types it. Inertia reads transform entries out of the array (see
190
+ * `styleValueFor` in `createMotionComponent`) rather than treating the array as
191
+ * an animatable scalar, so it is exempted from the `AnimatableValue` mapping —
192
+ * wrapping it there would offer a nonsensical `transform: [[...], [...]]`
193
+ * keyframe form.
194
+ *
195
+ * Conditional on `S` for the same reason as `boxShadow`: only appears where the
196
+ * underlying style actually has it.
197
+ */
198
+ type AnimatableTransformArray<S> = 'transform' extends keyof S ? {
199
+ transform?: S['transform'];
200
+ } : {};
187
201
  /**
188
202
  * The animation state shape inferred from the underlying component's style
189
203
  * prop. We narrow to the value side of `style` so consumers see ViewStyle on
@@ -196,11 +210,33 @@ type AnimatableStructuredExtras<S> = 'boxShadow' extends keyof S ? {
196
210
  * accepts any key. Excluding functions first keeps inference tight.
197
211
  */
198
212
  type _StyleValue<T> = Exclude<T, (...args: any[]) => any>;
213
+ /**
214
+ * The style keys Inertia's runtime actually drives — the type-level mirror of
215
+ * `ALL_KEYS` in `createMotionComponent`, minus the `shadowOffset*` synthetics
216
+ * (consumers write the nested `shadowOffset` object, not the axes) and minus
217
+ * `boxShadow` (handled by `AnimatableStructuredExtras`, whose value shape
218
+ * deliberately departs from `AnimatableValue`).
219
+ *
220
+ * **This list and `ALL_KEYS` must stay in sync.** They are separate because one
221
+ * is a type and the other is a runtime array, and TypeScript can't derive the
222
+ * former from a value living in a module that imports this one. The direction
223
+ * that matters: a key here but not in `ALL_KEYS` typechecks and then silently
224
+ * does nothing at runtime — which is precisely the defect this type was
225
+ * introduced to kill. `animate-keys.test-d.tsx` pins the two together.
226
+ *
227
+ * Before 0.0.5 this type mapped over the component's *entire* style surface, so
228
+ * `animate={{ paddingTop: 40 }}` compiled cleanly and was then dropped on the
229
+ * floor — no error, no warning. That contradicted the library's own headline
230
+ * differentiator (wrong props should error, not go unnoticed), so the mapping is
231
+ * now an intersection: a key must be both animatable by Inertia *and* present on
232
+ * the underlying component's style prop.
233
+ */
234
+ type AnimatableStyleKey = 'translateX' | 'translateY' | 'scaleX' | 'scaleY' | 'opacity' | 'width' | 'height' | 'borderRadius' | 'shadowOpacity' | 'shadowRadius' | 'elevation' | 'borderTopLeftRadius' | 'borderTopRightRadius' | 'borderBottomLeftRadius' | 'borderBottomRightRadius' | 'borderWidth' | 'borderTopWidth' | 'borderRightWidth' | 'borderBottomWidth' | 'borderLeftWidth' | 'top' | 'right' | 'bottom' | 'left' | 'padding' | 'paddingTop' | 'paddingRight' | 'paddingBottom' | 'paddingLeft' | 'paddingHorizontal' | 'paddingVertical' | 'margin' | 'marginTop' | 'marginRight' | 'marginBottom' | 'marginLeft' | 'marginHorizontal' | 'marginVertical' | 'flex' | 'flexGrow' | 'flexShrink' | 'fontSize' | 'letterSpacing' | 'lineHeight' | 'zIndex' | 'gap' | 'rowGap' | 'columnGap' | 'backgroundColor' | 'borderColor' | 'color' | 'tintColor' | 'shadowColor' | 'shadowOffset';
199
235
  type AnimateStyle<C> = C extends {
200
236
  style?: infer Raw;
201
- } ? _StyleValue<Raw> extends StyleProp<infer S> ? Omit<{
202
- [K in keyof S]?: AnimatableValue<S[K]>;
203
- }, 'boxShadow'> & AnimatableTransformExtras & AnimatableStructuredExtras<S> : never : never;
237
+ } ? _StyleValue<Raw> extends StyleProp<infer S> ? {
238
+ [K in keyof S as K extends AnimatableStyleKey ? K : never]?: K extends 'boxShadow' | 'transform' ? never : AnimatableValue<S[K]>;
239
+ } & AnimatableTransformExtras & AnimatableStructuredExtras<S> & AnimatableTransformArray<S> : never : never;
204
240
  interface AnimationCallbackInfo<S> {
205
241
  /**
206
242
  * The animatable key that just settled — typically a `keyof S` (e.g.
@@ -1,5 +1,5 @@
1
1
  import { SharedValue } from 'react-native-reanimated';
2
- import { a as TransitionInput, G as GestureLayerTransitions } from './types-37pN82yh.js';
2
+ import { a as TransitionInput, G as GestureLayerTransitions } from './types-BQgLJeQG.js';
3
3
 
4
4
  /**
5
5
  * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
@@ -1,5 +1,5 @@
1
1
  import { SharedValue } from 'react-native-reanimated';
2
- import { a as TransitionInput, G as GestureLayerTransitions } from './types-37pN82yh.mjs';
2
+ import { a as TransitionInput, G as GestureLayerTransitions } from './types-BQgLJeQG.mjs';
3
3
 
4
4
  /**
5
5
  * Handler bag returned by `useGesture`. Spread on a `Pressable` to drive the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootnative/inertia",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
5
5
  "license": "MIT",
6
6
  "author": "RootNative",
@@ -91,6 +91,78 @@ const NUMERIC_TOP_LEVEL_KEYS = [
91
91
  'shadowOpacity',
92
92
  'shadowRadius',
93
93
  'elevation',
94
+ // ─── Added in 0.0.5 ──────────────────────────────────────────────────────
95
+ //
96
+ // Every key below rides the generic numeric path: one shared value, resolved
97
+ // on the JS thread, emitted by the worklet through the same `out[key] = v`
98
+ // branch as `opacity`. None needs a new interpolation mode, so the cost is
99
+ // the shared value plus a `DEFAULT_RESTING` entry.
100
+ //
101
+ // The load-bearing constraint is the resting default, not the plumbing. A
102
+ // key declared only in `gesture` / `exit` / a non-active variant rests at
103
+ // `DEFAULT_RESTING` unless the static `style` names it, and the animated
104
+ // style merges *after* `style` — so a non-identity default silently stomps
105
+ // the layout. That is the `0.0.3` P0 class, and it is why the sizing and
106
+ // spacing keys below default to `0` only in the sense RN itself does (an
107
+ // unset `padding` *is* 0); `minWidth`/`maxWidth`/`aspectRatio` are
108
+ // deliberately excluded — their "unset" is not a number, so no default can
109
+ // stand in for it without changing layout on activation.
110
+ //
111
+ // Per-corner radii. Animating one corner is common (a card expanding into a
112
+ // sheet keeps its top corners and squares off the bottom); `borderRadius`
113
+ // alone can't express it.
114
+ 'borderTopLeftRadius',
115
+ 'borderTopRightRadius',
116
+ 'borderBottomLeftRadius',
117
+ 'borderBottomRightRadius',
118
+ // Border widths. `borderWidth` is the common case; the per-edge keys matter
119
+ // for underline-style focus affordances (`borderBottomWidth` on a field).
120
+ 'borderWidth',
121
+ 'borderTopWidth',
122
+ 'borderRightWidth',
123
+ 'borderBottomWidth',
124
+ 'borderLeftWidth',
125
+ // Absolute-position insets. Bread-and-butter for drawers, tooltips, and
126
+ // anything pinned to an edge that slides in.
127
+ 'top',
128
+ 'right',
129
+ 'bottom',
130
+ 'left',
131
+ // Spacing. Padding animates the box from the inside (a button growing its
132
+ // hit area on press); margin shifts it within its parent's flow.
133
+ 'padding',
134
+ 'paddingTop',
135
+ 'paddingRight',
136
+ 'paddingBottom',
137
+ 'paddingLeft',
138
+ 'paddingHorizontal',
139
+ 'paddingVertical',
140
+ 'margin',
141
+ 'marginTop',
142
+ 'marginRight',
143
+ 'marginBottom',
144
+ 'marginLeft',
145
+ 'marginHorizontal',
146
+ 'marginVertical',
147
+ // Flex sizing. `flex` / `flexGrow` interpolate the split between siblings —
148
+ // the idiomatic RN way to animate a pane resize without measuring.
149
+ 'flex',
150
+ 'flexGrow',
151
+ 'flexShrink',
152
+ // Text metrics. `TextStyle`-only at the type level (`AnimateStyle<C>` gates
153
+ // them per primitive), but the runtime table is shared across primitives —
154
+ // an unused slot is one ref, same as `tintColor` has always been.
155
+ 'fontSize',
156
+ 'letterSpacing',
157
+ 'lineHeight',
158
+ // Stacking. Integer-valued in practice, and interpolating it mid-flight is
159
+ // rarely what you want, but a `no-animation` transition on `zIndex` is the
160
+ // clean way to reorder at a step boundary in a sequence.
161
+ 'zIndex',
162
+ // Gap. Row/column gaps animate a list's density without touching children.
163
+ 'gap',
164
+ 'rowGap',
165
+ 'columnGap',
94
166
  ] as const
95
167
 
96
168
  // Color-valued keys. Reanimated's value setter detects color strings and
@@ -221,6 +293,54 @@ const DEFAULT_RESTING: Record<AnimatableKey, AnimatableSlotValue> = {
221
293
  shadowOpacity: 0,
222
294
  shadowRadius: 0,
223
295
  elevation: 0,
296
+ // 0.0.5 keys. Every one of these is 0 because that is RN's own unset value
297
+ // for it — an element with no `paddingTop` has 0 padding, no `borderWidth`
298
+ // has none, no `top` is unpinned at 0 within its positioning context. So a
299
+ // key that reaches its resting default lands where the element already was.
300
+ //
301
+ // The exception worth naming: `flex` / `flexGrow` / `flexShrink` do NOT have
302
+ // 0 as a universal identity (`flexShrink` defaults to 1 on the web, and RN's
303
+ // own default differs by axis). They are still 0 here, because the style-scan
304
+ // in the resting pass reads the real value off the static `style` whenever it
305
+ // is declared — and a consumer animating flex without declaring it is asking
306
+ // for the from-0 growth, which is the readable interpretation.
307
+ borderTopLeftRadius: 0,
308
+ borderTopRightRadius: 0,
309
+ borderBottomLeftRadius: 0,
310
+ borderBottomRightRadius: 0,
311
+ borderWidth: 0,
312
+ borderTopWidth: 0,
313
+ borderRightWidth: 0,
314
+ borderBottomWidth: 0,
315
+ borderLeftWidth: 0,
316
+ top: 0,
317
+ right: 0,
318
+ bottom: 0,
319
+ left: 0,
320
+ padding: 0,
321
+ paddingTop: 0,
322
+ paddingRight: 0,
323
+ paddingBottom: 0,
324
+ paddingLeft: 0,
325
+ paddingHorizontal: 0,
326
+ paddingVertical: 0,
327
+ margin: 0,
328
+ marginTop: 0,
329
+ marginRight: 0,
330
+ marginBottom: 0,
331
+ marginLeft: 0,
332
+ marginHorizontal: 0,
333
+ marginVertical: 0,
334
+ flex: 0,
335
+ flexGrow: 0,
336
+ flexShrink: 0,
337
+ fontSize: 0,
338
+ letterSpacing: 0,
339
+ lineHeight: 0,
340
+ zIndex: 0,
341
+ gap: 0,
342
+ rowGap: 0,
343
+ columnGap: 0,
224
344
  // 'transparent' is the only safe universal default for colors: it works as
225
345
  // an initial seed for any color animation (no jarring opaque flash on mount
226
346
  // when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
@@ -1245,74 +1365,38 @@ type SharedValueMap = Record<AnimatableKey, SharedValue<AnimatableSlotValue>>
1245
1365
  * are stable across renders (Reanimated's `useSharedValue` is a `useRef`
1246
1366
  * under the hood), so snapshotting the wrapping object once is safe.
1247
1367
  *
1248
- * Hooks are called in a stable, lexical order fine for rules-of-hooks.
1249
- * Unused shared values are cheap; the worklet skips them via
1250
- * `activeKeysRef`. Color keys are seeded with the initial color string so
1251
- * Reanimated's value setter recognizes the slot as a color from the first
1252
- * `withSpring` / `withTiming` call.
1368
+ * Hooks are called by iterating `ALL_KEYS`, which is a module-level `as const`
1369
+ * array its length and order are fixed at module evaluation, so the hook
1370
+ * sequence is identical on every render of every instance. That satisfies
1371
+ * rules-of-hooks exactly as a hand-written list does, and it is what keeps this
1372
+ * function from growing a line per key: the 0.0.5 additions took the table from
1373
+ * 23 keys to 63, and 63 near-identical `useSharedValue` lines is both a bigger
1374
+ * bundle and a standing invitation to add a key in one list but not the other
1375
+ * (the failure mode is a `sharedValues[key]` of `undefined` inside the worklet,
1376
+ * which is exactly how the first draft of that change broke).
1377
+ *
1378
+ * The ESLint exhaustive-deps rule can't see through the loop, hence the
1379
+ * disable — the invariant it would check for us is asserted above instead.
1380
+ *
1381
+ * Unused shared values are cheap; the worklet skips them via `activeKeysRef`.
1382
+ * Color keys are seeded with the initial color string so Reanimated's value
1383
+ * setter recognizes the slot as a color from the first `withSpring` /
1384
+ * `withTiming` call.
1253
1385
  */
1254
1386
  function useAnimatableSharedValues(
1255
1387
  init: (key: AnimatableKey) => AnimatableSlotValue,
1256
1388
  ): SharedValueMap {
1257
- const translateX = useSharedValue<AnimatableSlotValue>(init('translateX'))
1258
- const translateY = useSharedValue<AnimatableSlotValue>(init('translateY'))
1259
- const scale = useSharedValue<AnimatableSlotValue>(init('scale'))
1260
- const scaleX = useSharedValue<AnimatableSlotValue>(init('scaleX'))
1261
- const scaleY = useSharedValue<AnimatableSlotValue>(init('scaleY'))
1262
- const rotate = useSharedValue<AnimatableSlotValue>(init('rotate'))
1263
- const rotateX = useSharedValue<AnimatableSlotValue>(init('rotateX'))
1264
- const rotateY = useSharedValue<AnimatableSlotValue>(init('rotateY'))
1265
- const opacity = useSharedValue<AnimatableSlotValue>(init('opacity'))
1266
- const width = useSharedValue<AnimatableSlotValue>(init('width'))
1267
- const height = useSharedValue<AnimatableSlotValue>(init('height'))
1268
- const borderRadius = useSharedValue<AnimatableSlotValue>(init('borderRadius'))
1269
- const shadowOpacity = useSharedValue<AnimatableSlotValue>(
1270
- init('shadowOpacity'),
1271
- )
1272
- const shadowRadius = useSharedValue<AnimatableSlotValue>(init('shadowRadius'))
1273
- const elevation = useSharedValue<AnimatableSlotValue>(init('elevation'))
1274
- const backgroundColor = useSharedValue<AnimatableSlotValue>(
1275
- init('backgroundColor'),
1276
- )
1277
- const borderColor = useSharedValue<AnimatableSlotValue>(init('borderColor'))
1278
- const color = useSharedValue<AnimatableSlotValue>(init('color'))
1279
- const tintColor = useSharedValue<AnimatableSlotValue>(init('tintColor'))
1280
- const shadowColor = useSharedValue<AnimatableSlotValue>(init('shadowColor'))
1281
- const shadowOffsetWidth = useSharedValue<AnimatableSlotValue>(
1282
- init('shadowOffsetWidth'),
1283
- )
1284
- const shadowOffsetHeight = useSharedValue<AnimatableSlotValue>(
1285
- init('shadowOffsetHeight'),
1286
- )
1287
- const boxShadow = useSharedValue<AnimatableSlotValue>(init('boxShadow'))
1389
+ const entries: [AnimatableKey, SharedValue<AnimatableSlotValue>][] = []
1390
+ for (const key of ALL_KEYS) {
1391
+ // eslint-disable-next-line react-hooks/rules-of-hooks
1392
+ entries.push([key, useSharedValue<AnimatableSlotValue>(init(key))])
1393
+ }
1288
1394
 
1289
1395
  const ref = useRef<SharedValueMap | null>(null)
1290
1396
  if (ref.current === null) {
1291
- ref.current = {
1292
- translateX,
1293
- translateY,
1294
- scale,
1295
- scaleX,
1296
- scaleY,
1297
- rotate,
1298
- rotateX,
1299
- rotateY,
1300
- opacity,
1301
- width,
1302
- height,
1303
- borderRadius,
1304
- shadowOpacity,
1305
- shadowRadius,
1306
- elevation,
1307
- backgroundColor,
1308
- borderColor,
1309
- color,
1310
- tintColor,
1311
- shadowColor,
1312
- shadowOffsetWidth,
1313
- shadowOffsetHeight,
1314
- boxShadow,
1315
- }
1397
+ const map = {} as SharedValueMap
1398
+ for (const [key, sv] of entries) map[key] = sv
1399
+ ref.current = map
1316
1400
  }
1317
1401
 
1318
1402
  // Cancel every in-flight per-key animation when the primitive unmounts, so
@@ -77,6 +77,18 @@ function mergeTransition(
77
77
  base: TransitionConfig | undefined,
78
78
  override: Partial<TransitionConfig>,
79
79
  ): TransitionConfig {
80
+ // A `no-animation` base is a ceiling, not a default, so no step override can
81
+ // talk its way past it. This is the reduced-motion gate: `configFor` in the
82
+ // factory swaps every per-key transition for `{ type: 'no-animation' }`, and
83
+ // the step-type rule below would otherwise hand a step its own `withTiming`
84
+ // back — silently animating for a user who asked the OS not to. Keep this
85
+ // branch first; it is the whole reason the gate holds for sequences.
86
+ //
87
+ // Returning `base` also drops any step `delay`, which matches how the rest
88
+ // of the resolver already treats this type: `delayOf` and `repeatOf` both
89
+ // return `undefined` for `no-animation`, so a snap is never deferred or
90
+ // repeated anywhere in the library.
91
+ if (base?.type === 'no-animation') return base
80
92
  // If the override declares a `type`, it wins outright — mixing fields from
81
93
  // a spring base into a timing override produces garbage. Otherwise inherit
82
94
  // the base's type and shallow-merge the rest.
package/src/types.ts CHANGED
@@ -217,6 +217,22 @@ type AnimatableStructuredExtras<S> = 'boxShadow' extends keyof S
217
217
  : // eslint-disable-next-line @typescript-eslint/no-empty-object-type
218
218
  {}
219
219
 
220
+ /**
221
+ * The `transform: [...]` array form, passed through as the underlying style
222
+ * types it. Inertia reads transform entries out of the array (see
223
+ * `styleValueFor` in `createMotionComponent`) rather than treating the array as
224
+ * an animatable scalar, so it is exempted from the `AnimatableValue` mapping —
225
+ * wrapping it there would offer a nonsensical `transform: [[...], [...]]`
226
+ * keyframe form.
227
+ *
228
+ * Conditional on `S` for the same reason as `boxShadow`: only appears where the
229
+ * underlying style actually has it.
230
+ */
231
+ type AnimatableTransformArray<S> = 'transform' extends keyof S
232
+ ? { transform?: S['transform'] }
233
+ : // eslint-disable-next-line @typescript-eslint/no-empty-object-type
234
+ {}
235
+
220
236
  /**
221
237
  * The animation state shape inferred from the underlying component's style
222
238
  * prop. We narrow to the value side of `style` so consumers see ViewStyle on
@@ -231,11 +247,98 @@ type AnimatableStructuredExtras<S> = 'boxShadow' extends keyof S
231
247
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
232
248
  type _StyleValue<T> = Exclude<T, (...args: any[]) => any>
233
249
 
250
+ /**
251
+ * The style keys Inertia's runtime actually drives — the type-level mirror of
252
+ * `ALL_KEYS` in `createMotionComponent`, minus the `shadowOffset*` synthetics
253
+ * (consumers write the nested `shadowOffset` object, not the axes) and minus
254
+ * `boxShadow` (handled by `AnimatableStructuredExtras`, whose value shape
255
+ * deliberately departs from `AnimatableValue`).
256
+ *
257
+ * **This list and `ALL_KEYS` must stay in sync.** They are separate because one
258
+ * is a type and the other is a runtime array, and TypeScript can't derive the
259
+ * former from a value living in a module that imports this one. The direction
260
+ * that matters: a key here but not in `ALL_KEYS` typechecks and then silently
261
+ * does nothing at runtime — which is precisely the defect this type was
262
+ * introduced to kill. `animate-keys.test-d.tsx` pins the two together.
263
+ *
264
+ * Before 0.0.5 this type mapped over the component's *entire* style surface, so
265
+ * `animate={{ paddingTop: 40 }}` compiled cleanly and was then dropped on the
266
+ * floor — no error, no warning. That contradicted the library's own headline
267
+ * differentiator (wrong props should error, not go unnoticed), so the mapping is
268
+ * now an intersection: a key must be both animatable by Inertia *and* present on
269
+ * the underlying component's style prop.
270
+ */
271
+ type AnimatableStyleKey =
272
+ // Transform axes surfaced as top-level keys.
273
+ | 'translateX'
274
+ | 'translateY'
275
+ | 'scaleX'
276
+ | 'scaleY'
277
+ // Numeric top-level keys.
278
+ | 'opacity'
279
+ | 'width'
280
+ | 'height'
281
+ | 'borderRadius'
282
+ | 'shadowOpacity'
283
+ | 'shadowRadius'
284
+ | 'elevation'
285
+ | 'borderTopLeftRadius'
286
+ | 'borderTopRightRadius'
287
+ | 'borderBottomLeftRadius'
288
+ | 'borderBottomRightRadius'
289
+ | 'borderWidth'
290
+ | 'borderTopWidth'
291
+ | 'borderRightWidth'
292
+ | 'borderBottomWidth'
293
+ | 'borderLeftWidth'
294
+ | 'top'
295
+ | 'right'
296
+ | 'bottom'
297
+ | 'left'
298
+ | 'padding'
299
+ | 'paddingTop'
300
+ | 'paddingRight'
301
+ | 'paddingBottom'
302
+ | 'paddingLeft'
303
+ | 'paddingHorizontal'
304
+ | 'paddingVertical'
305
+ | 'margin'
306
+ | 'marginTop'
307
+ | 'marginRight'
308
+ | 'marginBottom'
309
+ | 'marginLeft'
310
+ | 'marginHorizontal'
311
+ | 'marginVertical'
312
+ | 'flex'
313
+ | 'flexGrow'
314
+ | 'flexShrink'
315
+ | 'fontSize'
316
+ | 'letterSpacing'
317
+ | 'lineHeight'
318
+ | 'zIndex'
319
+ | 'gap'
320
+ | 'rowGap'
321
+ | 'columnGap'
322
+ // Color keys.
323
+ | 'backgroundColor'
324
+ | 'borderColor'
325
+ | 'color'
326
+ | 'tintColor'
327
+ | 'shadowColor'
328
+ // The one nested-object style prop, written as `{ width, height }`.
329
+ | 'shadowOffset'
330
+
234
331
  export type AnimateStyle<C> = C extends { style?: infer Raw }
235
332
  ? _StyleValue<Raw> extends StyleProp<infer S>
236
- ? Omit<{ [K in keyof S]?: AnimatableValue<S[K]> }, 'boxShadow'> &
237
- AnimatableTransformExtras &
238
- AnimatableStructuredExtras<S>
333
+ ? {
334
+ [K in keyof S as K extends AnimatableStyleKey ? K : never]?: K extends
335
+ | 'boxShadow'
336
+ | 'transform'
337
+ ? never
338
+ : AnimatableValue<S[K]>
339
+ } & AnimatableTransformExtras &
340
+ AnimatableStructuredExtras<S> &
341
+ AnimatableTransformArray<S>
239
342
  : never
240
343
  : never
241
344
 
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkMYE5NMXW_js = require('./chunk-MYE5NMXW.js');
4
- var reactNative = require('react-native');
5
-
6
- var MotionImage = chunkMYE5NMXW_js.createMotionComponent(reactNative.Image);
7
-
8
- exports.MotionImage = MotionImage;
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkMYE5NMXW_js = require('./chunk-MYE5NMXW.js');
4
- var reactNative = require('react-native');
5
-
6
- var MotionText = chunkMYE5NMXW_js.createMotionComponent(reactNative.Text);
7
-
8
- exports.MotionText = MotionText;
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkMYE5NMXW_js = require('./chunk-MYE5NMXW.js');
4
- var reactNative = require('react-native');
5
-
6
- var MotionView = chunkMYE5NMXW_js.createMotionComponent(reactNative.View);
7
-
8
- exports.MotionView = MotionView;