@onlynative/inertia 0.0.1-alpha.1 → 0.0.1-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.
@@ -44,7 +44,28 @@ const TRANSFORM_KEYS = [
44
44
  'rotate',
45
45
  ] as const
46
46
 
47
- const TOP_LEVEL_KEYS = ['opacity', 'width', 'height', 'borderRadius'] as const
47
+ const NUMERIC_TOP_LEVEL_KEYS = [
48
+ 'opacity',
49
+ 'width',
50
+ 'height',
51
+ 'borderRadius',
52
+ ] as const
53
+
54
+ // Color-valued keys. Reanimated's value setter detects color strings and
55
+ // interpolates between their packed RGBA representations natively in
56
+ // `withSpring` / `withTiming` — so the resolver path is identical to numeric
57
+ // keys; only the shared-value seed and the resting default differ.
58
+ //
59
+ // `tintColor` is Image-only, but allocated unconditionally here: the
60
+ // per-primitive type system (`AnimateStyle<C>`) is what gates which keys
61
+ // `animate` accepts at compile time. An unused shared value is a single ref;
62
+ // allocating it everywhere keeps hook order stable and the factory generic.
63
+ const COLOR_KEYS = [
64
+ 'backgroundColor',
65
+ 'borderColor',
66
+ 'color',
67
+ 'tintColor',
68
+ ] as const
48
69
 
49
70
  /**
50
71
  * Per-effect transform-group coordinator. Counts how many transform-axis
@@ -54,7 +75,11 @@ const TOP_LEVEL_KEYS = ['opacity', 'width', 'height', 'borderRadius'] as const
54
75
  */
55
76
  type TransformGroup = { remaining: number }
56
77
 
57
- const ALL_KEYS = [...TRANSFORM_KEYS, ...TOP_LEVEL_KEYS] as const
78
+ const ALL_KEYS = [
79
+ ...TRANSFORM_KEYS,
80
+ ...NUMERIC_TOP_LEVEL_KEYS,
81
+ ...COLOR_KEYS,
82
+ ] as const
58
83
  type AnimatableKey = (typeof ALL_KEYS)[number]
59
84
  type TransformKey = (typeof TRANSFORM_KEYS)[number]
60
85
 
@@ -65,7 +90,7 @@ const TRANSFORM_KEY_SET = new Set<AnimatableKey>(TRANSFORM_KEYS)
65
90
  // Reanimated's style merging treats it as a no-op when present.
66
91
  const EXITING_POINTER_EVENTS_STYLE = { pointerEvents: 'none' } as const
67
92
 
68
- const DEFAULT_RESTING: Record<AnimatableKey, number> = {
93
+ const DEFAULT_RESTING: Record<AnimatableKey, number | string> = {
69
94
  translateX: 0,
70
95
  translateY: 0,
71
96
  scale: 1,
@@ -76,6 +101,14 @@ const DEFAULT_RESTING: Record<AnimatableKey, number> = {
76
101
  width: 0,
77
102
  height: 0,
78
103
  borderRadius: 0,
104
+ // 'transparent' is the only safe universal default for colors: it works as
105
+ // an initial seed for any color animation (no jarring opaque flash on mount
106
+ // when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
107
+ // any opaque target via Reanimated's color util.
108
+ backgroundColor: 'transparent',
109
+ borderColor: 'transparent',
110
+ color: 'transparent',
111
+ tintColor: 'transparent',
79
112
  }
80
113
 
81
114
  const TRANSITION_KEYS = new Set([
@@ -117,10 +150,9 @@ function transitionFor<S>(
117
150
  * `exit` / `transition` all infer from `C`'s `style` prop. There is no
118
151
  * shared `ViewStyle & TextStyle & ImageStyle` fallback.
119
152
  *
120
- * Alpha scope: numeric properties listed in `ALL_KEYS`, applied via
121
- * Reanimated shared values + `useAnimatedStyle`. Sequences, variants,
122
- * gestures, color animation, and the cross-render memoization optimization
123
- * land in later phases.
153
+ * Alpha scope: numeric properties (transforms, opacity, width, height,
154
+ * borderRadius) and color properties (backgroundColor, borderColor, color,
155
+ * tintColor) applied via Reanimated shared values + `useAnimatedStyle`.
124
156
  */
125
157
  export function createMotionComponent<C extends ComponentType<any>>(
126
158
  Component: C,
@@ -176,14 +208,16 @@ export function createMotionComponent<C extends ComponentType<any>>(
176
208
  )
177
209
 
178
210
  const animateRecord = (resolvedAnimate ?? {}) as Partial<
179
- Record<AnimatableKey, AnimatableValue<number>>
211
+ Record<AnimatableKey, AnimatableValue<number | string>>
180
212
  >
181
213
  const initialRecord =
182
214
  initial && initial !== false
183
- ? (initial as Partial<Record<AnimatableKey, number>>)
215
+ ? (initial as Partial<Record<AnimatableKey, number | string>>)
184
216
  : undefined
185
217
  const exitRecord = exit
186
- ? (exit as Partial<Record<AnimatableKey, AnimatableValue<number>>>)
218
+ ? (exit as Partial<
219
+ Record<AnimatableKey, AnimatableValue<number | string>>
220
+ >)
187
221
  : undefined
188
222
 
189
223
  // Gesture sub-state activation tracked as JS state so changes invalidate
@@ -406,7 +440,7 @@ export function createMotionComponent<C extends ComponentType<any>>(
406
440
  return Motion as unknown as MotionComponent<C>
407
441
  }
408
442
 
409
- type SharedValueMap = Record<AnimatableKey, SharedValue<number>>
443
+ type SharedValueMap = Record<AnimatableKey, SharedValue<number | string>>
410
444
 
411
445
  /**
412
446
  * Allocate one shared value per animatable key in `ALL_KEYS` and return a
@@ -422,21 +456,29 @@ type SharedValueMap = Record<AnimatableKey, SharedValue<number>>
422
456
  *
423
457
  * Hooks are called in a stable, lexical order — fine for rules-of-hooks.
424
458
  * Unused shared values are cheap; the worklet skips them via
425
- * `activeKeysRef`.
459
+ * `activeKeysRef`. Color keys are seeded with the initial color string so
460
+ * Reanimated's value setter recognizes the slot as a color from the first
461
+ * `withSpring` / `withTiming` call.
426
462
  */
427
463
  function useAnimatableSharedValues(
428
- init: (key: AnimatableKey) => number,
464
+ init: (key: AnimatableKey) => number | string,
429
465
  ): SharedValueMap {
430
- const translateX = useSharedValue(init('translateX'))
431
- const translateY = useSharedValue(init('translateY'))
432
- const scale = useSharedValue(init('scale'))
433
- const scaleX = useSharedValue(init('scaleX'))
434
- const scaleY = useSharedValue(init('scaleY'))
435
- const rotate = useSharedValue(init('rotate'))
436
- const opacity = useSharedValue(init('opacity'))
437
- const width = useSharedValue(init('width'))
438
- const height = useSharedValue(init('height'))
439
- const borderRadius = useSharedValue(init('borderRadius'))
466
+ const translateX = useSharedValue<number | string>(init('translateX'))
467
+ const translateY = useSharedValue<number | string>(init('translateY'))
468
+ const scale = useSharedValue<number | string>(init('scale'))
469
+ const scaleX = useSharedValue<number | string>(init('scaleX'))
470
+ const scaleY = useSharedValue<number | string>(init('scaleY'))
471
+ const rotate = useSharedValue<number | string>(init('rotate'))
472
+ const opacity = useSharedValue<number | string>(init('opacity'))
473
+ const width = useSharedValue<number | string>(init('width'))
474
+ const height = useSharedValue<number | string>(init('height'))
475
+ const borderRadius = useSharedValue<number | string>(init('borderRadius'))
476
+ const backgroundColor = useSharedValue<number | string>(
477
+ init('backgroundColor'),
478
+ )
479
+ const borderColor = useSharedValue<number | string>(init('borderColor'))
480
+ const color = useSharedValue<number | string>(init('color'))
481
+ const tintColor = useSharedValue<number | string>(init('tintColor'))
440
482
 
441
483
  const ref = useRef<SharedValueMap | null>(null)
442
484
  if (ref.current === null) {
@@ -451,6 +493,10 @@ function useAnimatableSharedValues(
451
493
  width,
452
494
  height,
453
495
  borderRadius,
496
+ backgroundColor,
497
+ borderColor,
498
+ color,
499
+ tintColor,
454
500
  }
455
501
  }
456
502
  return ref.current
@@ -472,7 +518,7 @@ function useAnimatableSharedValues(
472
518
  */
473
519
  function makeKeyCallbackFactory(
474
520
  key: string,
475
- sharedValue: SharedValue<number>,
521
+ sharedValue: SharedValue<number | string>,
476
522
  target: number | string | undefined,
477
523
  onAnimationEndRef: {
478
524
  current: ((info: AnimationCallbackInfo<unknown>) => void) | undefined
@@ -577,7 +623,7 @@ function makeKeyCallbackFactory(
577
623
  * Number of sequence steps in an animatable value. `1` for plain values and
578
624
  * single-step `{ to }` objects; the array length for keyframe arrays.
579
625
  */
580
- function stepCountOf(v: AnimatableValue<number> | undefined): number {
626
+ function stepCountOf(v: AnimatableValue<number | string> | undefined): number {
581
627
  if (Array.isArray(v)) return v.length
582
628
  return 1
583
629
  }
@@ -605,13 +651,13 @@ function totalIterationsOf(cfg: TransitionConfig | undefined): number {
605
651
  * objects use `to`. Returns `undefined` for unrecognized shapes.
606
652
  */
607
653
  function targetEndValue(
608
- v: AnimatableValue<number> | undefined,
654
+ v: AnimatableValue<number | string> | undefined,
609
655
  ): number | string | undefined {
610
656
  if (v === undefined) return undefined
611
657
  if (typeof v === 'number' || typeof v === 'string') return v
612
658
  if (Array.isArray(v)) {
613
659
  return v.length > 0
614
- ? targetEndValue(v[v.length - 1] as AnimatableValue<number>)
660
+ ? targetEndValue(v[v.length - 1] as AnimatableValue<number | string>)
615
661
  : undefined
616
662
  }
617
663
  if (typeof v === 'object' && v !== null && 'to' in v) {
@@ -667,20 +713,24 @@ function resolveAnimateInput(
667
713
  declare const __DEV__: boolean
668
714
 
669
715
  /**
670
- * Pick the resting/initial-frame number out of an `AnimatableValue`. Plain
671
- * numbers come through unchanged; sequence arrays use their first element;
672
- * `{ to }` step objects use `to`. Non-numeric or unresolvable shapes return
716
+ * Pick the resting/initial-frame value out of an `AnimatableValue`. Plain
717
+ * numbers and color strings come through unchanged; sequence arrays use their
718
+ * first element; `{ to }` step objects use `to`. Unresolvable shapes return
673
719
  * `undefined` so the caller can fall back to `DEFAULT_RESTING`.
674
720
  */
675
- function restValue(v: AnimatableValue<number> | undefined): number | undefined {
721
+ function restValue(
722
+ v: AnimatableValue<number | string> | undefined,
723
+ ): number | string | undefined {
676
724
  if (v === undefined) return undefined
677
- if (typeof v === 'number') return v
725
+ if (typeof v === 'number' || typeof v === 'string') return v
678
726
  if (Array.isArray(v)) {
679
- return v.length > 0 ? restValue(v[0] as AnimatableValue<number>) : undefined
727
+ return v.length > 0
728
+ ? restValue(v[0] as AnimatableValue<number | string>)
729
+ : undefined
680
730
  }
681
731
  if (typeof v === 'object' && v !== null && 'to' in v) {
682
732
  const to = (v as { to: unknown }).to
683
- return typeof to === 'number' ? to : undefined
733
+ return typeof to === 'number' || typeof to === 'string' ? to : undefined
684
734
  }
685
735
  return undefined
686
736
  }
@@ -728,7 +778,7 @@ function stableStringify(v: unknown): string {
728
778
  * `hovered` < `focused` < `focusVisible` < `pressed`.
729
779
  */
730
780
  function mergeGestureTargets(
731
- base: Partial<Record<AnimatableKey, AnimatableValue<number>>>,
781
+ base: Partial<Record<AnimatableKey, AnimatableValue<number | string>>>,
732
782
  gesture: GestureSubStates<unknown> | undefined,
733
783
  active: {
734
784
  pressed: boolean
@@ -736,9 +786,11 @@ function mergeGestureTargets(
736
786
  focusVisible: boolean
737
787
  hovered: boolean
738
788
  },
739
- ): Partial<Record<AnimatableKey, AnimatableValue<number>>> {
789
+ ): Partial<Record<AnimatableKey, AnimatableValue<number | string>>> {
740
790
  if (!gesture) return base
741
- const merged: Partial<Record<AnimatableKey, AnimatableValue<number>>> = {
791
+ const merged: Partial<
792
+ Record<AnimatableKey, AnimatableValue<number | string>>
793
+ > = {
742
794
  ...base,
743
795
  }
744
796
  const subStates = [
@@ -747,7 +799,7 @@ function mergeGestureTargets(
747
799
  gesture.focusVisible,
748
800
  gesture.pressed,
749
801
  ] as Array<
750
- Partial<Record<AnimatableKey, AnimatableValue<number>>> | undefined
802
+ Partial<Record<AnimatableKey, AnimatableValue<number | string>>> | undefined
751
803
  >
752
804
  for (const sub of subStates) {
753
805
  if (!sub) continue
@@ -761,7 +813,7 @@ function mergeGestureTargets(
761
813
  Object.assign(
762
814
  merged,
763
815
  gesture.hovered as Partial<
764
- Record<AnimatableKey, AnimatableValue<number>>
816
+ Record<AnimatableKey, AnimatableValue<number | string>>
765
817
  >,
766
818
  )
767
819
  }
@@ -769,7 +821,7 @@ function mergeGestureTargets(
769
821
  Object.assign(
770
822
  merged,
771
823
  gesture.focused as Partial<
772
- Record<AnimatableKey, AnimatableValue<number>>
824
+ Record<AnimatableKey, AnimatableValue<number | string>>
773
825
  >,
774
826
  )
775
827
  }
@@ -777,7 +829,7 @@ function mergeGestureTargets(
777
829
  Object.assign(
778
830
  merged,
779
831
  gesture.focusVisible as Partial<
780
- Record<AnimatableKey, AnimatableValue<number>>
832
+ Record<AnimatableKey, AnimatableValue<number | string>>
781
833
  >,
782
834
  )
783
835
  }
@@ -785,7 +837,7 @@ function mergeGestureTargets(
785
837
  Object.assign(
786
838
  merged,
787
839
  gesture.pressed as Partial<
788
- Record<AnimatableKey, AnimatableValue<number>>
840
+ Record<AnimatableKey, AnimatableValue<number | string>>
789
841
  >,
790
842
  )
791
843
  }