@rootnative/inertia 0.0.5 → 0.0.7

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 (65) hide show
  1. package/CHANGELOG.md +69 -1
  2. package/README.md +7 -1
  3. package/dist/{chunk-OAUWLPQH.mjs → chunk-52QSN2VQ.mjs} +1 -1
  4. package/dist/{chunk-VQ5D35UA.js → chunk-6V7MOBXO.js} +93 -33
  5. package/dist/{chunk-RIVVBABB.mjs → chunk-HPJMIBBK.mjs} +93 -34
  6. package/dist/{chunk-XSK5MNUH.mjs → chunk-KBFN4TRO.mjs} +1 -1
  7. package/dist/chunk-NPJ46457.js +8 -0
  8. package/dist/chunk-QJYFTTM2.js +28 -0
  9. package/dist/{chunk-QQVDZKSD.js → chunk-QYR66E2G.js} +2 -2
  10. package/dist/{chunk-GTJ6VAH5.mjs → chunk-RUIOM2YZ.mjs} +1 -1
  11. package/dist/{chunk-27MKBTSG.mjs → chunk-VSK2E35J.mjs} +1 -1
  12. package/dist/{chunk-27U6766G.js → chunk-WGCF3WQG.js} +2 -2
  13. package/dist/{chunk-COEJVWRZ.mjs → chunk-WMLS4TMX.mjs} +1 -1
  14. package/dist/chunk-YUTS6JRU.js +8 -0
  15. package/dist/chunk-ZOBOKLAS.mjs +22 -0
  16. package/dist/chunk-ZSOCRHU3.js +8 -0
  17. package/dist/gestureLayer/index.d.mts +2 -2
  18. package/dist/gestureLayer/index.d.ts +2 -2
  19. package/dist/index.d.mts +45 -9
  20. package/dist/index.d.ts +45 -9
  21. package/dist/index.js +32 -22
  22. package/dist/index.mjs +16 -13
  23. package/dist/motion/FlatList.d.mts +53 -0
  24. package/dist/motion/FlatList.d.ts +53 -0
  25. package/dist/motion/FlatList.js +13 -0
  26. package/dist/motion/FlatList.mjs +4 -0
  27. package/dist/motion/Image.d.mts +1 -1
  28. package/dist/motion/Image.d.ts +1 -1
  29. package/dist/motion/Image.js +3 -3
  30. package/dist/motion/Image.mjs +2 -2
  31. package/dist/motion/Pressable.d.mts +1 -1
  32. package/dist/motion/Pressable.d.ts +1 -1
  33. package/dist/motion/Pressable.js +3 -3
  34. package/dist/motion/Pressable.mjs +2 -2
  35. package/dist/motion/ScrollView.d.mts +1 -1
  36. package/dist/motion/ScrollView.d.ts +1 -1
  37. package/dist/motion/ScrollView.js +3 -3
  38. package/dist/motion/ScrollView.mjs +2 -2
  39. package/dist/motion/Text.d.mts +1 -1
  40. package/dist/motion/Text.d.ts +1 -1
  41. package/dist/motion/Text.js +3 -3
  42. package/dist/motion/Text.mjs +2 -2
  43. package/dist/motion/View.d.mts +1 -1
  44. package/dist/motion/View.d.ts +1 -1
  45. package/dist/motion/View.js +3 -3
  46. package/dist/motion/View.mjs +2 -2
  47. package/dist/touch/index.d.mts +1 -1
  48. package/dist/touch/index.d.ts +1 -1
  49. package/dist/{types-BQgLJeQG.d.mts → types-DyJpG64F.d.mts} +1 -1
  50. package/dist/{types-BQgLJeQG.d.ts → types-DyJpG64F.d.ts} +1 -1
  51. package/dist/{useGesture-DfaTx-3t.d.mts → useGesture-CnZQnYHH.d.mts} +1 -1
  52. package/dist/{useGesture-B0_CzOUz.d.ts → useGesture-DbH46EBp.d.ts} +1 -1
  53. package/jest-setup.js +7 -1
  54. package/llms.txt +8 -3
  55. package/package.json +8 -1
  56. package/src/index.ts +5 -0
  57. package/src/internal/boxShadow.ts +71 -9
  58. package/src/internal/color.ts +70 -0
  59. package/src/motion/FlatList.tsx +77 -0
  60. package/src/motion/createMotionComponent.tsx +116 -47
  61. package/src/motion/index.ts +3 -0
  62. package/src/values/useScroll.ts +9 -5
  63. package/dist/chunk-67GHRCF6.js +0 -8
  64. package/dist/chunk-GPOMFIIU.js +0 -8
  65. package/dist/chunk-K63LXGKS.js +0 -8
@@ -0,0 +1,77 @@
1
+ import type { FlatList as RNFlatList, FlatListProps } from 'react-native'
2
+ import Animated from 'react-native-reanimated'
3
+ import type { MotionProps, VariantsMap } from '../types'
4
+ import { createMotionComponent } from './createMotionComponent'
5
+
6
+ /**
7
+ * Animatable, virtualized `FlatList`.
8
+ *
9
+ * Built on Reanimated's `Animated.FlatList` rather than RN's `FlatList`. That
10
+ * wrapper supplies two things this primitive would otherwise have to
11
+ * re-implement: the `CellRendererComponent` injection that powers per-row
12
+ * `itemLayoutAnimation`, and a `scrollEventThrottle` default of 1.
13
+ *
14
+ * A note on that throttle default, because the reasoning is easy to get wrong
15
+ * from Reanimated's own source comment: it says RN defaults FlatList's
16
+ * `scrollEventThrottle` to 50, which **is stale**. On RN 0.81
17
+ * (`@react-native/virtualized-lists`, `VirtualizedList.js`) the default is
18
+ * `props.scrollEventThrottle ?? 0.0001` — effectively every frame. So the
19
+ * patch is belt-and-braces on current RN rather than the load-bearing reason
20
+ * to use the wrapper. It is still worth inheriting: it costs nothing, and it
21
+ * pins the behaviour if RN's default changes again. **Do not restate the "50"
22
+ * figure as fact** — verify against the installed RN before relying on it.
23
+ *
24
+ * This is the primitive that lets one list both virtualize and animate. The
25
+ * `useScroll()` handler works because `Motion.*` components are Reanimated
26
+ * animated components — the same mechanism `Motion.ScrollView` relies on, and
27
+ * nothing about it was ever specific to `ScrollView`:
28
+ *
29
+ * ```tsx
30
+ * const { scrollY, onScroll } = useScroll()
31
+ *
32
+ * <Motion.FlatList
33
+ * data={items}
34
+ * renderItem={renderItem}
35
+ * onScroll={onScroll}
36
+ * initial={{ opacity: 0 }}
37
+ * animate={{ opacity: 1 }}
38
+ * />
39
+ * ```
40
+ *
41
+ * Two scoping notes:
42
+ *
43
+ * - `animate` / `initial` / `gesture` apply to the **scroll container**, not to
44
+ * rows. Animate rows by using a `Motion.*` primitive inside `renderItem`.
45
+ * - The `layout` prop animates the list frame. Per-row layout animation is
46
+ * Reanimated's `itemLayoutAnimation`, which is forwarded through untouched.
47
+ * Note that row-level layout animation can fight the list's own measurement
48
+ * passes — measure before adopting it.
49
+ */
50
+ export const MotionFlatList = createMotionComponent(
51
+ Animated.FlatList as never,
52
+ // `createMotionComponent<C>` returns a non-generic `MotionComponent<C>`, so
53
+ // `data` / `renderItem` would collapse to `any` and lose `ItemT` inference.
54
+ // Restore it with the same call-signature cast Reanimated itself uses for
55
+ // this exact problem (see its `ReanimatedFlatList` export, and the
56
+ // `@ts-expect-error` above `AnimatedFlatList` explaining that
57
+ // `createAnimatedComponent` cannot create generic components).
58
+ //
59
+ // **Both** generics live on the one call signature, and that is deliberate:
60
+ // `ItemT` infers from `data` while `V` infers from `variants`, independently.
61
+ // Declaring only `ItemT` (the obvious first cut) silently drops the
62
+ // variant-key narrowing that `MotionComponent` provides on every other
63
+ // primitive — `animate="typo"` would stop being a compile error here and
64
+ // nowhere else. Both directions are pinned in
65
+ // `__type-tests__/flat-list.test-d.tsx`.
66
+ ) as unknown as <
67
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
68
+ ItemT = any,
69
+ V extends VariantsMap<FlatListProps<ItemT>> = VariantsMap<
70
+ FlatListProps<ItemT>
71
+ >,
72
+ >(
73
+ props: FlatListProps<ItemT> &
74
+ MotionProps<FlatListProps<ItemT>, V> & {
75
+ ref?: React.Ref<RNFlatList<ItemT>>
76
+ },
77
+ ) => React.ReactElement
@@ -23,11 +23,18 @@ import {
23
23
  } from '../config'
24
24
  import { isFocusVisible } from '../gestures'
25
25
  import {
26
+ layersToPayload,
26
27
  normalizeBoxShadow,
28
+ payloadToLayers,
27
29
  prepareBoxShadowAnimation,
28
- type AnimatedBoxShadowLayer,
30
+ type BoxShadowPayload,
29
31
  type SplitBoxShadow,
30
32
  } from '../internal/boxShadow'
33
+ import {
34
+ normalizeAnimatableColor,
35
+ normalizeAnimatableColorTarget,
36
+ TRANSPARENT,
37
+ } from '../internal/color'
31
38
  import { warnOnce } from '../internal/warnOnce'
32
39
  import {
33
40
  resolveLayoutTransition,
@@ -191,16 +198,20 @@ const COLOR_KEYS = [
191
198
  const SHADOW_OFFSET_KEYS = ['shadowOffsetWidth', 'shadowOffsetHeight'] as const
192
199
 
193
200
  // Keys whose shared value holds a structure rather than a scalar. `boxShadow`
194
- // is the only one: its slot carries an array of layer objects, which
201
+ // is the only one: its slot carries the layers keyed by index, which
195
202
  // Reanimated's animation drivers recurse into, animating each leaf number and
196
- // color independently (`arrayOnStart` → `objectOnStart` in Reanimated's
197
- // `animation/util.ts`).
203
+ // color independently (`objectOnStart` in Reanimated's `animation/util.ts`).
204
+ //
205
+ // Index-keyed and not an array, which is load-bearing — Reanimated recurses
206
+ // into objects but not into arrays. See `BoxShadowPayload` for the mechanism
207
+ // and for what it looked like when this was an array (`0.0.4`/`0.0.5`: dead
208
+ // under the default spring, silently correct-looking under timing).
198
209
  //
199
- // Passing the CSS string through instead would NOT work — a box-shadow string
200
- // isn't a color, so it lands in Reanimated's prefix-number-suffix branch,
201
- // which is built for values like '100%' and would pull a single number out of
202
- // a four-value shadow. All string parsing therefore happens on the JS thread,
203
- // once per change, in `internal/boxShadow.ts`.
210
+ // Passing the CSS string through instead would NOT work either — a box-shadow
211
+ // string isn't a color, so it lands in Reanimated's prefix-number-suffix
212
+ // branch, which is built for values like '100%' and would pull a single number
213
+ // out of a four-value shadow. All string parsing therefore happens on the JS
214
+ // thread, once per change, in `internal/boxShadow.ts`.
204
215
  const STRUCTURED_KEYS = ['boxShadow'] as const
205
216
 
206
217
  // Keys a shared-element transition (`layoutId`) carries from the source
@@ -253,15 +264,16 @@ const SHARED_STYLE_KEY_SET = new Set<AnimatableKey>(SHARED_STYLE_KEYS)
253
264
 
254
265
  /**
255
266
  * What a per-key shared value can hold. Scalars for every key except
256
- * `boxShadow`, whose slot carries the layer array (see `STRUCTURED_KEYS`).
267
+ * `boxShadow`, whose slot carries the index-keyed layer payload (see
268
+ * `STRUCTURED_KEYS`).
257
269
  */
258
- type AnimatableSlotValue = number | string | readonly AnimatedBoxShadowLayer[]
270
+ type AnimatableSlotValue = number | string | BoxShadowPayload
259
271
 
260
272
  /**
261
273
  * Resting `boxShadow` — no shadow at all. Frozen and hoisted so every
262
274
  * primitive shares one reference and an untouched slot never allocates.
263
275
  */
264
- const NO_BOX_SHADOW: readonly AnimatedBoxShadowLayer[] = Object.freeze([])
276
+ const NO_BOX_SHADOW: BoxShadowPayload = Object.freeze({})
265
277
 
266
278
  const GESTURE_LAYER_NAMES = [
267
279
  'hovered',
@@ -341,15 +353,21 @@ const DEFAULT_RESTING: Record<AnimatableKey, AnimatableSlotValue> = {
341
353
  gap: 0,
342
354
  rowGap: 0,
343
355
  columnGap: 0,
344
- // 'transparent' is the only safe universal default for colors: it works as
345
- // an initial seed for any color animation (no jarring opaque flash on mount
346
- // when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
347
- // any opaque target via Reanimated's color util.
348
- backgroundColor: 'transparent',
349
- borderColor: 'transparent',
350
- color: 'transparent',
351
- tintColor: 'transparent',
352
- shadowColor: 'transparent',
356
+ // Fully transparent black is the only safe universal default for colors: it
357
+ // works as an initial seed for any color animation (no jarring opaque flash
358
+ // on mount when `initial` is omitted) and interpolates cleanly into any
359
+ // opaque target.
360
+ //
361
+ // Spelled `rgba(0, 0, 0, 0)` and NOT `'transparent'`, which is not optional.
362
+ // Reanimated's color-name table maps `transparent` to `undefined`, so it is
363
+ // the one named color `isColor()` rejects — a slot resting at the keyword
364
+ // takes the prefix-number-suffix branch on its next animation and produces
365
+ // `NaN` instead of a color. See `TRANSPARENT` in `internal/boxShadow.ts`.
366
+ backgroundColor: TRANSPARENT,
367
+ borderColor: TRANSPARENT,
368
+ color: TRANSPARENT,
369
+ tintColor: TRANSPARENT,
370
+ shadowColor: TRANSPARENT,
353
371
  shadowOffsetWidth: 0,
354
372
  shadowOffsetHeight: 0,
355
373
  boxShadow: NO_BOX_SHADOW,
@@ -730,12 +748,20 @@ export function createMotionComponent<C extends ComponentType<any>>(
730
748
  const raw = flat.boxShadow as BoxShadowInput | undefined
731
749
  if (raw !== undefined) {
732
750
  styleRestingShadow = normalizeBoxShadow(raw)
733
- styleResting.boxShadow = styleRestingShadow.layers
751
+ styleResting.boxShadow = layersToPayload(
752
+ styleRestingShadow.layers,
753
+ )
734
754
  }
735
755
  continue
736
756
  }
737
757
  const v = styleValueFor(flat, key)
738
- if (v !== undefined) styleResting[key] = v
758
+ // A static `style` may legitimately say `'transparent'`; the slot
759
+ // it seeds must not, or the next animation off that value dies.
760
+ if (v !== undefined) {
761
+ styleResting[key] = COLOR_KEY_SET.has(key)
762
+ ? normalizeAnimatableColor(v)
763
+ : v
764
+ }
739
765
  }
740
766
  }
741
767
  }
@@ -754,14 +780,13 @@ export function createMotionComponent<C extends ComponentType<any>>(
754
780
  boxShadowSeedRef.current =
755
781
  source !== undefined
756
782
  ? normalizeBoxShadow(source)
757
- : (styleRestingShadow ?? {
758
- layers: [...NO_BOX_SHADOW],
759
- insets: null,
760
- })
783
+ : (styleRestingShadow ?? { layers: [], insets: null })
761
784
  }
762
785
 
763
786
  const sharedValues = useAnimatableSharedValues((key) => {
764
- if (key === 'boxShadow') return boxShadowSeedRef.current!.layers
787
+ if (key === 'boxShadow') {
788
+ return layersToPayload(boxShadowSeedRef.current!.layers)
789
+ }
765
790
  // Shadow offset synthetics seed from the corresponding axis on the
766
791
  // `shadowOffset: { width, height }` source — the consumer doesn't write
767
792
  // `shadowOffsetWidth` / `shadowOffsetHeight` directly. Fall back to the
@@ -788,16 +813,21 @@ export function createMotionComponent<C extends ComponentType<any>>(
788
813
  DEFAULT_RESTING[key]
789
814
  )
790
815
  }
816
+ // Colors are normalized on the way in: `initial` and `animate` are
817
+ // consumer strings and may say `'transparent'`, which Reanimated
818
+ // cannot animate *away from* (see `internal/color.ts`). The two
819
+ // fallbacks below are already normalized.
791
820
  if (initial === false) {
792
821
  const a = animateRecord[key]
793
- return restValue(a) ?? styleResting[key] ?? DEFAULT_RESTING[key]
822
+ const seed = restValue(a) ?? styleResting[key] ?? DEFAULT_RESTING[key]
823
+ return COLOR_KEY_SET.has(key) ? normalizeAnimatableColor(seed) : seed
794
824
  }
795
- return (
825
+ const seed =
796
826
  initialRecord?.[key] ??
797
827
  restValue(animateRecord[key]) ??
798
828
  styleResting[key] ??
799
829
  DEFAULT_RESTING[key]
800
- )
830
+ return COLOR_KEY_SET.has(key) ? normalizeAnimatableColor(seed) : seed
801
831
  })
802
832
 
803
833
  // Keep never-driven keys tracking the *live* static style. The seed above
@@ -1014,8 +1044,17 @@ export function createMotionComponent<C extends ComponentType<any>>(
1014
1044
  isExiting ? onSettle : undefined,
1015
1045
  TRANSFORM_KEY_SET.has(key) ? transformGroup : undefined,
1016
1046
  )
1047
+ // Normalized for the driver only, and after `targetEndValue` above:
1048
+ // `onAnimationEnd` reports the target the consumer declared, not our
1049
+ // rewriting of it. A color target of `'transparent'` animates fine
1050
+ // — Reanimated dispatches on the *source* — but under
1051
+ // `'no-animation'` (and so under reduced motion) it is assigned
1052
+ // straight into the slot, and the next animation would start from a
1053
+ // value that can't be parsed.
1017
1054
  sharedValues[key].value = resolveAnimatableValue(
1018
- target,
1055
+ COLOR_KEY_SET.has(key)
1056
+ ? normalizeAnimatableColorTarget(target)
1057
+ : target,
1019
1058
  cfg,
1020
1059
  factory,
1021
1060
  ) as never
@@ -1243,17 +1282,19 @@ export function createMotionComponent<C extends ComponentType<any>>(
1243
1282
  out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH }
1244
1283
  }
1245
1284
  if (hasBoxShadow) {
1246
- const layers = sharedValues.boxShadow
1247
- .value as readonly AnimatedBoxShadowLayer[]
1285
+ // The slot holds the layers keyed by index (Reanimated recurses into
1286
+ // objects, not arrays — see `BoxShadowPayload`); RN wants an array,
1287
+ // so this is where the two shapes meet.
1288
+ const payload = sharedValues.boxShadow.value as BoxShadowPayload
1248
1289
  const insets = boxShadowInsets.value
1249
- // Fast path — no inset layer anywhere, so the animated array is
1250
- // already exactly what RN wants and crosses over untouched.
1290
+ // Fast path — no inset layer anywhere, so each layer crosses over by
1291
+ // reference and only the array itself is allocated.
1251
1292
  if (insets === null) {
1252
- out.boxShadow = layers
1293
+ out.boxShadow = payloadToLayers(payload)
1253
1294
  } else {
1254
1295
  const withInset = []
1255
- for (let i = 0; i < layers.length; i++) {
1256
- withInset.push({ ...layers[i], inset: insets[i] })
1296
+ for (let i = 0; payload[i] !== undefined; i++) {
1297
+ withInset.push({ ...payload[i], inset: insets[i] })
1257
1298
  }
1258
1299
  out.boxShadow = withInset
1259
1300
  }
@@ -1486,6 +1527,13 @@ function makeKeyCallbackFactory(
1486
1527
  const reportedIteration = state.iteration
1487
1528
  if (phase === 'sequence' || phase === 'repeat') state.iteration++
1488
1529
 
1530
+ // `boxShadow`'s slot is keyed by index so Reanimated will recurse into it;
1531
+ // that is an internal shape, and the consumer gets the layer list.
1532
+ const reportedValue =
1533
+ key === 'boxShadow' && value !== undefined
1534
+ ? payloadToLayers(value as BoxShadowPayload)
1535
+ : value
1536
+
1489
1537
  const fn = onAnimationEndRef.current
1490
1538
  if (fn) {
1491
1539
  // Transform-group coalescing: a multi-axis translate / scale /
@@ -1501,7 +1549,7 @@ function makeKeyCallbackFactory(
1501
1549
  fn({
1502
1550
  key: 'transform' as never,
1503
1551
  finished,
1504
- value,
1552
+ value: reportedValue,
1505
1553
  target,
1506
1554
  phase,
1507
1555
  step,
@@ -1512,7 +1560,7 @@ function makeKeyCallbackFactory(
1512
1560
  fn({
1513
1561
  key: key as never,
1514
1562
  finished,
1515
- value,
1563
+ value: reportedValue,
1516
1564
  target,
1517
1565
  phase,
1518
1566
  step,
@@ -1609,20 +1657,18 @@ function driveBoxShadow(
1609
1657
  cfg: TransitionConfig | undefined,
1610
1658
  factory: CallbackFactory | undefined,
1611
1659
  ): void {
1612
- const currentLayers = Array.isArray(slot.value)
1613
- ? (slot.value as readonly AnimatedBoxShadowLayer[])
1614
- : NO_BOX_SHADOW
1660
+ const currentLayers = payloadToLayers(slot.value as BoxShadowPayload)
1615
1661
  const { from, to, insets } = prepareBoxShadowAnimation(
1616
- { layers: [...currentLayers], insets: insetSlot.value },
1662
+ { layers: currentLayers, insets: insetSlot.value },
1617
1663
  target,
1618
1664
  )
1619
1665
  insetSlot.value = insets
1620
- if (from.length !== currentLayers.length) slot.value = from
1666
+ if (from.length !== currentLayers.length) slot.value = layersToPayload(from)
1621
1667
  // `resolveTransition` is typed for the scalar surface it was written for;
1622
1668
  // Reanimated itself accepts the structured target and recurses into it.
1623
1669
  slot.value = resolveTransition(
1624
1670
  cfg,
1625
- to as unknown as number,
1671
+ layersToPayload(to) as unknown as number,
1626
1672
  factory?.('animation', undefined),
1627
1673
  ) as AnimatableSlotValue
1628
1674
  }
@@ -1979,6 +2025,26 @@ function useGestureHandlers(
1979
2025
  // forward to those when present so wrapping consumers stay consistent.
1980
2026
  handlers.onPressIn = compose(rest.onPressIn, () => setPressed(true))
1981
2027
  handlers.onPressOut = compose(rest.onPressOut, () => setPressed(false))
2028
+ // Web pointer events. `onTouchStart` reaches the DOM as a real
2029
+ // `touchstart` listener under react-native-web, which a mouse never
2030
+ // fires — so without these a plain `Motion.View` (anything that isn't a
2031
+ // Pressable, i.e. has no `onPressIn` path) was inert under a desktop
2032
+ // click while `Motion.Pressable` worked. Pointer events cover mouse, pen
2033
+ // and touch, so `pressed` means "any pointer" on every platform.
2034
+ //
2035
+ // A web touch fires `touchstart` *and* `pointerdown`; both set the same
2036
+ // boolean to the same value, so the overlap is idempotent, not a
2037
+ // double-toggle. React Native has no pointer props, so these are inert
2038
+ // on native and cost nothing there.
2039
+ handlers.onPointerDown = compose(rest.onPointerDown, () =>
2040
+ setPressed(true),
2041
+ )
2042
+ handlers.onPointerUp = compose(rest.onPointerUp, () => setPressed(false))
2043
+ // Fires when the browser takes over the gesture (scroll, drag start) —
2044
+ // without it the pressed layer would stick on after the pointer is gone.
2045
+ handlers.onPointerCancel = compose(rest.onPointerCancel, () =>
2046
+ setPressed(false),
2047
+ )
1982
2048
  }
1983
2049
  // Mount onFocus/onBlur if either focus sub-state is declared. The two flags
1984
2050
  // are independent: `focused` always tracks focus; `focusVisible` only
@@ -2015,6 +2081,9 @@ function useGestureHandlers(
2015
2081
  rest.onTouchCancel,
2016
2082
  rest.onPressIn,
2017
2083
  rest.onPressOut,
2084
+ rest.onPointerDown,
2085
+ rest.onPointerUp,
2086
+ rest.onPointerCancel,
2018
2087
  rest.onFocus,
2019
2088
  rest.onBlur,
2020
2089
  rest.onMouseEnter,
@@ -1,3 +1,4 @@
1
+ import { MotionFlatList } from './FlatList'
1
2
  import { MotionImage } from './Image'
2
3
  import { MotionPressable } from './Pressable'
3
4
  import { MotionScrollView } from './ScrollView'
@@ -11,6 +12,7 @@ export {
11
12
  MotionImage,
12
13
  MotionPressable,
13
14
  MotionScrollView,
15
+ MotionFlatList,
14
16
  }
15
17
 
16
18
  /**
@@ -23,4 +25,5 @@ export const Motion = {
23
25
  Image: MotionImage,
24
26
  Pressable: MotionPressable,
25
27
  ScrollView: MotionScrollView,
28
+ FlatList: MotionFlatList,
26
29
  } as const
@@ -11,10 +11,10 @@ export interface UseScrollResult {
11
11
  /** Vertical scroll offset in points. */
12
12
  scrollY: SharedValue<number>
13
13
  /**
14
- * Handler to pass to a `Motion.ScrollView`'s `onScroll` prop (or any other
15
- * Reanimated `Animated.ScrollView`). The handler is opaque to JS it runs
16
- * as a worklet — but the type narrows to the same shape RN's native
17
- * `onScroll` prop expects so it composes cleanly.
14
+ * Handler to pass to the `onScroll` prop of `Motion.ScrollView` or
15
+ * `Motion.FlatList` (or any other Reanimated animated scroller). The handler
16
+ * is opaque to JS — it runs as a worklet — but the type narrows to the same
17
+ * shape RN's native `onScroll` prop expects so it composes cleanly.
18
18
  */
19
19
  onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void
20
20
  }
@@ -47,9 +47,13 @@ export interface UseScrollResult {
47
47
  * read from any worklet (`useAnimatedStyle`, `useDerivedValue`,
48
48
  * `useTransform`) without a JS-thread bounce.
49
49
  *
50
- * Remember to set `scrollEventThrottle={16}` on the `ScrollView` for 60Hz
50
+ * Remember to set `scrollEventThrottle={16}` on a `Motion.ScrollView` for 60Hz
51
51
  * updates — RN's default is to dispatch on every event, which on iOS still
52
52
  * means one per frame, but Android benefits from the explicit cap.
53
+ *
54
+ * `Motion.FlatList` needs no such setting — it defaults `scrollEventThrottle`
55
+ * to 1 for you. Prefer it over `Motion.ScrollView` for long or unbounded lists:
56
+ * it virtualizes, and both accept this handler.
53
57
  */
54
58
  export function useScroll(): UseScrollResult {
55
59
  const scrollX = useSharedValue(0)
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkVQ5D35UA_js = require('./chunk-VQ5D35UA.js');
4
- var reactNative = require('react-native');
5
-
6
- var MotionText = chunkVQ5D35UA_js.createMotionComponent(reactNative.Text);
7
-
8
- exports.MotionText = MotionText;
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkVQ5D35UA_js = require('./chunk-VQ5D35UA.js');
4
- var reactNative = require('react-native');
5
-
6
- var MotionImage = chunkVQ5D35UA_js.createMotionComponent(reactNative.Image);
7
-
8
- exports.MotionImage = MotionImage;
@@ -1,8 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkVQ5D35UA_js = require('./chunk-VQ5D35UA.js');
4
- var reactNative = require('react-native');
5
-
6
- var MotionView = chunkVQ5D35UA_js.createMotionComponent(reactNative.View);
7
-
8
- exports.MotionView = MotionView;