@rootnative/inertia 0.0.4 → 0.0.6
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 +87 -1
- package/README.md +5 -1
- package/dist/{chunk-55W7BNO2.mjs → chunk-2ICQLWH2.mjs} +211 -93
- package/dist/{chunk-D5KAHWMC.js → chunk-4NAMD62I.js} +7 -7
- package/dist/{chunk-CENTULW6.js → chunk-5MGWHOSV.js} +2 -2
- package/dist/{chunk-MYE5NMXW.js → chunk-767UKZXG.js} +235 -116
- package/dist/{chunk-NAOXQJ7U.mjs → chunk-BAAQI37F.mjs} +1 -1
- package/dist/{chunk-RF7J5FRM.mjs → chunk-C3EDC5ZW.mjs} +1 -1
- package/dist/{chunk-YKGY22SB.mjs → chunk-CMHVF6F4.mjs} +1 -1
- package/dist/{chunk-4ASOELLA.mjs → chunk-F7LJX56B.mjs} +1 -1
- package/dist/chunk-FWWVHLXB.js +8 -0
- package/dist/chunk-K5SI6VXS.js +8 -0
- package/dist/{chunk-WVRCKOPO.js → chunk-OBRGJAST.js} +3 -3
- package/dist/{chunk-K3CLP74S.mjs → chunk-OW5XTGVN.mjs} +2 -2
- package/dist/{chunk-J5Q46OPW.mjs → chunk-PFPO7DX2.mjs} +1 -1
- package/dist/{chunk-7A6WTXNK.js → chunk-PM6CVGXJ.js} +1 -0
- package/dist/{chunk-TU2XFPAK.mjs → chunk-REYL77RE.mjs} +1 -0
- package/dist/chunk-STARIT6W.js +8 -0
- package/dist/{chunk-XMEVPEMH.js → chunk-X7B5WR5A.js} +2 -2
- package/dist/{chunk-QKC3APP4.mjs → chunk-Z3HCJ43H.mjs} +1 -1
- package/dist/gestureLayer/index.d.mts +2 -2
- package/dist/gestureLayer/index.d.ts +2 -2
- package/dist/gestureLayer/index.js +10 -10
- package/dist/gestureLayer/index.mjs +3 -3
- package/dist/index.d.mts +32 -4
- package/dist/index.d.ts +32 -4
- package/dist/index.js +52 -48
- package/dist/index.mjs +17 -17
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +5 -5
- package/dist/motion/Image.mjs +4 -4
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +5 -5
- package/dist/motion/Pressable.mjs +4 -4
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +5 -5
- package/dist/motion/ScrollView.mjs +4 -4
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +5 -5
- package/dist/motion/Text.mjs +4 -4
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +5 -5
- package/dist/motion/View.mjs +4 -4
- package/dist/touch/index.d.mts +1 -1
- package/dist/touch/index.d.ts +1 -1
- package/dist/touch/index.js +3 -3
- package/dist/touch/index.mjs +1 -1
- package/dist/{types-37pN82yh.d.mts → types-BQgLJeQG.d.mts} +39 -3
- package/dist/{types-37pN82yh.d.ts → types-BQgLJeQG.d.ts} +39 -3
- package/dist/{useGesture-Cl4uzZIr.d.ts → useGesture-B0_CzOUz.d.ts} +1 -1
- package/dist/{useGesture-_IKkS8Dv.d.mts → useGesture-DfaTx-3t.d.mts} +1 -1
- package/llms.txt +1 -0
- package/package.json +1 -1
- package/src/index.ts +4 -0
- package/src/internal/boxShadow.ts +71 -9
- package/src/internal/color.ts +70 -0
- package/src/motion/createMotionComponent.tsx +238 -108
- package/src/transitions/resolveSequence.ts +12 -0
- package/src/types.ts +106 -3
- package/dist/chunk-5SRD2WCO.js +0 -8
- package/dist/chunk-TVFNJ25Z.js +0 -8
- package/dist/chunk-VLDIFL3F.js +0 -8
|
@@ -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,
|
|
@@ -91,6 +98,78 @@ const NUMERIC_TOP_LEVEL_KEYS = [
|
|
|
91
98
|
'shadowOpacity',
|
|
92
99
|
'shadowRadius',
|
|
93
100
|
'elevation',
|
|
101
|
+
// ─── Added in 0.0.5 ──────────────────────────────────────────────────────
|
|
102
|
+
//
|
|
103
|
+
// Every key below rides the generic numeric path: one shared value, resolved
|
|
104
|
+
// on the JS thread, emitted by the worklet through the same `out[key] = v`
|
|
105
|
+
// branch as `opacity`. None needs a new interpolation mode, so the cost is
|
|
106
|
+
// the shared value plus a `DEFAULT_RESTING` entry.
|
|
107
|
+
//
|
|
108
|
+
// The load-bearing constraint is the resting default, not the plumbing. A
|
|
109
|
+
// key declared only in `gesture` / `exit` / a non-active variant rests at
|
|
110
|
+
// `DEFAULT_RESTING` unless the static `style` names it, and the animated
|
|
111
|
+
// style merges *after* `style` — so a non-identity default silently stomps
|
|
112
|
+
// the layout. That is the `0.0.3` P0 class, and it is why the sizing and
|
|
113
|
+
// spacing keys below default to `0` only in the sense RN itself does (an
|
|
114
|
+
// unset `padding` *is* 0); `minWidth`/`maxWidth`/`aspectRatio` are
|
|
115
|
+
// deliberately excluded — their "unset" is not a number, so no default can
|
|
116
|
+
// stand in for it without changing layout on activation.
|
|
117
|
+
//
|
|
118
|
+
// Per-corner radii. Animating one corner is common (a card expanding into a
|
|
119
|
+
// sheet keeps its top corners and squares off the bottom); `borderRadius`
|
|
120
|
+
// alone can't express it.
|
|
121
|
+
'borderTopLeftRadius',
|
|
122
|
+
'borderTopRightRadius',
|
|
123
|
+
'borderBottomLeftRadius',
|
|
124
|
+
'borderBottomRightRadius',
|
|
125
|
+
// Border widths. `borderWidth` is the common case; the per-edge keys matter
|
|
126
|
+
// for underline-style focus affordances (`borderBottomWidth` on a field).
|
|
127
|
+
'borderWidth',
|
|
128
|
+
'borderTopWidth',
|
|
129
|
+
'borderRightWidth',
|
|
130
|
+
'borderBottomWidth',
|
|
131
|
+
'borderLeftWidth',
|
|
132
|
+
// Absolute-position insets. Bread-and-butter for drawers, tooltips, and
|
|
133
|
+
// anything pinned to an edge that slides in.
|
|
134
|
+
'top',
|
|
135
|
+
'right',
|
|
136
|
+
'bottom',
|
|
137
|
+
'left',
|
|
138
|
+
// Spacing. Padding animates the box from the inside (a button growing its
|
|
139
|
+
// hit area on press); margin shifts it within its parent's flow.
|
|
140
|
+
'padding',
|
|
141
|
+
'paddingTop',
|
|
142
|
+
'paddingRight',
|
|
143
|
+
'paddingBottom',
|
|
144
|
+
'paddingLeft',
|
|
145
|
+
'paddingHorizontal',
|
|
146
|
+
'paddingVertical',
|
|
147
|
+
'margin',
|
|
148
|
+
'marginTop',
|
|
149
|
+
'marginRight',
|
|
150
|
+
'marginBottom',
|
|
151
|
+
'marginLeft',
|
|
152
|
+
'marginHorizontal',
|
|
153
|
+
'marginVertical',
|
|
154
|
+
// Flex sizing. `flex` / `flexGrow` interpolate the split between siblings —
|
|
155
|
+
// the idiomatic RN way to animate a pane resize without measuring.
|
|
156
|
+
'flex',
|
|
157
|
+
'flexGrow',
|
|
158
|
+
'flexShrink',
|
|
159
|
+
// Text metrics. `TextStyle`-only at the type level (`AnimateStyle<C>` gates
|
|
160
|
+
// them per primitive), but the runtime table is shared across primitives —
|
|
161
|
+
// an unused slot is one ref, same as `tintColor` has always been.
|
|
162
|
+
'fontSize',
|
|
163
|
+
'letterSpacing',
|
|
164
|
+
'lineHeight',
|
|
165
|
+
// Stacking. Integer-valued in practice, and interpolating it mid-flight is
|
|
166
|
+
// rarely what you want, but a `no-animation` transition on `zIndex` is the
|
|
167
|
+
// clean way to reorder at a step boundary in a sequence.
|
|
168
|
+
'zIndex',
|
|
169
|
+
// Gap. Row/column gaps animate a list's density without touching children.
|
|
170
|
+
'gap',
|
|
171
|
+
'rowGap',
|
|
172
|
+
'columnGap',
|
|
94
173
|
] as const
|
|
95
174
|
|
|
96
175
|
// Color-valued keys. Reanimated's value setter detects color strings and
|
|
@@ -119,16 +198,20 @@ const COLOR_KEYS = [
|
|
|
119
198
|
const SHADOW_OFFSET_KEYS = ['shadowOffsetWidth', 'shadowOffsetHeight'] as const
|
|
120
199
|
|
|
121
200
|
// Keys whose shared value holds a structure rather than a scalar. `boxShadow`
|
|
122
|
-
// is the only one: its slot carries
|
|
201
|
+
// is the only one: its slot carries the layers keyed by index, which
|
|
123
202
|
// Reanimated's animation drivers recurse into, animating each leaf number and
|
|
124
|
-
// color independently (`
|
|
125
|
-
//
|
|
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).
|
|
126
209
|
//
|
|
127
|
-
// Passing the CSS string through instead would NOT work — a box-shadow
|
|
128
|
-
// isn't a color, so it lands in Reanimated's prefix-number-suffix
|
|
129
|
-
// which is built for values like '100%' and would pull a single number
|
|
130
|
-
// a four-value shadow. All string parsing therefore happens on the JS
|
|
131
|
-
// 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`.
|
|
132
215
|
const STRUCTURED_KEYS = ['boxShadow'] as const
|
|
133
216
|
|
|
134
217
|
// Keys a shared-element transition (`layoutId`) carries from the source
|
|
@@ -181,15 +264,16 @@ const SHARED_STYLE_KEY_SET = new Set<AnimatableKey>(SHARED_STYLE_KEYS)
|
|
|
181
264
|
|
|
182
265
|
/**
|
|
183
266
|
* What a per-key shared value can hold. Scalars for every key except
|
|
184
|
-
* `boxShadow`, whose slot carries the layer
|
|
267
|
+
* `boxShadow`, whose slot carries the index-keyed layer payload (see
|
|
268
|
+
* `STRUCTURED_KEYS`).
|
|
185
269
|
*/
|
|
186
|
-
type AnimatableSlotValue = number | string |
|
|
270
|
+
type AnimatableSlotValue = number | string | BoxShadowPayload
|
|
187
271
|
|
|
188
272
|
/**
|
|
189
273
|
* Resting `boxShadow` — no shadow at all. Frozen and hoisted so every
|
|
190
274
|
* primitive shares one reference and an untouched slot never allocates.
|
|
191
275
|
*/
|
|
192
|
-
const NO_BOX_SHADOW:
|
|
276
|
+
const NO_BOX_SHADOW: BoxShadowPayload = Object.freeze({})
|
|
193
277
|
|
|
194
278
|
const GESTURE_LAYER_NAMES = [
|
|
195
279
|
'hovered',
|
|
@@ -221,15 +305,69 @@ const DEFAULT_RESTING: Record<AnimatableKey, AnimatableSlotValue> = {
|
|
|
221
305
|
shadowOpacity: 0,
|
|
222
306
|
shadowRadius: 0,
|
|
223
307
|
elevation: 0,
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
308
|
+
// 0.0.5 keys. Every one of these is 0 because that is RN's own unset value
|
|
309
|
+
// for it — an element with no `paddingTop` has 0 padding, no `borderWidth`
|
|
310
|
+
// has none, no `top` is unpinned at 0 within its positioning context. So a
|
|
311
|
+
// key that reaches its resting default lands where the element already was.
|
|
312
|
+
//
|
|
313
|
+
// The exception worth naming: `flex` / `flexGrow` / `flexShrink` do NOT have
|
|
314
|
+
// 0 as a universal identity (`flexShrink` defaults to 1 on the web, and RN's
|
|
315
|
+
// own default differs by axis). They are still 0 here, because the style-scan
|
|
316
|
+
// in the resting pass reads the real value off the static `style` whenever it
|
|
317
|
+
// is declared — and a consumer animating flex without declaring it is asking
|
|
318
|
+
// for the from-0 growth, which is the readable interpretation.
|
|
319
|
+
borderTopLeftRadius: 0,
|
|
320
|
+
borderTopRightRadius: 0,
|
|
321
|
+
borderBottomLeftRadius: 0,
|
|
322
|
+
borderBottomRightRadius: 0,
|
|
323
|
+
borderWidth: 0,
|
|
324
|
+
borderTopWidth: 0,
|
|
325
|
+
borderRightWidth: 0,
|
|
326
|
+
borderBottomWidth: 0,
|
|
327
|
+
borderLeftWidth: 0,
|
|
328
|
+
top: 0,
|
|
329
|
+
right: 0,
|
|
330
|
+
bottom: 0,
|
|
331
|
+
left: 0,
|
|
332
|
+
padding: 0,
|
|
333
|
+
paddingTop: 0,
|
|
334
|
+
paddingRight: 0,
|
|
335
|
+
paddingBottom: 0,
|
|
336
|
+
paddingLeft: 0,
|
|
337
|
+
paddingHorizontal: 0,
|
|
338
|
+
paddingVertical: 0,
|
|
339
|
+
margin: 0,
|
|
340
|
+
marginTop: 0,
|
|
341
|
+
marginRight: 0,
|
|
342
|
+
marginBottom: 0,
|
|
343
|
+
marginLeft: 0,
|
|
344
|
+
marginHorizontal: 0,
|
|
345
|
+
marginVertical: 0,
|
|
346
|
+
flex: 0,
|
|
347
|
+
flexGrow: 0,
|
|
348
|
+
flexShrink: 0,
|
|
349
|
+
fontSize: 0,
|
|
350
|
+
letterSpacing: 0,
|
|
351
|
+
lineHeight: 0,
|
|
352
|
+
zIndex: 0,
|
|
353
|
+
gap: 0,
|
|
354
|
+
rowGap: 0,
|
|
355
|
+
columnGap: 0,
|
|
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,
|
|
233
371
|
shadowOffsetWidth: 0,
|
|
234
372
|
shadowOffsetHeight: 0,
|
|
235
373
|
boxShadow: NO_BOX_SHADOW,
|
|
@@ -610,12 +748,20 @@ export function createMotionComponent<C extends ComponentType<any>>(
|
|
|
610
748
|
const raw = flat.boxShadow as BoxShadowInput | undefined
|
|
611
749
|
if (raw !== undefined) {
|
|
612
750
|
styleRestingShadow = normalizeBoxShadow(raw)
|
|
613
|
-
styleResting.boxShadow =
|
|
751
|
+
styleResting.boxShadow = layersToPayload(
|
|
752
|
+
styleRestingShadow.layers,
|
|
753
|
+
)
|
|
614
754
|
}
|
|
615
755
|
continue
|
|
616
756
|
}
|
|
617
757
|
const v = styleValueFor(flat, key)
|
|
618
|
-
|
|
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
|
+
}
|
|
619
765
|
}
|
|
620
766
|
}
|
|
621
767
|
}
|
|
@@ -634,14 +780,13 @@ export function createMotionComponent<C extends ComponentType<any>>(
|
|
|
634
780
|
boxShadowSeedRef.current =
|
|
635
781
|
source !== undefined
|
|
636
782
|
? normalizeBoxShadow(source)
|
|
637
|
-
: (styleRestingShadow ?? {
|
|
638
|
-
layers: [...NO_BOX_SHADOW],
|
|
639
|
-
insets: null,
|
|
640
|
-
})
|
|
783
|
+
: (styleRestingShadow ?? { layers: [], insets: null })
|
|
641
784
|
}
|
|
642
785
|
|
|
643
786
|
const sharedValues = useAnimatableSharedValues((key) => {
|
|
644
|
-
if (key === 'boxShadow')
|
|
787
|
+
if (key === 'boxShadow') {
|
|
788
|
+
return layersToPayload(boxShadowSeedRef.current!.layers)
|
|
789
|
+
}
|
|
645
790
|
// Shadow offset synthetics seed from the corresponding axis on the
|
|
646
791
|
// `shadowOffset: { width, height }` source — the consumer doesn't write
|
|
647
792
|
// `shadowOffsetWidth` / `shadowOffsetHeight` directly. Fall back to the
|
|
@@ -668,16 +813,21 @@ export function createMotionComponent<C extends ComponentType<any>>(
|
|
|
668
813
|
DEFAULT_RESTING[key]
|
|
669
814
|
)
|
|
670
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.
|
|
671
820
|
if (initial === false) {
|
|
672
821
|
const a = animateRecord[key]
|
|
673
|
-
|
|
822
|
+
const seed = restValue(a) ?? styleResting[key] ?? DEFAULT_RESTING[key]
|
|
823
|
+
return COLOR_KEY_SET.has(key) ? normalizeAnimatableColor(seed) : seed
|
|
674
824
|
}
|
|
675
|
-
|
|
825
|
+
const seed =
|
|
676
826
|
initialRecord?.[key] ??
|
|
677
827
|
restValue(animateRecord[key]) ??
|
|
678
828
|
styleResting[key] ??
|
|
679
829
|
DEFAULT_RESTING[key]
|
|
680
|
-
)
|
|
830
|
+
return COLOR_KEY_SET.has(key) ? normalizeAnimatableColor(seed) : seed
|
|
681
831
|
})
|
|
682
832
|
|
|
683
833
|
// Keep never-driven keys tracking the *live* static style. The seed above
|
|
@@ -894,8 +1044,17 @@ export function createMotionComponent<C extends ComponentType<any>>(
|
|
|
894
1044
|
isExiting ? onSettle : undefined,
|
|
895
1045
|
TRANSFORM_KEY_SET.has(key) ? transformGroup : undefined,
|
|
896
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.
|
|
897
1054
|
sharedValues[key].value = resolveAnimatableValue(
|
|
898
|
-
|
|
1055
|
+
COLOR_KEY_SET.has(key)
|
|
1056
|
+
? normalizeAnimatableColorTarget(target)
|
|
1057
|
+
: target,
|
|
899
1058
|
cfg,
|
|
900
1059
|
factory,
|
|
901
1060
|
) as never
|
|
@@ -1123,17 +1282,19 @@ export function createMotionComponent<C extends ComponentType<any>>(
|
|
|
1123
1282
|
out.shadowOffset = { width: shadowOffsetW, height: shadowOffsetH }
|
|
1124
1283
|
}
|
|
1125
1284
|
if (hasBoxShadow) {
|
|
1126
|
-
|
|
1127
|
-
|
|
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
|
|
1128
1289
|
const insets = boxShadowInsets.value
|
|
1129
|
-
// Fast path — no inset layer anywhere, so
|
|
1130
|
-
//
|
|
1290
|
+
// Fast path — no inset layer anywhere, so each layer crosses over by
|
|
1291
|
+
// reference and only the array itself is allocated.
|
|
1131
1292
|
if (insets === null) {
|
|
1132
|
-
out.boxShadow =
|
|
1293
|
+
out.boxShadow = payloadToLayers(payload)
|
|
1133
1294
|
} else {
|
|
1134
1295
|
const withInset = []
|
|
1135
|
-
for (let i = 0; i
|
|
1136
|
-
withInset.push({ ...
|
|
1296
|
+
for (let i = 0; payload[i] !== undefined; i++) {
|
|
1297
|
+
withInset.push({ ...payload[i], inset: insets[i] })
|
|
1137
1298
|
}
|
|
1138
1299
|
out.boxShadow = withInset
|
|
1139
1300
|
}
|
|
@@ -1245,74 +1406,38 @@ type SharedValueMap = Record<AnimatableKey, SharedValue<AnimatableSlotValue>>
|
|
|
1245
1406
|
* are stable across renders (Reanimated's `useSharedValue` is a `useRef`
|
|
1246
1407
|
* under the hood), so snapshotting the wrapping object once is safe.
|
|
1247
1408
|
*
|
|
1248
|
-
* Hooks are called
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1252
|
-
*
|
|
1409
|
+
* Hooks are called by iterating `ALL_KEYS`, which is a module-level `as const`
|
|
1410
|
+
* array — its length and order are fixed at module evaluation, so the hook
|
|
1411
|
+
* sequence is identical on every render of every instance. That satisfies
|
|
1412
|
+
* rules-of-hooks exactly as a hand-written list does, and it is what keeps this
|
|
1413
|
+
* function from growing a line per key: the 0.0.5 additions took the table from
|
|
1414
|
+
* 23 keys to 63, and 63 near-identical `useSharedValue` lines is both a bigger
|
|
1415
|
+
* bundle and a standing invitation to add a key in one list but not the other
|
|
1416
|
+
* (the failure mode is a `sharedValues[key]` of `undefined` inside the worklet,
|
|
1417
|
+
* which is exactly how the first draft of that change broke).
|
|
1418
|
+
*
|
|
1419
|
+
* The ESLint exhaustive-deps rule can't see through the loop, hence the
|
|
1420
|
+
* disable — the invariant it would check for us is asserted above instead.
|
|
1421
|
+
*
|
|
1422
|
+
* Unused shared values are cheap; the worklet skips them via `activeKeysRef`.
|
|
1423
|
+
* Color keys are seeded with the initial color string so Reanimated's value
|
|
1424
|
+
* setter recognizes the slot as a color from the first `withSpring` /
|
|
1425
|
+
* `withTiming` call.
|
|
1253
1426
|
*/
|
|
1254
1427
|
function useAnimatableSharedValues(
|
|
1255
1428
|
init: (key: AnimatableKey) => AnimatableSlotValue,
|
|
1256
1429
|
): SharedValueMap {
|
|
1257
|
-
const
|
|
1258
|
-
const
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
const rotate = useSharedValue<AnimatableSlotValue>(init('rotate'))
|
|
1263
|
-
const rotateX = useSharedValue<AnimatableSlotValue>(init('rotateX'))
|
|
1264
|
-
const rotateY = useSharedValue<AnimatableSlotValue>(init('rotateY'))
|
|
1265
|
-
const opacity = useSharedValue<AnimatableSlotValue>(init('opacity'))
|
|
1266
|
-
const width = useSharedValue<AnimatableSlotValue>(init('width'))
|
|
1267
|
-
const height = useSharedValue<AnimatableSlotValue>(init('height'))
|
|
1268
|
-
const borderRadius = useSharedValue<AnimatableSlotValue>(init('borderRadius'))
|
|
1269
|
-
const shadowOpacity = useSharedValue<AnimatableSlotValue>(
|
|
1270
|
-
init('shadowOpacity'),
|
|
1271
|
-
)
|
|
1272
|
-
const shadowRadius = useSharedValue<AnimatableSlotValue>(init('shadowRadius'))
|
|
1273
|
-
const elevation = useSharedValue<AnimatableSlotValue>(init('elevation'))
|
|
1274
|
-
const backgroundColor = useSharedValue<AnimatableSlotValue>(
|
|
1275
|
-
init('backgroundColor'),
|
|
1276
|
-
)
|
|
1277
|
-
const borderColor = useSharedValue<AnimatableSlotValue>(init('borderColor'))
|
|
1278
|
-
const color = useSharedValue<AnimatableSlotValue>(init('color'))
|
|
1279
|
-
const tintColor = useSharedValue<AnimatableSlotValue>(init('tintColor'))
|
|
1280
|
-
const shadowColor = useSharedValue<AnimatableSlotValue>(init('shadowColor'))
|
|
1281
|
-
const shadowOffsetWidth = useSharedValue<AnimatableSlotValue>(
|
|
1282
|
-
init('shadowOffsetWidth'),
|
|
1283
|
-
)
|
|
1284
|
-
const shadowOffsetHeight = useSharedValue<AnimatableSlotValue>(
|
|
1285
|
-
init('shadowOffsetHeight'),
|
|
1286
|
-
)
|
|
1287
|
-
const boxShadow = useSharedValue<AnimatableSlotValue>(init('boxShadow'))
|
|
1430
|
+
const entries: [AnimatableKey, SharedValue<AnimatableSlotValue>][] = []
|
|
1431
|
+
for (const key of ALL_KEYS) {
|
|
1432
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
1433
|
+
entries.push([key, useSharedValue<AnimatableSlotValue>(init(key))])
|
|
1434
|
+
}
|
|
1288
1435
|
|
|
1289
1436
|
const ref = useRef<SharedValueMap | null>(null)
|
|
1290
1437
|
if (ref.current === null) {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
scale,
|
|
1295
|
-
scaleX,
|
|
1296
|
-
scaleY,
|
|
1297
|
-
rotate,
|
|
1298
|
-
rotateX,
|
|
1299
|
-
rotateY,
|
|
1300
|
-
opacity,
|
|
1301
|
-
width,
|
|
1302
|
-
height,
|
|
1303
|
-
borderRadius,
|
|
1304
|
-
shadowOpacity,
|
|
1305
|
-
shadowRadius,
|
|
1306
|
-
elevation,
|
|
1307
|
-
backgroundColor,
|
|
1308
|
-
borderColor,
|
|
1309
|
-
color,
|
|
1310
|
-
tintColor,
|
|
1311
|
-
shadowColor,
|
|
1312
|
-
shadowOffsetWidth,
|
|
1313
|
-
shadowOffsetHeight,
|
|
1314
|
-
boxShadow,
|
|
1315
|
-
}
|
|
1438
|
+
const map = {} as SharedValueMap
|
|
1439
|
+
for (const [key, sv] of entries) map[key] = sv
|
|
1440
|
+
ref.current = map
|
|
1316
1441
|
}
|
|
1317
1442
|
|
|
1318
1443
|
// Cancel every in-flight per-key animation when the primitive unmounts, so
|
|
@@ -1402,6 +1527,13 @@ function makeKeyCallbackFactory(
|
|
|
1402
1527
|
const reportedIteration = state.iteration
|
|
1403
1528
|
if (phase === 'sequence' || phase === 'repeat') state.iteration++
|
|
1404
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
|
+
|
|
1405
1537
|
const fn = onAnimationEndRef.current
|
|
1406
1538
|
if (fn) {
|
|
1407
1539
|
// Transform-group coalescing: a multi-axis translate / scale /
|
|
@@ -1417,7 +1549,7 @@ function makeKeyCallbackFactory(
|
|
|
1417
1549
|
fn({
|
|
1418
1550
|
key: 'transform' as never,
|
|
1419
1551
|
finished,
|
|
1420
|
-
value,
|
|
1552
|
+
value: reportedValue,
|
|
1421
1553
|
target,
|
|
1422
1554
|
phase,
|
|
1423
1555
|
step,
|
|
@@ -1428,7 +1560,7 @@ function makeKeyCallbackFactory(
|
|
|
1428
1560
|
fn({
|
|
1429
1561
|
key: key as never,
|
|
1430
1562
|
finished,
|
|
1431
|
-
value,
|
|
1563
|
+
value: reportedValue,
|
|
1432
1564
|
target,
|
|
1433
1565
|
phase,
|
|
1434
1566
|
step,
|
|
@@ -1525,20 +1657,18 @@ function driveBoxShadow(
|
|
|
1525
1657
|
cfg: TransitionConfig | undefined,
|
|
1526
1658
|
factory: CallbackFactory | undefined,
|
|
1527
1659
|
): void {
|
|
1528
|
-
const currentLayers =
|
|
1529
|
-
? (slot.value as readonly AnimatedBoxShadowLayer[])
|
|
1530
|
-
: NO_BOX_SHADOW
|
|
1660
|
+
const currentLayers = payloadToLayers(slot.value as BoxShadowPayload)
|
|
1531
1661
|
const { from, to, insets } = prepareBoxShadowAnimation(
|
|
1532
|
-
{ layers:
|
|
1662
|
+
{ layers: currentLayers, insets: insetSlot.value },
|
|
1533
1663
|
target,
|
|
1534
1664
|
)
|
|
1535
1665
|
insetSlot.value = insets
|
|
1536
|
-
if (from.length !== currentLayers.length) slot.value = from
|
|
1666
|
+
if (from.length !== currentLayers.length) slot.value = layersToPayload(from)
|
|
1537
1667
|
// `resolveTransition` is typed for the scalar surface it was written for;
|
|
1538
1668
|
// Reanimated itself accepts the structured target and recurses into it.
|
|
1539
1669
|
slot.value = resolveTransition(
|
|
1540
1670
|
cfg,
|
|
1541
|
-
to as unknown as number,
|
|
1671
|
+
layersToPayload(to) as unknown as number,
|
|
1542
1672
|
factory?.('animation', undefined),
|
|
1543
1673
|
) as AnimatableSlotValue
|
|
1544
1674
|
}
|
|
@@ -77,6 +77,18 @@ function mergeTransition(
|
|
|
77
77
|
base: TransitionConfig | undefined,
|
|
78
78
|
override: Partial<TransitionConfig>,
|
|
79
79
|
): TransitionConfig {
|
|
80
|
+
// A `no-animation` base is a ceiling, not a default, so no step override can
|
|
81
|
+
// talk its way past it. This is the reduced-motion gate: `configFor` in the
|
|
82
|
+
// factory swaps every per-key transition for `{ type: 'no-animation' }`, and
|
|
83
|
+
// the step-type rule below would otherwise hand a step its own `withTiming`
|
|
84
|
+
// back — silently animating for a user who asked the OS not to. Keep this
|
|
85
|
+
// branch first; it is the whole reason the gate holds for sequences.
|
|
86
|
+
//
|
|
87
|
+
// Returning `base` also drops any step `delay`, which matches how the rest
|
|
88
|
+
// of the resolver already treats this type: `delayOf` and `repeatOf` both
|
|
89
|
+
// return `undefined` for `no-animation`, so a snap is never deferred or
|
|
90
|
+
// repeated anywhere in the library.
|
|
91
|
+
if (base?.type === 'no-animation') return base
|
|
80
92
|
// If the override declares a `type`, it wins outright — mixing fields from
|
|
81
93
|
// a spring base into a timing override produces garbage. Otherwise inherit
|
|
82
94
|
// the base's type and shallow-merge the rest.
|
package/src/types.ts
CHANGED
|
@@ -217,6 +217,22 @@ type AnimatableStructuredExtras<S> = 'boxShadow' extends keyof S
|
|
|
217
217
|
: // eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
218
218
|
{}
|
|
219
219
|
|
|
220
|
+
/**
|
|
221
|
+
* The `transform: [...]` array form, passed through as the underlying style
|
|
222
|
+
* types it. Inertia reads transform entries out of the array (see
|
|
223
|
+
* `styleValueFor` in `createMotionComponent`) rather than treating the array as
|
|
224
|
+
* an animatable scalar, so it is exempted from the `AnimatableValue` mapping —
|
|
225
|
+
* wrapping it there would offer a nonsensical `transform: [[...], [...]]`
|
|
226
|
+
* keyframe form.
|
|
227
|
+
*
|
|
228
|
+
* Conditional on `S` for the same reason as `boxShadow`: only appears where the
|
|
229
|
+
* underlying style actually has it.
|
|
230
|
+
*/
|
|
231
|
+
type AnimatableTransformArray<S> = 'transform' extends keyof S
|
|
232
|
+
? { transform?: S['transform'] }
|
|
233
|
+
: // eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
234
|
+
{}
|
|
235
|
+
|
|
220
236
|
/**
|
|
221
237
|
* The animation state shape inferred from the underlying component's style
|
|
222
238
|
* prop. We narrow to the value side of `style` so consumers see ViewStyle on
|
|
@@ -231,11 +247,98 @@ type AnimatableStructuredExtras<S> = 'boxShadow' extends keyof S
|
|
|
231
247
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
232
248
|
type _StyleValue<T> = Exclude<T, (...args: any[]) => any>
|
|
233
249
|
|
|
250
|
+
/**
|
|
251
|
+
* The style keys Inertia's runtime actually drives — the type-level mirror of
|
|
252
|
+
* `ALL_KEYS` in `createMotionComponent`, minus the `shadowOffset*` synthetics
|
|
253
|
+
* (consumers write the nested `shadowOffset` object, not the axes) and minus
|
|
254
|
+
* `boxShadow` (handled by `AnimatableStructuredExtras`, whose value shape
|
|
255
|
+
* deliberately departs from `AnimatableValue`).
|
|
256
|
+
*
|
|
257
|
+
* **This list and `ALL_KEYS` must stay in sync.** They are separate because one
|
|
258
|
+
* is a type and the other is a runtime array, and TypeScript can't derive the
|
|
259
|
+
* former from a value living in a module that imports this one. The direction
|
|
260
|
+
* that matters: a key here but not in `ALL_KEYS` typechecks and then silently
|
|
261
|
+
* does nothing at runtime — which is precisely the defect this type was
|
|
262
|
+
* introduced to kill. `animate-keys.test-d.tsx` pins the two together.
|
|
263
|
+
*
|
|
264
|
+
* Before 0.0.5 this type mapped over the component's *entire* style surface, so
|
|
265
|
+
* `animate={{ paddingTop: 40 }}` compiled cleanly and was then dropped on the
|
|
266
|
+
* floor — no error, no warning. That contradicted the library's own headline
|
|
267
|
+
* differentiator (wrong props should error, not go unnoticed), so the mapping is
|
|
268
|
+
* now an intersection: a key must be both animatable by Inertia *and* present on
|
|
269
|
+
* the underlying component's style prop.
|
|
270
|
+
*/
|
|
271
|
+
type AnimatableStyleKey =
|
|
272
|
+
// Transform axes surfaced as top-level keys.
|
|
273
|
+
| 'translateX'
|
|
274
|
+
| 'translateY'
|
|
275
|
+
| 'scaleX'
|
|
276
|
+
| 'scaleY'
|
|
277
|
+
// Numeric top-level keys.
|
|
278
|
+
| 'opacity'
|
|
279
|
+
| 'width'
|
|
280
|
+
| 'height'
|
|
281
|
+
| 'borderRadius'
|
|
282
|
+
| 'shadowOpacity'
|
|
283
|
+
| 'shadowRadius'
|
|
284
|
+
| 'elevation'
|
|
285
|
+
| 'borderTopLeftRadius'
|
|
286
|
+
| 'borderTopRightRadius'
|
|
287
|
+
| 'borderBottomLeftRadius'
|
|
288
|
+
| 'borderBottomRightRadius'
|
|
289
|
+
| 'borderWidth'
|
|
290
|
+
| 'borderTopWidth'
|
|
291
|
+
| 'borderRightWidth'
|
|
292
|
+
| 'borderBottomWidth'
|
|
293
|
+
| 'borderLeftWidth'
|
|
294
|
+
| 'top'
|
|
295
|
+
| 'right'
|
|
296
|
+
| 'bottom'
|
|
297
|
+
| 'left'
|
|
298
|
+
| 'padding'
|
|
299
|
+
| 'paddingTop'
|
|
300
|
+
| 'paddingRight'
|
|
301
|
+
| 'paddingBottom'
|
|
302
|
+
| 'paddingLeft'
|
|
303
|
+
| 'paddingHorizontal'
|
|
304
|
+
| 'paddingVertical'
|
|
305
|
+
| 'margin'
|
|
306
|
+
| 'marginTop'
|
|
307
|
+
| 'marginRight'
|
|
308
|
+
| 'marginBottom'
|
|
309
|
+
| 'marginLeft'
|
|
310
|
+
| 'marginHorizontal'
|
|
311
|
+
| 'marginVertical'
|
|
312
|
+
| 'flex'
|
|
313
|
+
| 'flexGrow'
|
|
314
|
+
| 'flexShrink'
|
|
315
|
+
| 'fontSize'
|
|
316
|
+
| 'letterSpacing'
|
|
317
|
+
| 'lineHeight'
|
|
318
|
+
| 'zIndex'
|
|
319
|
+
| 'gap'
|
|
320
|
+
| 'rowGap'
|
|
321
|
+
| 'columnGap'
|
|
322
|
+
// Color keys.
|
|
323
|
+
| 'backgroundColor'
|
|
324
|
+
| 'borderColor'
|
|
325
|
+
| 'color'
|
|
326
|
+
| 'tintColor'
|
|
327
|
+
| 'shadowColor'
|
|
328
|
+
// The one nested-object style prop, written as `{ width, height }`.
|
|
329
|
+
| 'shadowOffset'
|
|
330
|
+
|
|
234
331
|
export type AnimateStyle<C> = C extends { style?: infer Raw }
|
|
235
332
|
? _StyleValue<Raw> extends StyleProp<infer S>
|
|
236
|
-
?
|
|
237
|
-
|
|
238
|
-
|
|
333
|
+
? {
|
|
334
|
+
[K in keyof S as K extends AnimatableStyleKey ? K : never]?: K extends
|
|
335
|
+
| 'boxShadow'
|
|
336
|
+
| 'transform'
|
|
337
|
+
? never
|
|
338
|
+
: AnimatableValue<S[K]>
|
|
339
|
+
} & AnimatableTransformExtras &
|
|
340
|
+
AnimatableStructuredExtras<S> &
|
|
341
|
+
AnimatableTransformArray<S>
|
|
239
342
|
: never
|
|
240
343
|
: never
|
|
241
344
|
|
package/dist/chunk-5SRD2WCO.js
DELETED
package/dist/chunk-TVFNJ25Z.js
DELETED
package/dist/chunk-VLDIFL3F.js
DELETED