@rootnative/inertia 0.0.0-alpha.0 → 0.0.0-alpha.2

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 (79) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -0
  3. package/dist/gestureLayer/index.d.mts +48 -7
  4. package/dist/gestureLayer/index.d.ts +48 -7
  5. package/dist/gestureLayer/index.js +107 -30
  6. package/dist/gestureLayer/index.mjs +107 -30
  7. package/dist/index.d.mts +127 -16
  8. package/dist/index.d.ts +127 -16
  9. package/dist/index.js +177 -62
  10. package/dist/index.mjs +175 -63
  11. package/dist/motion/Image.d.mts +1 -1
  12. package/dist/motion/Image.d.ts +1 -1
  13. package/dist/motion/Image.js +90 -50
  14. package/dist/motion/Image.mjs +90 -50
  15. package/dist/motion/Pressable.d.mts +1 -1
  16. package/dist/motion/Pressable.d.ts +1 -1
  17. package/dist/motion/Pressable.js +90 -50
  18. package/dist/motion/Pressable.mjs +90 -50
  19. package/dist/motion/ScrollView.d.mts +1 -1
  20. package/dist/motion/ScrollView.d.ts +1 -1
  21. package/dist/motion/ScrollView.js +90 -50
  22. package/dist/motion/ScrollView.mjs +90 -50
  23. package/dist/motion/Text.d.mts +1 -1
  24. package/dist/motion/Text.d.ts +1 -1
  25. package/dist/motion/Text.js +90 -50
  26. package/dist/motion/Text.mjs +90 -50
  27. package/dist/motion/View.d.mts +1 -1
  28. package/dist/motion/View.d.ts +1 -1
  29. package/dist/motion/View.js +90 -50
  30. package/dist/motion/View.mjs +90 -50
  31. package/dist/testing/index.js +0 -2
  32. package/dist/testing/index.mjs +0 -2
  33. package/dist/touch/index.d.mts +1 -1
  34. package/dist/touch/index.d.ts +1 -1
  35. package/dist/touch/index.js +0 -2
  36. package/dist/touch/index.mjs +0 -2
  37. package/dist/{types-cU43dEmH.d.mts → types-BzEgiUdJ.d.mts} +58 -9
  38. package/dist/{types-cU43dEmH.d.ts → types-BzEgiUdJ.d.ts} +58 -9
  39. package/dist/{useGesture-BnY65PlQ.d.ts → useGesture-BRLgiNOC.d.ts} +6 -4
  40. package/dist/{useGesture-DxtXdz-K.d.mts → useGesture-C0GBS7d2.d.mts} +6 -4
  41. package/llms.txt +9 -5
  42. package/package.json +2 -1
  43. package/src/config/MotionConfig.tsx +55 -9
  44. package/src/config/MotionConfigContext.ts +21 -1
  45. package/src/config/index.ts +7 -1
  46. package/src/config/namedTransitions.ts +80 -0
  47. package/src/gestureLayer/index.ts +1 -0
  48. package/src/gestureLayer/useGestureLayer.ts +92 -8
  49. package/src/index.ts +20 -2
  50. package/src/motion/createMotionComponent.tsx +36 -6
  51. package/src/transitions/cubicBezier.ts +126 -0
  52. package/src/transitions/index.ts +1 -0
  53. package/src/types.ts +63 -8
  54. package/src/values/useAnimation.ts +12 -6
  55. package/src/values/useBooleanSpring.ts +5 -3
  56. package/src/values/useGesture.ts +25 -7
  57. package/src/values/useMotionValue.ts +11 -0
  58. package/src/values/useScroll.ts +8 -1
  59. package/src/values/useSpring.ts +46 -9
  60. package/dist/gestureLayer/index.js.map +0 -1
  61. package/dist/gestureLayer/index.mjs.map +0 -1
  62. package/dist/index.js.map +0 -1
  63. package/dist/index.mjs.map +0 -1
  64. package/dist/motion/Image.js.map +0 -1
  65. package/dist/motion/Image.mjs.map +0 -1
  66. package/dist/motion/Pressable.js.map +0 -1
  67. package/dist/motion/Pressable.mjs.map +0 -1
  68. package/dist/motion/ScrollView.js.map +0 -1
  69. package/dist/motion/ScrollView.mjs.map +0 -1
  70. package/dist/motion/Text.js.map +0 -1
  71. package/dist/motion/Text.mjs.map +0 -1
  72. package/dist/motion/View.js.map +0 -1
  73. package/dist/motion/View.mjs.map +0 -1
  74. package/dist/testing/index.js.map +0 -1
  75. package/dist/testing/index.mjs.map +0 -1
  76. package/dist/touch/index.js.map +0 -1
  77. package/dist/touch/index.mjs.map +0 -1
  78. package/src/__type-tests__/animate.test-d.tsx +0 -88
  79. package/src/__type-tests__/variants.test-d.tsx +0 -67
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to `@rootnative/inertia` are documented here. The format fol
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ### Added
8
+
9
+ - **Named transition registry** — `<MotionConfig transitions={{ name: TransitionConfig }}>` registers named transitions for the subtree; the name is accepted everywhere a `TransitionConfig` is: the `transition` prop (top-level, per-property, per gesture layer), the `layout` prop, and `useAnimation` / `useSpring` / `useBooleanSpring` / `useGesture` / `useGestureLayer`. Names resolve at the nearest provider; nested providers merge with child-overrides-per-name; unknown names warn in dev and fall back to the default spring. No presets ship — names are consumer vocabulary. New exports: `useNamedTransitions()`, `resolveNamedTransition()`, and the `TransitionName` / `TransitionInput` / `NamedTransitions` / `RegisteredTransitions` types (`RegisteredTransitions` is the augmentation point for compile-time-typed names).
10
+
11
+ - **`cubicBezier()` easing helper** — builds a `timing.easing` value from cubic-bezier control points as four numbers, as a W3C CSS `cubic-bezier(x1, y1, x2, y2)` string, or as a CSS keyword (`'linear'` / `'ease'` / `'ease-in'` / `'ease-out'` / `'ease-in-out'`). Makes CSS-format design-token easings directly consumable (pair with the named-transition registry). Invalid input throws: `x1` / `x2` must be finite and within `[0, 1]`; `step-*` keywords and the CSS `linear(...)` function are unsupported. The `EasingFunction` / `EasingFunctionFactory` / `EasingInput` types are now exported from the root barrel.
12
+
13
+ ### Changed
14
+
15
+ - **Nested `<MotionConfig>` now inherits `reducedMotion`** from its ancestor when the prop is omitted (previously an inner provider silently reset the subtree to the `'user'` default). A transitions-only inner provider no longer clobbers an outer `reducedMotion="never"` / `"always"`.
16
+
7
17
  ## [0.0.0-alpha.0]
8
18
 
9
19
  Initial alpha publish. The full v0.1 surface is in place; APIs are still subject to change before `0.1.0`.
package/README.md CHANGED
@@ -126,6 +126,8 @@ Full docs, every primitive's example screen, and an `llms-full.txt` reference li
126
126
  - [llms.txt](https://rootnative.github.io/inertia/llms.txt) — concise overview
127
127
  - [llms-full.txt](https://rootnative.github.io/inertia/llms-full.txt) — full API reference
128
128
 
129
+ AI agents: this package ships its own copy of the reference — read `node_modules/@rootnative/inertia/llms.txt` for the full API, no network needed.
130
+
129
131
  ## License
130
132
 
131
133
  [MIT](./LICENSE) © RootNative
@@ -1,6 +1,6 @@
1
- import { AnimatedStyle } from 'react-native-reanimated';
2
- import { U as UseGestureHandlers } from '../useGesture-DxtXdz-K.mjs';
3
- import { T as TransitionConfig, h as GestureLayerTransitions } from '../types-cU43dEmH.mjs';
1
+ import { SharedValue, AnimatedStyle } from 'react-native-reanimated';
2
+ import { U as UseGestureHandlers } from '../useGesture-C0GBS7d2.mjs';
3
+ import { T as TransitionInput, n as GestureLayerTransitions } from '../types-BzEgiUdJ.mjs';
4
4
  import 'react';
5
5
  import 'react-native';
6
6
 
@@ -49,10 +49,31 @@ interface UseGestureLayerOptions {
49
49
  /**
50
50
  * Transition forwarded to the underlying `useGesture` hook. Either a single
51
51
  * `TransitionConfig` for every gesture layer, or a `GestureLayerTransitions`
52
- * map for per-layer fades. Reduced motion collapses every transition to
53
- * `no-animation`.
52
+ * map for per-layer fades. A `TransitionName` registered on the nearest
53
+ * `<MotionConfig transitions>` is accepted in both positions. Reduced
54
+ * motion collapses every transition to `no-animation`.
54
55
  */
55
- transition?: TransitionConfig | GestureLayerTransitions;
56
+ transition?: TransitionInput | GestureLayerTransitions;
57
+ }
58
+ /**
59
+ * The per-state 0↔1 progress shared values behind a `useGestureLayer` call.
60
+ * The gesture entries are the same shared values `useGesture` owns; `disabled`
61
+ * is driven by `options.disabled`. All five are stable across renders — feed
62
+ * them into any `useAnimatedStyle` / `useDerivedValue` (or hooks like
63
+ * `useShadow({ progress })`) to derive extra styles from the same gesture
64
+ * wiring without a second `useGesture` call.
65
+ */
66
+ interface GestureLayerProgress {
67
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
68
+ hovered: SharedValue<number>;
69
+ /** 0↔1 progress for the focused layer (any focus modality). */
70
+ focused: SharedValue<number>;
71
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
72
+ focusVisible: SharedValue<number>;
73
+ /** 0↔1 progress for the pressed layer. */
74
+ pressed: SharedValue<number>;
75
+ /** 0↔1 progress for the disabled override (driven by `options.disabled`). */
76
+ disabled: SharedValue<number>;
56
77
  }
57
78
  interface UseGestureLayerResult {
58
79
  /**
@@ -62,6 +83,12 @@ interface UseGestureLayerResult {
62
83
  style: AnimatedStyle<Record<string, unknown>>;
63
84
  /** Handlers to spread on the receiving `Pressable`. */
64
85
  handlers: UseGestureHandlers;
86
+ /**
87
+ * Per-state progress shared values — the inputs the composed `style` is
88
+ * derived from. Read-only by convention: writing to them fights the
89
+ * handlers.
90
+ */
91
+ states: GestureLayerProgress;
65
92
  }
66
93
  /**
67
94
  * A "strongest active layer wins" interactive-feedback primitive. Sits one
@@ -84,6 +111,13 @@ interface UseGestureLayerResult {
84
111
  * keys — when active, it lerps the composed value toward the `disabled`
85
112
  * target.
86
113
  *
114
+ * Alongside `style` and `handlers`, the hook returns `states` — the per-state
115
+ * 0↔1 progress shared values the style is derived from (the four gesture
116
+ * layers plus the disabled override). Feed them into other progress-driven
117
+ * hooks (`useShadow`, `useColorTransition`) or a custom `useAnimatedStyle`
118
+ * to derive extra styles from the same gesture wiring — no second
119
+ * `useGesture` call, no duplicated handlers.
120
+ *
87
121
  * Reach for this when you want MD3 / iOS-translucent state-layer overlays
88
122
  * without rewriting the worklet by hand for every consumer; reach for plain
89
123
  * `useGesture()` when you need a composition model this hook doesn't
@@ -113,7 +147,14 @@ interface UseGestureLayerResult {
113
147
  * )
114
148
  * }
115
149
  * ```
150
+ *
151
+ * @example Elevation crossfade driven by the hover progress
152
+ * ```tsx
153
+ * const { style, handlers, states } = useGestureLayer(layers, options)
154
+ * const shadow = useShadow({ from: restShadow, to: raisedShadow, progress: states.hovered })
155
+ * // <Animated.View style={[style, shadow]} />
156
+ * ```
116
157
  */
117
158
  declare function useGestureLayer(states: GestureLayerStates, options?: UseGestureLayerOptions): UseGestureLayerResult;
118
159
 
119
- export { type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
160
+ export { type GestureLayerProgress, type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
@@ -1,6 +1,6 @@
1
- import { AnimatedStyle } from 'react-native-reanimated';
2
- import { U as UseGestureHandlers } from '../useGesture-BnY65PlQ.js';
3
- import { T as TransitionConfig, h as GestureLayerTransitions } from '../types-cU43dEmH.js';
1
+ import { SharedValue, AnimatedStyle } from 'react-native-reanimated';
2
+ import { U as UseGestureHandlers } from '../useGesture-BRLgiNOC.js';
3
+ import { T as TransitionInput, n as GestureLayerTransitions } from '../types-BzEgiUdJ.js';
4
4
  import 'react';
5
5
  import 'react-native';
6
6
 
@@ -49,10 +49,31 @@ interface UseGestureLayerOptions {
49
49
  /**
50
50
  * Transition forwarded to the underlying `useGesture` hook. Either a single
51
51
  * `TransitionConfig` for every gesture layer, or a `GestureLayerTransitions`
52
- * map for per-layer fades. Reduced motion collapses every transition to
53
- * `no-animation`.
52
+ * map for per-layer fades. A `TransitionName` registered on the nearest
53
+ * `<MotionConfig transitions>` is accepted in both positions. Reduced
54
+ * motion collapses every transition to `no-animation`.
54
55
  */
55
- transition?: TransitionConfig | GestureLayerTransitions;
56
+ transition?: TransitionInput | GestureLayerTransitions;
57
+ }
58
+ /**
59
+ * The per-state 0↔1 progress shared values behind a `useGestureLayer` call.
60
+ * The gesture entries are the same shared values `useGesture` owns; `disabled`
61
+ * is driven by `options.disabled`. All five are stable across renders — feed
62
+ * them into any `useAnimatedStyle` / `useDerivedValue` (or hooks like
63
+ * `useShadow({ progress })`) to derive extra styles from the same gesture
64
+ * wiring without a second `useGesture` call.
65
+ */
66
+ interface GestureLayerProgress {
67
+ /** 0↔1 progress for the hovered layer (web only — stays at 0 on native). */
68
+ hovered: SharedValue<number>;
69
+ /** 0↔1 progress for the focused layer (any focus modality). */
70
+ focused: SharedValue<number>;
71
+ /** 0↔1 progress for the focusVisible layer (keyboard focus only). */
72
+ focusVisible: SharedValue<number>;
73
+ /** 0↔1 progress for the pressed layer. */
74
+ pressed: SharedValue<number>;
75
+ /** 0↔1 progress for the disabled override (driven by `options.disabled`). */
76
+ disabled: SharedValue<number>;
56
77
  }
57
78
  interface UseGestureLayerResult {
58
79
  /**
@@ -62,6 +83,12 @@ interface UseGestureLayerResult {
62
83
  style: AnimatedStyle<Record<string, unknown>>;
63
84
  /** Handlers to spread on the receiving `Pressable`. */
64
85
  handlers: UseGestureHandlers;
86
+ /**
87
+ * Per-state progress shared values — the inputs the composed `style` is
88
+ * derived from. Read-only by convention: writing to them fights the
89
+ * handlers.
90
+ */
91
+ states: GestureLayerProgress;
65
92
  }
66
93
  /**
67
94
  * A "strongest active layer wins" interactive-feedback primitive. Sits one
@@ -84,6 +111,13 @@ interface UseGestureLayerResult {
84
111
  * keys — when active, it lerps the composed value toward the `disabled`
85
112
  * target.
86
113
  *
114
+ * Alongside `style` and `handlers`, the hook returns `states` — the per-state
115
+ * 0↔1 progress shared values the style is derived from (the four gesture
116
+ * layers plus the disabled override). Feed them into other progress-driven
117
+ * hooks (`useShadow`, `useColorTransition`) or a custom `useAnimatedStyle`
118
+ * to derive extra styles from the same gesture wiring — no second
119
+ * `useGesture` call, no duplicated handlers.
120
+ *
87
121
  * Reach for this when you want MD3 / iOS-translucent state-layer overlays
88
122
  * without rewriting the worklet by hand for every consumer; reach for plain
89
123
  * `useGesture()` when you need a composition model this hook doesn't
@@ -113,7 +147,14 @@ interface UseGestureLayerResult {
113
147
  * )
114
148
  * }
115
149
  * ```
150
+ *
151
+ * @example Elevation crossfade driven by the hover progress
152
+ * ```tsx
153
+ * const { style, handlers, states } = useGestureLayer(layers, options)
154
+ * const shadow = useShadow({ from: restShadow, to: raisedShadow, progress: states.hovered })
155
+ * // <Animated.View style={[style, shadow]} />
156
+ * ```
116
157
  */
117
158
  declare function useGestureLayer(states: GestureLayerStates, options?: UseGestureLayerOptions): UseGestureLayerResult;
118
159
 
119
- export { type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
160
+ export { type GestureLayerProgress, type GestureLayerStates, type GestureLayerStyle, type UseGestureLayerOptions, type UseGestureLayerResult, useGestureLayer };
@@ -6,8 +6,31 @@ var reactNativeWorklets = require('react-native-worklets');
6
6
  var reactNative = require('react-native');
7
7
 
8
8
  // src/gestureLayer/useGestureLayer.ts
9
+
10
+ // src/transitions/sig.ts
11
+ function stableSig(value) {
12
+ if (value === void 0) return "";
13
+ try {
14
+ return stableStringify(value);
15
+ } catch {
16
+ return String(value);
17
+ }
18
+ }
19
+ function stableStringify(v) {
20
+ if (v === null || typeof v !== "object") {
21
+ if (typeof v === "function" || v === void 0) return "null";
22
+ return JSON.stringify(v);
23
+ }
24
+ if (Array.isArray(v)) {
25
+ return "[" + v.map(stableStringify).join(",") + "]";
26
+ }
27
+ const obj = v;
28
+ const keys = Object.keys(obj).sort();
29
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
30
+ }
9
31
  var DEFAULT_MOTION_CONFIG = {
10
- reducedMotion: "user"
32
+ reducedMotion: "user",
33
+ transitions: {}
11
34
  };
12
35
  var MotionConfigContext = react.createContext(
13
36
  DEFAULT_MOTION_CONFIG
@@ -15,6 +38,9 @@ var MotionConfigContext = react.createContext(
15
38
  function useMotionConfig() {
16
39
  return react.useContext(MotionConfigContext);
17
40
  }
41
+ function useNamedTransitions() {
42
+ return useMotionConfig().transitions;
43
+ }
18
44
  function useShouldReduceMotion() {
19
45
  const { reducedMotion } = useMotionConfig();
20
46
  const osReduced = reactNativeReanimated.useReducedMotion();
@@ -22,6 +48,59 @@ function useShouldReduceMotion() {
22
48
  if (reducedMotion === "always") return true;
23
49
  return osReduced;
24
50
  }
51
+
52
+ // src/transitions/keys.ts
53
+ var TRANSITION_CONFIG_KEYS = /* @__PURE__ */ new Set([
54
+ "type",
55
+ "tension",
56
+ "friction",
57
+ "mass",
58
+ "velocity",
59
+ "restSpeedThreshold",
60
+ "restDisplacementThreshold",
61
+ "duration",
62
+ "easing",
63
+ "delay",
64
+ "repeat",
65
+ "deceleration",
66
+ "clamp"
67
+ ]);
68
+ function isTopLevelTransition(t) {
69
+ if (t === null || typeof t !== "object") return false;
70
+ const keys = Object.keys(t);
71
+ if (keys.length === 0) return false;
72
+ return keys.every((k) => TRANSITION_CONFIG_KEYS.has(k));
73
+ }
74
+
75
+ // src/config/namedTransitions.ts
76
+ var UNKNOWN_NAME_FALLBACK = { type: "spring" };
77
+ function lookupNamedTransition(name, registry) {
78
+ const cfg = registry[name];
79
+ if (cfg) return cfg;
80
+ if (__DEV__) {
81
+ console.warn(
82
+ `[inertia] Unknown transition name "${name}" \u2014 falling back to the default spring. Register it on a provider: <MotionConfig transitions={{ '${name}': { ... } }}>.`
83
+ );
84
+ }
85
+ return UNKNOWN_NAME_FALLBACK;
86
+ }
87
+ function resolveNamedTransitionProp(transition, registry) {
88
+ if (transition === void 0) return void 0;
89
+ if (typeof transition === "string") {
90
+ return lookupNamedTransition(transition, registry);
91
+ }
92
+ if (isTopLevelTransition(transition)) return transition;
93
+ const map = transition;
94
+ let out = null;
95
+ for (const key in map) {
96
+ const value = map[key];
97
+ if (typeof value === "string") {
98
+ if (out === null) out = { ...map };
99
+ out[key] = lookupNamedTransition(value, registry);
100
+ }
101
+ }
102
+ return out ?? transition;
103
+ }
25
104
  function ensureWorkletEasing(easing) {
26
105
  if (!easing) return void 0;
27
106
  const fn = isEasingFactory(easing) ? easing.factory() : easing;
@@ -117,29 +196,6 @@ function delayOf(cfg) {
117
196
  if (cfg.type === "no-animation") return void 0;
118
197
  return cfg.delay;
119
198
  }
120
-
121
- // src/transitions/keys.ts
122
- var TRANSITION_CONFIG_KEYS = /* @__PURE__ */ new Set([
123
- "type",
124
- "tension",
125
- "friction",
126
- "mass",
127
- "velocity",
128
- "restSpeedThreshold",
129
- "restDisplacementThreshold",
130
- "duration",
131
- "easing",
132
- "delay",
133
- "repeat",
134
- "deceleration",
135
- "clamp"
136
- ]);
137
- function isTopLevelTransition(t) {
138
- if (t === null || typeof t !== "object") return false;
139
- const keys = Object.keys(t);
140
- if (keys.length === 0) return false;
141
- return keys.every((k) => TRANSITION_CONFIG_KEYS.has(k));
142
- }
143
199
  var modality = "keyboard";
144
200
  var installed = false;
145
201
  function setKeyboard() {
@@ -171,9 +227,10 @@ function useGesture(transition) {
171
227
  const focusVisible = reactNativeReanimated.useSharedValue(0);
172
228
  const hovered = reactNativeReanimated.useSharedValue(0);
173
229
  const shouldReduceMotion = useShouldReduceMotion();
230
+ const resolved = resolveNamedTransitionProp(transition, useNamedTransitions());
174
231
  const setLayer = react.useCallback(
175
232
  (sv, layer, target) => {
176
- const cfg = shouldReduceMotion ? { type: "no-animation" } : layerTransition(layer, transition) ?? { type: "spring" };
233
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : layerTransition(layer, resolved) ?? { type: "spring" };
177
234
  sv.value = resolveTransition(cfg, target);
178
235
  },
179
236
  // The transition is intentionally read on every call rather than cooked
@@ -212,15 +269,20 @@ function layerTransition(layer, transition) {
212
269
 
213
270
  // src/gestureLayer/useGestureLayer.ts
214
271
  function useGestureLayer(states, options = {}) {
215
- const { disabled: isDisabled = false, transition } = options;
272
+ const { disabled: isDisabled = false, transition: transitionInput } = options;
216
273
  const shouldReduceMotion = useShouldReduceMotion();
274
+ const transition = resolveNamedTransitionProp(
275
+ transitionInput,
276
+ useNamedTransitions()
277
+ );
217
278
  const gesture = useGesture(transition);
218
279
  const disabledProgress = reactNativeReanimated.useSharedValue(0);
280
+ const transitionSig = stableSig(transition);
219
281
  react.useEffect(() => {
220
282
  const target = isDisabled ? 1 : 0;
221
283
  const cfg = shouldReduceMotion ? { type: "no-animation" } : disabledTransition(transition) ?? { type: "spring" };
222
284
  disabledProgress.value = resolveTransition(cfg, target);
223
- }, [isDisabled, shouldReduceMotion, transition, disabledProgress]);
285
+ }, [isDisabled, shouldReduceMotion, transitionSig, disabledProgress]);
224
286
  const meta = react.useMemo(() => {
225
287
  const layers = {
226
288
  rest: states.rest,
@@ -330,9 +392,26 @@ function useGestureLayer(states, options = {}) {
330
392
  }
331
393
  return out;
332
394
  });
395
+ const progress = react.useMemo(
396
+ () => ({
397
+ hovered: gesture.hovered,
398
+ focused: gesture.focused,
399
+ focusVisible: gesture.focusVisible,
400
+ pressed: gesture.pressed,
401
+ disabled: disabledProgress
402
+ }),
403
+ [
404
+ gesture.hovered,
405
+ gesture.focused,
406
+ gesture.focusVisible,
407
+ gesture.pressed,
408
+ disabledProgress
409
+ ]
410
+ );
333
411
  return {
334
412
  style,
335
- handlers: gesture.handlers
413
+ handlers: gesture.handlers,
414
+ states: progress
336
415
  };
337
416
  }
338
417
  function disabledTransition(transition) {
@@ -342,5 +421,3 @@ function disabledTransition(transition) {
342
421
  }
343
422
 
344
423
  exports.useGestureLayer = useGestureLayer;
345
- //# sourceMappingURL=index.js.map
346
- //# sourceMappingURL=index.js.map
@@ -4,8 +4,31 @@ import { isWorkletFunction } from 'react-native-worklets';
4
4
  import { Platform } from 'react-native';
5
5
 
6
6
  // src/gestureLayer/useGestureLayer.ts
7
+
8
+ // src/transitions/sig.ts
9
+ function stableSig(value) {
10
+ if (value === void 0) return "";
11
+ try {
12
+ return stableStringify(value);
13
+ } catch {
14
+ return String(value);
15
+ }
16
+ }
17
+ function stableStringify(v) {
18
+ if (v === null || typeof v !== "object") {
19
+ if (typeof v === "function" || v === void 0) return "null";
20
+ return JSON.stringify(v);
21
+ }
22
+ if (Array.isArray(v)) {
23
+ return "[" + v.map(stableStringify).join(",") + "]";
24
+ }
25
+ const obj = v;
26
+ const keys = Object.keys(obj).sort();
27
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
28
+ }
7
29
  var DEFAULT_MOTION_CONFIG = {
8
- reducedMotion: "user"
30
+ reducedMotion: "user",
31
+ transitions: {}
9
32
  };
10
33
  var MotionConfigContext = createContext(
11
34
  DEFAULT_MOTION_CONFIG
@@ -13,6 +36,9 @@ var MotionConfigContext = createContext(
13
36
  function useMotionConfig() {
14
37
  return useContext(MotionConfigContext);
15
38
  }
39
+ function useNamedTransitions() {
40
+ return useMotionConfig().transitions;
41
+ }
16
42
  function useShouldReduceMotion() {
17
43
  const { reducedMotion } = useMotionConfig();
18
44
  const osReduced = useReducedMotion();
@@ -20,6 +46,59 @@ function useShouldReduceMotion() {
20
46
  if (reducedMotion === "always") return true;
21
47
  return osReduced;
22
48
  }
49
+
50
+ // src/transitions/keys.ts
51
+ var TRANSITION_CONFIG_KEYS = /* @__PURE__ */ new Set([
52
+ "type",
53
+ "tension",
54
+ "friction",
55
+ "mass",
56
+ "velocity",
57
+ "restSpeedThreshold",
58
+ "restDisplacementThreshold",
59
+ "duration",
60
+ "easing",
61
+ "delay",
62
+ "repeat",
63
+ "deceleration",
64
+ "clamp"
65
+ ]);
66
+ function isTopLevelTransition(t) {
67
+ if (t === null || typeof t !== "object") return false;
68
+ const keys = Object.keys(t);
69
+ if (keys.length === 0) return false;
70
+ return keys.every((k) => TRANSITION_CONFIG_KEYS.has(k));
71
+ }
72
+
73
+ // src/config/namedTransitions.ts
74
+ var UNKNOWN_NAME_FALLBACK = { type: "spring" };
75
+ function lookupNamedTransition(name, registry) {
76
+ const cfg = registry[name];
77
+ if (cfg) return cfg;
78
+ if (__DEV__) {
79
+ console.warn(
80
+ `[inertia] Unknown transition name "${name}" \u2014 falling back to the default spring. Register it on a provider: <MotionConfig transitions={{ '${name}': { ... } }}>.`
81
+ );
82
+ }
83
+ return UNKNOWN_NAME_FALLBACK;
84
+ }
85
+ function resolveNamedTransitionProp(transition, registry) {
86
+ if (transition === void 0) return void 0;
87
+ if (typeof transition === "string") {
88
+ return lookupNamedTransition(transition, registry);
89
+ }
90
+ if (isTopLevelTransition(transition)) return transition;
91
+ const map = transition;
92
+ let out = null;
93
+ for (const key in map) {
94
+ const value = map[key];
95
+ if (typeof value === "string") {
96
+ if (out === null) out = { ...map };
97
+ out[key] = lookupNamedTransition(value, registry);
98
+ }
99
+ }
100
+ return out ?? transition;
101
+ }
23
102
  function ensureWorkletEasing(easing) {
24
103
  if (!easing) return void 0;
25
104
  const fn = isEasingFactory(easing) ? easing.factory() : easing;
@@ -115,29 +194,6 @@ function delayOf(cfg) {
115
194
  if (cfg.type === "no-animation") return void 0;
116
195
  return cfg.delay;
117
196
  }
118
-
119
- // src/transitions/keys.ts
120
- var TRANSITION_CONFIG_KEYS = /* @__PURE__ */ new Set([
121
- "type",
122
- "tension",
123
- "friction",
124
- "mass",
125
- "velocity",
126
- "restSpeedThreshold",
127
- "restDisplacementThreshold",
128
- "duration",
129
- "easing",
130
- "delay",
131
- "repeat",
132
- "deceleration",
133
- "clamp"
134
- ]);
135
- function isTopLevelTransition(t) {
136
- if (t === null || typeof t !== "object") return false;
137
- const keys = Object.keys(t);
138
- if (keys.length === 0) return false;
139
- return keys.every((k) => TRANSITION_CONFIG_KEYS.has(k));
140
- }
141
197
  var modality = "keyboard";
142
198
  var installed = false;
143
199
  function setKeyboard() {
@@ -169,9 +225,10 @@ function useGesture(transition) {
169
225
  const focusVisible = useSharedValue(0);
170
226
  const hovered = useSharedValue(0);
171
227
  const shouldReduceMotion = useShouldReduceMotion();
228
+ const resolved = resolveNamedTransitionProp(transition, useNamedTransitions());
172
229
  const setLayer = useCallback(
173
230
  (sv, layer, target) => {
174
- const cfg = shouldReduceMotion ? { type: "no-animation" } : layerTransition(layer, transition) ?? { type: "spring" };
231
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : layerTransition(layer, resolved) ?? { type: "spring" };
175
232
  sv.value = resolveTransition(cfg, target);
176
233
  },
177
234
  // The transition is intentionally read on every call rather than cooked
@@ -210,15 +267,20 @@ function layerTransition(layer, transition) {
210
267
 
211
268
  // src/gestureLayer/useGestureLayer.ts
212
269
  function useGestureLayer(states, options = {}) {
213
- const { disabled: isDisabled = false, transition } = options;
270
+ const { disabled: isDisabled = false, transition: transitionInput } = options;
214
271
  const shouldReduceMotion = useShouldReduceMotion();
272
+ const transition = resolveNamedTransitionProp(
273
+ transitionInput,
274
+ useNamedTransitions()
275
+ );
215
276
  const gesture = useGesture(transition);
216
277
  const disabledProgress = useSharedValue(0);
278
+ const transitionSig = stableSig(transition);
217
279
  useEffect(() => {
218
280
  const target = isDisabled ? 1 : 0;
219
281
  const cfg = shouldReduceMotion ? { type: "no-animation" } : disabledTransition(transition) ?? { type: "spring" };
220
282
  disabledProgress.value = resolveTransition(cfg, target);
221
- }, [isDisabled, shouldReduceMotion, transition, disabledProgress]);
283
+ }, [isDisabled, shouldReduceMotion, transitionSig, disabledProgress]);
222
284
  const meta = useMemo(() => {
223
285
  const layers = {
224
286
  rest: states.rest,
@@ -328,9 +390,26 @@ function useGestureLayer(states, options = {}) {
328
390
  }
329
391
  return out;
330
392
  });
393
+ const progress = useMemo(
394
+ () => ({
395
+ hovered: gesture.hovered,
396
+ focused: gesture.focused,
397
+ focusVisible: gesture.focusVisible,
398
+ pressed: gesture.pressed,
399
+ disabled: disabledProgress
400
+ }),
401
+ [
402
+ gesture.hovered,
403
+ gesture.focused,
404
+ gesture.focusVisible,
405
+ gesture.pressed,
406
+ disabledProgress
407
+ ]
408
+ );
331
409
  return {
332
410
  style,
333
- handlers: gesture.handlers
411
+ handlers: gesture.handlers,
412
+ states: progress
334
413
  };
335
414
  }
336
415
  function disabledTransition(transition) {
@@ -340,5 +419,3 @@ function disabledTransition(transition) {
340
419
  }
341
420
 
342
421
  export { useGestureLayer };
343
- //# sourceMappingURL=index.mjs.map
344
- //# sourceMappingURL=index.mjs.map