@rootnative/inertia 0.0.2 → 0.0.3

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 (37) hide show
  1. package/CHANGELOG.md +24 -2
  2. package/dist/{chunk-NKA6XR77.js → chunk-3XTVY34H.js} +2 -2
  3. package/dist/{chunk-V6BTXHZK.mjs → chunk-46P57VMY.mjs} +1 -1
  4. package/dist/{chunk-IWLU3VDE.js → chunk-BP3Y2SHQ.js} +132 -26
  5. package/dist/{chunk-TUMNV4P7.mjs → chunk-BQQTHG2V.mjs} +1 -1
  6. package/dist/{chunk-LYMLQ6WQ.mjs → chunk-CSODMRJ7.mjs} +132 -26
  7. package/dist/chunk-FNVFV4EY.js +8 -0
  8. package/dist/chunk-FWQOXA43.js +8 -0
  9. package/dist/chunk-KBP4LR75.js +8 -0
  10. package/dist/{chunk-2DHKV2XY.mjs → chunk-O22NXXCZ.mjs} +1 -1
  11. package/dist/{chunk-HFDZAHWP.mjs → chunk-OQV66TBQ.mjs} +1 -1
  12. package/dist/{chunk-ZN3PNGHQ.mjs → chunk-SGUHE5CX.mjs} +1 -1
  13. package/dist/{chunk-TUYHTHVV.js → chunk-W5MC3P4N.js} +2 -2
  14. package/dist/index.d.mts +10 -8
  15. package/dist/index.d.ts +10 -8
  16. package/dist/index.js +41 -28
  17. package/dist/index.mjs +34 -21
  18. package/dist/motion/Image.js +3 -3
  19. package/dist/motion/Image.mjs +2 -2
  20. package/dist/motion/Pressable.js +3 -3
  21. package/dist/motion/Pressable.mjs +2 -2
  22. package/dist/motion/ScrollView.js +3 -3
  23. package/dist/motion/ScrollView.mjs +2 -2
  24. package/dist/motion/Text.js +3 -3
  25. package/dist/motion/Text.mjs +2 -2
  26. package/dist/motion/View.js +3 -3
  27. package/dist/motion/View.mjs +2 -2
  28. package/package.json +1 -1
  29. package/src/layout/index.ts +1 -0
  30. package/src/layout/sharedRegistry.ts +51 -2
  31. package/src/motion/createMotionComponent.tsx +176 -20
  32. package/src/presence/Presence.tsx +73 -10
  33. package/src/values/useAnimator.ts +25 -14
  34. package/src/values/useColorCascade.ts +34 -16
  35. package/dist/chunk-34Q4UM6V.js +0 -8
  36. package/dist/chunk-KYJROYCG.js +0 -8
  37. package/dist/chunk-X5J5M3K3.js +0 -8
package/dist/index.d.mts CHANGED
@@ -355,9 +355,11 @@ declare function useAnimation(target: number, transition?: TransitionInput): Sha
355
355
  * `<MotionConfig reducedMotion>`. Hand-rolled `resolveTransition` writes
356
356
  * silently bypass that setting — a correctness bug this hook fixes.
357
357
  *
358
- * The returned callback is stable across renders (it reads the registry and
359
- * the reduced-motion flag live inside the body), so it can be dropped straight
360
- * into memoized handlers.
358
+ * The returned callback is identity-stable for the lifetime of the component
359
+ * it reads the registry and the reduced-motion flag out of refs at call time,
360
+ * so neither a new `<MotionConfig transitions>` map nor a reduced-motion change
361
+ * gives it a new identity. Drop it straight into memoized handlers or a
362
+ * `useCallback` dependency list without churning them.
361
363
  *
362
364
  * This is not a new animation API — it starts animations in Inertia's existing
363
365
  * transition vocabulary, so it does not conflict with the "no imperative-only
@@ -501,11 +503,11 @@ interface UseColorCascadeOptions {
501
503
  * hook is not a replacement for it. For a mixed numeric + color cascade, or
502
504
  * function-valued layers, drop to a hand-rolled `useAnimatedStyle`.
503
505
  *
504
- * The layer chain is resolved once on the JS thread and memoized on a
505
- * structural signature (colors + key), so a fresh-but-equal `layers` array
506
- * each render produces no new UI-thread closure (CLAUDE.md principle 8). The
507
- * `progress` shared values are read live in the worklet, so their identity is
508
- * intentionally excluded from the signature.
506
+ * The layer chain is resolved once on the JS thread and kept identity-stable,
507
+ * so a fresh-but-equal `layers` array each render produces no new UI-thread
508
+ * closure (CLAUDE.md principle 8). Changing a colour, the `key`, the base
509
+ * `rest`, the layer count, or **which shared value drives a layer** all rewire
510
+ * the worklet as you'd expect.
509
511
  */
510
512
  declare function useColorCascade(rest: string, layers: readonly ColorCascadeLayer[], options?: UseColorCascadeOptions): ReturnType<typeof useAnimatedStyle>;
511
513
 
package/dist/index.d.ts CHANGED
@@ -355,9 +355,11 @@ declare function useAnimation(target: number, transition?: TransitionInput): Sha
355
355
  * `<MotionConfig reducedMotion>`. Hand-rolled `resolveTransition` writes
356
356
  * silently bypass that setting — a correctness bug this hook fixes.
357
357
  *
358
- * The returned callback is stable across renders (it reads the registry and
359
- * the reduced-motion flag live inside the body), so it can be dropped straight
360
- * into memoized handlers.
358
+ * The returned callback is identity-stable for the lifetime of the component
359
+ * it reads the registry and the reduced-motion flag out of refs at call time,
360
+ * so neither a new `<MotionConfig transitions>` map nor a reduced-motion change
361
+ * gives it a new identity. Drop it straight into memoized handlers or a
362
+ * `useCallback` dependency list without churning them.
361
363
  *
362
364
  * This is not a new animation API — it starts animations in Inertia's existing
363
365
  * transition vocabulary, so it does not conflict with the "no imperative-only
@@ -501,11 +503,11 @@ interface UseColorCascadeOptions {
501
503
  * hook is not a replacement for it. For a mixed numeric + color cascade, or
502
504
  * function-valued layers, drop to a hand-rolled `useAnimatedStyle`.
503
505
  *
504
- * The layer chain is resolved once on the JS thread and memoized on a
505
- * structural signature (colors + key), so a fresh-but-equal `layers` array
506
- * each render produces no new UI-thread closure (CLAUDE.md principle 8). The
507
- * `progress` shared values are read live in the worklet, so their identity is
508
- * intentionally excluded from the signature.
506
+ * The layer chain is resolved once on the JS thread and kept identity-stable,
507
+ * so a fresh-but-equal `layers` array each render produces no new UI-thread
508
+ * closure (CLAUDE.md principle 8). Changing a colour, the `key`, the base
509
+ * `rest`, the layer count, or **which shared value drives a layer** all rewire
510
+ * the worklet as you'd expect.
509
511
  */
510
512
  declare function useColorCascade(rest: string, layers: readonly ColorCascadeLayer[], options?: UseColorCascadeOptions): ReturnType<typeof useAnimatedStyle>;
511
513
 
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var chunk4PEHWDAZ_js = require('./chunk-4PEHWDAZ.js');
4
- var chunkKYJROYCG_js = require('./chunk-KYJROYCG.js');
5
- var chunkX5J5M3K3_js = require('./chunk-X5J5M3K3.js');
6
- var chunk34Q4UM6V_js = require('./chunk-34Q4UM6V.js');
7
- var chunkNKA6XR77_js = require('./chunk-NKA6XR77.js');
8
- var chunkTUYHTHVV_js = require('./chunk-TUYHTHVV.js');
9
- var chunkIWLU3VDE_js = require('./chunk-IWLU3VDE.js');
4
+ var chunkFNVFV4EY_js = require('./chunk-FNVFV4EY.js');
5
+ var chunkFWQOXA43_js = require('./chunk-FWQOXA43.js');
6
+ var chunkKBP4LR75_js = require('./chunk-KBP4LR75.js');
7
+ var chunk3XTVY34H_js = require('./chunk-3XTVY34H.js');
8
+ var chunkW5MC3P4N_js = require('./chunk-W5MC3P4N.js');
9
+ var chunkBP3Y2SHQ_js = require('./chunk-BP3Y2SHQ.js');
10
10
  var chunk7AOERN53_js = require('./chunk-7AOERN53.js');
11
11
  var chunkPTRF47DA_js = require('./chunk-PTRF47DA.js');
12
12
  var react = require('react');
@@ -15,11 +15,11 @@ var reactNativeWorklets = require('react-native-worklets');
15
15
 
16
16
  // src/motion/index.ts
17
17
  var Motion = {
18
- View: chunkKYJROYCG_js.MotionView,
19
- Text: chunkX5J5M3K3_js.MotionText,
20
- Image: chunk34Q4UM6V_js.MotionImage,
21
- Pressable: chunkNKA6XR77_js.MotionPressable,
22
- ScrollView: chunkTUYHTHVV_js.MotionScrollView
18
+ View: chunkFNVFV4EY_js.MotionView,
19
+ Text: chunkFWQOXA43_js.MotionText,
20
+ Image: chunkKBP4LR75_js.MotionImage,
21
+ Pressable: chunk3XTVY34H_js.MotionPressable,
22
+ ScrollView: chunkW5MC3P4N_js.MotionScrollView
23
23
  };
24
24
  function useAnimation(target, transition) {
25
25
  const output = reactNativeReanimated.useSharedValue(target);
@@ -41,14 +41,15 @@ function useAnimation(target, transition) {
41
41
  function useAnimator() {
42
42
  const registry = chunk7AOERN53_js.useNamedTransitions();
43
43
  const shouldReduceMotion = chunk7AOERN53_js.useShouldReduceMotion();
44
- return react.useCallback(
45
- (value, to, transition) => {
46
- const resolved = chunk7AOERN53_js.resolveNamedTransition(transition, registry);
47
- const cfg = shouldReduceMotion ? { type: "no-animation" } : resolved ?? { type: "spring" };
48
- value.value = chunkPTRF47DA_js.resolveTransition(cfg, to);
49
- },
50
- [registry, shouldReduceMotion]
51
- );
44
+ const registryRef = react.useRef(registry);
45
+ registryRef.current = registry;
46
+ const reduceMotionRef = react.useRef(shouldReduceMotion);
47
+ reduceMotionRef.current = shouldReduceMotion;
48
+ return react.useCallback((value, to, transition) => {
49
+ const resolved = chunk7AOERN53_js.resolveNamedTransition(transition, registryRef.current);
50
+ const cfg = reduceMotionRef.current ? { type: "no-animation" } : resolved ?? { type: "spring" };
51
+ value.value = chunkPTRF47DA_js.resolveTransition(cfg, to);
52
+ }, []);
52
53
  }
53
54
  function useSpring(target, config) {
54
55
  const spring = resolveSpringInput(config, chunk7AOERN53_js.useNamedTransitions());
@@ -119,7 +120,19 @@ function useColorCascade(rest, layers, options) {
119
120
  const key = options?.key ?? "backgroundColor";
120
121
  const sig = `${key}|${rest}|${layers.length}|${layers.map((l) => l.color).join(",")}`;
121
122
  const colors = react.useMemo(() => layers.map((l) => l.color), [sig]);
122
- const progressValues = react.useMemo(() => layers.map((l) => l.progress), [sig]);
123
+ const progressRef = react.useRef([]);
124
+ const prevProgress = progressRef.current;
125
+ let progressChanged = prevProgress.length !== layers.length;
126
+ if (!progressChanged) {
127
+ for (let i = 0; i < layers.length; i++) {
128
+ if (prevProgress[i] !== layers[i].progress) {
129
+ progressChanged = true;
130
+ break;
131
+ }
132
+ }
133
+ }
134
+ if (progressChanged) progressRef.current = layers.map((l) => l.progress);
135
+ const progressValues = progressRef.current;
123
136
  return reactNativeReanimated.useAnimatedStyle(() => {
124
137
  "worklet";
125
138
  let acc = rest;
@@ -575,35 +588,35 @@ Object.defineProperty(exports, "useGesture", {
575
588
  });
576
589
  Object.defineProperty(exports, "MotionView", {
577
590
  enumerable: true,
578
- get: function () { return chunkKYJROYCG_js.MotionView; }
591
+ get: function () { return chunkFNVFV4EY_js.MotionView; }
579
592
  });
580
593
  Object.defineProperty(exports, "MotionText", {
581
594
  enumerable: true,
582
- get: function () { return chunkX5J5M3K3_js.MotionText; }
595
+ get: function () { return chunkFWQOXA43_js.MotionText; }
583
596
  });
584
597
  Object.defineProperty(exports, "MotionImage", {
585
598
  enumerable: true,
586
- get: function () { return chunk34Q4UM6V_js.MotionImage; }
599
+ get: function () { return chunkKBP4LR75_js.MotionImage; }
587
600
  });
588
601
  Object.defineProperty(exports, "MotionPressable", {
589
602
  enumerable: true,
590
- get: function () { return chunkNKA6XR77_js.MotionPressable; }
603
+ get: function () { return chunk3XTVY34H_js.MotionPressable; }
591
604
  });
592
605
  Object.defineProperty(exports, "MotionScrollView", {
593
606
  enumerable: true,
594
- get: function () { return chunkTUYHTHVV_js.MotionScrollView; }
607
+ get: function () { return chunkW5MC3P4N_js.MotionScrollView; }
595
608
  });
596
609
  Object.defineProperty(exports, "Presence", {
597
610
  enumerable: true,
598
- get: function () { return chunkIWLU3VDE_js.Presence; }
611
+ get: function () { return chunkBP3Y2SHQ_js.Presence; }
599
612
  });
600
613
  Object.defineProperty(exports, "createMotionComponent", {
601
614
  enumerable: true,
602
- get: function () { return chunkIWLU3VDE_js.createMotionComponent; }
615
+ get: function () { return chunkBP3Y2SHQ_js.createMotionComponent; }
603
616
  });
604
617
  Object.defineProperty(exports, "usePresence", {
605
618
  enumerable: true,
606
- get: function () { return chunkIWLU3VDE_js.usePresence; }
619
+ get: function () { return chunkBP3Y2SHQ_js.usePresence; }
607
620
  });
608
621
  Object.defineProperty(exports, "MotionConfig", {
609
622
  enumerable: true,
package/dist/index.mjs CHANGED
@@ -1,20 +1,20 @@
1
1
  export { useGesture } from './chunk-RGNX6UZN.mjs';
2
- import { MotionView } from './chunk-TUMNV4P7.mjs';
3
- export { MotionView } from './chunk-TUMNV4P7.mjs';
4
- import { MotionText } from './chunk-ZN3PNGHQ.mjs';
5
- export { MotionText } from './chunk-ZN3PNGHQ.mjs';
6
- import { MotionImage } from './chunk-2DHKV2XY.mjs';
7
- export { MotionImage } from './chunk-2DHKV2XY.mjs';
8
- import { MotionPressable } from './chunk-V6BTXHZK.mjs';
9
- export { MotionPressable } from './chunk-V6BTXHZK.mjs';
10
- import { MotionScrollView } from './chunk-HFDZAHWP.mjs';
11
- export { MotionScrollView } from './chunk-HFDZAHWP.mjs';
12
- export { Presence, createMotionComponent, usePresence } from './chunk-LYMLQ6WQ.mjs';
2
+ import { MotionView } from './chunk-BQQTHG2V.mjs';
3
+ export { MotionView } from './chunk-BQQTHG2V.mjs';
4
+ import { MotionText } from './chunk-SGUHE5CX.mjs';
5
+ export { MotionText } from './chunk-SGUHE5CX.mjs';
6
+ import { MotionImage } from './chunk-O22NXXCZ.mjs';
7
+ export { MotionImage } from './chunk-O22NXXCZ.mjs';
8
+ import { MotionPressable } from './chunk-46P57VMY.mjs';
9
+ export { MotionPressable } from './chunk-46P57VMY.mjs';
10
+ import { MotionScrollView } from './chunk-OQV66TBQ.mjs';
11
+ export { MotionScrollView } from './chunk-OQV66TBQ.mjs';
12
+ export { Presence, createMotionComponent, usePresence } from './chunk-CSODMRJ7.mjs';
13
13
  import { useShouldReduceMotion, resolveNamedTransition, useNamedTransitions, lookupNamedTransition } from './chunk-R63GIUNU.mjs';
14
14
  export { MotionConfig, resolveNamedTransition, useMotionConfig, useNamedTransitions, useShouldReduceMotion } from './chunk-R63GIUNU.mjs';
15
15
  import { stableSig, resolveTransition, springToReanimated, warnNonWorkletOnce } from './chunk-CY7Y64C3.mjs';
16
16
  export { buildReleaseAnimation, cubicBezier, ensureWorkletEasing, resolveAnimatableValue, resolveTransition } from './chunk-CY7Y64C3.mjs';
17
- import { useEffect, useCallback, useMemo, useRef } from 'react';
17
+ import { useEffect, useRef, useCallback, useMemo } from 'react';
18
18
  import { useSharedValue, cancelAnimation, withSpring, useAnimatedReaction, useAnimatedStyle, interpolateColor, interpolate, useDerivedValue, Extrapolation, useAnimatedScrollHandler } from 'react-native-reanimated';
19
19
  import { isWorkletFunction } from 'react-native-worklets';
20
20
 
@@ -46,14 +46,15 @@ function useAnimation(target, transition) {
46
46
  function useAnimator() {
47
47
  const registry = useNamedTransitions();
48
48
  const shouldReduceMotion = useShouldReduceMotion();
49
- return useCallback(
50
- (value, to, transition) => {
51
- const resolved = resolveNamedTransition(transition, registry);
52
- const cfg = shouldReduceMotion ? { type: "no-animation" } : resolved ?? { type: "spring" };
53
- value.value = resolveTransition(cfg, to);
54
- },
55
- [registry, shouldReduceMotion]
56
- );
49
+ const registryRef = useRef(registry);
50
+ registryRef.current = registry;
51
+ const reduceMotionRef = useRef(shouldReduceMotion);
52
+ reduceMotionRef.current = shouldReduceMotion;
53
+ return useCallback((value, to, transition) => {
54
+ const resolved = resolveNamedTransition(transition, registryRef.current);
55
+ const cfg = reduceMotionRef.current ? { type: "no-animation" } : resolved ?? { type: "spring" };
56
+ value.value = resolveTransition(cfg, to);
57
+ }, []);
57
58
  }
58
59
  function useSpring(target, config) {
59
60
  const spring = resolveSpringInput(config, useNamedTransitions());
@@ -124,7 +125,19 @@ function useColorCascade(rest, layers, options) {
124
125
  const key = options?.key ?? "backgroundColor";
125
126
  const sig = `${key}|${rest}|${layers.length}|${layers.map((l) => l.color).join(",")}`;
126
127
  const colors = useMemo(() => layers.map((l) => l.color), [sig]);
127
- const progressValues = useMemo(() => layers.map((l) => l.progress), [sig]);
128
+ const progressRef = useRef([]);
129
+ const prevProgress = progressRef.current;
130
+ let progressChanged = prevProgress.length !== layers.length;
131
+ if (!progressChanged) {
132
+ for (let i = 0; i < layers.length; i++) {
133
+ if (prevProgress[i] !== layers[i].progress) {
134
+ progressChanged = true;
135
+ break;
136
+ }
137
+ }
138
+ }
139
+ if (progressChanged) progressRef.current = layers.map((l) => l.progress);
140
+ const progressValues = progressRef.current;
128
141
  return useAnimatedStyle(() => {
129
142
  "worklet";
130
143
  let acc = rest;
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunk34Q4UM6V_js = require('../chunk-34Q4UM6V.js');
4
- require('../chunk-IWLU3VDE.js');
3
+ var chunkKBP4LR75_js = require('../chunk-KBP4LR75.js');
4
+ require('../chunk-BP3Y2SHQ.js');
5
5
  require('../chunk-7AOERN53.js');
6
6
  require('../chunk-PTRF47DA.js');
7
7
 
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
9
9
 
10
10
  Object.defineProperty(exports, "MotionImage", {
11
11
  enumerable: true,
12
- get: function () { return chunk34Q4UM6V_js.MotionImage; }
12
+ get: function () { return chunkKBP4LR75_js.MotionImage; }
13
13
  });
@@ -1,4 +1,4 @@
1
- export { MotionImage } from '../chunk-2DHKV2XY.mjs';
2
- import '../chunk-LYMLQ6WQ.mjs';
1
+ export { MotionImage } from '../chunk-O22NXXCZ.mjs';
2
+ import '../chunk-CSODMRJ7.mjs';
3
3
  import '../chunk-R63GIUNU.mjs';
4
4
  import '../chunk-CY7Y64C3.mjs';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkNKA6XR77_js = require('../chunk-NKA6XR77.js');
4
- require('../chunk-IWLU3VDE.js');
3
+ var chunk3XTVY34H_js = require('../chunk-3XTVY34H.js');
4
+ require('../chunk-BP3Y2SHQ.js');
5
5
  require('../chunk-7AOERN53.js');
6
6
  require('../chunk-PTRF47DA.js');
7
7
 
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
9
9
 
10
10
  Object.defineProperty(exports, "MotionPressable", {
11
11
  enumerable: true,
12
- get: function () { return chunkNKA6XR77_js.MotionPressable; }
12
+ get: function () { return chunk3XTVY34H_js.MotionPressable; }
13
13
  });
@@ -1,4 +1,4 @@
1
- export { MotionPressable } from '../chunk-V6BTXHZK.mjs';
2
- import '../chunk-LYMLQ6WQ.mjs';
1
+ export { MotionPressable } from '../chunk-46P57VMY.mjs';
2
+ import '../chunk-CSODMRJ7.mjs';
3
3
  import '../chunk-R63GIUNU.mjs';
4
4
  import '../chunk-CY7Y64C3.mjs';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkTUYHTHVV_js = require('../chunk-TUYHTHVV.js');
4
- require('../chunk-IWLU3VDE.js');
3
+ var chunkW5MC3P4N_js = require('../chunk-W5MC3P4N.js');
4
+ require('../chunk-BP3Y2SHQ.js');
5
5
  require('../chunk-7AOERN53.js');
6
6
  require('../chunk-PTRF47DA.js');
7
7
 
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
9
9
 
10
10
  Object.defineProperty(exports, "MotionScrollView", {
11
11
  enumerable: true,
12
- get: function () { return chunkTUYHTHVV_js.MotionScrollView; }
12
+ get: function () { return chunkW5MC3P4N_js.MotionScrollView; }
13
13
  });
@@ -1,4 +1,4 @@
1
- export { MotionScrollView } from '../chunk-HFDZAHWP.mjs';
2
- import '../chunk-LYMLQ6WQ.mjs';
1
+ export { MotionScrollView } from '../chunk-OQV66TBQ.mjs';
2
+ import '../chunk-CSODMRJ7.mjs';
3
3
  import '../chunk-R63GIUNU.mjs';
4
4
  import '../chunk-CY7Y64C3.mjs';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkX5J5M3K3_js = require('../chunk-X5J5M3K3.js');
4
- require('../chunk-IWLU3VDE.js');
3
+ var chunkFWQOXA43_js = require('../chunk-FWQOXA43.js');
4
+ require('../chunk-BP3Y2SHQ.js');
5
5
  require('../chunk-7AOERN53.js');
6
6
  require('../chunk-PTRF47DA.js');
7
7
 
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
9
9
 
10
10
  Object.defineProperty(exports, "MotionText", {
11
11
  enumerable: true,
12
- get: function () { return chunkX5J5M3K3_js.MotionText; }
12
+ get: function () { return chunkFWQOXA43_js.MotionText; }
13
13
  });
@@ -1,4 +1,4 @@
1
- export { MotionText } from '../chunk-ZN3PNGHQ.mjs';
2
- import '../chunk-LYMLQ6WQ.mjs';
1
+ export { MotionText } from '../chunk-SGUHE5CX.mjs';
2
+ import '../chunk-CSODMRJ7.mjs';
3
3
  import '../chunk-R63GIUNU.mjs';
4
4
  import '../chunk-CY7Y64C3.mjs';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkKYJROYCG_js = require('../chunk-KYJROYCG.js');
4
- require('../chunk-IWLU3VDE.js');
3
+ var chunkFNVFV4EY_js = require('../chunk-FNVFV4EY.js');
4
+ require('../chunk-BP3Y2SHQ.js');
5
5
  require('../chunk-7AOERN53.js');
6
6
  require('../chunk-PTRF47DA.js');
7
7
 
@@ -9,5 +9,5 @@ require('../chunk-PTRF47DA.js');
9
9
 
10
10
  Object.defineProperty(exports, "MotionView", {
11
11
  enumerable: true,
12
- get: function () { return chunkKYJROYCG_js.MotionView; }
12
+ get: function () { return chunkFNVFV4EY_js.MotionView; }
13
13
  });
@@ -1,4 +1,4 @@
1
- export { MotionView } from '../chunk-TUMNV4P7.mjs';
2
- import '../chunk-LYMLQ6WQ.mjs';
1
+ export { MotionView } from '../chunk-BQQTHG2V.mjs';
2
+ import '../chunk-CSODMRJ7.mjs';
3
3
  import '../chunk-R63GIUNU.mjs';
4
4
  import '../chunk-CY7Y64C3.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rootnative/inertia",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Declarative animation primitives for React Native, built on react-native-reanimated.",
5
5
  "license": "MIT",
6
6
  "author": "RootNative",
@@ -7,6 +7,7 @@ export {
7
7
  releaseLayout,
8
8
  SHARED_LAYOUT_TTL_MS,
9
9
  __setSharedLayoutClock,
10
+ __sharedRegistrySize,
10
11
  type SharedRect,
11
12
  } from './sharedRegistry'
12
13
  export {
@@ -51,6 +51,37 @@ export const SHARED_LAYOUT_TTL_MS = 1000
51
51
  */
52
52
  let now = (): number => Date.now()
53
53
 
54
+ /**
55
+ * When the last expiry sweep ran, so the scan is amortized to at most once per
56
+ * TTL window rather than running on every write.
57
+ */
58
+ let lastSweep = 0
59
+
60
+ /**
61
+ * Drop every entry whose TTL has passed.
62
+ *
63
+ * Without this the map only ever shrank via `consumeLayout` / `peekSharedLayout`,
64
+ * so a `layoutId` that unmounted and was never remounted left its rect behind
65
+ * for the lifetime of the process. Bounded by distinct-id count, which is small
66
+ * for a handful of hero images but not for per-item ids in a long-lived list
67
+ * (`layoutId={`photo-${item.id}`}`).
68
+ *
69
+ * Sweeping a *live* element's entry is harmless: while mounted it re-registers
70
+ * on every `onLayout`, and on unmount `releaseLayout` re-adds it with a fresh
71
+ * TTL. So the only thing an over-eager sweep can cost is a FLIP source that was
72
+ * already too old to be used.
73
+ *
74
+ * Time-gated so a burst of layout events doesn't turn into a burst of full
75
+ * scans — worst case an expired entry survives one extra TTL window.
76
+ */
77
+ function sweepExpired(at: number): void {
78
+ if (at - lastSweep < SHARED_LAYOUT_TTL_MS) return
79
+ lastSweep = at
80
+ for (const [id, entry] of REGISTRY) {
81
+ if (entry.expiresAt < at) REGISTRY.delete(id)
82
+ }
83
+ }
84
+
54
85
  /**
55
86
  * Update the latest known rect for `id`. Called on every `onLayout` of a
56
87
  * Motion primitive with `layoutId` set so the registry always holds a
@@ -58,7 +89,9 @@ let now = (): number => Date.now()
58
89
  * transition. Resets the TTL each call.
59
90
  */
60
91
  export function registerLayout(id: string, rect: SharedRect): void {
61
- REGISTRY.set(id, { rect, expiresAt: now() + SHARED_LAYOUT_TTL_MS })
92
+ const at = now()
93
+ sweepExpired(at)
94
+ REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS })
62
95
  }
63
96
 
64
97
  /**
@@ -67,7 +100,9 @@ export function registerLayout(id: string, rect: SharedRect): void {
67
100
  * is purely intent-documenting at the call site.
68
101
  */
69
102
  export function releaseLayout(id: string, rect: SharedRect): void {
70
- REGISTRY.set(id, { rect, expiresAt: now() + SHARED_LAYOUT_TTL_MS })
103
+ const at = now()
104
+ sweepExpired(at)
105
+ REGISTRY.set(id, { rect, expiresAt: at + SHARED_LAYOUT_TTL_MS })
71
106
  }
72
107
 
73
108
  /**
@@ -88,6 +123,7 @@ export function consumeLayout(id: string): SharedRect | undefined {
88
123
  /** Drop all entries. Tests use this to isolate between cases. */
89
124
  export function clearSharedRegistry(): void {
90
125
  REGISTRY.clear()
126
+ lastSweep = 0
91
127
  }
92
128
 
93
129
  /**
@@ -108,4 +144,17 @@ export function peekSharedLayout(id: string): SharedRect | undefined {
108
144
  */
109
145
  export function __setSharedLayoutClock(fn: (() => number) | undefined): void {
110
146
  now = fn ?? Date.now
147
+ // Swapping the clock makes the previous sweep timestamp meaningless — a
148
+ // stubbed clock usually starts near 0, which would otherwise suppress every
149
+ // sweep until it caught up past the real-time value recorded earlier.
150
+ lastSweep = 0
151
+ }
152
+
153
+ /**
154
+ * Test hook: how many entries the registry is holding, expired or not. Used to
155
+ * assert that released-but-never-consumed rects are actually evicted. Not
156
+ * exported from the package root — reachable only from inside the workspace.
157
+ */
158
+ export function __sharedRegistrySize(): number {
159
+ return REGISTRY.size
111
160
  }