@rootnative/inertia 0.0.0-alpha.0

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 (113) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +131 -0
  4. package/dist/gestureLayer/index.d.mts +119 -0
  5. package/dist/gestureLayer/index.d.ts +119 -0
  6. package/dist/gestureLayer/index.js +346 -0
  7. package/dist/gestureLayer/index.js.map +1 -0
  8. package/dist/gestureLayer/index.mjs +344 -0
  9. package/dist/gestureLayer/index.mjs.map +1 -0
  10. package/dist/index.d.mts +507 -0
  11. package/dist/index.d.ts +507 -0
  12. package/dist/index.js +1546 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/index.mjs +1515 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/motion/Image.d.mts +12 -0
  17. package/dist/motion/Image.d.ts +12 -0
  18. package/dist/motion/Image.js +1138 -0
  19. package/dist/motion/Image.js.map +1 -0
  20. package/dist/motion/Image.mjs +1132 -0
  21. package/dist/motion/Image.mjs.map +1 -0
  22. package/dist/motion/Pressable.d.mts +15 -0
  23. package/dist/motion/Pressable.d.ts +15 -0
  24. package/dist/motion/Pressable.js +1138 -0
  25. package/dist/motion/Pressable.js.map +1 -0
  26. package/dist/motion/Pressable.mjs +1132 -0
  27. package/dist/motion/Pressable.mjs.map +1 -0
  28. package/dist/motion/ScrollView.d.mts +12 -0
  29. package/dist/motion/ScrollView.d.ts +12 -0
  30. package/dist/motion/ScrollView.js +1138 -0
  31. package/dist/motion/ScrollView.js.map +1 -0
  32. package/dist/motion/ScrollView.mjs +1132 -0
  33. package/dist/motion/ScrollView.mjs.map +1 -0
  34. package/dist/motion/Text.d.mts +11 -0
  35. package/dist/motion/Text.d.ts +11 -0
  36. package/dist/motion/Text.js +1138 -0
  37. package/dist/motion/Text.js.map +1 -0
  38. package/dist/motion/Text.mjs +1132 -0
  39. package/dist/motion/Text.mjs.map +1 -0
  40. package/dist/motion/View.d.mts +11 -0
  41. package/dist/motion/View.d.ts +11 -0
  42. package/dist/motion/View.js +1138 -0
  43. package/dist/motion/View.js.map +1 -0
  44. package/dist/motion/View.mjs +1132 -0
  45. package/dist/motion/View.mjs.map +1 -0
  46. package/dist/testing/index.d.mts +57 -0
  47. package/dist/testing/index.d.ts +57 -0
  48. package/dist/testing/index.js +19 -0
  49. package/dist/testing/index.js.map +1 -0
  50. package/dist/testing/index.mjs +16 -0
  51. package/dist/testing/index.mjs.map +1 -0
  52. package/dist/touch/index.d.mts +146 -0
  53. package/dist/touch/index.d.ts +146 -0
  54. package/dist/touch/index.js +166 -0
  55. package/dist/touch/index.js.map +1 -0
  56. package/dist/touch/index.mjs +164 -0
  57. package/dist/touch/index.mjs.map +1 -0
  58. package/dist/types-cU43dEmH.d.mts +339 -0
  59. package/dist/types-cU43dEmH.d.ts +339 -0
  60. package/dist/useGesture-BnY65PlQ.d.ts +84 -0
  61. package/dist/useGesture-DxtXdz-K.d.mts +84 -0
  62. package/jest-preset.js +33 -0
  63. package/jest-setup.js +213 -0
  64. package/llms.txt +142 -0
  65. package/package.json +151 -0
  66. package/src/__type-tests__/animate.test-d.tsx +88 -0
  67. package/src/__type-tests__/variants.test-d.tsx +67 -0
  68. package/src/config/MotionConfig.tsx +30 -0
  69. package/src/config/MotionConfigContext.ts +53 -0
  70. package/src/config/index.ts +9 -0
  71. package/src/gestureLayer/index.ts +21 -0
  72. package/src/gestureLayer/useGestureLayer.ts +285 -0
  73. package/src/gestures/focusVisibility.ts +61 -0
  74. package/src/gestures/index.ts +1 -0
  75. package/src/index.ts +72 -0
  76. package/src/layout/index.ts +16 -0
  77. package/src/layout/resolveLayout.ts +54 -0
  78. package/src/layout/sharedRegistry.ts +111 -0
  79. package/src/layout/useSharedLayout.ts +289 -0
  80. package/src/motion/Image.tsx +9 -0
  81. package/src/motion/Pressable.tsx +12 -0
  82. package/src/motion/ScrollView.tsx +9 -0
  83. package/src/motion/Text.tsx +8 -0
  84. package/src/motion/View.tsx +8 -0
  85. package/src/motion/createMotionComponent.tsx +1306 -0
  86. package/src/motion/index.ts +26 -0
  87. package/src/motion/installCheck.ts +65 -0
  88. package/src/presence/Presence.tsx +165 -0
  89. package/src/presence/PresenceContext.ts +28 -0
  90. package/src/presence/index.ts +6 -0
  91. package/src/testing/index.ts +78 -0
  92. package/src/touch/index.ts +18 -0
  93. package/src/touch/useTouchDrag.ts +289 -0
  94. package/src/transitions/easing.ts +53 -0
  95. package/src/transitions/index.ts +7 -0
  96. package/src/transitions/keys.ts +32 -0
  97. package/src/transitions/resolve.ts +169 -0
  98. package/src/transitions/resolveSequence.ts +87 -0
  99. package/src/transitions/runtime.ts +63 -0
  100. package/src/transitions/sig.ts +40 -0
  101. package/src/transitions/spring.ts +42 -0
  102. package/src/types.ts +383 -0
  103. package/src/values/index.ts +26 -0
  104. package/src/values/useAnimation.ts +69 -0
  105. package/src/values/useBooleanSpring.ts +33 -0
  106. package/src/values/useColorTransition.ts +72 -0
  107. package/src/values/useGesture.ts +144 -0
  108. package/src/values/useMotionValue.ts +33 -0
  109. package/src/values/useScroll.ts +72 -0
  110. package/src/values/useShadow.ts +116 -0
  111. package/src/values/useSpring.ts +98 -0
  112. package/src/values/useTransform.ts +132 -0
  113. package/src/values/useVariants.ts +60 -0
package/dist/index.js ADDED
@@ -0,0 +1,1546 @@
1
+ 'use strict';
2
+
3
+ var reactNative = require('react-native');
4
+ var react = require('react');
5
+ var Animated = require('react-native-reanimated');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var reactNativeWorklets = require('react-native-worklets');
8
+
9
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
10
+
11
+ var Animated__default = /*#__PURE__*/_interopDefault(Animated);
12
+
13
+ // src/motion/Image.tsx
14
+ var DEFAULT_MOTION_CONFIG = {
15
+ reducedMotion: "user"
16
+ };
17
+ var MotionConfigContext = react.createContext(
18
+ DEFAULT_MOTION_CONFIG
19
+ );
20
+ function useMotionConfig() {
21
+ return react.useContext(MotionConfigContext);
22
+ }
23
+ function useShouldReduceMotion() {
24
+ const { reducedMotion } = useMotionConfig();
25
+ const osReduced = Animated.useReducedMotion();
26
+ if (reducedMotion === "never") return false;
27
+ if (reducedMotion === "always") return true;
28
+ return osReduced;
29
+ }
30
+ function MotionConfig({
31
+ reducedMotion = "user",
32
+ children
33
+ }) {
34
+ const value = react.useMemo(
35
+ () => ({ reducedMotion }),
36
+ [reducedMotion]
37
+ );
38
+ return /* @__PURE__ */ jsxRuntime.jsx(MotionConfigContext.Provider, { value, children });
39
+ }
40
+ var modality = "keyboard";
41
+ var installed = false;
42
+ function setKeyboard() {
43
+ modality = "keyboard";
44
+ }
45
+ function setPointer() {
46
+ modality = "pointer";
47
+ }
48
+ function ensureInstalled() {
49
+ if (installed) return;
50
+ if (reactNative.Platform.OS !== "web") return;
51
+ if (typeof document === "undefined") return;
52
+ document.addEventListener("keydown", setKeyboard, true);
53
+ document.addEventListener("mousedown", setPointer, true);
54
+ document.addEventListener("pointerdown", setPointer, true);
55
+ document.addEventListener("touchstart", setPointer, true);
56
+ installed = true;
57
+ }
58
+ function isFocusVisible() {
59
+ if (reactNative.Platform.OS !== "web") return true;
60
+ ensureInstalled();
61
+ return modality === "keyboard";
62
+ }
63
+ function ensureWorkletEasing(easing) {
64
+ if (!easing) return void 0;
65
+ const fn = isEasingFactory(easing) ? easing.factory() : easing;
66
+ if (reactNativeWorklets.isWorkletFunction(fn)) return fn;
67
+ const wrapped = (t) => {
68
+ "worklet";
69
+ return fn(t);
70
+ };
71
+ return wrapped;
72
+ }
73
+ function isEasingFactory(value) {
74
+ return typeof value === "object" && value !== null && "factory" in value && typeof value.factory === "function";
75
+ }
76
+
77
+ // src/transitions/spring.ts
78
+ var DEFAULT_SPRING = {
79
+ tension: 170,
80
+ friction: 26,
81
+ mass: 1
82
+ };
83
+ function springToReanimated(t) {
84
+ "worklet";
85
+ return {
86
+ stiffness: t.tension ?? DEFAULT_SPRING.tension,
87
+ damping: t.friction ?? DEFAULT_SPRING.friction,
88
+ mass: t.mass ?? DEFAULT_SPRING.mass,
89
+ velocity: t.velocity,
90
+ restSpeedThreshold: t.restSpeedThreshold,
91
+ restDisplacementThreshold: t.restDisplacementThreshold
92
+ };
93
+ }
94
+
95
+ // src/layout/resolveLayout.ts
96
+ function resolveLayoutTransition(layout) {
97
+ if (!layout) return void 0;
98
+ const cfg = layout === true ? { type: "spring" } : layout;
99
+ if (cfg.type === "no-animation") return void 0;
100
+ if (cfg.type === "timing") {
101
+ let builder2 = Animated.LinearTransition.duration(cfg.duration ?? 300);
102
+ const easing = ensureWorkletEasing(cfg.easing);
103
+ if (easing) builder2 = builder2.easing(easing);
104
+ if (cfg.delay) builder2 = builder2.delay(cfg.delay);
105
+ return builder2;
106
+ }
107
+ const spring = cfg.type === "decay" ? { type: "spring" } : cfg;
108
+ const { stiffness, damping, mass } = springToReanimated({
109
+ ...DEFAULT_SPRING,
110
+ ...spring
111
+ });
112
+ let builder = Animated.LinearTransition.springify().stiffness(stiffness).damping(damping).mass(mass);
113
+ if ("delay" in spring && spring.delay) builder = builder.delay(spring.delay);
114
+ return builder;
115
+ }
116
+
117
+ // src/layout/sharedRegistry.ts
118
+ var REGISTRY = /* @__PURE__ */ new Map();
119
+ var SHARED_LAYOUT_TTL_MS = 1e3;
120
+ var now = () => Date.now();
121
+ function registerLayout(id, rect) {
122
+ REGISTRY.set(id, { rect, expiresAt: now() + SHARED_LAYOUT_TTL_MS });
123
+ }
124
+ function releaseLayout(id, rect) {
125
+ REGISTRY.set(id, { rect, expiresAt: now() + SHARED_LAYOUT_TTL_MS });
126
+ }
127
+ function consumeLayout(id) {
128
+ const entry = REGISTRY.get(id);
129
+ if (!entry) return void 0;
130
+ REGISTRY.delete(id);
131
+ if (entry.expiresAt < now()) return void 0;
132
+ return entry.rect;
133
+ }
134
+ function useSharedLayout(options) {
135
+ const { layoutId, userRef, transition, shouldReduceMotion, userOnLayout } = options;
136
+ const dx = Animated.useSharedValue(0);
137
+ const dy = Animated.useSharedValue(0);
138
+ const sx = Animated.useSharedValue(1);
139
+ const sy = Animated.useSharedValue(1);
140
+ const lastRectRef = react.useRef(null);
141
+ const consumedRef = react.useRef(false);
142
+ const transitionRef = react.useRef(transition);
143
+ transitionRef.current = transition;
144
+ const reducedMotionRef = react.useRef(shouldReduceMotion);
145
+ reducedMotionRef.current = shouldReduceMotion;
146
+ const setRef = react.useCallback(
147
+ (node) => {
148
+ if (typeof userRef === "function") userRef(node);
149
+ else if (userRef) userRef.current = node;
150
+ },
151
+ [userRef]
152
+ );
153
+ const onLayout = react.useCallback(
154
+ (event) => {
155
+ userOnLayout?.(event);
156
+ if (!layoutId) return;
157
+ const { x, y, width, height } = event.nativeEvent.layout;
158
+ const rect = { x, y, width, height };
159
+ lastRectRef.current = rect;
160
+ let source;
161
+ if (!consumedRef.current) {
162
+ consumedRef.current = true;
163
+ source = consumeLayout(layoutId);
164
+ }
165
+ registerLayout(layoutId, rect);
166
+ if (source) {
167
+ applyFlip({
168
+ source,
169
+ target: rect,
170
+ dx,
171
+ dy,
172
+ sx,
173
+ sy,
174
+ transition: transitionRef.current,
175
+ shouldReduceMotion: reducedMotionRef.current
176
+ });
177
+ }
178
+ },
179
+ // dx/dy/sx/sy are stable refs from useSharedValue, but eslint's
180
+ // exhaustive-deps would flag them — including them is harmless and
181
+ // silences the warning.
182
+ [layoutId, userOnLayout, dx, dy, sx, sy]
183
+ );
184
+ react.useEffect(() => {
185
+ consumedRef.current = false;
186
+ }, [layoutId]);
187
+ react.useEffect(() => {
188
+ return () => {
189
+ if (!layoutId) return;
190
+ const rect = lastRectRef.current;
191
+ if (!rect) return;
192
+ releaseLayout(layoutId, rect);
193
+ };
194
+ }, [layoutId]);
195
+ return react.useMemo(
196
+ () => ({
197
+ flip: { dx, dy, sx, sy },
198
+ setRef,
199
+ onLayout
200
+ }),
201
+ [dx, dy, sx, sy, setRef, onLayout]
202
+ );
203
+ }
204
+ function applyFlip(args) {
205
+ const { source, target, dx, dy, sx, sy, transition, shouldReduceMotion } = args;
206
+ const sourceCenterX = source.x + source.width / 2;
207
+ const sourceCenterY = source.y + source.height / 2;
208
+ const targetCenterX = target.x + target.width / 2;
209
+ const targetCenterY = target.y + target.height / 2;
210
+ const deltaX = sourceCenterX - targetCenterX;
211
+ const deltaY = sourceCenterY - targetCenterY;
212
+ const scaleX = target.width > 0 ? source.width / target.width : 1;
213
+ const scaleY = target.height > 0 ? source.height / target.height : 1;
214
+ if (shouldReduceMotion) {
215
+ dx.value = 0;
216
+ dy.value = 0;
217
+ sx.value = 1;
218
+ sy.value = 1;
219
+ return;
220
+ }
221
+ if (transition?.type === "no-animation") {
222
+ dx.value = 0;
223
+ dy.value = 0;
224
+ sx.value = 1;
225
+ sy.value = 1;
226
+ return;
227
+ }
228
+ if (transition?.type === "timing") {
229
+ const duration = transition.duration ?? 300;
230
+ dx.value = Animated.withSequence(
231
+ Animated.withTiming(deltaX, { duration: 0 }),
232
+ Animated.withTiming(0, { duration })
233
+ );
234
+ dy.value = Animated.withSequence(
235
+ Animated.withTiming(deltaY, { duration: 0 }),
236
+ Animated.withTiming(0, { duration })
237
+ );
238
+ sx.value = Animated.withSequence(
239
+ Animated.withTiming(scaleX, { duration: 0 }),
240
+ Animated.withTiming(1, { duration })
241
+ );
242
+ sy.value = Animated.withSequence(
243
+ Animated.withTiming(scaleY, { duration: 0 }),
244
+ Animated.withTiming(1, { duration })
245
+ );
246
+ return;
247
+ }
248
+ const springCfg = transition?.type === "spring" ? { ...DEFAULT_SPRING, ...transition } : { ...DEFAULT_SPRING };
249
+ const springParams = springToReanimated(springCfg);
250
+ dx.value = Animated.withSequence(
251
+ Animated.withTiming(deltaX, { duration: 0 }),
252
+ Animated.withSpring(0, springParams)
253
+ );
254
+ dy.value = Animated.withSequence(
255
+ Animated.withTiming(deltaY, { duration: 0 }),
256
+ Animated.withSpring(0, springParams)
257
+ );
258
+ sx.value = Animated.withSequence(
259
+ Animated.withTiming(scaleX, { duration: 0 }),
260
+ Animated.withSpring(1, springParams)
261
+ );
262
+ sy.value = Animated.withSequence(
263
+ Animated.withTiming(scaleY, { duration: 0 }),
264
+ Animated.withSpring(1, springParams)
265
+ );
266
+ }
267
+ var PresenceContext = react.createContext(null);
268
+ function usePresence() {
269
+ return react.useContext(PresenceContext);
270
+ }
271
+ function Presence({ children }) {
272
+ const incoming = react.useMemo(() => {
273
+ const out = [];
274
+ react.Children.forEach(children, (child) => {
275
+ if (!react.isValidElement(child)) return;
276
+ if (child.key === null) {
277
+ if (__DEV__) {
278
+ console.warn(
279
+ "[inertia] <Presence> children must have a `key`. Skipping a keyless child."
280
+ );
281
+ }
282
+ return;
283
+ }
284
+ out.push(child);
285
+ });
286
+ return out;
287
+ }, [children]);
288
+ const [exiting, setExiting] = react.useState(
289
+ () => /* @__PURE__ */ new Map()
290
+ );
291
+ const prevIncomingRef = react.useRef(incoming);
292
+ if (prevIncomingRef.current !== incoming) {
293
+ const prev = prevIncomingRef.current;
294
+ prevIncomingRef.current = incoming;
295
+ const incomingKeys = new Set(incoming.map((el) => el.key));
296
+ let next = null;
297
+ const ensureMutable = () => {
298
+ if (!next) next = new Map(exiting);
299
+ return next;
300
+ };
301
+ for (const oldEl of prev) {
302
+ const key = oldEl.key;
303
+ if (!incomingKeys.has(key) && !exiting.has(key)) {
304
+ ensureMutable().set(key, oldEl);
305
+ }
306
+ }
307
+ for (const el of incoming) {
308
+ const key = el.key;
309
+ if (exiting.has(key)) {
310
+ ensureMutable().delete(key);
311
+ }
312
+ }
313
+ if (next) setExiting(next);
314
+ }
315
+ const handleRemove = react.useCallback((key) => {
316
+ setExiting((prev) => {
317
+ if (!prev.has(key)) return prev;
318
+ const next = new Map(prev);
319
+ next.delete(key);
320
+ return next;
321
+ });
322
+ }, []);
323
+ const renderList = [];
324
+ for (const el of incoming) {
325
+ renderList.push({
326
+ key: el.key,
327
+ element: el,
328
+ isPresent: true
329
+ });
330
+ }
331
+ for (const [key, el] of exiting) {
332
+ if (!renderList.some((entry) => entry.key === key)) {
333
+ renderList.push({ key, element: el, isPresent: false });
334
+ }
335
+ }
336
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderList.map(({ key, element, isPresent }) => /* @__PURE__ */ jsxRuntime.jsx(
337
+ PresenceItem,
338
+ {
339
+ itemKey: key,
340
+ isPresent,
341
+ onRemove: handleRemove,
342
+ children: element
343
+ },
344
+ key
345
+ )) });
346
+ }
347
+ function PresenceItem({
348
+ itemKey,
349
+ isPresent,
350
+ onRemove,
351
+ children
352
+ }) {
353
+ const value = react.useMemo(
354
+ () => ({
355
+ isPresent,
356
+ safeToRemove: () => onRemove(itemKey)
357
+ }),
358
+ [isPresent, itemKey, onRemove]
359
+ );
360
+ return /* @__PURE__ */ jsxRuntime.jsx(PresenceContext.Provider, { value, children });
361
+ }
362
+ var DEFAULT_TIMING_DURATION = 250;
363
+ function buildSpring(cfg, toValue, cb) {
364
+ return Animated.withSpring(toValue, springToReanimated(cfg), cb);
365
+ }
366
+ function buildTiming(cfg, toValue, cb) {
367
+ return Animated.withTiming(
368
+ toValue,
369
+ {
370
+ duration: cfg.duration ?? DEFAULT_TIMING_DURATION,
371
+ easing: ensureWorkletEasing(cfg.easing) ?? Animated.Easing.inOut(Animated.Easing.ease)
372
+ },
373
+ cb
374
+ );
375
+ }
376
+ function buildDecay(cfg, cb) {
377
+ return Animated.withDecay(
378
+ {
379
+ velocity: cfg.velocity ?? 0,
380
+ deceleration: cfg.deceleration,
381
+ clamp: cfg.clamp
382
+ },
383
+ cb
384
+ );
385
+ }
386
+ function buildOne(cfg, toValue, cb) {
387
+ if (cfg.type === "no-animation") {
388
+ if (cb) cb(true, toValue);
389
+ return toValue;
390
+ }
391
+ if (cfg.type === "decay") return buildDecay(cfg, cb);
392
+ if (cfg.type === "timing") return buildTiming(cfg, toValue, cb);
393
+ return buildSpring(cfg, toValue, cb);
394
+ }
395
+ function applyRepeat(animation, repeat) {
396
+ if (repeat === void 0) return animation;
397
+ if (repeat === "infinite") {
398
+ return Animated.withRepeat(animation, -1, true);
399
+ }
400
+ if (typeof repeat === "number") {
401
+ return Animated.withRepeat(animation, repeat, true);
402
+ }
403
+ const count = repeat.count === "infinite" ? -1 : repeat.count;
404
+ const alternate = repeat.alternate ?? true;
405
+ return Animated.withRepeat(animation, count, alternate);
406
+ }
407
+ function applyDelay(animation, delay) {
408
+ if (!delay || delay <= 0) return animation;
409
+ return Animated.withDelay(delay, animation);
410
+ }
411
+ function resolveTransition(config, toValue, callback) {
412
+ const cfg = config ?? { type: "spring" };
413
+ const base = buildOne(cfg, toValue, callback);
414
+ const repeated = applyRepeat(base, repeatOf(cfg));
415
+ return applyDelay(repeated, delayOf(cfg));
416
+ }
417
+ function repeatOf(cfg) {
418
+ if (cfg.type === "no-animation" || cfg.type === "decay") return void 0;
419
+ return cfg.repeat;
420
+ }
421
+ function stripRepeat(cfg) {
422
+ if (!cfg) return cfg;
423
+ if (cfg.type === "no-animation" || cfg.type === "decay") return cfg;
424
+ if (cfg.repeat === void 0) return cfg;
425
+ const next = { ...cfg };
426
+ delete next.repeat;
427
+ return next;
428
+ }
429
+ function delayOf(cfg) {
430
+ if (cfg.type === "no-animation") return void 0;
431
+ return cfg.delay;
432
+ }
433
+ function isStepObject(v) {
434
+ return typeof v === "object" && v !== null && !Array.isArray(v) && "to" in v;
435
+ }
436
+ function resolveAnimatableValue(value, base, factory) {
437
+ if (Array.isArray(value)) {
438
+ const steps = value;
439
+ const stepBase = stripRepeat(base);
440
+ const animations = steps.map(
441
+ (step2, i) => resolveStep(step2, stepBase, factory?.("step", i))
442
+ );
443
+ const seq = Animated.withSequence(...animations);
444
+ return applyRepeat(seq, base ? repeatOf(base) : void 0);
445
+ }
446
+ const step = value;
447
+ const cb = factory?.("animation", void 0);
448
+ if (isStepObject(step)) {
449
+ return resolveStep(step, base, cb);
450
+ }
451
+ return resolveTransition(base, step, cb);
452
+ }
453
+ function resolveStep(step, base, cb) {
454
+ if (isStepObject(step)) {
455
+ const { to, ...override } = step;
456
+ const merged = mergeTransition(base, override);
457
+ return resolveTransition(merged, to, cb);
458
+ }
459
+ return resolveTransition(base, step, cb);
460
+ }
461
+ function mergeTransition(base, override) {
462
+ if (override.type && base && override.type !== base.type) {
463
+ return override;
464
+ }
465
+ return { ...base ?? { type: "spring" }, ...override };
466
+ }
467
+
468
+ // src/transitions/keys.ts
469
+ var TRANSITION_CONFIG_KEYS = /* @__PURE__ */ new Set([
470
+ "type",
471
+ "tension",
472
+ "friction",
473
+ "mass",
474
+ "velocity",
475
+ "restSpeedThreshold",
476
+ "restDisplacementThreshold",
477
+ "duration",
478
+ "easing",
479
+ "delay",
480
+ "repeat",
481
+ "deceleration",
482
+ "clamp"
483
+ ]);
484
+ function isTopLevelTransition(t) {
485
+ if (t === null || typeof t !== "object") return false;
486
+ const keys = Object.keys(t);
487
+ if (keys.length === 0) return false;
488
+ return keys.every((k) => TRANSITION_CONFIG_KEYS.has(k));
489
+ }
490
+ var DEFAULT_TIMING_DURATION2 = 250;
491
+ function buildReleaseAnimation(transition, toValue) {
492
+ "worklet";
493
+ if (transition.type === "no-animation") return toValue;
494
+ if (transition.type === "decay") {
495
+ const cfg = { velocity: transition.velocity ?? 0 };
496
+ if (transition.deceleration !== void 0) {
497
+ cfg.deceleration = transition.deceleration;
498
+ }
499
+ if (transition.clamp !== void 0) cfg.clamp = transition.clamp;
500
+ return Animated.withDecay(cfg);
501
+ }
502
+ if (transition.type === "timing") {
503
+ const e = transition.easing;
504
+ const easingFn = e && typeof e === "object" && "factory" in e ? e.factory() : e ?? Animated.Easing.inOut(Animated.Easing.ease);
505
+ return Animated.withTiming(toValue, {
506
+ duration: transition.duration ?? DEFAULT_TIMING_DURATION2,
507
+ easing: easingFn
508
+ });
509
+ }
510
+ return Animated.withSpring(toValue, springToReanimated(transition));
511
+ }
512
+
513
+ // src/transitions/sig.ts
514
+ function stableSig(value) {
515
+ if (value === void 0) return "";
516
+ try {
517
+ return stableStringify(value);
518
+ } catch {
519
+ return String(value);
520
+ }
521
+ }
522
+ function stableStringify(v) {
523
+ if (v === null || typeof v !== "object") {
524
+ if (typeof v === "function" || v === void 0) return "null";
525
+ return JSON.stringify(v);
526
+ }
527
+ if (Array.isArray(v)) {
528
+ return "[" + v.map(stableStringify).join(",") + "]";
529
+ }
530
+ const obj = v;
531
+ const keys = Object.keys(obj).sort();
532
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
533
+ }
534
+ var alreadyChecked = false;
535
+ function ensureReanimatedInstalled() {
536
+ if (!__DEV__ || alreadyChecked) return;
537
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "test") {
538
+ return;
539
+ }
540
+ alreadyChecked = true;
541
+ const version = Animated.reanimatedVersion;
542
+ if (version) {
543
+ const major = parseInt(version.split(".")[0] ?? "0", 10);
544
+ if (major < 4) {
545
+ console.error(
546
+ `[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).`
547
+ );
548
+ return;
549
+ }
550
+ }
551
+ const probe = function probe2() {
552
+ "worklet";
553
+ return 0;
554
+ };
555
+ if (typeof probe.__workletHash !== "number") {
556
+ console.error(
557
+ `[inertia] The Reanimated worklets babel plugin is not configured. Add \`'react-native-worklets/plugin'\` as the LAST entry in the \`plugins\` array of your \`babel.config.js\`, then restart Metro with a fresh cache: \`npx expo start -c\` or \`npx react-native start --reset-cache\`.`
558
+ );
559
+ }
560
+ }
561
+ var TRANSFORM_KEYS = [
562
+ "translateX",
563
+ "translateY",
564
+ "scale",
565
+ "scaleX",
566
+ "scaleY",
567
+ "rotate",
568
+ "rotateX",
569
+ "rotateY"
570
+ ];
571
+ var ROTATION_KEYS = /* @__PURE__ */ new Set(["rotate", "rotateX", "rotateY"]);
572
+ var NUMERIC_TOP_LEVEL_KEYS = [
573
+ "opacity",
574
+ "width",
575
+ "height",
576
+ "borderRadius",
577
+ "shadowOpacity",
578
+ "shadowRadius",
579
+ "elevation"
580
+ ];
581
+ var COLOR_KEYS = [
582
+ "backgroundColor",
583
+ "borderColor",
584
+ "color",
585
+ "tintColor",
586
+ "shadowColor"
587
+ ];
588
+ var SHADOW_OFFSET_KEYS = ["shadowOffsetWidth", "shadowOffsetHeight"];
589
+ var ALL_KEYS = [
590
+ ...TRANSFORM_KEYS,
591
+ ...NUMERIC_TOP_LEVEL_KEYS,
592
+ ...COLOR_KEYS,
593
+ ...SHADOW_OFFSET_KEYS
594
+ ];
595
+ var TRANSFORM_KEY_SET = new Set(TRANSFORM_KEYS);
596
+ var COLOR_KEY_SET = new Set(COLOR_KEYS);
597
+ var SHADOW_OFFSET_KEY_SET = new Set(SHADOW_OFFSET_KEYS);
598
+ var GESTURE_LAYER_NAMES = [
599
+ "hovered",
600
+ "focused",
601
+ "focusVisible",
602
+ "pressed"
603
+ ];
604
+ var GESTURE_LAYER_NAME_SET = new Set(GESTURE_LAYER_NAMES);
605
+ var EXITING_POINTER_EVENTS_STYLE = { pointerEvents: "none" };
606
+ var DEFAULT_RESTING = {
607
+ translateX: 0,
608
+ translateY: 0,
609
+ scale: 1,
610
+ scaleX: 1,
611
+ scaleY: 1,
612
+ rotate: 0,
613
+ rotateX: 0,
614
+ rotateY: 0,
615
+ opacity: 1,
616
+ width: 0,
617
+ height: 0,
618
+ borderRadius: 0,
619
+ shadowOpacity: 0,
620
+ shadowRadius: 0,
621
+ elevation: 0,
622
+ // 'transparent' is the only safe universal default for colors: it works as
623
+ // an initial seed for any color animation (no jarring opaque flash on mount
624
+ // when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
625
+ // any opaque target via Reanimated's color util.
626
+ backgroundColor: "transparent",
627
+ borderColor: "transparent",
628
+ color: "transparent",
629
+ tintColor: "transparent",
630
+ shadowColor: "transparent",
631
+ shadowOffsetWidth: 0,
632
+ shadowOffsetHeight: 0
633
+ };
634
+ function transitionFor(prop, transition) {
635
+ if (!transition) return void 0;
636
+ if (isTopLevelTransition(transition)) return transition;
637
+ if (GESTURE_LAYER_NAME_SET.has(prop)) return void 0;
638
+ return transition[prop];
639
+ }
640
+ function gestureLayerTransitionFor(layer, transition) {
641
+ if (!transition) return void 0;
642
+ if (isTopLevelTransition(transition)) return transition;
643
+ return transition[layer];
644
+ }
645
+ function createMotionComponent(Component) {
646
+ ensureReanimatedInstalled();
647
+ const AnimatedComponent = Animated__default.default.createAnimatedComponent(
648
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
649
+ Component
650
+ );
651
+ const Motion2 = react.forwardRef(function Motion3(props, ref) {
652
+ const {
653
+ initial,
654
+ animate,
655
+ exit,
656
+ transition,
657
+ variants,
658
+ controller,
659
+ gesture,
660
+ layout,
661
+ layoutId,
662
+ onAnimationEnd,
663
+ style,
664
+ onLayout: userOnLayout,
665
+ ...rest
666
+ } = props;
667
+ if (__DEV__ && typeof style === "function") {
668
+ throw new Error(
669
+ "[inertia] `style` must be a style object or array of style objects, not a function. The function-form `style={(state) => ...}` Pressable API is not supported \u2014 use `gesture.pressed` (or `gesture.focused`, etc.) to drive state-dependent styling instead."
670
+ );
671
+ }
672
+ const presence = usePresence();
673
+ const isExiting = presence !== null && presence.isPresent === false;
674
+ const shouldReduceMotion = useShouldReduceMotion();
675
+ const onAnimationEndRef = react.useRef(onAnimationEnd);
676
+ onAnimationEndRef.current = onAnimationEnd;
677
+ const variantKey = useControllerKey(controller);
678
+ const resolvedAnimate = resolveAnimateInput(
679
+ animate,
680
+ variants,
681
+ variantKey
682
+ );
683
+ const animateRecord = resolvedAnimate ?? {};
684
+ const initialRecord = initial && initial !== false ? initial : void 0;
685
+ const exitRecord = exit ? exit : void 0;
686
+ const [pressed, setPressed] = react.useState(false);
687
+ const [focused, setFocused] = react.useState(false);
688
+ const [focusVisible, setFocusVisible] = react.useState(false);
689
+ const [hovered, setHovered] = react.useState(false);
690
+ const touched = /* @__PURE__ */ new Set();
691
+ collectTouchedKeys(touched, animateRecord);
692
+ if (initialRecord) collectTouchedKeys(touched, initialRecord);
693
+ if (variants) {
694
+ for (const variant of Object.values(variants)) {
695
+ if (!variant) continue;
696
+ collectTouchedKeys(touched, variant);
697
+ }
698
+ }
699
+ if (gesture) {
700
+ for (const subState of [
701
+ gesture.pressed,
702
+ gesture.focused,
703
+ gesture.focusVisible,
704
+ gesture.hovered
705
+ ]) {
706
+ if (!subState) continue;
707
+ collectTouchedKeys(touched, subState);
708
+ }
709
+ }
710
+ if (exitRecord) collectTouchedKeys(touched, exitRecord);
711
+ const activeKeysRef = react.useRef(null);
712
+ const hasTransformRef = react.useRef(false);
713
+ const hasShadowOffsetRef = react.useRef(false);
714
+ const prevActive = activeKeysRef.current;
715
+ let grew = prevActive === null;
716
+ if (!grew && prevActive) {
717
+ for (const k of touched) {
718
+ if (!prevActive.includes(k)) {
719
+ grew = true;
720
+ break;
721
+ }
722
+ }
723
+ }
724
+ if (grew) {
725
+ const merged = new Set(prevActive ?? []);
726
+ for (const k of touched) merged.add(k);
727
+ activeKeysRef.current = ALL_KEYS.filter((k) => merged.has(k));
728
+ hasTransformRef.current = activeKeysRef.current.some(
729
+ (k) => TRANSFORM_KEY_SET.has(k)
730
+ );
731
+ hasShadowOffsetRef.current = activeKeysRef.current.some(
732
+ (k) => SHADOW_OFFSET_KEY_SET.has(k)
733
+ );
734
+ }
735
+ const sharedValues = useAnimatableSharedValues((key) => {
736
+ if (SHADOW_OFFSET_KEY_SET.has(key)) {
737
+ const axis = shadowOffsetAxisFor(key);
738
+ if (initial === false) {
739
+ return shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
740
+ }
741
+ return shadowOffsetAxisValue(
742
+ initialRecord?.shadowOffset,
743
+ axis
744
+ ) ?? shadowOffsetAxisValue(animateRecord.shadowOffset, axis) ?? DEFAULT_RESTING[key];
745
+ }
746
+ if (initial === false) {
747
+ const a = animateRecord[key];
748
+ return restValue(a) ?? DEFAULT_RESTING[key];
749
+ }
750
+ return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? DEFAULT_RESTING[key];
751
+ });
752
+ const pressedProgress = Animated.useSharedValue(0);
753
+ const focusedProgress = Animated.useSharedValue(0);
754
+ const focusVisibleProgress = Animated.useSharedValue(0);
755
+ const hoveredProgress = Animated.useSharedValue(0);
756
+ const gestureSV = Animated.useSharedValue(
757
+ resolveGestureLayers(gesture)
758
+ );
759
+ const gestureTargetsSig = stableSig(gesture);
760
+ react.useEffect(() => {
761
+ gestureSV.value = resolveGestureLayers(gesture);
762
+ }, [gestureTargetsSig]);
763
+ const baseRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : animateRecord;
764
+ const baseSig = stableSig(baseRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
765
+ const transitionSig = stableSig(transition);
766
+ const safeToRemoveRef = react.useRef(void 0);
767
+ safeToRemoveRef.current = presence?.safeToRemove;
768
+ react.useEffect(() => {
769
+ if (isExiting && (!exitRecord || Object.keys(exitRecord).length === 0)) {
770
+ safeToRemoveRef.current?.();
771
+ return;
772
+ }
773
+ let pending = 0;
774
+ let done = false;
775
+ const onSettle = () => {
776
+ if (done) return;
777
+ pending--;
778
+ if (pending <= 0) {
779
+ done = true;
780
+ if (isExiting) safeToRemoveRef.current?.();
781
+ }
782
+ };
783
+ let transformPending = 0;
784
+ for (const k of ALL_KEYS) {
785
+ if (TRANSFORM_KEY_SET.has(k) && baseRecord[k] !== void 0) {
786
+ transformPending++;
787
+ }
788
+ }
789
+ const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
790
+ for (const key of ALL_KEYS) {
791
+ const target = SHADOW_OFFSET_KEY_SET.has(key) ? shadowOffsetAxisValue(
792
+ baseRecord.shadowOffset,
793
+ shadowOffsetAxisFor(key)
794
+ ) : baseRecord[key];
795
+ if (target === void 0) continue;
796
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : transitionFor(
797
+ SHADOW_OFFSET_KEY_SET.has(key) ? "shadowOffset" : key,
798
+ transition
799
+ );
800
+ if (isExiting) pending++;
801
+ const factory = makeKeyCallbackFactory(
802
+ key,
803
+ sharedValues[key],
804
+ targetEndValue(target),
805
+ onAnimationEndRef,
806
+ {
807
+ stepCount: stepCountOf(target),
808
+ totalIterations: totalIterationsOf(cfg)
809
+ },
810
+ isExiting ? onSettle : void 0,
811
+ TRANSFORM_KEY_SET.has(key) ? transformGroup : void 0
812
+ );
813
+ sharedValues[key].value = resolveAnimatableValue(
814
+ target,
815
+ cfg,
816
+ factory
817
+ );
818
+ }
819
+ if (isExiting && pending === 0) {
820
+ safeToRemoveRef.current?.();
821
+ }
822
+ }, [baseSig, transitionSig]);
823
+ useGestureLayerProgress(
824
+ pressedProgress,
825
+ pressed,
826
+ gesture?.pressed != null,
827
+ "pressed",
828
+ transition,
829
+ isExiting,
830
+ shouldReduceMotion
831
+ );
832
+ useGestureLayerProgress(
833
+ focusedProgress,
834
+ focused,
835
+ gesture?.focused != null,
836
+ "focused",
837
+ transition,
838
+ isExiting,
839
+ shouldReduceMotion
840
+ );
841
+ useGestureLayerProgress(
842
+ focusVisibleProgress,
843
+ focusVisible,
844
+ gesture?.focusVisible != null,
845
+ "focusVisible",
846
+ transition,
847
+ isExiting,
848
+ shouldReduceMotion
849
+ );
850
+ useGestureLayerProgress(
851
+ hoveredProgress,
852
+ hovered,
853
+ gesture?.hovered != null,
854
+ "hovered",
855
+ transition,
856
+ isExiting,
857
+ shouldReduceMotion
858
+ );
859
+ const sharedLayout = useSharedLayout({
860
+ layoutId,
861
+ userRef: ref,
862
+ transition: isTopLevelTransition(transition) ? transition : void 0,
863
+ shouldReduceMotion,
864
+ userOnLayout
865
+ });
866
+ const flip = sharedLayout.flip;
867
+ const hasLayoutId = layoutId !== void 0;
868
+ const animatedStyle = Animated.useAnimatedStyle(() => {
869
+ const activeKeys = activeKeysRef.current;
870
+ const hasTransform = hasTransformRef.current;
871
+ const hasShadowOffset = hasShadowOffsetRef.current;
872
+ const out = {};
873
+ const transform = [];
874
+ let shadowOffsetW = 0;
875
+ let shadowOffsetH = 0;
876
+ const ph = hoveredProgress.value;
877
+ const pf = focusedProgress.value;
878
+ const pfv = focusVisibleProgress.value;
879
+ const pp = pressedProgress.value;
880
+ const layers = gestureSV.value;
881
+ const hoveredLayer = layers ? layers.hovered : null;
882
+ const focusedLayer = layers ? layers.focused : null;
883
+ const focusVisibleLayer = layers ? layers.focusVisible : null;
884
+ const pressedLayer = layers ? layers.pressed : null;
885
+ for (const key of activeKeys) {
886
+ let v = sharedValues[key].value;
887
+ const isColor = COLOR_KEY_SET.has(key);
888
+ if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
889
+ const t = hoveredLayer[key];
890
+ v = isColor ? Animated.interpolateColor(ph, [0, 1], [v, t]) : v + (t - v) * ph;
891
+ }
892
+ if (focusedLayer && pf > 0 && focusedLayer[key] !== void 0) {
893
+ const t = focusedLayer[key];
894
+ v = isColor ? Animated.interpolateColor(pf, [0, 1], [v, t]) : v + (t - v) * pf;
895
+ }
896
+ if (focusVisibleLayer && pfv > 0 && focusVisibleLayer[key] !== void 0) {
897
+ const t = focusVisibleLayer[key];
898
+ v = isColor ? Animated.interpolateColor(pfv, [0, 1], [v, t]) : v + (t - v) * pfv;
899
+ }
900
+ if (pressedLayer && pp > 0 && pressedLayer[key] !== void 0) {
901
+ const t = pressedLayer[key];
902
+ v = isColor ? Animated.interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
903
+ }
904
+ if (TRANSFORM_KEY_SET.has(key)) {
905
+ transform.push(
906
+ ROTATION_KEYS.has(key) ? { [key]: `${v}deg` } : { [key]: v }
907
+ );
908
+ } else if (key === "shadowOffsetWidth") {
909
+ shadowOffsetW = v;
910
+ } else if (key === "shadowOffsetHeight") {
911
+ shadowOffsetH = v;
912
+ } else {
913
+ out[key] = v;
914
+ }
915
+ }
916
+ if (hasLayoutId) {
917
+ transform.push({ translateX: flip.dx.value });
918
+ transform.push({ translateY: flip.dy.value });
919
+ transform.push({ scaleX: flip.sx.value });
920
+ transform.push({ scaleY: flip.sy.value });
921
+ }
922
+ if (hasTransform || hasLayoutId) out.transform = transform;
923
+ if (hasShadowOffset) {
924
+ out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH };
925
+ }
926
+ return out;
927
+ });
928
+ const mergedStyle = react.useMemo(
929
+ () => isExiting ? [style, animatedStyle, EXITING_POINTER_EVENTS_STYLE] : [style, animatedStyle],
930
+ [style, animatedStyle, isExiting]
931
+ );
932
+ const gestureHandlers = useGestureHandlers(
933
+ gesture,
934
+ rest,
935
+ setPressed,
936
+ setFocused,
937
+ setFocusVisible,
938
+ setHovered
939
+ );
940
+ const layoutSig = stableSig(layout);
941
+ const layoutTransition = react.useMemo(
942
+ () => shouldReduceMotion ? void 0 : resolveLayoutTransition(layout),
943
+ // eslint-disable-next-line react-hooks/exhaustive-deps
944
+ [layoutSig, shouldReduceMotion]
945
+ );
946
+ return /* @__PURE__ */ jsxRuntime.jsx(
947
+ AnimatedComponent,
948
+ {
949
+ ref: sharedLayout.setRef,
950
+ ...rest,
951
+ ...gestureHandlers,
952
+ onLayout: sharedLayout.onLayout,
953
+ layout: layoutTransition,
954
+ style: mergedStyle
955
+ }
956
+ );
957
+ });
958
+ Motion2.displayName = `Motion(${Component.displayName ?? Component.name ?? "Component"})`;
959
+ return Motion2;
960
+ }
961
+ function useAnimatableSharedValues(init) {
962
+ const translateX = Animated.useSharedValue(init("translateX"));
963
+ const translateY = Animated.useSharedValue(init("translateY"));
964
+ const scale = Animated.useSharedValue(init("scale"));
965
+ const scaleX = Animated.useSharedValue(init("scaleX"));
966
+ const scaleY = Animated.useSharedValue(init("scaleY"));
967
+ const rotate = Animated.useSharedValue(init("rotate"));
968
+ const rotateX = Animated.useSharedValue(init("rotateX"));
969
+ const rotateY = Animated.useSharedValue(init("rotateY"));
970
+ const opacity = Animated.useSharedValue(init("opacity"));
971
+ const width = Animated.useSharedValue(init("width"));
972
+ const height = Animated.useSharedValue(init("height"));
973
+ const borderRadius = Animated.useSharedValue(init("borderRadius"));
974
+ const shadowOpacity = Animated.useSharedValue(init("shadowOpacity"));
975
+ const shadowRadius = Animated.useSharedValue(init("shadowRadius"));
976
+ const elevation = Animated.useSharedValue(init("elevation"));
977
+ const backgroundColor = Animated.useSharedValue(
978
+ init("backgroundColor")
979
+ );
980
+ const borderColor = Animated.useSharedValue(init("borderColor"));
981
+ const color = Animated.useSharedValue(init("color"));
982
+ const tintColor = Animated.useSharedValue(init("tintColor"));
983
+ const shadowColor = Animated.useSharedValue(init("shadowColor"));
984
+ const shadowOffsetWidth = Animated.useSharedValue(
985
+ init("shadowOffsetWidth")
986
+ );
987
+ const shadowOffsetHeight = Animated.useSharedValue(
988
+ init("shadowOffsetHeight")
989
+ );
990
+ const ref = react.useRef(null);
991
+ if (ref.current === null) {
992
+ ref.current = {
993
+ translateX,
994
+ translateY,
995
+ scale,
996
+ scaleX,
997
+ scaleY,
998
+ rotate,
999
+ rotateX,
1000
+ rotateY,
1001
+ opacity,
1002
+ width,
1003
+ height,
1004
+ borderRadius,
1005
+ shadowOpacity,
1006
+ shadowRadius,
1007
+ elevation,
1008
+ backgroundColor,
1009
+ borderColor,
1010
+ color,
1011
+ tintColor,
1012
+ shadowColor,
1013
+ shadowOffsetWidth,
1014
+ shadowOffsetHeight
1015
+ };
1016
+ }
1017
+ return ref.current;
1018
+ }
1019
+ function makeKeyCallbackFactory(key, sharedValue, target, onAnimationEndRef, meta, onSettle, transformGroup) {
1020
+ if (!onAnimationEndRef.current && !onSettle) return void 0;
1021
+ const state = { iteration: 0 };
1022
+ const isTransformKey = TRANSFORM_KEY_SET.has(key);
1023
+ const dispatch = (rawPhase, step, finished, value) => {
1024
+ const isLastIteration = state.iteration >= meta.totalIterations - 1;
1025
+ let phase;
1026
+ let isTerminal = false;
1027
+ if (rawPhase === "step") {
1028
+ const isLastInPass = step !== void 0 && step === meta.stepCount - 1;
1029
+ if (!isLastInPass) {
1030
+ phase = "step";
1031
+ } else if (isLastIteration) {
1032
+ phase = "animation";
1033
+ isTerminal = true;
1034
+ } else {
1035
+ phase = "sequence";
1036
+ }
1037
+ } else if (isLastIteration) {
1038
+ phase = "animation";
1039
+ isTerminal = true;
1040
+ } else {
1041
+ phase = "repeat";
1042
+ }
1043
+ const reportedIteration = state.iteration;
1044
+ if (phase === "sequence" || phase === "repeat") state.iteration++;
1045
+ const fn = onAnimationEndRef.current;
1046
+ if (fn) {
1047
+ if (isTransformKey && transformGroup && phase === "animation") {
1048
+ transformGroup.remaining--;
1049
+ if (transformGroup.remaining <= 0) {
1050
+ fn({
1051
+ key: "transform",
1052
+ finished,
1053
+ value,
1054
+ target,
1055
+ phase,
1056
+ step,
1057
+ iteration: reportedIteration
1058
+ });
1059
+ }
1060
+ } else {
1061
+ fn({
1062
+ key,
1063
+ finished,
1064
+ value,
1065
+ target,
1066
+ phase,
1067
+ step,
1068
+ iteration: reportedIteration
1069
+ });
1070
+ }
1071
+ }
1072
+ if (onSettle && isTerminal) onSettle();
1073
+ };
1074
+ return (rawPhase, step) => {
1075
+ const cb = (finished) => {
1076
+ "worklet";
1077
+ Animated.runOnJS(dispatch)(rawPhase, step, !!finished, sharedValue.value);
1078
+ };
1079
+ return cb;
1080
+ };
1081
+ }
1082
+ function shadowOffsetAxisFor(key) {
1083
+ return key === "shadowOffsetWidth" ? "width" : "height";
1084
+ }
1085
+ function shadowOffsetAxisValue(source, axis) {
1086
+ return source?.[axis];
1087
+ }
1088
+ function collectTouchedKeys(touched, record) {
1089
+ for (const k of ALL_KEYS) {
1090
+ if (k in record) touched.add(k);
1091
+ }
1092
+ if ("shadowOffset" in record && record.shadowOffset) {
1093
+ const so = record.shadowOffset;
1094
+ if (so.width !== void 0) touched.add("shadowOffsetWidth");
1095
+ if (so.height !== void 0) touched.add("shadowOffsetHeight");
1096
+ }
1097
+ }
1098
+ function stepCountOf(v) {
1099
+ if (Array.isArray(v)) return v.length;
1100
+ return 1;
1101
+ }
1102
+ function totalIterationsOf(cfg) {
1103
+ if (!cfg || cfg.type === "no-animation" || cfg.type === "decay") return 1;
1104
+ const r = cfg.repeat;
1105
+ if (r === void 0) return 1;
1106
+ if (r === "infinite") return Number.POSITIVE_INFINITY;
1107
+ if (typeof r === "number") return r;
1108
+ if (r.count === "infinite") return Number.POSITIVE_INFINITY;
1109
+ return r.count;
1110
+ }
1111
+ function targetEndValue(v) {
1112
+ if (v === void 0) return void 0;
1113
+ if (typeof v === "number" || typeof v === "string") return v;
1114
+ if (Array.isArray(v)) {
1115
+ return v.length > 0 ? targetEndValue(v[v.length - 1]) : void 0;
1116
+ }
1117
+ if (typeof v === "object" && v !== null && "to" in v) {
1118
+ const to = v.to;
1119
+ return typeof to === "number" || typeof to === "string" ? to : void 0;
1120
+ }
1121
+ return void 0;
1122
+ }
1123
+ function useControllerKey(controller) {
1124
+ const [, setTick] = react.useState(0);
1125
+ react.useEffect(() => {
1126
+ if (!controller) return;
1127
+ const unsub = controller.subscribe(() => setTick((n) => n + 1));
1128
+ return unsub;
1129
+ }, [controller]);
1130
+ return controller?.current;
1131
+ }
1132
+ function resolveAnimateInput(animate, variants, controllerKey) {
1133
+ if (controllerKey !== void 0 && variants && controllerKey in variants) {
1134
+ return variants[controllerKey];
1135
+ }
1136
+ if (typeof animate === "string") {
1137
+ if (variants && animate in variants) return variants[animate];
1138
+ if (__DEV__) {
1139
+ console.warn(
1140
+ `[inertia] animate="${animate}" but no matching variant. Did you forget to pass \`variants\`?`
1141
+ );
1142
+ }
1143
+ return void 0;
1144
+ }
1145
+ return animate;
1146
+ }
1147
+ function restValue(v) {
1148
+ if (v === void 0) return void 0;
1149
+ if (typeof v === "number" || typeof v === "string") return v;
1150
+ if (Array.isArray(v)) {
1151
+ return v.length > 0 ? restValue(v[0]) : void 0;
1152
+ }
1153
+ if (typeof v === "object" && v !== null && "to" in v) {
1154
+ const to = v.to;
1155
+ return typeof to === "number" || typeof to === "string" ? to : void 0;
1156
+ }
1157
+ return void 0;
1158
+ }
1159
+ function resolveGestureLayers(gesture) {
1160
+ if (!gesture) return null;
1161
+ const out = {};
1162
+ for (const layer of GESTURE_LAYER_NAMES) {
1163
+ const subState = gesture[layer];
1164
+ if (!subState) continue;
1165
+ const resolved = {};
1166
+ for (const key of ALL_KEYS) {
1167
+ if (SHADOW_OFFSET_KEY_SET.has(key)) {
1168
+ const axis = shadowOffsetAxisFor(key);
1169
+ const so = subState.shadowOffset;
1170
+ const v = shadowOffsetAxisValue(so, axis);
1171
+ if (v !== void 0) resolved[key] = v;
1172
+ continue;
1173
+ }
1174
+ const raw = subState[key];
1175
+ if (raw === void 0) continue;
1176
+ const t = targetEndValue(raw);
1177
+ if (t !== void 0) resolved[key] = t;
1178
+ }
1179
+ out[layer] = resolved;
1180
+ }
1181
+ return out;
1182
+ }
1183
+ function useGestureLayerProgress(progress, active, declared, layer, transition, isExiting, shouldReduceMotion) {
1184
+ const layerCfgSig = stableSig(gestureLayerTransitionFor(layer, transition));
1185
+ react.useEffect(() => {
1186
+ if (!declared) return;
1187
+ if (isExiting) {
1188
+ progress.value = 0;
1189
+ return;
1190
+ }
1191
+ const target = active ? 1 : 0;
1192
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : gestureLayerTransitionFor(layer, transition) ?? { type: "spring" };
1193
+ progress.value = resolveTransition(cfg, target);
1194
+ }, [active, declared, isExiting, shouldReduceMotion, layerCfgSig]);
1195
+ }
1196
+ function useGestureHandlers(gesture, rest, setPressed, setFocused, setFocusVisible, setHovered) {
1197
+ const hasPressed = gesture?.pressed ? 1 : 0;
1198
+ const hasFocused = gesture?.focused ? 1 : 0;
1199
+ const hasFocusVisible = gesture?.focusVisible ? 1 : 0;
1200
+ const hasHovered = gesture?.hovered ? 1 : 0;
1201
+ return react.useMemo(() => {
1202
+ if (!gesture) return {};
1203
+ const handlers = {};
1204
+ if (gesture.pressed) {
1205
+ handlers.onTouchStart = compose(rest.onTouchStart, () => setPressed(true));
1206
+ handlers.onTouchEnd = compose(rest.onTouchEnd, () => setPressed(false));
1207
+ handlers.onTouchCancel = compose(
1208
+ rest.onTouchCancel,
1209
+ () => setPressed(false)
1210
+ );
1211
+ handlers.onPressIn = compose(rest.onPressIn, () => setPressed(true));
1212
+ handlers.onPressOut = compose(rest.onPressOut, () => setPressed(false));
1213
+ }
1214
+ if (gesture.focused || gesture.focusVisible) {
1215
+ handlers.onFocus = compose(rest.onFocus, () => {
1216
+ if (gesture.focused) setFocused(true);
1217
+ if (gesture.focusVisible && isFocusVisible()) setFocusVisible(true);
1218
+ });
1219
+ handlers.onBlur = compose(rest.onBlur, () => {
1220
+ if (gesture.focused) setFocused(false);
1221
+ if (gesture.focusVisible) setFocusVisible(false);
1222
+ });
1223
+ }
1224
+ if (gesture.hovered) {
1225
+ handlers.onMouseEnter = compose(rest.onMouseEnter, () => setHovered(true));
1226
+ handlers.onMouseLeave = compose(
1227
+ rest.onMouseLeave,
1228
+ () => setHovered(false)
1229
+ );
1230
+ }
1231
+ return handlers;
1232
+ }, [
1233
+ hasPressed,
1234
+ hasFocused,
1235
+ hasFocusVisible,
1236
+ hasHovered,
1237
+ rest.onTouchStart,
1238
+ rest.onTouchEnd,
1239
+ rest.onTouchCancel,
1240
+ rest.onPressIn,
1241
+ rest.onPressOut,
1242
+ rest.onFocus,
1243
+ rest.onBlur,
1244
+ rest.onMouseEnter,
1245
+ rest.onMouseLeave
1246
+ ]);
1247
+ }
1248
+ function compose(user, ours) {
1249
+ if (typeof user !== "function") return ours;
1250
+ return (event) => {
1251
+ user(event);
1252
+ ours(event);
1253
+ };
1254
+ }
1255
+
1256
+ // src/motion/Image.tsx
1257
+ var MotionImage = createMotionComponent(reactNative.Image);
1258
+ var MotionPressable = createMotionComponent(reactNative.Pressable);
1259
+ var MotionScrollView = createMotionComponent(reactNative.ScrollView);
1260
+ var MotionText = createMotionComponent(reactNative.Text);
1261
+ var MotionView = createMotionComponent(reactNative.View);
1262
+
1263
+ // src/motion/index.ts
1264
+ var Motion = {
1265
+ View: MotionView,
1266
+ Text: MotionText,
1267
+ Image: MotionImage,
1268
+ Pressable: MotionPressable,
1269
+ ScrollView: MotionScrollView
1270
+ };
1271
+ function useAnimation(target, transition) {
1272
+ const output = Animated.useSharedValue(target);
1273
+ const shouldReduceMotion = useShouldReduceMotion();
1274
+ const cfgSig = stableSig(transition);
1275
+ react.useEffect(() => {
1276
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : transition ?? { type: "spring" };
1277
+ output.value = resolveTransition(cfg, target);
1278
+ }, [target, cfgSig, shouldReduceMotion]);
1279
+ return output;
1280
+ }
1281
+ function useSpring(target, config) {
1282
+ const reanimConfig = react.useMemo(
1283
+ () => springToReanimated(config ?? {}),
1284
+ // Keyed on the resolved primitive fields rather than the `config` object
1285
+ // identity: callers routinely pass a fresh object literal each render, so
1286
+ // depending on `config` itself would rebuild the Reanimated config on
1287
+ // every render and defeat the memo.
1288
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1289
+ [
1290
+ config?.tension,
1291
+ config?.friction,
1292
+ config?.mass,
1293
+ config?.velocity,
1294
+ config?.restSpeedThreshold,
1295
+ config?.restDisplacementThreshold
1296
+ ]
1297
+ );
1298
+ const isSharedTarget = isSharedValue(target);
1299
+ const initial = isSharedTarget ? target.value : target;
1300
+ const output = Animated.useSharedValue(initial);
1301
+ react.useEffect(() => {
1302
+ if (isSharedTarget) return;
1303
+ output.value = Animated.withSpring(target, reanimConfig);
1304
+ }, [isSharedTarget, target, reanimConfig]);
1305
+ Animated.useAnimatedReaction(
1306
+ () => {
1307
+ "worklet";
1308
+ if (!isSharedTarget) return null;
1309
+ return target.value;
1310
+ },
1311
+ (next, prev) => {
1312
+ "worklet";
1313
+ if (next === null || next === prev) return;
1314
+ output.value = Animated.withSpring(next, reanimConfig);
1315
+ },
1316
+ [isSharedTarget, reanimConfig]
1317
+ );
1318
+ return output;
1319
+ }
1320
+ function isSharedValue(v) {
1321
+ return typeof v === "object" && v !== null && "value" in v;
1322
+ }
1323
+
1324
+ // src/values/useBooleanSpring.ts
1325
+ function useBooleanSpring(active, springConfig) {
1326
+ return useSpring(active ? 1 : 0, springConfig);
1327
+ }
1328
+ function useColorTransition(progress, range, options) {
1329
+ const key = options?.key ?? "backgroundColor";
1330
+ const from = range[0];
1331
+ const to = range[1];
1332
+ return Animated.useAnimatedStyle(() => {
1333
+ "worklet";
1334
+ return { [key]: Animated.interpolateColor(progress.value, [0, 1], [from, to]) };
1335
+ });
1336
+ }
1337
+ function useGesture(transition) {
1338
+ const pressed = Animated.useSharedValue(0);
1339
+ const focused = Animated.useSharedValue(0);
1340
+ const focusVisible = Animated.useSharedValue(0);
1341
+ const hovered = Animated.useSharedValue(0);
1342
+ const shouldReduceMotion = useShouldReduceMotion();
1343
+ const setLayer = react.useCallback(
1344
+ (sv, layer, target) => {
1345
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : layerTransition(layer, transition) ?? { type: "spring" };
1346
+ sv.value = resolveTransition(cfg, target);
1347
+ },
1348
+ // The transition is intentionally read on every call rather than cooked
1349
+ // into the dep array — a fresh literal each render would otherwise
1350
+ // rebuild the handler bag and break composing consumers that key off
1351
+ // handler identity. `transition` is read inside the callback closure;
1352
+ // shared values are stable so the only dep that matters is the reduce-
1353
+ // motion flag.
1354
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1355
+ [shouldReduceMotion]
1356
+ );
1357
+ const handlers = react.useMemo(
1358
+ () => ({
1359
+ onPressIn: () => setLayer(pressed, "pressed", 1),
1360
+ onPressOut: () => setLayer(pressed, "pressed", 0),
1361
+ onHoverIn: () => setLayer(hovered, "hovered", 1),
1362
+ onHoverOut: () => setLayer(hovered, "hovered", 0),
1363
+ onFocus: () => {
1364
+ setLayer(focused, "focused", 1);
1365
+ if (isFocusVisible()) setLayer(focusVisible, "focusVisible", 1);
1366
+ },
1367
+ onBlur: () => {
1368
+ setLayer(focused, "focused", 0);
1369
+ setLayer(focusVisible, "focusVisible", 0);
1370
+ }
1371
+ }),
1372
+ [setLayer, pressed, focused, focusVisible, hovered]
1373
+ );
1374
+ return { pressed, focused, focusVisible, hovered, handlers };
1375
+ }
1376
+ function layerTransition(layer, transition) {
1377
+ if (!transition) return void 0;
1378
+ if (isTopLevelTransition(transition)) return transition;
1379
+ return transition[layer];
1380
+ }
1381
+ function useMotionValue(initial) {
1382
+ return Animated.useSharedValue(initial);
1383
+ }
1384
+ function useTransform(arg1, inputRange, outputRange, options) {
1385
+ let producer;
1386
+ if (typeof arg1 === "function") {
1387
+ const userFn = arg1;
1388
+ producer = reactNativeWorklets.isWorkletFunction(userFn) ? userFn : () => {
1389
+ "worklet";
1390
+ return userFn();
1391
+ };
1392
+ } else {
1393
+ const source = arg1;
1394
+ const input = inputRange;
1395
+ const output = outputRange;
1396
+ const isColor = output.length > 0 && typeof output[0] === "string";
1397
+ const extrapolateLeft = mapExtrapolation(options?.extrapolateLeft);
1398
+ const extrapolateRight = mapExtrapolation(options?.extrapolateRight);
1399
+ producer = isColor ? () => {
1400
+ "worklet";
1401
+ return Animated.interpolateColor(
1402
+ source.value,
1403
+ input,
1404
+ output
1405
+ );
1406
+ } : () => {
1407
+ "worklet";
1408
+ return Animated.interpolate(
1409
+ source.value,
1410
+ input,
1411
+ output,
1412
+ { extrapolateLeft, extrapolateRight }
1413
+ );
1414
+ };
1415
+ }
1416
+ return Animated.useDerivedValue(producer);
1417
+ }
1418
+ function mapExtrapolation(mode) {
1419
+ if (mode === "identity") return Animated.Extrapolation.IDENTITY;
1420
+ if (mode === "extend") return Animated.Extrapolation.EXTEND;
1421
+ return Animated.Extrapolation.CLAMP;
1422
+ }
1423
+ function useScroll() {
1424
+ const scrollX = Animated.useSharedValue(0);
1425
+ const scrollY = Animated.useSharedValue(0);
1426
+ const handler = Animated.useAnimatedScrollHandler({
1427
+ onScroll: (event) => {
1428
+ "worklet";
1429
+ scrollX.value = event.contentOffset.x;
1430
+ scrollY.value = event.contentOffset.y;
1431
+ }
1432
+ });
1433
+ return {
1434
+ scrollX,
1435
+ scrollY,
1436
+ onScroll: handler
1437
+ };
1438
+ }
1439
+ function useShadow({
1440
+ from,
1441
+ to,
1442
+ progress
1443
+ }) {
1444
+ const hasOpacity = from.shadowOpacity !== void 0 || to.shadowOpacity !== void 0;
1445
+ const hasRadius = from.shadowRadius !== void 0 || to.shadowRadius !== void 0;
1446
+ const hasElevation = from.elevation !== void 0 || to.elevation !== void 0;
1447
+ const hasColor = from.shadowColor !== void 0 || to.shadowColor !== void 0;
1448
+ const hasOffset = from.shadowOffset !== void 0 || to.shadowOffset !== void 0;
1449
+ const opacityFrom = from.shadowOpacity ?? 0;
1450
+ const opacityTo = to.shadowOpacity ?? 0;
1451
+ const radiusFrom = from.shadowRadius ?? 0;
1452
+ const radiusTo = to.shadowRadius ?? 0;
1453
+ const elevationFrom = from.elevation ?? 0;
1454
+ const elevationTo = to.elevation ?? 0;
1455
+ const colorFrom = from.shadowColor ?? "transparent";
1456
+ const colorTo = to.shadowColor ?? "transparent";
1457
+ const offsetWFrom = from.shadowOffset?.width ?? 0;
1458
+ const offsetWTo = to.shadowOffset?.width ?? 0;
1459
+ const offsetHFrom = from.shadowOffset?.height ?? 0;
1460
+ const offsetHTo = to.shadowOffset?.height ?? 0;
1461
+ return Animated.useAnimatedStyle(() => {
1462
+ "worklet";
1463
+ const t = progress.value;
1464
+ const out = {};
1465
+ if (hasOpacity) {
1466
+ out.shadowOpacity = Animated.interpolate(t, [0, 1], [opacityFrom, opacityTo]);
1467
+ }
1468
+ if (hasRadius) {
1469
+ out.shadowRadius = Animated.interpolate(t, [0, 1], [radiusFrom, radiusTo]);
1470
+ }
1471
+ if (hasElevation) {
1472
+ out.elevation = Animated.interpolate(t, [0, 1], [elevationFrom, elevationTo]);
1473
+ }
1474
+ if (hasColor) {
1475
+ out.shadowColor = Animated.interpolateColor(t, [0, 1], [colorFrom, colorTo]);
1476
+ }
1477
+ if (hasOffset) {
1478
+ out.shadowOffset = {
1479
+ width: Animated.interpolate(t, [0, 1], [offsetWFrom, offsetWTo]),
1480
+ height: Animated.interpolate(t, [0, 1], [offsetHFrom, offsetHTo])
1481
+ };
1482
+ }
1483
+ return out;
1484
+ });
1485
+ }
1486
+ function useVariants(variants, initial) {
1487
+ const variantsRef = react.useRef(variants);
1488
+ return react.useMemo(() => {
1489
+ const listeners = /* @__PURE__ */ new Set();
1490
+ let current = initial ?? (Object.keys(variantsRef.current)[0] ?? "");
1491
+ const controller = {
1492
+ get current() {
1493
+ return current;
1494
+ },
1495
+ transitionTo(next) {
1496
+ if (next === current) return;
1497
+ if (!(next in variantsRef.current)) {
1498
+ if (__DEV__) {
1499
+ console.warn(
1500
+ `[inertia] useVariants: unknown variant "${String(next)}". Known keys: ${Object.keys(variantsRef.current).join(", ")}`
1501
+ );
1502
+ }
1503
+ return;
1504
+ }
1505
+ current = next;
1506
+ for (const fn of listeners) fn(next);
1507
+ },
1508
+ subscribe(listener) {
1509
+ listeners.add(listener);
1510
+ return () => {
1511
+ listeners.delete(listener);
1512
+ };
1513
+ }
1514
+ };
1515
+ return controller;
1516
+ }, []);
1517
+ }
1518
+
1519
+ exports.Motion = Motion;
1520
+ exports.MotionConfig = MotionConfig;
1521
+ exports.MotionImage = MotionImage;
1522
+ exports.MotionPressable = MotionPressable;
1523
+ exports.MotionScrollView = MotionScrollView;
1524
+ exports.MotionText = MotionText;
1525
+ exports.MotionView = MotionView;
1526
+ exports.Presence = Presence;
1527
+ exports.buildReleaseAnimation = buildReleaseAnimation;
1528
+ exports.createMotionComponent = createMotionComponent;
1529
+ exports.ensureWorkletEasing = ensureWorkletEasing;
1530
+ exports.resolveAnimatableValue = resolveAnimatableValue;
1531
+ exports.resolveTransition = resolveTransition;
1532
+ exports.useAnimation = useAnimation;
1533
+ exports.useBooleanSpring = useBooleanSpring;
1534
+ exports.useColorTransition = useColorTransition;
1535
+ exports.useGesture = useGesture;
1536
+ exports.useMotionConfig = useMotionConfig;
1537
+ exports.useMotionValue = useMotionValue;
1538
+ exports.usePresence = usePresence;
1539
+ exports.useScroll = useScroll;
1540
+ exports.useShadow = useShadow;
1541
+ exports.useShouldReduceMotion = useShouldReduceMotion;
1542
+ exports.useSpring = useSpring;
1543
+ exports.useTransform = useTransform;
1544
+ exports.useVariants = useVariants;
1545
+ //# sourceMappingURL=index.js.map
1546
+ //# sourceMappingURL=index.js.map