@onlynative/inertia 0.0.1-alpha.2 → 0.0.1-alpha.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 (44) hide show
  1. package/README.md +29 -2
  2. package/dist/index.d.mts +2 -2
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +170 -58
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +171 -59
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/motion/Image.d.mts +1 -1
  9. package/dist/motion/Image.d.ts +1 -1
  10. package/dist/motion/Image.js +170 -58
  11. package/dist/motion/Image.js.map +1 -1
  12. package/dist/motion/Image.mjs +171 -59
  13. package/dist/motion/Image.mjs.map +1 -1
  14. package/dist/motion/Pressable.d.mts +1 -1
  15. package/dist/motion/Pressable.d.ts +1 -1
  16. package/dist/motion/Pressable.js +170 -58
  17. package/dist/motion/Pressable.js.map +1 -1
  18. package/dist/motion/Pressable.mjs +171 -59
  19. package/dist/motion/Pressable.mjs.map +1 -1
  20. package/dist/motion/ScrollView.d.mts +1 -1
  21. package/dist/motion/ScrollView.d.ts +1 -1
  22. package/dist/motion/ScrollView.js +170 -58
  23. package/dist/motion/ScrollView.js.map +1 -1
  24. package/dist/motion/ScrollView.mjs +171 -59
  25. package/dist/motion/ScrollView.mjs.map +1 -1
  26. package/dist/motion/Text.d.mts +1 -1
  27. package/dist/motion/Text.d.ts +1 -1
  28. package/dist/motion/Text.js +170 -58
  29. package/dist/motion/Text.js.map +1 -1
  30. package/dist/motion/Text.mjs +171 -59
  31. package/dist/motion/Text.mjs.map +1 -1
  32. package/dist/motion/View.d.mts +1 -1
  33. package/dist/motion/View.d.ts +1 -1
  34. package/dist/motion/View.js +170 -58
  35. package/dist/motion/View.js.map +1 -1
  36. package/dist/motion/View.mjs +171 -59
  37. package/dist/motion/View.mjs.map +1 -1
  38. package/dist/{types-DeZZzE_e.d.mts → types-DAhX3fC2.d.mts} +40 -16
  39. package/dist/{types-DeZZzE_e.d.ts → types-DAhX3fC2.d.ts} +40 -16
  40. package/llms.txt +25 -2
  41. package/package.json +1 -1
  42. package/src/motion/createMotionComponent.tsx +258 -97
  43. package/src/motion/installCheck.ts +69 -0
  44. package/src/types.ts +44 -16
@@ -1,9 +1,14 @@
1
1
  import { Image, Platform } from 'react-native';
2
2
  import { createContext, forwardRef, useRef, useState, useEffect, useMemo, useContext } from 'react';
3
- import Animated, { useAnimatedStyle, useReducedMotion, useSharedValue, withSequence, runOnJS, withRepeat, withDelay, withDecay, withTiming, Easing, withSpring, isWorkletFunction } from 'react-native-reanimated';
3
+ import Animated, { useSharedValue, useAnimatedStyle, interpolateColor, useReducedMotion, withSequence, runOnJS, withRepeat, withDelay, withDecay, withTiming, Easing, withSpring, isWorkletFunction } from 'react-native-reanimated';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
6
- // src/motion/Image.tsx
6
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
7
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
8
+ }) : x)(function(x) {
9
+ if (typeof require !== "undefined") return require.apply(this, arguments);
10
+ throw Error('Dynamic require of "' + x + '" is not supported');
11
+ });
7
12
  var DEFAULT_MOTION_CONFIG = {
8
13
  reducedMotion: "user"
9
14
  };
@@ -178,6 +183,40 @@ function mergeTransition(base, override) {
178
183
  }
179
184
  return { ...base ?? { type: "spring" }, ...override };
180
185
  }
186
+
187
+ // src/motion/installCheck.ts
188
+ var alreadyChecked = false;
189
+ function ensureReanimatedInstalled() {
190
+ if (!__DEV__ || alreadyChecked) return;
191
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "test") {
192
+ return;
193
+ }
194
+ alreadyChecked = true;
195
+ let version;
196
+ try {
197
+ const pkg = __require("react-native-reanimated/package.json");
198
+ version = pkg.version;
199
+ } catch {
200
+ }
201
+ if (version) {
202
+ const major = parseInt(version.split(".")[0] ?? "0", 10);
203
+ if (major < 4) {
204
+ console.error(
205
+ `[inertia] react-native-reanimated v${version} is installed, but @onlynative/inertia requires v4.0.0 or later. Upgrade with \`pnpm add react-native-reanimated@^4\` (or your package manager's equivalent).`
206
+ );
207
+ return;
208
+ }
209
+ }
210
+ const probe = function probe2() {
211
+ "worklet";
212
+ return 0;
213
+ };
214
+ if (typeof probe.__workletHash !== "number") {
215
+ console.error(
216
+ `[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\`.`
217
+ );
218
+ }
219
+ }
181
220
  var TRANSFORM_KEYS = [
182
221
  "translateX",
183
222
  "translateY",
@@ -204,6 +243,14 @@ var ALL_KEYS = [
204
243
  ...COLOR_KEYS
205
244
  ];
206
245
  var TRANSFORM_KEY_SET = new Set(TRANSFORM_KEYS);
246
+ var COLOR_KEY_SET = new Set(COLOR_KEYS);
247
+ var GESTURE_LAYER_NAMES = [
248
+ "hovered",
249
+ "focused",
250
+ "focusVisible",
251
+ "pressed"
252
+ ];
253
+ var GESTURE_LAYER_NAME_SET = new Set(GESTURE_LAYER_NAMES);
207
254
  var EXITING_POINTER_EVENTS_STYLE = { pointerEvents: "none" };
208
255
  var DEFAULT_RESTING = {
209
256
  translateX: 0,
@@ -249,10 +296,18 @@ function isTopLevelTransition(t) {
249
296
  function transitionFor(prop, transition) {
250
297
  if (!transition) return void 0;
251
298
  if (isTopLevelTransition(transition)) return transition;
299
+ if (GESTURE_LAYER_NAME_SET.has(prop)) return void 0;
252
300
  return transition[prop];
253
301
  }
302
+ function gestureLayerTransitionFor(layer, transition) {
303
+ if (!transition) return void 0;
304
+ if (isTopLevelTransition(transition)) return transition;
305
+ return transition[layer];
306
+ }
254
307
  function createMotionComponent(Component) {
308
+ ensureReanimatedInstalled();
255
309
  const AnimatedComponent = Animated.createAnimatedComponent(
310
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
311
  Component
257
312
  );
258
313
  const Motion = forwardRef(function Motion2(props, ref) {
@@ -331,13 +386,19 @@ function createMotionComponent(Component) {
331
386
  }
332
387
  return initialRecord?.[key] ?? restValue(animateRecord[key]) ?? DEFAULT_RESTING[key];
333
388
  });
334
- const mergedRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : mergeGestureTargets(animateRecord, gesture, {
335
- pressed,
336
- focused,
337
- focusVisible,
338
- hovered
339
- });
340
- const mergedSig = stableSig(mergedRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
389
+ const pressedProgress = useSharedValue(0);
390
+ const focusedProgress = useSharedValue(0);
391
+ const focusVisibleProgress = useSharedValue(0);
392
+ const hoveredProgress = useSharedValue(0);
393
+ const gestureSV = useSharedValue(
394
+ resolveGestureLayers(gesture)
395
+ );
396
+ const gestureTargetsSig = stableSig(gesture);
397
+ useEffect(() => {
398
+ gestureSV.value = resolveGestureLayers(gesture);
399
+ }, [gestureTargetsSig]);
400
+ const baseRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : animateRecord;
401
+ const baseSig = stableSig(baseRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
341
402
  const transitionSig = stableSig(transition);
342
403
  const safeToRemoveRef = useRef(void 0);
343
404
  safeToRemoveRef.current = presence?.safeToRemove;
@@ -358,13 +419,13 @@ function createMotionComponent(Component) {
358
419
  };
359
420
  let transformPending = 0;
360
421
  for (const k of ALL_KEYS) {
361
- if (TRANSFORM_KEY_SET.has(k) && mergedRecord[k] !== void 0) {
422
+ if (TRANSFORM_KEY_SET.has(k) && baseRecord[k] !== void 0) {
362
423
  transformPending++;
363
424
  }
364
425
  }
365
426
  const transformGroup = transformPending > 0 ? { remaining: transformPending } : void 0;
366
427
  for (const key of ALL_KEYS) {
367
- const target = mergedRecord[key];
428
+ const target = baseRecord[key];
368
429
  if (target === void 0) continue;
369
430
  const cfg = shouldReduceMotion ? { type: "no-animation" } : transitionFor(key, transition);
370
431
  if (isExiting) pending++;
@@ -389,14 +450,76 @@ function createMotionComponent(Component) {
389
450
  if (isExiting && pending === 0) {
390
451
  safeToRemoveRef.current?.();
391
452
  }
392
- }, [mergedSig, transitionSig]);
453
+ }, [baseSig, transitionSig]);
454
+ useGestureLayerProgress(
455
+ pressedProgress,
456
+ pressed,
457
+ gesture?.pressed != null,
458
+ "pressed",
459
+ transition,
460
+ isExiting,
461
+ shouldReduceMotion
462
+ );
463
+ useGestureLayerProgress(
464
+ focusedProgress,
465
+ focused,
466
+ gesture?.focused != null,
467
+ "focused",
468
+ transition,
469
+ isExiting,
470
+ shouldReduceMotion
471
+ );
472
+ useGestureLayerProgress(
473
+ focusVisibleProgress,
474
+ focusVisible,
475
+ gesture?.focusVisible != null,
476
+ "focusVisible",
477
+ transition,
478
+ isExiting,
479
+ shouldReduceMotion
480
+ );
481
+ useGestureLayerProgress(
482
+ hoveredProgress,
483
+ hovered,
484
+ gesture?.hovered != null,
485
+ "hovered",
486
+ transition,
487
+ isExiting,
488
+ shouldReduceMotion
489
+ );
393
490
  const animatedStyle = useAnimatedStyle(() => {
394
491
  const activeKeys = activeKeysRef.current;
395
492
  const hasTransform = hasTransformRef.current;
396
493
  const out = {};
397
494
  const transform = [];
495
+ const ph = hoveredProgress.value;
496
+ const pf = focusedProgress.value;
497
+ const pfv = focusVisibleProgress.value;
498
+ const pp = pressedProgress.value;
499
+ const layers = gestureSV.value;
500
+ const hoveredLayer = layers ? layers.hovered : null;
501
+ const focusedLayer = layers ? layers.focused : null;
502
+ const focusVisibleLayer = layers ? layers.focusVisible : null;
503
+ const pressedLayer = layers ? layers.pressed : null;
398
504
  for (const key of activeKeys) {
399
- const v = sharedValues[key].value;
505
+ let v = sharedValues[key].value;
506
+ const isColor = COLOR_KEY_SET.has(key);
507
+ if (hoveredLayer && ph > 0 && hoveredLayer[key] !== void 0) {
508
+ const t = hoveredLayer[key];
509
+ v = isColor ? interpolateColor(ph, [0, 1], [v, t]) : v + (t - v) * ph;
510
+ }
511
+ if (focusedLayer && pf > 0 && focusedLayer[key] !== void 0) {
512
+ const t = focusedLayer[key];
513
+ v = isColor ? interpolateColor(pf, [0, 1], [v, t]) : v + (t - v) * pf;
514
+ }
515
+ if (focusVisibleLayer && pfv > 0 && focusVisibleLayer[key] !== void 0) {
516
+ const t = focusVisibleLayer[key];
517
+ v = isColor ? interpolateColor(pfv, [0, 1], [v, t]) : v + (t - v) * pfv;
518
+ }
519
+ if (pressedLayer && pp > 0 && pressedLayer[key] !== void 0) {
520
+ const t = pressedLayer[key];
521
+ v = isColor ? interpolateColor(pp, [0, 1], [v, t]) : v + (t - v) * pp;
522
+ }
400
523
  if (TRANSFORM_KEY_SET.has(key)) {
401
524
  transform.push(
402
525
  key === "rotate" ? { rotate: `${v}deg` } : { [key]: v }
@@ -615,52 +738,41 @@ function stableStringify(v) {
615
738
  const keys = Object.keys(obj).sort();
616
739
  return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
617
740
  }
618
- function mergeGestureTargets(base, gesture, active) {
619
- if (!gesture) return base;
620
- const merged = {
621
- ...base
622
- };
623
- const subStates = [
624
- gesture.hovered,
625
- gesture.focused,
626
- gesture.focusVisible,
627
- gesture.pressed
628
- ];
629
- for (const sub of subStates) {
630
- if (!sub) continue;
631
- for (const k of ALL_KEYS) {
632
- if (k in sub && !(k in merged)) {
633
- merged[k] = DEFAULT_RESTING[k];
634
- }
741
+ function resolveGestureLayers(gesture) {
742
+ if (!gesture) return null;
743
+ const out = {};
744
+ for (const layer of GESTURE_LAYER_NAMES) {
745
+ const subState = gesture[layer];
746
+ if (!subState) continue;
747
+ const resolved = {};
748
+ for (const key of ALL_KEYS) {
749
+ const raw = subState[key];
750
+ if (raw === void 0) continue;
751
+ const t = targetEndValue(raw);
752
+ if (t !== void 0) resolved[key] = t;
635
753
  }
754
+ out[layer] = resolved;
636
755
  }
637
- if (active.hovered && gesture.hovered) {
638
- Object.assign(
639
- merged,
640
- gesture.hovered
641
- );
642
- }
643
- if (active.focused && gesture.focused) {
644
- Object.assign(
645
- merged,
646
- gesture.focused
647
- );
648
- }
649
- if (active.focusVisible && gesture.focusVisible) {
650
- Object.assign(
651
- merged,
652
- gesture.focusVisible
653
- );
654
- }
655
- if (active.pressed && gesture.pressed) {
656
- Object.assign(
657
- merged,
658
- gesture.pressed
659
- );
660
- }
661
- return merged;
756
+ return out;
757
+ }
758
+ function useGestureLayerProgress(progress, active, declared, layer, transition, isExiting, shouldReduceMotion) {
759
+ const layerCfgSig = stableSig(gestureLayerTransitionFor(layer, transition));
760
+ useEffect(() => {
761
+ if (!declared) return;
762
+ if (isExiting) {
763
+ progress.value = 0;
764
+ return;
765
+ }
766
+ const target = active ? 1 : 0;
767
+ const cfg = shouldReduceMotion ? { type: "no-animation" } : gestureLayerTransitionFor(layer, transition) ?? { type: "spring" };
768
+ progress.value = resolveTransition(cfg, target);
769
+ }, [active, declared, isExiting, shouldReduceMotion, layerCfgSig]);
662
770
  }
663
771
  function useGestureHandlers(gesture, rest, setPressed, setFocused, setFocusVisible, setHovered) {
772
+ const hasPressed = gesture?.pressed ? 1 : 0;
773
+ const hasFocused = gesture?.focused ? 1 : 0;
774
+ const hasFocusVisible = gesture?.focusVisible ? 1 : 0;
775
+ const hasHovered = gesture?.hovered ? 1 : 0;
664
776
  return useMemo(() => {
665
777
  if (!gesture) return {};
666
778
  const handlers = {};
@@ -693,10 +805,10 @@ function useGestureHandlers(gesture, rest, setPressed, setFocused, setFocusVisib
693
805
  }
694
806
  return handlers;
695
807
  }, [
696
- gesture?.pressed ? 1 : 0,
697
- gesture?.focused ? 1 : 0,
698
- gesture?.focusVisible ? 1 : 0,
699
- gesture?.hovered ? 1 : 0,
808
+ hasPressed,
809
+ hasFocused,
810
+ hasFocusVisible,
811
+ hasHovered,
700
812
  rest.onTouchStart,
701
813
  rest.onTouchEnd,
702
814
  rest.onTouchCancel,