@onlynative/inertia 0.0.1-alpha.0 → 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.
- package/README.md +7 -7
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +84 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +85 -11
- package/dist/index.mjs.map +1 -1
- package/dist/motion/Image.d.mts +1 -1
- package/dist/motion/Image.d.ts +1 -1
- package/dist/motion/Image.js +84 -10
- package/dist/motion/Image.js.map +1 -1
- package/dist/motion/Image.mjs +85 -11
- package/dist/motion/Image.mjs.map +1 -1
- package/dist/motion/Pressable.d.mts +1 -1
- package/dist/motion/Pressable.d.ts +1 -1
- package/dist/motion/Pressable.js +84 -10
- package/dist/motion/Pressable.js.map +1 -1
- package/dist/motion/Pressable.mjs +85 -11
- package/dist/motion/Pressable.mjs.map +1 -1
- package/dist/motion/ScrollView.d.mts +1 -1
- package/dist/motion/ScrollView.d.ts +1 -1
- package/dist/motion/ScrollView.js +84 -10
- package/dist/motion/ScrollView.js.map +1 -1
- package/dist/motion/ScrollView.mjs +85 -11
- package/dist/motion/ScrollView.mjs.map +1 -1
- package/dist/motion/Text.d.mts +1 -1
- package/dist/motion/Text.d.ts +1 -1
- package/dist/motion/Text.js +84 -10
- package/dist/motion/Text.js.map +1 -1
- package/dist/motion/Text.mjs +85 -11
- package/dist/motion/Text.mjs.map +1 -1
- package/dist/motion/View.d.mts +1 -1
- package/dist/motion/View.d.ts +1 -1
- package/dist/motion/View.js +84 -10
- package/dist/motion/View.js.map +1 -1
- package/dist/motion/View.mjs +85 -11
- package/dist/motion/View.mjs.map +1 -1
- package/dist/testing/index.d.mts +57 -0
- package/dist/testing/index.d.ts +57 -0
- package/dist/testing/index.js +19 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/index.mjs +16 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/{types-CmbXx-G3.d.mts → types-DeZZzE_e.d.mts} +20 -3
- package/dist/{types-CmbXx-G3.d.ts → types-DeZZzE_e.d.ts} +20 -3
- package/llms.txt +5 -1
- package/package.json +19 -12
- package/src/gestures/focusVisibility.ts +61 -0
- package/src/gestures/index.ts +1 -0
- package/src/motion/createMotionComponent.tsx +132 -47
- package/src/testing/index.ts +78 -0
- package/src/types.ts +20 -3
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ export function FadeIn() {
|
|
|
42
42
|
- **Primitives** — `Motion.View`, `Motion.Text`, `Motion.Image`, `Motion.Pressable`, `Motion.ScrollView`. Per-primitive style inference (no shared `ViewStyle & TextStyle & ImageStyle` fallback).
|
|
43
43
|
- **Sequences and keyframes** — `animate={{ x: [0, 100, 0] }}` with per-step transitions; unified `repeat: number | 'infinite' | { count, alternate }`.
|
|
44
44
|
- **Variants** — `variants={{ open, closed }}` with `animate="open"`. Programmatic control via `useVariants` + `controller={...}`.
|
|
45
|
-
- **Gestures** — single `gesture` prop on every primitive: `gesture={{ pressed, focused, hovered }}`. Zero overhead when omitted.
|
|
45
|
+
- **Gestures** — single `gesture` prop on every primitive: `gesture={{ pressed, focused, focusVisible, hovered }}`. `focusVisible` engages only on keyboard focus (W3C `:focus-visible`) so click-focus on web doesn't flash a ring; on native it tracks `focused`. Zero overhead when omitted.
|
|
46
46
|
- **`<Presence>`** — mount/unmount transitions; exiting children automatically receive `pointerEvents: 'none'`.
|
|
47
47
|
- **`<MotionConfig reducedMotion>`** — OS reduce-motion honored end-to-end (`'user' | 'never' | 'always'`).
|
|
48
48
|
- **Per-primitive subpath imports** — `@onlynative/inertia/view`, `/text`, `/image`, `/pressable`, `/scroll-view`.
|
|
@@ -62,18 +62,18 @@ A `Motion.View`-only import currently bundles to ~3.2 kB brotlied (excluding pee
|
|
|
62
62
|
|
|
63
63
|
## Transitions
|
|
64
64
|
|
|
65
|
-
| `type` | Public config keys | Maps to
|
|
66
|
-
| -------------------- | -------------------------------------------------------------------------------------------- |
|
|
67
|
-
| `'spring'` (default) | `tension`, `friction`, `mass`, `velocity`, `restSpeedThreshold`, `restDisplacementThreshold` | `withSpring`
|
|
68
|
-
| `'timing'` | `duration`, `easing`, `delay` | `withTiming`
|
|
69
|
-
| `'decay'` | `velocity`, `deceleration`, `clamp` | `withDecay`
|
|
65
|
+
| `type` | Public config keys | Maps to |
|
|
66
|
+
| -------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------- |
|
|
67
|
+
| `'spring'` (default) | `tension`, `friction`, `mass`, `velocity`, `restSpeedThreshold`, `restDisplacementThreshold` | `withSpring` |
|
|
68
|
+
| `'timing'` | `duration`, `easing`, `delay` | `withTiming` |
|
|
69
|
+
| `'decay'` | `velocity`, `deceleration`, `clamp` | `withDecay` |
|
|
70
70
|
| `'no-animation'` | — | direct assignment, no interpolation |
|
|
71
71
|
|
|
72
72
|
Plus, on any transition: `delay`, `repeat`. Per-property transitions take precedence over the top-level transition. Spring config uses **react-spring vocabulary** (`tension`/`friction`); Reanimated's raw `stiffness`/`damping` is never on the public surface.
|
|
73
73
|
|
|
74
74
|
## Animatable properties
|
|
75
75
|
|
|
76
|
-
`opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `
|
|
76
|
+
Numeric: `opacity`, `translateX`, `translateY`, `scale`, `scaleX`, `scaleY`, `rotate`, `rotateX`, `rotateY`, `width`, `height`, `borderRadius`. Color: `backgroundColor`, `borderColor`, `color`, `tintColor` (Image only — `Motion.View` rejects it at compile time). Layout transforms via `transform: [...]`. Color targets are forwarded straight through `withSpring` / `withTiming`; Reanimated's value setter packs the string to RGBA and interpolates on the UI thread.
|
|
77
77
|
|
|
78
78
|
Out of scope for `0.x`: SVG path morphing, gradient interpolation, shared-element transitions across screens.
|
|
79
79
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import * as react_native from 'react-native';
|
|
4
|
-
import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, V as VariantController } from './types-
|
|
5
|
-
export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, G as GestureSubStates, c as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, S as SequenceStep, d as SpringTransition, e as TimingTransition, f as Transition, g as VariantsMap } from './types-
|
|
4
|
+
import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, V as VariantController } from './types-DeZZzE_e.mjs';
|
|
5
|
+
export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, G as GestureSubStates, c as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, S as SequenceStep, d as SpringTransition, e as TimingTransition, f as Transition, g as VariantsMap } from './types-DeZZzE_e.mjs';
|
|
6
6
|
export { MotionImage } from './motion/Image.mjs';
|
|
7
7
|
export { MotionPressable } from './motion/Pressable.mjs';
|
|
8
8
|
export { MotionScrollView } from './motion/ScrollView.mjs';
|
|
@@ -16,10 +16,9 @@ export { MotionView } from './motion/View.mjs';
|
|
|
16
16
|
* `exit` / `transition` all infer from `C`'s `style` prop. There is no
|
|
17
17
|
* shared `ViewStyle & TextStyle & ImageStyle` fallback.
|
|
18
18
|
*
|
|
19
|
-
* Alpha scope: numeric properties
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* land in later phases.
|
|
19
|
+
* Alpha scope: numeric properties (transforms, opacity, width, height,
|
|
20
|
+
* borderRadius) and color properties (backgroundColor, borderColor, color,
|
|
21
|
+
* tintColor) applied via Reanimated shared values + `useAnimatedStyle`.
|
|
23
22
|
*/
|
|
24
23
|
declare function createMotionComponent<C extends ComponentType<any>>(Component: C): MotionComponent<C>;
|
|
25
24
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
3
|
import * as react_native from 'react-native';
|
|
4
|
-
import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, V as VariantController } from './types-
|
|
5
|
-
export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, G as GestureSubStates, c as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, S as SequenceStep, d as SpringTransition, e as TimingTransition, f as Transition, g as VariantsMap } from './types-
|
|
4
|
+
import { M as MotionComponent, A as AnimatableValue, T as TransitionConfig, V as VariantController } from './types-DeZZzE_e.js';
|
|
5
|
+
export { a as AnimateStyle, b as AnimationCallbackInfo, D as DecayTransition, G as GestureSubStates, c as MotionProps, N as NoAnimationTransition, P as PerPropertyTransition, R as RepeatConfig, S as SequenceStep, d as SpringTransition, e as TimingTransition, f as Transition, g as VariantsMap } from './types-DeZZzE_e.js';
|
|
6
6
|
export { MotionImage } from './motion/Image.js';
|
|
7
7
|
export { MotionPressable } from './motion/Pressable.js';
|
|
8
8
|
export { MotionScrollView } from './motion/ScrollView.js';
|
|
@@ -16,10 +16,9 @@ export { MotionView } from './motion/View.js';
|
|
|
16
16
|
* `exit` / `transition` all infer from `C`'s `style` prop. There is no
|
|
17
17
|
* shared `ViewStyle & TextStyle & ImageStyle` fallback.
|
|
18
18
|
*
|
|
19
|
-
* Alpha scope: numeric properties
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* land in later phases.
|
|
19
|
+
* Alpha scope: numeric properties (transforms, opacity, width, height,
|
|
20
|
+
* borderRadius) and color properties (backgroundColor, borderColor, color,
|
|
21
|
+
* tintColor) applied via Reanimated shared values + `useAnimatedStyle`.
|
|
23
22
|
*/
|
|
24
23
|
declare function createMotionComponent<C extends ComponentType<any>>(Component: C): MotionComponent<C>;
|
|
25
24
|
|
package/dist/index.js
CHANGED
|
@@ -36,6 +36,29 @@ function MotionConfig({
|
|
|
36
36
|
);
|
|
37
37
|
return /* @__PURE__ */ jsxRuntime.jsx(MotionConfigContext.Provider, { value, children });
|
|
38
38
|
}
|
|
39
|
+
var modality = "keyboard";
|
|
40
|
+
var installed = false;
|
|
41
|
+
function setKeyboard() {
|
|
42
|
+
modality = "keyboard";
|
|
43
|
+
}
|
|
44
|
+
function setPointer() {
|
|
45
|
+
modality = "pointer";
|
|
46
|
+
}
|
|
47
|
+
function ensureInstalled() {
|
|
48
|
+
if (installed) return;
|
|
49
|
+
if (reactNative.Platform.OS !== "web") return;
|
|
50
|
+
if (typeof document === "undefined") return;
|
|
51
|
+
document.addEventListener("keydown", setKeyboard, true);
|
|
52
|
+
document.addEventListener("mousedown", setPointer, true);
|
|
53
|
+
document.addEventListener("pointerdown", setPointer, true);
|
|
54
|
+
document.addEventListener("touchstart", setPointer, true);
|
|
55
|
+
installed = true;
|
|
56
|
+
}
|
|
57
|
+
function isFocusVisible() {
|
|
58
|
+
if (reactNative.Platform.OS !== "web") return true;
|
|
59
|
+
ensureInstalled();
|
|
60
|
+
return modality === "keyboard";
|
|
61
|
+
}
|
|
39
62
|
var PresenceContext = react.createContext(null);
|
|
40
63
|
function usePresence() {
|
|
41
64
|
return react.useContext(PresenceContext);
|
|
@@ -270,8 +293,23 @@ var TRANSFORM_KEYS = [
|
|
|
270
293
|
"scaleY",
|
|
271
294
|
"rotate"
|
|
272
295
|
];
|
|
273
|
-
var
|
|
274
|
-
|
|
296
|
+
var NUMERIC_TOP_LEVEL_KEYS = [
|
|
297
|
+
"opacity",
|
|
298
|
+
"width",
|
|
299
|
+
"height",
|
|
300
|
+
"borderRadius"
|
|
301
|
+
];
|
|
302
|
+
var COLOR_KEYS = [
|
|
303
|
+
"backgroundColor",
|
|
304
|
+
"borderColor",
|
|
305
|
+
"color",
|
|
306
|
+
"tintColor"
|
|
307
|
+
];
|
|
308
|
+
var ALL_KEYS = [
|
|
309
|
+
...TRANSFORM_KEYS,
|
|
310
|
+
...NUMERIC_TOP_LEVEL_KEYS,
|
|
311
|
+
...COLOR_KEYS
|
|
312
|
+
];
|
|
275
313
|
var TRANSFORM_KEY_SET = new Set(TRANSFORM_KEYS);
|
|
276
314
|
var EXITING_POINTER_EVENTS_STYLE = { pointerEvents: "none" };
|
|
277
315
|
var DEFAULT_RESTING = {
|
|
@@ -284,7 +322,15 @@ var DEFAULT_RESTING = {
|
|
|
284
322
|
opacity: 1,
|
|
285
323
|
width: 0,
|
|
286
324
|
height: 0,
|
|
287
|
-
borderRadius: 0
|
|
325
|
+
borderRadius: 0,
|
|
326
|
+
// 'transparent' is the only safe universal default for colors: it works as
|
|
327
|
+
// an initial seed for any color animation (no jarring opaque flash on mount
|
|
328
|
+
// when `initial` is omitted) and rgba(0,0,0,0) interpolates cleanly into
|
|
329
|
+
// any opaque target via Reanimated's color util.
|
|
330
|
+
backgroundColor: "transparent",
|
|
331
|
+
borderColor: "transparent",
|
|
332
|
+
color: "transparent",
|
|
333
|
+
tintColor: "transparent"
|
|
288
334
|
};
|
|
289
335
|
var TRANSITION_KEYS = /* @__PURE__ */ new Set([
|
|
290
336
|
"type",
|
|
@@ -345,6 +391,7 @@ function createMotionComponent(Component) {
|
|
|
345
391
|
const exitRecord = exit ? exit : void 0;
|
|
346
392
|
const [pressed, setPressed] = react.useState(false);
|
|
347
393
|
const [focused, setFocused] = react.useState(false);
|
|
394
|
+
const [focusVisible, setFocusVisible] = react.useState(false);
|
|
348
395
|
const [hovered, setHovered] = react.useState(false);
|
|
349
396
|
const activeKeysRef = react.useRef(null);
|
|
350
397
|
if (activeKeysRef.current === null) {
|
|
@@ -365,6 +412,7 @@ function createMotionComponent(Component) {
|
|
|
365
412
|
for (const subState of [
|
|
366
413
|
gesture.pressed,
|
|
367
414
|
gesture.focused,
|
|
415
|
+
gesture.focusVisible,
|
|
368
416
|
gesture.hovered
|
|
369
417
|
]) {
|
|
370
418
|
if (!subState) continue;
|
|
@@ -393,6 +441,7 @@ function createMotionComponent(Component) {
|
|
|
393
441
|
const mergedRecord = isExiting && exitRecord ? { ...animateRecord, ...exitRecord } : mergeGestureTargets(animateRecord, gesture, {
|
|
394
442
|
pressed,
|
|
395
443
|
focused,
|
|
444
|
+
focusVisible,
|
|
396
445
|
hovered
|
|
397
446
|
});
|
|
398
447
|
const mergedSig = stableSig(mergedRecord) + (isExiting ? "|exit" : "") + (shouldReduceMotion ? "|rm" : "");
|
|
@@ -475,6 +524,7 @@ function createMotionComponent(Component) {
|
|
|
475
524
|
rest,
|
|
476
525
|
setPressed,
|
|
477
526
|
setFocused,
|
|
527
|
+
setFocusVisible,
|
|
478
528
|
setHovered
|
|
479
529
|
);
|
|
480
530
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -501,6 +551,12 @@ function useAnimatableSharedValues(init) {
|
|
|
501
551
|
const width = Animated.useSharedValue(init("width"));
|
|
502
552
|
const height = Animated.useSharedValue(init("height"));
|
|
503
553
|
const borderRadius = Animated.useSharedValue(init("borderRadius"));
|
|
554
|
+
const backgroundColor = Animated.useSharedValue(
|
|
555
|
+
init("backgroundColor")
|
|
556
|
+
);
|
|
557
|
+
const borderColor = Animated.useSharedValue(init("borderColor"));
|
|
558
|
+
const color = Animated.useSharedValue(init("color"));
|
|
559
|
+
const tintColor = Animated.useSharedValue(init("tintColor"));
|
|
504
560
|
const ref = react.useRef(null);
|
|
505
561
|
if (ref.current === null) {
|
|
506
562
|
ref.current = {
|
|
@@ -513,7 +569,11 @@ function useAnimatableSharedValues(init) {
|
|
|
513
569
|
opacity,
|
|
514
570
|
width,
|
|
515
571
|
height,
|
|
516
|
-
borderRadius
|
|
572
|
+
borderRadius,
|
|
573
|
+
backgroundColor,
|
|
574
|
+
borderColor,
|
|
575
|
+
color,
|
|
576
|
+
tintColor
|
|
517
577
|
};
|
|
518
578
|
}
|
|
519
579
|
return ref.current;
|
|
@@ -632,13 +692,13 @@ function resolveAnimateInput(animate, variants, controllerKey) {
|
|
|
632
692
|
}
|
|
633
693
|
function restValue(v) {
|
|
634
694
|
if (v === void 0) return void 0;
|
|
635
|
-
if (typeof v === "number") return v;
|
|
695
|
+
if (typeof v === "number" || typeof v === "string") return v;
|
|
636
696
|
if (Array.isArray(v)) {
|
|
637
697
|
return v.length > 0 ? restValue(v[0]) : void 0;
|
|
638
698
|
}
|
|
639
699
|
if (typeof v === "object" && v !== null && "to" in v) {
|
|
640
700
|
const to = v.to;
|
|
641
|
-
return typeof to === "number" ? to : void 0;
|
|
701
|
+
return typeof to === "number" || typeof to === "string" ? to : void 0;
|
|
642
702
|
}
|
|
643
703
|
return void 0;
|
|
644
704
|
}
|
|
@@ -670,6 +730,7 @@ function mergeGestureTargets(base, gesture, active) {
|
|
|
670
730
|
const subStates = [
|
|
671
731
|
gesture.hovered,
|
|
672
732
|
gesture.focused,
|
|
733
|
+
gesture.focusVisible,
|
|
673
734
|
gesture.pressed
|
|
674
735
|
];
|
|
675
736
|
for (const sub of subStates) {
|
|
@@ -692,6 +753,12 @@ function mergeGestureTargets(base, gesture, active) {
|
|
|
692
753
|
gesture.focused
|
|
693
754
|
);
|
|
694
755
|
}
|
|
756
|
+
if (active.focusVisible && gesture.focusVisible) {
|
|
757
|
+
Object.assign(
|
|
758
|
+
merged,
|
|
759
|
+
gesture.focusVisible
|
|
760
|
+
);
|
|
761
|
+
}
|
|
695
762
|
if (active.pressed && gesture.pressed) {
|
|
696
763
|
Object.assign(
|
|
697
764
|
merged,
|
|
@@ -700,7 +767,7 @@ function mergeGestureTargets(base, gesture, active) {
|
|
|
700
767
|
}
|
|
701
768
|
return merged;
|
|
702
769
|
}
|
|
703
|
-
function useGestureHandlers(gesture, rest, setPressed, setFocused, setHovered) {
|
|
770
|
+
function useGestureHandlers(gesture, rest, setPressed, setFocused, setFocusVisible, setHovered) {
|
|
704
771
|
return react.useMemo(() => {
|
|
705
772
|
if (!gesture) return {};
|
|
706
773
|
const handlers = {};
|
|
@@ -714,9 +781,15 @@ function useGestureHandlers(gesture, rest, setPressed, setFocused, setHovered) {
|
|
|
714
781
|
handlers.onPressIn = compose(rest.onPressIn, () => setPressed(true));
|
|
715
782
|
handlers.onPressOut = compose(rest.onPressOut, () => setPressed(false));
|
|
716
783
|
}
|
|
717
|
-
if (gesture.focused) {
|
|
718
|
-
handlers.onFocus = compose(rest.onFocus, () =>
|
|
719
|
-
|
|
784
|
+
if (gesture.focused || gesture.focusVisible) {
|
|
785
|
+
handlers.onFocus = compose(rest.onFocus, () => {
|
|
786
|
+
if (gesture.focused) setFocused(true);
|
|
787
|
+
if (gesture.focusVisible && isFocusVisible()) setFocusVisible(true);
|
|
788
|
+
});
|
|
789
|
+
handlers.onBlur = compose(rest.onBlur, () => {
|
|
790
|
+
if (gesture.focused) setFocused(false);
|
|
791
|
+
if (gesture.focusVisible) setFocusVisible(false);
|
|
792
|
+
});
|
|
720
793
|
}
|
|
721
794
|
if (gesture.hovered) {
|
|
722
795
|
handlers.onMouseEnter = compose(rest.onMouseEnter, () => setHovered(true));
|
|
@@ -729,6 +802,7 @@ function useGestureHandlers(gesture, rest, setPressed, setFocused, setHovered) {
|
|
|
729
802
|
}, [
|
|
730
803
|
gesture?.pressed ? 1 : 0,
|
|
731
804
|
gesture?.focused ? 1 : 0,
|
|
805
|
+
gesture?.focusVisible ? 1 : 0,
|
|
732
806
|
gesture?.hovered ? 1 : 0,
|
|
733
807
|
rest.onTouchStart,
|
|
734
808
|
rest.onTouchEnd,
|