@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.
- package/CHANGELOG.md +69 -1
- package/README.md +7 -1
- package/dist/{chunk-OAUWLPQH.mjs → chunk-52QSN2VQ.mjs} +1 -1
- package/dist/{chunk-VQ5D35UA.js → chunk-6V7MOBXO.js} +93 -33
- package/dist/{chunk-RIVVBABB.mjs → chunk-HPJMIBBK.mjs} +93 -34
- package/dist/{chunk-XSK5MNUH.mjs → chunk-KBFN4TRO.mjs} +1 -1
- package/dist/chunk-NPJ46457.js +8 -0
- package/dist/chunk-QJYFTTM2.js +28 -0
- package/dist/{chunk-QQVDZKSD.js → chunk-QYR66E2G.js} +2 -2
- package/dist/{chunk-GTJ6VAH5.mjs → chunk-RUIOM2YZ.mjs} +1 -1
- package/dist/{chunk-27MKBTSG.mjs → chunk-VSK2E35J.mjs} +1 -1
- package/dist/{chunk-27U6766G.js → chunk-WGCF3WQG.js} +2 -2
- package/dist/{chunk-COEJVWRZ.mjs → chunk-WMLS4TMX.mjs} +1 -1
- package/dist/chunk-YUTS6JRU.js +8 -0
- package/dist/chunk-ZOBOKLAS.mjs +22 -0
- package/dist/chunk-ZSOCRHU3.js +8 -0
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/index.d.mts +45 -9
- package/dist/index.d.ts +45 -9
- package/dist/index.js +32 -22
- package/dist/index.mjs +16 -13
- package/dist/motion/FlatList.d.mts +53 -0
- package/dist/motion/FlatList.d.ts +53 -0
- package/dist/motion/FlatList.js +13 -0
- package/dist/motion/FlatList.mjs +4 -0
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +3 -3
- package/dist/motion/Image.mjs +2 -2
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +3 -3
- package/dist/motion/Pressable.mjs +2 -2
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +3 -3
- package/dist/motion/ScrollView.mjs +2 -2
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +3 -3
- package/dist/motion/Text.mjs +2 -2
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +3 -3
- package/dist/motion/View.mjs +2 -2
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/{types-BQgLJeQG.d.mts → types-DyJpG64F.d.mts} +1 -1
- package/dist/{types-BQgLJeQG.d.ts → types-DyJpG64F.d.ts} +1 -1
- package/dist/{useGesture-DfaTx-3t.d.mts → useGesture-CnZQnYHH.d.mts} +1 -1
- package/dist/{useGesture-B0_CzOUz.d.ts → useGesture-DbH46EBp.d.ts} +1 -1
- package/jest-setup.js +7 -1
- package/llms.txt +8 -3
- package/package.json +8 -1
- package/src/index.ts +5 -0
- package/src/internal/boxShadow.ts +71 -9
- package/src/internal/color.ts +70 -0
- package/src/motion/FlatList.tsx +77 -0
- package/src/motion/createMotionComponent.tsx +116 -47
- package/src/motion/index.ts +3 -0
- package/src/values/useScroll.ts +9 -5
- package/dist/chunk-67GHRCF6.js +0 -8
- package/dist/chunk-GPOMFIIU.js +0 -8
- 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
|
|
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
|
|
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 (`
|
|
197
|
-
//
|
|
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
|
|
200
|
-
// isn't a color, so it lands in Reanimated's prefix-number-suffix
|
|
201
|
-
// which is built for values like '100%' and would pull a single number
|
|
202
|
-
// a four-value shadow. All string parsing therefore happens on the JS
|
|
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
|
|
267
|
+
* `boxShadow`, whose slot carries the index-keyed layer payload (see
|
|
268
|
+
* `STRUCTURED_KEYS`).
|
|
257
269
|
*/
|
|
258
|
-
type AnimatableSlotValue = number | string |
|
|
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:
|
|
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
|
-
//
|
|
345
|
-
// an initial seed for any color animation (no jarring opaque flash
|
|
346
|
-
// when `initial` is omitted) and
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
color
|
|
351
|
-
|
|
352
|
-
|
|
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 =
|
|
751
|
+
styleResting.boxShadow = layersToPayload(
|
|
752
|
+
styleRestingShadow.layers,
|
|
753
|
+
)
|
|
734
754
|
}
|
|
735
755
|
continue
|
|
736
756
|
}
|
|
737
757
|
const v = styleValueFor(flat, key)
|
|
738
|
-
|
|
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')
|
|
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
|
-
|
|
822
|
+
const seed = restValue(a) ?? styleResting[key] ?? DEFAULT_RESTING[key]
|
|
823
|
+
return COLOR_KEY_SET.has(key) ? normalizeAnimatableColor(seed) : seed
|
|
794
824
|
}
|
|
795
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1247
|
-
|
|
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
|
|
1250
|
-
//
|
|
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 =
|
|
1293
|
+
out.boxShadow = payloadToLayers(payload)
|
|
1253
1294
|
} else {
|
|
1254
1295
|
const withInset = []
|
|
1255
|
-
for (let i = 0; i
|
|
1256
|
-
withInset.push({ ...
|
|
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 =
|
|
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:
|
|
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,
|
package/src/motion/index.ts
CHANGED
|
@@ -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
|
package/src/values/useScroll.ts
CHANGED
|
@@ -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
|
|
15
|
-
*
|
|
16
|
-
* as a worklet — but the type narrows to the same
|
|
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
|
|
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)
|
package/dist/chunk-67GHRCF6.js
DELETED
package/dist/chunk-GPOMFIIU.js
DELETED
package/dist/chunk-K63LXGKS.js
DELETED