@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.
Files changed (75) hide show
  1. package/CHANGELOG.md +92 -5
  2. package/README.md +9 -3
  3. package/dist/{chunk-OQV66TBQ.mjs → chunk-27MKBTSG.mjs} +1 -1
  4. package/dist/{chunk-3XTVY34H.js → chunk-27U6766G.js} +2 -2
  5. package/dist/{chunk-4PEHWDAZ.js → chunk-4NAMD62I.js} +7 -7
  6. package/dist/chunk-67GHRCF6.js +8 -0
  7. package/dist/{chunk-SGUHE5CX.mjs → chunk-COEJVWRZ.mjs} +1 -1
  8. package/dist/chunk-GPOMFIIU.js +8 -0
  9. package/dist/{chunk-BQQTHG2V.mjs → chunk-GTJ6VAH5.mjs} +1 -1
  10. package/dist/chunk-K63LXGKS.js +8 -0
  11. package/dist/{chunk-46P57VMY.mjs → chunk-OAUWLPQH.mjs} +1 -1
  12. package/dist/{chunk-7AOERN53.js → chunk-OBRGJAST.js} +3 -3
  13. package/dist/{chunk-RGNX6UZN.mjs → chunk-OW5XTGVN.mjs} +2 -2
  14. package/dist/{chunk-PTRF47DA.js → chunk-PM6CVGXJ.js} +11 -3
  15. package/dist/{chunk-W5MC3P4N.js → chunk-QQVDZKSD.js} +2 -2
  16. package/dist/{chunk-CY7Y64C3.mjs → chunk-REYL77RE.mjs} +11 -4
  17. package/dist/{chunk-CSODMRJ7.mjs → chunk-RIVVBABB.mjs} +597 -134
  18. package/dist/{chunk-BP3Y2SHQ.js → chunk-VQ5D35UA.js} +617 -152
  19. package/dist/{chunk-O22NXXCZ.mjs → chunk-XSK5MNUH.mjs} +1 -1
  20. package/dist/{chunk-R63GIUNU.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 +4 -4
  26. package/dist/index.d.ts +4 -4
  27. package/dist/index.js +48 -169
  28. package/dist/index.mjs +17 -137
  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-G1dBU2IQ.d.mts → types-BQgLJeQG.d.mts} +85 -14
  54. package/dist/{types-G1dBU2IQ.d.ts → types-BQgLJeQG.d.ts} +85 -14
  55. package/dist/{useGesture-D1e4ixJo.d.ts → useGesture-B0_CzOUz.d.ts} +1 -1
  56. package/dist/{useGesture-RFY6kTL3.d.mts → useGesture-DfaTx-3t.d.mts} +1 -1
  57. package/llms.txt +3 -1
  58. package/package.json +1 -1
  59. package/src/index.ts +2 -1
  60. package/src/internal/boxShadow.ts +177 -6
  61. package/src/internal/nonWorkletWarning.ts +4 -6
  62. package/src/internal/warnOnce.ts +28 -0
  63. package/src/layout/index.ts +10 -0
  64. package/src/layout/measureWindow.ts +135 -0
  65. package/src/layout/sharedRegistry.ts +107 -18
  66. package/src/layout/useSharedLayout.ts +256 -91
  67. package/src/motion/createMotionComponent.tsx +497 -74
  68. package/src/motion/installCheck.ts +1 -1
  69. package/src/transitions/index.ts +1 -1
  70. package/src/transitions/resolveSequence.ts +12 -0
  71. package/src/types.ts +155 -12
  72. package/src/values/useColorTransition.ts +1 -1
  73. package/dist/chunk-FNVFV4EY.js +0 -8
  74. package/dist/chunk-FWQOXA43.js +0 -8
  75. package/dist/chunk-KBP4LR75.js +0 -8
@@ -1,5 +1,5 @@
1
- import { useNamedTransitions, resolveNamedTransitionProp, lookupNamedTransition, useShouldReduceMotion, isFocusVisible } from './chunk-R63GIUNU.mjs';
2
- import { stableSig, resolveAnimatableValue, isTopLevelTransition, resolveTransition, ensureWorkletEasing, springToReanimated, DEFAULT_SPRING } from './chunk-CY7Y64C3.mjs';
1
+ import { useNamedTransitions, resolveNamedTransitionProp, lookupNamedTransition, useShouldReduceMotion, isFocusVisible } from './chunk-Z3HCJ43H.mjs';
2
+ import { warnOnce, stableSig, resolveAnimatableValue, isTopLevelTransition, resolveTransition, ensureWorkletEasing, springToReanimated, DEFAULT_SPRING } from './chunk-REYL77RE.mjs';
3
3
  import { createContext, useContext, useMemo, Children, isValidElement, useState, useRef, useCallback, forwardRef, useEffect } from 'react';
4
4
  import { jsx, Fragment } from 'react/jsx-runtime';
5
5
  import Animated, { useSharedValue, cancelAnimation, useAnimatedStyle, interpolateColor, reanimatedVersion, runOnJS, LinearTransition, withSequence, withTiming, withSpring } from 'react-native-reanimated';
@@ -129,6 +129,175 @@ function PresenceItem({
129
129
  );
130
130
  return /* @__PURE__ */ jsx(PresenceContext.Provider, { value, children });
131
131
  }
132
+
133
+ // src/internal/boxShadow.ts
134
+ var LENGTH = /^[+-]?(\d+\.?\d*|\.\d+)(px)?$/i;
135
+ var UNIT_LIKE = /^[+-]?(\d+\.?\d*|\.\d+)[a-z%]+$/i;
136
+ function invalid(input, reason) {
137
+ return new Error(
138
+ `[inertia] parseBoxShadow: ${reason} in ${JSON.stringify(input)}. Expected CSS box-shadow syntax with px lengths: '[inset] <offset-x> <offset-y> [blur] [spread] [color], ...'`
139
+ );
140
+ }
141
+ function splitLayers(input) {
142
+ const layers = [];
143
+ let depth = 0;
144
+ let start = 0;
145
+ for (let i = 0; i < input.length; i++) {
146
+ const ch = input[i];
147
+ if (ch === "(") depth++;
148
+ else if (ch === ")") depth--;
149
+ else if (ch === "," && depth === 0) {
150
+ layers.push(input.slice(start, i));
151
+ start = i + 1;
152
+ }
153
+ }
154
+ layers.push(input.slice(start));
155
+ return layers;
156
+ }
157
+ function tokenize(layer) {
158
+ const tokens = [];
159
+ let depth = 0;
160
+ let current = "";
161
+ for (const ch of layer) {
162
+ if (ch === "(") depth++;
163
+ else if (ch === ")") depth--;
164
+ if (depth === 0 && /\s/.test(ch)) {
165
+ if (current) tokens.push(current);
166
+ current = "";
167
+ } else {
168
+ current += ch;
169
+ }
170
+ }
171
+ if (current) tokens.push(current);
172
+ return tokens;
173
+ }
174
+ function parseBoxShadow(input) {
175
+ const trimmed = input.trim();
176
+ if (trimmed === "") throw invalid(input, "empty string");
177
+ if (trimmed.toLowerCase() === "none") return [];
178
+ return splitLayers(trimmed).map((layerString) => {
179
+ const tokens = tokenize(layerString.trim());
180
+ if (tokens.length === 0) throw invalid(input, "empty layer");
181
+ const lengths = [];
182
+ let color;
183
+ let inset = false;
184
+ for (const token of tokens) {
185
+ if (token.toLowerCase() === "inset") {
186
+ if (inset) throw invalid(input, "duplicate 'inset'");
187
+ inset = true;
188
+ } else if (LENGTH.test(token)) {
189
+ lengths.push(parseFloat(token));
190
+ } else if (UNIT_LIKE.test(token)) {
191
+ throw invalid(input, `unsupported unit in ${JSON.stringify(token)}`);
192
+ } else {
193
+ if (color !== void 0) throw invalid(input, "multiple colors");
194
+ color = token;
195
+ }
196
+ }
197
+ if (lengths.length < 2 || lengths.length > 4) {
198
+ throw invalid(input, `expected 2-4 lengths, got ${lengths.length}`);
199
+ }
200
+ const [offsetX = 0, offsetY = 0, blurRadius = 0, spreadDistance = 0] = lengths;
201
+ if (blurRadius < 0) throw invalid(input, "negative blur radius");
202
+ return {
203
+ offsetX,
204
+ offsetY,
205
+ blurRadius,
206
+ spreadDistance,
207
+ color: color ?? "black",
208
+ inset
209
+ };
210
+ });
211
+ }
212
+ function resolveBoxShadowInput(input) {
213
+ if (input === void 0) return [];
214
+ if (typeof input === "string") return parseBoxShadow(input);
215
+ return input.map((layer) => ({
216
+ offsetX: coerceLength(layer.offsetX, "offsetX"),
217
+ offsetY: coerceLength(layer.offsetY, "offsetY"),
218
+ blurRadius: coerceLength(layer.blurRadius, "blurRadius"),
219
+ spreadDistance: coerceLength(layer.spreadDistance, "spreadDistance"),
220
+ color: layer.color ?? "black",
221
+ inset: layer.inset ?? false
222
+ }));
223
+ }
224
+ function pairBoxShadowLayers(from, to) {
225
+ const count = Math.max(from.length, to.length);
226
+ const pairs = [];
227
+ for (let i = 0; i < count; i++) {
228
+ const a = from[i];
229
+ const b = to[i];
230
+ const fromLayer = a ?? invisibleLayer(b.inset);
231
+ const toLayer = b ?? invisibleLayer(a.inset);
232
+ if (fromLayer.inset !== toLayer.inset) {
233
+ throw new Error(
234
+ `[inertia] useShadow: boxShadow layer ${i} is 'inset' on one side but not the other \u2014 inset cannot be interpolated. Give both sides the same inset-ness (pad with a transparent layer if needed).`
235
+ );
236
+ }
237
+ pairs.push({ from: fromLayer, to: toLayer });
238
+ }
239
+ return pairs;
240
+ }
241
+ function invisibleLayer(inset) {
242
+ return {
243
+ offsetX: 0,
244
+ offsetY: 0,
245
+ blurRadius: 0,
246
+ spreadDistance: 0,
247
+ color: "transparent",
248
+ inset
249
+ };
250
+ }
251
+ function coerceLength(value, field) {
252
+ if (value === void 0) return 0;
253
+ if (typeof value === "number") return value;
254
+ const trimmed = typeof value === "string" ? value.trim() : "";
255
+ if (!LENGTH.test(trimmed)) {
256
+ throw new Error(
257
+ `[inertia] boxShadow: ${field} must be a number or a px length, got ${JSON.stringify(value)}.`
258
+ );
259
+ }
260
+ return parseFloat(trimmed);
261
+ }
262
+ function strip(layer) {
263
+ const { inset: _inset, ...rest } = layer;
264
+ return rest;
265
+ }
266
+ function markInset(insets, i, count) {
267
+ const list = insets ?? new Array(count).fill(false);
268
+ list[i] = true;
269
+ return list;
270
+ }
271
+ function normalizeBoxShadow(input) {
272
+ const resolved = resolveBoxShadowInput(input);
273
+ const layers = [];
274
+ let insets = null;
275
+ for (let i = 0; i < resolved.length; i++) {
276
+ const layer = resolved[i];
277
+ layers.push(strip(layer));
278
+ if (layer.inset) insets = markInset(insets, i, resolved.length);
279
+ }
280
+ return { layers, insets };
281
+ }
282
+ function prepareBoxShadowAnimation(current, target) {
283
+ const pairs = pairBoxShadowLayers(
284
+ current.layers.map((layer, i) => ({
285
+ ...layer,
286
+ inset: current.insets?.[i] ?? false
287
+ })),
288
+ resolveBoxShadowInput(target)
289
+ );
290
+ const from = [];
291
+ const to = [];
292
+ let insets = null;
293
+ for (let i = 0; i < pairs.length; i++) {
294
+ const pair = pairs[i];
295
+ from.push(strip(pair.from));
296
+ to.push(strip(pair.to));
297
+ if (pair.to.inset) insets = markInset(insets, i, pairs.length);
298
+ }
299
+ return { from, to, insets };
300
+ }
132
301
  function resolveLayoutTransition(layout) {
133
302
  if (!layout) return void 0;
134
303
  const cfg = layout === true ? { type: "spring" } : layout;
@@ -162,72 +331,138 @@ function sweepExpired(at) {
162
331
  if (entry.expiresAt < at) REGISTRY.delete(id);
163
332
  }
164
333
  }
165
- function registerLayout(id, rect) {
334
+ function registerLayout(id, rect, remeasure, readStyles) {
166
335
  const at = now();
167
336
  sweepExpired(at);
168
- REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS });
337
+ REGISTRY.set(id, {
338
+ rect,
339
+ expiresAt: at + SHARED_LAYOUT_TTL_MS,
340
+ remeasure,
341
+ readStyles
342
+ });
169
343
  }
170
- function releaseLayout(id, rect) {
344
+ function releaseLayout(id, rect, styles) {
171
345
  const at = now();
172
346
  sweepExpired(at);
173
- REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS });
347
+ REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS, styles });
174
348
  }
175
349
  function consumeLayout(id) {
176
350
  const entry = REGISTRY.get(id);
177
351
  if (!entry) return void 0;
178
352
  REGISTRY.delete(id);
179
353
  if (entry.expiresAt < now()) return void 0;
180
- return entry.rect;
354
+ return {
355
+ rect: entry.rect,
356
+ remeasure: entry.remeasure,
357
+ styles: entry.styles,
358
+ readStyles: entry.readStyles
359
+ };
360
+ }
361
+
362
+ // src/layout/measureWindow.ts
363
+ var defaultMeasurer = (node) => {
364
+ const measure = node?.measureInWindow;
365
+ if (typeof measure !== "function") return void 0;
366
+ let result;
367
+ let returned = false;
368
+ try {
369
+ measure.call(node, (x, y, width, height) => {
370
+ if (returned) return;
371
+ result = { x, y, width, height };
372
+ });
373
+ } catch {
374
+ returned = true;
375
+ return void 0;
376
+ }
377
+ returned = true;
378
+ return result;
379
+ };
380
+ var measurer = defaultMeasurer;
381
+ function usable(rect) {
382
+ const { x, y, width, height } = rect;
383
+ for (const v of [x, y, width, height]) {
384
+ if (typeof v !== "number" || !Number.isFinite(v)) return false;
385
+ }
386
+ return width !== 0 || height !== 0;
387
+ }
388
+ function measureWindowRect(node) {
389
+ const measured = measurer(node);
390
+ if (!measured || !usable(measured)) return void 0;
391
+ return toSharedRect(measured, "window");
392
+ }
393
+ function toSharedRect(rect, space) {
394
+ return { ...rect, space };
181
395
  }
182
396
  function useSharedLayout(options) {
183
- const { layoutId, userRef, transition, shouldReduceMotion, userOnLayout } = options;
397
+ const {
398
+ layoutId,
399
+ userRef,
400
+ transition,
401
+ shouldReduceMotion,
402
+ userOnLayout,
403
+ readStyles
404
+ } = options;
184
405
  const dx = useSharedValue(0);
185
406
  const dy = useSharedValue(0);
186
407
  const sx = useSharedValue(1);
187
408
  const sy = useSharedValue(1);
409
+ const snapshot = useSharedValue(null);
410
+ const carryProgress = useSharedValue(0);
188
411
  const lastRectRef = useRef(null);
189
412
  const consumedRef = useRef(false);
413
+ const nodeRef = useRef(null);
190
414
  const transitionRef = useRef(transition);
191
415
  transitionRef.current = transition;
192
416
  const reducedMotionRef = useRef(shouldReduceMotion);
193
417
  reducedMotionRef.current = shouldReduceMotion;
418
+ const readStylesRef = useRef(readStyles);
419
+ readStylesRef.current = readStyles;
194
420
  const setRef = useCallback(
195
421
  (node) => {
422
+ nodeRef.current = node;
196
423
  if (typeof userRef === "function") userRef(node);
197
424
  else if (userRef) userRef.current = node;
198
425
  },
199
426
  [userRef]
200
427
  );
428
+ const remeasure = useCallback(() => measureWindowRect(nodeRef.current), []);
429
+ const snapshotStyles = useCallback(() => readStylesRef.current?.(), []);
430
+ const startTransition = useCallback(
431
+ (source, sourceRect, target) => {
432
+ if (sourceRect.space !== target.space) return;
433
+ const shared = {
434
+ transition: transitionRef.current,
435
+ shouldReduceMotion: reducedMotionRef.current
436
+ };
437
+ applyFlip({ source: sourceRect, target, dx, dy, sx, sy, ...shared });
438
+ applyStyleCarry({
439
+ snapshot,
440
+ progress: carryProgress,
441
+ // Prefer a live read for the same reason the rect is re-measured: a
442
+ // still-mounted source may have moved on since its last layout.
443
+ styles: source.readStyles?.() ?? source.styles,
444
+ ...shared
445
+ });
446
+ },
447
+ [dx, dy, sx, sy, snapshot, carryProgress]
448
+ );
201
449
  const onLayout = useCallback(
202
450
  (event) => {
203
451
  userOnLayout?.(event);
204
452
  if (!layoutId) return;
205
453
  const { x, y, width, height } = event.nativeEvent.layout;
206
- const rect = { x, y, width, height };
207
- lastRectRef.current = rect;
208
454
  let source;
209
455
  if (!consumedRef.current) {
210
456
  consumedRef.current = true;
211
457
  source = consumeLayout(layoutId);
212
458
  }
213
- registerLayout(layoutId, rect);
214
- if (source) {
215
- applyFlip({
216
- source,
217
- target: rect,
218
- dx,
219
- dy,
220
- sx,
221
- sy,
222
- transition: transitionRef.current,
223
- shouldReduceMotion: reducedMotionRef.current
224
- });
225
- }
459
+ const rect = measureWindowRect(nodeRef.current) ?? { x, y, width, height, space: "parent" };
460
+ lastRectRef.current = rect;
461
+ registerLayout(layoutId, rect, remeasure, snapshotStyles);
462
+ if (!source) return;
463
+ startTransition(source, source.remeasure?.() ?? source.rect, rect);
226
464
  },
227
- // dx/dy/sx/sy are stable refs from useSharedValue, but eslint's
228
- // exhaustive-deps would flag them — including them is harmless and
229
- // silences the warning.
230
- [layoutId, userOnLayout, dx, dy, sx, sy]
465
+ [layoutId, userOnLayout, remeasure, snapshotStyles, startTransition]
231
466
  );
232
467
  useEffect(() => {
233
468
  consumedRef.current = false;
@@ -237,18 +472,49 @@ function useSharedLayout(options) {
237
472
  if (!layoutId) return;
238
473
  const rect = lastRectRef.current;
239
474
  if (!rect) return;
240
- releaseLayout(layoutId, rect);
475
+ releaseLayout(layoutId, rect, snapshotStyles());
241
476
  };
242
- }, [layoutId]);
477
+ }, [layoutId, snapshotStyles]);
478
+ useEffect(
479
+ () => () => {
480
+ cancelAnimation(dx);
481
+ cancelAnimation(dy);
482
+ cancelAnimation(sx);
483
+ cancelAnimation(sy);
484
+ cancelAnimation(carryProgress);
485
+ },
486
+ // The FLIP shared values are identity-stable per hook instance.
487
+ // eslint-disable-next-line react-hooks/exhaustive-deps
488
+ []
489
+ );
243
490
  return useMemo(
244
491
  () => ({
245
492
  flip: { dx, dy, sx, sy },
493
+ carry: { snapshot, progress: carryProgress },
246
494
  setRef,
247
495
  onLayout
248
496
  }),
249
- [dx, dy, sx, sy, setRef, onLayout]
497
+ [dx, dy, sx, sy, snapshot, carryProgress, setRef, onLayout]
250
498
  );
251
499
  }
500
+ function legBuilder(transition) {
501
+ if (transition?.type === "timing") {
502
+ const duration = transition.duration ?? 300;
503
+ return (from, to) => withSequence(
504
+ withTiming(from, { duration: 0 }),
505
+ withTiming(to, { duration })
506
+ );
507
+ }
508
+ const springCfg = transition?.type === "spring" ? { ...DEFAULT_SPRING, ...transition } : { type: "spring", ...DEFAULT_SPRING };
509
+ const springParams = springToReanimated(springCfg);
510
+ return (from, to) => withSequence(
511
+ withTiming(from, { duration: 0 }),
512
+ withSpring(to, springParams)
513
+ );
514
+ }
515
+ function shouldSnap(transition, shouldReduceMotion) {
516
+ return shouldReduceMotion || transition?.type === "no-animation";
517
+ }
252
518
  function applyFlip(args) {
253
519
  const { source, target, dx, dy, sx, sy, transition, shouldReduceMotion } = args;
254
520
  const sourceCenterX = source.x + source.width / 2;
@@ -259,58 +525,29 @@ function applyFlip(args) {
259
525
  const deltaY = sourceCenterY - targetCenterY;
260
526
  const scaleX = target.width > 0 ? source.width / target.width : 1;
261
527
  const scaleY = target.height > 0 ? source.height / target.height : 1;
262
- if (shouldReduceMotion) {
263
- dx.value = 0;
264
- dy.value = 0;
265
- sx.value = 1;
266
- sy.value = 1;
267
- return;
268
- }
269
- if (transition?.type === "no-animation") {
528
+ if (shouldSnap(transition, shouldReduceMotion)) {
270
529
  dx.value = 0;
271
530
  dy.value = 0;
272
531
  sx.value = 1;
273
532
  sy.value = 1;
274
533
  return;
275
534
  }
276
- if (transition?.type === "timing") {
277
- const duration = transition.duration ?? 300;
278
- dx.value = withSequence(
279
- withTiming(deltaX, { duration: 0 }),
280
- withTiming(0, { duration })
281
- );
282
- dy.value = withSequence(
283
- withTiming(deltaY, { duration: 0 }),
284
- withTiming(0, { duration })
285
- );
286
- sx.value = withSequence(
287
- withTiming(scaleX, { duration: 0 }),
288
- withTiming(1, { duration })
289
- );
290
- sy.value = withSequence(
291
- withTiming(scaleY, { duration: 0 }),
292
- withTiming(1, { duration })
293
- );
535
+ const leg = legBuilder(transition);
536
+ dx.value = leg(deltaX, 0);
537
+ dy.value = leg(deltaY, 0);
538
+ sx.value = leg(scaleX, 1);
539
+ sy.value = leg(scaleY, 1);
540
+ }
541
+ function applyStyleCarry(args) {
542
+ const { snapshot, progress, styles, transition, shouldReduceMotion } = args;
543
+ if (!styles) return;
544
+ if (shouldSnap(transition, shouldReduceMotion)) {
545
+ snapshot.value = null;
546
+ progress.value = 0;
294
547
  return;
295
548
  }
296
- const springCfg = transition?.type === "spring" ? { ...DEFAULT_SPRING, ...transition } : { type: "spring", ...DEFAULT_SPRING };
297
- const springParams = springToReanimated(springCfg);
298
- dx.value = withSequence(
299
- withTiming(deltaX, { duration: 0 }),
300
- withSpring(0, springParams)
301
- );
302
- dy.value = withSequence(
303
- withTiming(deltaY, { duration: 0 }),
304
- withSpring(0, springParams)
305
- );
306
- sx.value = withSequence(
307
- withTiming(scaleX, { duration: 0 }),
308
- withSpring(1, springParams)
309
- );
310
- sy.value = withSequence(
311
- withTiming(scaleY, { duration: 0 }),
312
- withSpring(1, springParams)
313
- );
549
+ snapshot.value = styles;
550
+ progress.value = legBuilder(transition)(1, 0);
314
551
  }
315
552
  var alreadyChecked = false;
316
553
  function ensureReanimatedInstalled() {
@@ -324,7 +561,7 @@ function ensureReanimatedInstalled() {
324
561
  const major = parseInt(version.split(".")[0] ?? "0", 10);
325
562
  if (major < 4) {
326
563
  console.error(
327
- `[inertia] react-native-reanimated v${version} is installed, but @rootnative/inertia requires v4.0.0 or later. Upgrade with \`pnpm add react-native-reanimated@^4\` (or your package manager's equivalent).`
564
+ `[inertia] react-native-reanimated ${version} is installed, but @rootnative/inertia requires 4.0.0 or later. Upgrade with \`pnpm add react-native-reanimated@^4\` (or your package manager's equivalent).`
328
565
  );
329
566
  return;
330
567
  }
@@ -357,7 +594,79 @@ var NUMERIC_TOP_LEVEL_KEYS = [
357
594
  "borderRadius",
358
595
  "shadowOpacity",
359
596
  "shadowRadius",
360
- "elevation"
597
+ "elevation",
598
+ // ─── Added in 0.0.5 ──────────────────────────────────────────────────────
599
+ //
600
+ // Every key below rides the generic numeric path: one shared value, resolved
601
+ // on the JS thread, emitted by the worklet through the same `out[key] = v`
602
+ // branch as `opacity`. None needs a new interpolation mode, so the cost is
603
+ // the shared value plus a `DEFAULT_RESTING` entry.
604
+ //
605
+ // The load-bearing constraint is the resting default, not the plumbing. A
606
+ // key declared only in `gesture` / `exit` / a non-active variant rests at
607
+ // `DEFAULT_RESTING` unless the static `style` names it, and the animated
608
+ // style merges *after* `style` — so a non-identity default silently stomps
609
+ // the layout. That is the `0.0.3` P0 class, and it is why the sizing and
610
+ // spacing keys below default to `0` only in the sense RN itself does (an
611
+ // unset `padding` *is* 0); `minWidth`/`maxWidth`/`aspectRatio` are
612
+ // deliberately excluded — their "unset" is not a number, so no default can
613
+ // stand in for it without changing layout on activation.
614
+ //
615
+ // Per-corner radii. Animating one corner is common (a card expanding into a
616
+ // sheet keeps its top corners and squares off the bottom); `borderRadius`
617
+ // alone can't express it.
618
+ "borderTopLeftRadius",
619
+ "borderTopRightRadius",
620
+ "borderBottomLeftRadius",
621
+ "borderBottomRightRadius",
622
+ // Border widths. `borderWidth` is the common case; the per-edge keys matter
623
+ // for underline-style focus affordances (`borderBottomWidth` on a field).
624
+ "borderWidth",
625
+ "borderTopWidth",
626
+ "borderRightWidth",
627
+ "borderBottomWidth",
628
+ "borderLeftWidth",
629
+ // Absolute-position insets. Bread-and-butter for drawers, tooltips, and
630
+ // anything pinned to an edge that slides in.
631
+ "top",
632
+ "right",
633
+ "bottom",
634
+ "left",
635
+ // Spacing. Padding animates the box from the inside (a button growing its
636
+ // hit area on press); margin shifts it within its parent's flow.
637
+ "padding",
638
+ "paddingTop",
639
+ "paddingRight",
640
+ "paddingBottom",
641
+ "paddingLeft",
642
+ "paddingHorizontal",
643
+ "paddingVertical",
644
+ "margin",
645
+ "marginTop",
646
+ "marginRight",
647
+ "marginBottom",
648
+ "marginLeft",
649
+ "marginHorizontal",
650
+ "marginVertical",
651
+ // Flex sizing. `flex` / `flexGrow` interpolate the split between siblings —
652
+ // the idiomatic RN way to animate a pane resize without measuring.
653
+ "flex",
654
+ "flexGrow",
655
+ "flexShrink",
656
+ // Text metrics. `TextStyle`-only at the type level (`AnimateStyle<C>` gates
657
+ // them per primitive), but the runtime table is shared across primitives —
658
+ // an unused slot is one ref, same as `tintColor` has always been.
659
+ "fontSize",
660
+ "letterSpacing",
661
+ "lineHeight",
662
+ // Stacking. Integer-valued in practice, and interpolating it mid-flight is
663
+ // rarely what you want, but a `no-animation` transition on `zIndex` is the
664
+ // clean way to reorder at a step boundary in a sequence.
665
+ "zIndex",
666
+ // Gap. Row/column gaps animate a list's density without touching children.
667
+ "gap",
668
+ "rowGap",
669
+ "columnGap"
361
670
  ];
362
671
  var COLOR_KEYS = [
363
672
  "backgroundColor",
@@ -367,15 +676,28 @@ var COLOR_KEYS = [
367
676
  "shadowColor"
368
677
  ];
369
678
  var SHADOW_OFFSET_KEYS = ["shadowOffsetWidth", "shadowOffsetHeight"];
679
+ var STRUCTURED_KEYS = ["boxShadow"];
680
+ var SHARED_STYLE_KEYS = [
681
+ "opacity",
682
+ "borderRadius",
683
+ "backgroundColor",
684
+ "borderColor",
685
+ "color",
686
+ "tintColor"
687
+ ];
370
688
  var ALL_KEYS = [
371
689
  ...TRANSFORM_KEYS,
372
690
  ...NUMERIC_TOP_LEVEL_KEYS,
373
691
  ...COLOR_KEYS,
374
- ...SHADOW_OFFSET_KEYS
692
+ ...SHADOW_OFFSET_KEYS,
693
+ ...STRUCTURED_KEYS
375
694
  ];
376
695
  var TRANSFORM_KEY_SET = new Set(TRANSFORM_KEYS);
377
696
  var COLOR_KEY_SET = new Set(COLOR_KEYS);
378
697
  var SHADOW_OFFSET_KEY_SET = new Set(SHADOW_OFFSET_KEYS);
698
+ var STRUCTURED_KEY_SET = new Set(STRUCTURED_KEYS);
699
+ var SHARED_STYLE_KEY_SET = new Set(SHARED_STYLE_KEYS);
700
+ var NO_BOX_SHADOW = Object.freeze([]);
379
701
  var GESTURE_LAYER_NAMES = [
380
702
  "hovered",
381
703
  "focused",
@@ -400,6 +722,54 @@ var DEFAULT_RESTING = {
400
722
  shadowOpacity: 0,
401
723
  shadowRadius: 0,
402
724
  elevation: 0,
725
+ // 0.0.5 keys. Every one of these is 0 because that is RN's own unset value
726
+ // for it — an element with no `paddingTop` has 0 padding, no `borderWidth`
727
+ // has none, no `top` is unpinned at 0 within its positioning context. So a
728
+ // key that reaches its resting default lands where the element already was.
729
+ //
730
+ // The exception worth naming: `flex` / `flexGrow` / `flexShrink` do NOT have
731
+ // 0 as a universal identity (`flexShrink` defaults to 1 on the web, and RN's
732
+ // own default differs by axis). They are still 0 here, because the style-scan
733
+ // in the resting pass reads the real value off the static `style` whenever it
734
+ // is declared — and a consumer animating flex without declaring it is asking
735
+ // for the from-0 growth, which is the readable interpretation.
736
+ borderTopLeftRadius: 0,
737
+ borderTopRightRadius: 0,
738
+ borderBottomLeftRadius: 0,
739
+ borderBottomRightRadius: 0,
740
+ borderWidth: 0,
741
+ borderTopWidth: 0,
742
+ borderRightWidth: 0,
743
+ borderBottomWidth: 0,
744
+ borderLeftWidth: 0,
745
+ top: 0,
746
+ right: 0,
747
+ bottom: 0,
748
+ left: 0,
749
+ padding: 0,
750
+ paddingTop: 0,
751
+ paddingRight: 0,
752
+ paddingBottom: 0,
753
+ paddingLeft: 0,
754
+ paddingHorizontal: 0,
755
+ paddingVertical: 0,
756
+ margin: 0,
757
+ marginTop: 0,
758
+ marginRight: 0,
759
+ marginBottom: 0,
760
+ marginLeft: 0,
761
+ marginHorizontal: 0,
762
+ marginVertical: 0,
763
+ flex: 0,
764
+ flexGrow: 0,
765
+ flexShrink: 0,
766
+ fontSize: 0,
767
+ letterSpacing: 0,
768
+ lineHeight: 0,
769
+ zIndex: 0,
770
+ gap: 0,
771
+ rowGap: 0,
772
+ columnGap: 0,
403
773
  // 'transparent' is the only safe universal default for colors: it works as
404
774
  // an initial seed for any color animation (no jarring opaque flash on mount
405
775
  // when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
@@ -410,7 +780,8 @@ var DEFAULT_RESTING = {
410
780
  tintColor: "transparent",
411
781
  shadowColor: "transparent",
412
782
  shadowOffsetWidth: 0,
413
- shadowOffsetHeight: 0
783
+ shadowOffsetHeight: 0,
784
+ boxShadow: NO_BOX_SHADOW
414
785
  };
415
786
  function transitionFor(prop, transition) {
416
787
  if (!transition) return void 0;
@@ -501,6 +872,16 @@ function createMotionComponent(Component) {
501
872
  const [focused, setFocused] = useState(false);
502
873
  const [focusVisible, setFocusVisible] = useState(false);
503
874
  const [hovered, setHovered] = useState(false);
875
+ const hasLayoutId = layoutId !== void 0;
876
+ let flatStyle;
877
+ let flatStyleRead = false;
878
+ const getFlatStyle = () => {
879
+ if (!flatStyleRead) {
880
+ flatStyleRead = true;
881
+ flatStyle = StyleSheet.flatten(style);
882
+ }
883
+ return flatStyle;
884
+ };
504
885
  const touched = /* @__PURE__ */ new Set();
505
886
  collectTouchedKeys(touched, animateRecord);
506
887
  if (initialRecord) collectTouchedKeys(touched, initialRecord);
@@ -522,9 +903,19 @@ function createMotionComponent(Component) {
522
903
  }
523
904
  }
524
905
  if (exitRecord) collectTouchedKeys(touched, exitRecord);
906
+ if (hasLayoutId) {
907
+ const flat = getFlatStyle();
908
+ if (flat) {
909
+ for (const key of SHARED_STYLE_KEYS) {
910
+ if (touched.has(key)) continue;
911
+ if (styleValueFor(flat, key) !== void 0) touched.add(key);
912
+ }
913
+ }
914
+ }
525
915
  const activeKeysRef = useRef(null);
526
916
  const hasTransformRef = useRef(false);
527
917
  const hasShadowOffsetRef = useRef(false);
918
+ const hasBoxShadowRef = useRef(false);
528
919
  const prevActive = activeKeysRef.current;
529
920
  let grew = prevActive === null;
530
921
  if (!grew && prevActive) {
@@ -545,6 +936,15 @@ function createMotionComponent(Component) {
545
936
  hasShadowOffsetRef.current = activeKeysRef.current.some(
546
937
  (k) => SHADOW_OFFSET_KEY_SET.has(k)
547
938
  );
939
+ hasBoxShadowRef.current = activeKeysRef.current.includes("boxShadow");
940
+ if (__DEV__ && hasBoxShadowRef.current && activeKeysRef.current.some(
941
+ (k) => k !== "boxShadow" && k.startsWith("shadow")
942
+ )) {
943
+ warnOnce(
944
+ "boxShadow-with-native-shadow",
945
+ "[inertia] `boxShadow` is animated alongside the native `shadow*` keys on the same element, which applies two shadow systems at once. Pick one: `boxShadow` for the cross-platform CSS form, or the native `shadow*` keys."
946
+ );
947
+ }
548
948
  }
549
949
  const drivenNow = /* @__PURE__ */ new Set();
550
950
  collectTouchedKeys(drivenNow, animateRecord);
@@ -555,17 +955,35 @@ function createMotionComponent(Component) {
555
955
  const activeKeys = activeKeysRef.current;
556
956
  const everDriven = everDrivenRef.current;
557
957
  const styleResting = {};
958
+ let styleRestingShadow = null;
558
959
  if (activeKeys.some((k) => !everDriven.has(k))) {
559
- const flat = StyleSheet.flatten(style);
960
+ const flat = getFlatStyle();
560
961
  if (flat) {
561
962
  for (const key of activeKeys) {
562
963
  if (everDriven.has(key)) continue;
964
+ if (key === "boxShadow") {
965
+ const raw = flat.boxShadow;
966
+ if (raw !== void 0) {
967
+ styleRestingShadow = normalizeBoxShadow(raw);
968
+ styleResting.boxShadow = styleRestingShadow.layers;
969
+ }
970
+ continue;
971
+ }
563
972
  const v = styleValueFor(flat, key);
564
973
  if (v !== void 0) styleResting[key] = v;
565
974
  }
566
975
  }
567
976
  }
977
+ const boxShadowSeedRef = useRef(null);
978
+ if (boxShadowSeedRef.current === null) {
979
+ const source = initial === false ? animateRecord.boxShadow : initialRecord?.boxShadow ?? animateRecord.boxShadow;
980
+ boxShadowSeedRef.current = source !== void 0 ? normalizeBoxShadow(source) : styleRestingShadow ?? {
981
+ layers: [...NO_BOX_SHADOW],
982
+ insets: null
983
+ };
984
+ }
568
985
  const sharedValues = useAnimatableSharedValues((key) => {
986
+ if (key === "boxShadow") return boxShadowSeedRef.current.layers;
569
987
  if (SHADOW_OFFSET_KEY_SET.has(key)) {
570
988
  const axis = shadowOffsetAxisFor(key);
571
989
  if (initial === false) {
@@ -582,11 +1000,17 @@ function createMotionComponent(Component) {
582
1000
  }
583
1001
  return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? styleResting[key] ?? DEFAULT_RESTING[key];
584
1002
  });
1003
+ const boxShadowInsets = useSharedValue(
1004
+ boxShadowSeedRef.current.insets
1005
+ );
585
1006
  const styleRestingSig = stableSig(styleResting);
586
1007
  useEffect(() => {
587
1008
  for (const key of activeKeysRef.current) {
588
1009
  if (everDrivenRef.current.has(key)) continue;
589
1010
  sharedValues[key].value = styleResting[key] ?? DEFAULT_RESTING[key];
1011
+ if (key === "boxShadow") {
1012
+ boxShadowInsets.value = styleRestingShadow?.insets ?? null;
1013
+ }
590
1014
  }
591
1015
  }, [styleRestingSig]);
592
1016
  const pressedProgress = useSharedValue(0);
@@ -643,6 +1067,30 @@ function createMotionComponent(Component) {
643
1067
  }
644
1068
  const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
645
1069
  for (const key of ALL_KEYS) {
1070
+ if (key === "boxShadow") {
1071
+ const shadowTarget = baseRecord.boxShadow;
1072
+ if (shadowTarget === void 0) continue;
1073
+ const cfg2 = configFor("boxShadow");
1074
+ if (isExiting && reachesTerminalPhase(cfg2)) pending++;
1075
+ driveBoxShadow(
1076
+ sharedValues.boxShadow,
1077
+ boxShadowInsets,
1078
+ shadowTarget,
1079
+ cfg2,
1080
+ makeKeyCallbackFactory(
1081
+ "boxShadow",
1082
+ sharedValues.boxShadow,
1083
+ // The declared target, not the padded one — the padding is an
1084
+ // implementation detail of getting Reanimated to interpolate.
1085
+ shadowTarget,
1086
+ onAnimationEndRef,
1087
+ { stepCount: 1, totalIterations: totalIterationsOf(cfg2) },
1088
+ isExiting ? onSettle : void 0,
1089
+ void 0
1090
+ )
1091
+ );
1092
+ continue;
1093
+ }
646
1094
  const target = SHADOW_OFFSET_KEY_SET.has(key) ? shadowOffsetAxisValue(
647
1095
  baseRecord.shadowOffset,
648
1096
  shadowOffsetAxisFor(key)
@@ -708,19 +1156,34 @@ function createMotionComponent(Component) {
708
1156
  isExiting,
709
1157
  shouldReduceMotion
710
1158
  );
1159
+ const readSharedStyles = () => {
1160
+ if (!hasLayoutId) return void 0;
1161
+ const out = {};
1162
+ let any = false;
1163
+ for (const key of activeKeysRef.current) {
1164
+ if (!SHARED_STYLE_KEY_SET.has(key)) continue;
1165
+ const v = sharedValues[key].value;
1166
+ if (typeof v !== "number" && typeof v !== "string") continue;
1167
+ out[key] = v;
1168
+ any = true;
1169
+ }
1170
+ return any ? out : void 0;
1171
+ };
711
1172
  const sharedLayout = useSharedLayout({
712
1173
  layoutId,
713
1174
  userRef: ref,
714
1175
  transition: isTopLevelTransition(transition) ? transition : void 0,
715
1176
  shouldReduceMotion,
716
- userOnLayout
1177
+ userOnLayout,
1178
+ readStyles: readSharedStyles
717
1179
  });
718
1180
  const flip = sharedLayout.flip;
719
- const hasLayoutId = layoutId !== void 0;
1181
+ const carry = sharedLayout.carry;
720
1182
  const animatedStyle = useAnimatedStyle(() => {
721
1183
  const activeKeys2 = activeKeysRef.current;
722
1184
  const hasTransform = hasTransformRef.current;
723
1185
  const hasShadowOffset = hasShadowOffsetRef.current;
1186
+ const hasBoxShadow = hasBoxShadowRef.current;
724
1187
  const out = {};
725
1188
  const transform = [];
726
1189
  let shadowOffsetW = 0;
@@ -729,12 +1192,15 @@ function createMotionComponent(Component) {
729
1192
  const pf = focusedProgress.value;
730
1193
  const pfv = focusVisibleProgress.value;
731
1194
  const pp = pressedProgress.value;
1195
+ const carried = carry.snapshot.value;
1196
+ const pc = carry.progress.value;
732
1197
  const layers = gestureSV.value;
733
1198
  const hoveredLayer = layers ? layers.hovered : null;
734
1199
  const focusedLayer = layers ? layers.focused : null;
735
1200
  const focusVisibleLayer = layers ? layers.focusVisible : null;
736
1201
  const pressedLayer = layers ? layers.pressed : null;
737
1202
  for (const key of activeKeys2) {
1203
+ if (key === "boxShadow") continue;
738
1204
  let v = sharedValues[key].value;
739
1205
  const isColor = COLOR_KEY_SET.has(key);
740
1206
  if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
@@ -753,6 +1219,12 @@ function createMotionComponent(Component) {
753
1219
  const t = pressedLayer[key];
754
1220
  v = isColor ? interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
755
1221
  }
1222
+ if (carried !== null && pc > 0) {
1223
+ const s = carried[key];
1224
+ if (s !== void 0) {
1225
+ v = isColor ? interpolateColor(pc, [0, 1], [v, s]) : v + (s - v) * pc;
1226
+ }
1227
+ }
756
1228
  if (TRANSFORM_KEY_SET.has(key)) {
757
1229
  transform.push(
758
1230
  ROTATION_KEYS.has(key) ? { [key]: `${v}deg` } : { [key]: v }
@@ -775,6 +1247,19 @@ function createMotionComponent(Component) {
775
1247
  if (hasShadowOffset) {
776
1248
  out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH };
777
1249
  }
1250
+ if (hasBoxShadow) {
1251
+ const layers2 = sharedValues.boxShadow.value;
1252
+ const insets = boxShadowInsets.value;
1253
+ if (insets === null) {
1254
+ out.boxShadow = layers2;
1255
+ } else {
1256
+ const withInset = [];
1257
+ for (let i = 0; i < layers2.length; i++) {
1258
+ withInset.push({ ...layers2[i], inset: insets[i] });
1259
+ }
1260
+ out.boxShadow = withInset;
1261
+ }
1262
+ }
778
1263
  return out;
779
1264
  });
780
1265
  const mergedStyle = useMemo(
@@ -837,60 +1322,15 @@ function hasMotionProps(props) {
837
1322
  return false;
838
1323
  }
839
1324
  function useAnimatableSharedValues(init) {
840
- const translateX = useSharedValue(init("translateX"));
841
- const translateY = useSharedValue(init("translateY"));
842
- const scale = useSharedValue(init("scale"));
843
- const scaleX = useSharedValue(init("scaleX"));
844
- const scaleY = useSharedValue(init("scaleY"));
845
- const rotate = useSharedValue(init("rotate"));
846
- const rotateX = useSharedValue(init("rotateX"));
847
- const rotateY = useSharedValue(init("rotateY"));
848
- const opacity = useSharedValue(init("opacity"));
849
- const width = useSharedValue(init("width"));
850
- const height = useSharedValue(init("height"));
851
- const borderRadius = useSharedValue(init("borderRadius"));
852
- const shadowOpacity = useSharedValue(init("shadowOpacity"));
853
- const shadowRadius = useSharedValue(init("shadowRadius"));
854
- const elevation = useSharedValue(init("elevation"));
855
- const backgroundColor = useSharedValue(
856
- init("backgroundColor")
857
- );
858
- const borderColor = useSharedValue(init("borderColor"));
859
- const color = useSharedValue(init("color"));
860
- const tintColor = useSharedValue(init("tintColor"));
861
- const shadowColor = useSharedValue(init("shadowColor"));
862
- const shadowOffsetWidth = useSharedValue(
863
- init("shadowOffsetWidth")
864
- );
865
- const shadowOffsetHeight = useSharedValue(
866
- init("shadowOffsetHeight")
867
- );
1325
+ const entries = [];
1326
+ for (const key of ALL_KEYS) {
1327
+ entries.push([key, useSharedValue(init(key))]);
1328
+ }
868
1329
  const ref = useRef(null);
869
1330
  if (ref.current === null) {
870
- ref.current = {
871
- translateX,
872
- translateY,
873
- scale,
874
- scaleX,
875
- scaleY,
876
- rotate,
877
- rotateX,
878
- rotateY,
879
- opacity,
880
- width,
881
- height,
882
- borderRadius,
883
- shadowOpacity,
884
- shadowRadius,
885
- elevation,
886
- backgroundColor,
887
- borderColor,
888
- color,
889
- tintColor,
890
- shadowColor,
891
- shadowOffsetWidth,
892
- shadowOffsetHeight
893
- };
1331
+ const map2 = {};
1332
+ for (const [key, sv] of entries) map2[key] = sv;
1333
+ ref.current = map2;
894
1334
  }
895
1335
  const map = ref.current;
896
1336
  useEffect(
@@ -974,6 +1414,20 @@ function shadowOffsetAxisFor(key) {
974
1414
  function shadowOffsetAxisValue(source, axis) {
975
1415
  return source?.[axis];
976
1416
  }
1417
+ function driveBoxShadow(slot, insetSlot, target, cfg, factory) {
1418
+ const currentLayers = Array.isArray(slot.value) ? slot.value : NO_BOX_SHADOW;
1419
+ const { from, to, insets } = prepareBoxShadowAnimation(
1420
+ { layers: [...currentLayers], insets: insetSlot.value },
1421
+ target
1422
+ );
1423
+ insetSlot.value = insets;
1424
+ if (from.length !== currentLayers.length) slot.value = from;
1425
+ slot.value = resolveTransition(
1426
+ cfg,
1427
+ to,
1428
+ factory?.("animation", void 0)
1429
+ );
1430
+ }
977
1431
  function styleValueFor(flat, key) {
978
1432
  if (SHADOW_OFFSET_KEY_SET.has(key)) {
979
1433
  return shadowOffsetAxisValue(
@@ -1090,6 +1544,15 @@ function resolveGestureLayers(gesture) {
1090
1544
  if (!subState) continue;
1091
1545
  const resolved = {};
1092
1546
  for (const key of ALL_KEYS) {
1547
+ if (STRUCTURED_KEY_SET.has(key)) {
1548
+ if (__DEV__ && subState[key] !== void 0) {
1549
+ warnOnce(
1550
+ `gesture-structured-${layer}-${key}`,
1551
+ `[inertia] \`${key}\` is not supported inside \`gesture.${layer}\` and will be ignored. Drive it from \`animate\` (optionally via a variant keyed off the same state), or interpolate it yourself with \`useShadow\`.`
1552
+ );
1553
+ }
1554
+ continue;
1555
+ }
1093
1556
  if (SHADOW_OFFSET_KEY_SET.has(key)) {
1094
1557
  const axis = shadowOffsetAxisFor(key);
1095
1558
  const so = subState.shadowOffset;
@@ -1179,4 +1642,4 @@ function compose(user, ours) {
1179
1642
  };
1180
1643
  }
1181
1644
 
1182
- export { Presence, createMotionComponent, usePresence };
1645
+ export { Presence, createMotionComponent, pairBoxShadowLayers, resolveBoxShadowInput, usePresence };