@symbiote-native/engine 0.1.0
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/LICENSE +21 -0
- package/README.md +124 -0
- package/build/accessibility-info/index.android.d.ts +3 -0
- package/build/accessibility-info/index.android.js +166 -0
- package/build/accessibility-info/index.d.ts +1 -0
- package/build/accessibility-info/index.ios.d.ts +3 -0
- package/build/accessibility-info/index.ios.js +219 -0
- package/build/accessibility-info/index.js +5 -0
- package/build/accessibility-info/shared.d.ts +34 -0
- package/build/accessibility-info/shared.js +13 -0
- package/build/action-sheet-ios/index.d.ts +36 -0
- package/build/action-sheet-ios/index.js +74 -0
- package/build/alert/index.android.d.ts +5 -0
- package/build/alert/index.android.js +117 -0
- package/build/alert/index.d.ts +1 -0
- package/build/alert/index.ios.d.ts +7 -0
- package/build/alert/index.ios.js +83 -0
- package/build/alert/index.js +8 -0
- package/build/alert/shared.d.ts +19 -0
- package/build/alert/shared.js +17 -0
- package/build/animated/animated-component-shared.d.ts +5 -0
- package/build/animated/animated-component-shared.js +54 -0
- package/build/animated/animation.d.ts +9 -0
- package/build/animated/animation.js +6 -0
- package/build/animated/animations/base.d.ts +27 -0
- package/build/animated/animations/base.js +90 -0
- package/build/animated/animations/composition.d.ts +38 -0
- package/build/animated/animations/composition.js +236 -0
- package/build/animated/animations/decay.d.ts +22 -0
- package/build/animated/animations/decay.js +65 -0
- package/build/animated/animations/raf.d.ts +5 -0
- package/build/animated/animations/raf.js +39 -0
- package/build/animated/animations/spring-config.d.ts +6 -0
- package/build/animated/animations/spring-config.js +55 -0
- package/build/animated/animations/spring.d.ts +50 -0
- package/build/animated/animations/spring.js +207 -0
- package/build/animated/animations/timing.d.ts +27 -0
- package/build/animated/animations/timing.js +101 -0
- package/build/animated/animations/tracking.d.ts +14 -0
- package/build/animated/animations/tracking.js +43 -0
- package/build/animated/bezier.d.ts +1 -0
- package/build/animated/bezier.js +101 -0
- package/build/animated/color.d.ts +37 -0
- package/build/animated/color.js +183 -0
- package/build/animated/easing.d.ts +20 -0
- package/build/animated/easing.js +96 -0
- package/build/animated/event.d.ts +36 -0
- package/build/animated/event.js +252 -0
- package/build/animated/graph.d.ts +38 -0
- package/build/animated/graph.js +227 -0
- package/build/animated/index.d.ts +20 -0
- package/build/animated/index.js +28 -0
- package/build/animated/interpolation-node.d.ts +16 -0
- package/build/animated/interpolation-node.js +57 -0
- package/build/animated/interpolation.d.ts +22 -0
- package/build/animated/interpolation.js +199 -0
- package/build/animated/mock.d.ts +56 -0
- package/build/animated/mock.js +127 -0
- package/build/animated/native/native-animated.d.ts +43 -0
- package/build/animated/native/native-animated.js +146 -0
- package/build/animated/operators.d.ts +80 -0
- package/build/animated/operators.js +266 -0
- package/build/animated/props.d.ts +20 -0
- package/build/animated/props.js +187 -0
- package/build/animated/style.d.ts +26 -0
- package/build/animated/style.js +187 -0
- package/build/animated/value-xy.d.ts +35 -0
- package/build/animated/value-xy.js +106 -0
- package/build/animated/value.d.ts +36 -0
- package/build/animated/value.js +185 -0
- package/build/app-registry/index.d.ts +40 -0
- package/build/app-registry/index.js +144 -0
- package/build/app-state/index.d.ts +16 -0
- package/build/app-state/index.js +105 -0
- package/build/appearance/index.d.ts +12 -0
- package/build/appearance/index.js +84 -0
- package/build/back-handler/index.d.ts +14 -0
- package/build/back-handler/index.js +106 -0
- package/build/commit.d.ts +16 -0
- package/build/commit.js +678 -0
- package/build/debug.d.ts +5 -0
- package/build/debug.js +18 -0
- package/build/dimensions/index.d.ts +28 -0
- package/build/dimensions/index.js +148 -0
- package/build/dispatch.d.ts +2 -0
- package/build/dispatch.js +18 -0
- package/build/events/index.d.ts +1 -0
- package/build/events/index.js +691 -0
- package/build/fabric.d.ts +32 -0
- package/build/fabric.js +59 -0
- package/build/host-instance/index.d.ts +11 -0
- package/build/host-instance/index.js +49 -0
- package/build/i18n-manager/index.d.ts +13 -0
- package/build/i18n-manager/index.js +91 -0
- package/build/index.d.ts +80 -0
- package/build/index.js +72 -0
- package/build/interaction-manager/index.d.ts +45 -0
- package/build/interaction-manager/index.js +222 -0
- package/build/keyboard/index.d.ts +31 -0
- package/build/keyboard/index.js +142 -0
- package/build/layout-animation/index.d.ts +66 -0
- package/build/layout-animation/index.js +183 -0
- package/build/linking/index.android.d.ts +2 -0
- package/build/linking/index.android.js +18 -0
- package/build/linking/index.d.ts +1 -0
- package/build/linking/index.ios.d.ts +2 -0
- package/build/linking/index.ios.js +9 -0
- package/build/linking/index.js +6 -0
- package/build/linking/shared.d.ts +32 -0
- package/build/linking/shared.js +98 -0
- package/build/native-events.d.ts +24 -0
- package/build/native-events.js +129 -0
- package/build/native-modules.d.ts +6 -0
- package/build/native-modules.js +57 -0
- package/build/node.d.ts +36 -0
- package/build/node.js +194 -0
- package/build/pan-responder/index.d.ts +53 -0
- package/build/pan-responder/index.js +353 -0
- package/build/permissions-android/index.d.ts +115 -0
- package/build/permissions-android/index.js +185 -0
- package/build/pixel-ratio/index.d.ts +8 -0
- package/build/pixel-ratio/index.js +27 -0
- package/build/platform/index.android.d.ts +22 -0
- package/build/platform/index.android.js +60 -0
- package/build/platform/index.d.ts +1 -0
- package/build/platform/index.ios.d.ts +18 -0
- package/build/platform/index.ios.js +62 -0
- package/build/platform/index.js +5 -0
- package/build/platform/shared.d.ts +25 -0
- package/build/platform/shared.js +41 -0
- package/build/platform-color.d.ts +19 -0
- package/build/platform-color.js +25 -0
- package/build/post-commit.d.ts +4 -0
- package/build/post-commit.js +16 -0
- package/build/process-aspect-ratio.d.ts +1 -0
- package/build/process-aspect-ratio.js +34 -0
- package/build/process-background-image/index.d.ts +28 -0
- package/build/process-background-image/index.js +557 -0
- package/build/process-box-shadow/index.d.ts +11 -0
- package/build/process-box-shadow/index.js +193 -0
- package/build/process-filter.d.ts +31 -0
- package/build/process-filter.js +304 -0
- package/build/process-font-variant.d.ts +1 -0
- package/build/process-font-variant.js +17 -0
- package/build/process-transform/index.d.ts +5 -0
- package/build/process-transform/index.js +120 -0
- package/build/process-transform-origin/index.d.ts +3 -0
- package/build/process-transform-origin/index.js +108 -0
- package/build/registry.d.ts +31 -0
- package/build/registry.js +145 -0
- package/build/settings/index.d.ts +8 -0
- package/build/settings/index.js +126 -0
- package/build/share/index.android.d.ts +3 -0
- package/build/share/index.android.js +56 -0
- package/build/share/index.d.ts +1 -0
- package/build/share/index.ios.d.ts +3 -0
- package/build/share/index.ios.js +47 -0
- package/build/share/index.js +6 -0
- package/build/share/shared.d.ts +32 -0
- package/build/share/shared.js +32 -0
- package/build/status-bar/index.android.d.ts +5 -0
- package/build/status-bar/index.android.js +83 -0
- package/build/status-bar/index.d.ts +1 -0
- package/build/status-bar/index.ios.d.ts +5 -0
- package/build/status-bar/index.ios.js +66 -0
- package/build/status-bar/index.js +4 -0
- package/build/status-bar/shared.d.ts +22 -0
- package/build/status-bar/shared.js +22 -0
- package/build/style/index.d.ts +1 -0
- package/build/style/index.js +30 -0
- package/build/style-registry/index.d.ts +11 -0
- package/build/style-registry/index.js +165 -0
- package/build/style-sheet/index.d.ts +20 -0
- package/build/style-sheet/index.js +121 -0
- package/build/styles.d.ts +220 -0
- package/build/styles.js +7 -0
- package/build/surface.d.ts +16 -0
- package/build/surface.js +67 -0
- package/build/tags.d.ts +1 -0
- package/build/tags.js +10 -0
- package/build/text-input-state.d.ts +5 -0
- package/build/text-input-state.js +29 -0
- package/build/toast-android/index.d.ts +10 -0
- package/build/toast-android/index.js +108 -0
- package/build/vibration/index.android.d.ts +2 -0
- package/build/vibration/index.android.js +18 -0
- package/build/vibration/index.d.ts +1 -0
- package/build/vibration/index.ios.d.ts +2 -0
- package/build/vibration/index.ios.js +54 -0
- package/build/vibration/index.js +6 -0
- package/build/vibration/shared.d.ts +15 -0
- package/build/vibration/shared.js +68 -0
- package/build/view-config.d.ts +1 -0
- package/build/view-config.js +114 -0
- package/package.json +41 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IAnimation, IEndCallback } from '../animation';
|
|
2
|
+
import type { AnimatedValue } from '../value';
|
|
3
|
+
import { type IEasingFunction } from '../easing';
|
|
4
|
+
import type { INativeAnimationConfig } from '../native/native-animated';
|
|
5
|
+
import { BaseAnimation, type IAnimationConfig } from './base';
|
|
6
|
+
export interface ITimingAnimationConfig extends IAnimationConfig {
|
|
7
|
+
toValue: number;
|
|
8
|
+
easing?: IEasingFunction;
|
|
9
|
+
duration?: number;
|
|
10
|
+
delay?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare class TimingAnimation extends BaseAnimation {
|
|
13
|
+
private startTime;
|
|
14
|
+
private fromValue;
|
|
15
|
+
private readonly toValue;
|
|
16
|
+
private readonly duration;
|
|
17
|
+
private readonly delay;
|
|
18
|
+
private readonly easing;
|
|
19
|
+
private onUpdate;
|
|
20
|
+
private animationFrame;
|
|
21
|
+
private timeout;
|
|
22
|
+
constructor(config: ITimingAnimationConfig);
|
|
23
|
+
protected getNativeAnimationConfig(): INativeAnimationConfig;
|
|
24
|
+
start(fromValue: number, onUpdate: (value: number) => void, onEnd: IEndCallback, _previousAnimation: IAnimation | null, animatedValue: AnimatedValue): void;
|
|
25
|
+
private onFrame;
|
|
26
|
+
stop(): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// TimingAnimation: ported from RN's animations/TimingAnimation.js, JS path
|
|
2
|
+
// only (ADR 0016). Walks a value from `fromValue` to `toValue` over `duration`
|
|
3
|
+
// ms, shaping progress through an easing function. The native-frame export and
|
|
4
|
+
// __startAnimationIfNative branch are dropped.
|
|
5
|
+
import { Easing } from '../easing';
|
|
6
|
+
import { dlog } from '../../debug';
|
|
7
|
+
import { BaseAnimation } from './base';
|
|
8
|
+
import { cancelFrame, clearTimer, requestFrame, setTimer } from './raf';
|
|
9
|
+
let cachedEaseInOut;
|
|
10
|
+
function easeInOut() {
|
|
11
|
+
if (cachedEaseInOut === undefined) {
|
|
12
|
+
cachedEaseInOut = Easing.inOut(Easing.ease);
|
|
13
|
+
}
|
|
14
|
+
return cachedEaseInOut;
|
|
15
|
+
}
|
|
16
|
+
export class TimingAnimation extends BaseAnimation {
|
|
17
|
+
startTime = 0;
|
|
18
|
+
fromValue = 0;
|
|
19
|
+
toValue;
|
|
20
|
+
duration;
|
|
21
|
+
delay;
|
|
22
|
+
easing;
|
|
23
|
+
onUpdate = () => { };
|
|
24
|
+
animationFrame = null;
|
|
25
|
+
timeout = null;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
super(config);
|
|
28
|
+
this.toValue = config.toValue;
|
|
29
|
+
this.easing = config.easing ?? easeInOut();
|
|
30
|
+
this.duration = config.duration ?? 500;
|
|
31
|
+
this.delay = config.delay ?? 0;
|
|
32
|
+
}
|
|
33
|
+
// Native: hand the easing curve to native as a per-frame sample table.
|
|
34
|
+
getNativeAnimationConfig() {
|
|
35
|
+
const frameDuration = 1000 / 60;
|
|
36
|
+
const numFrames = Math.round(this.duration / frameDuration);
|
|
37
|
+
const frames = [];
|
|
38
|
+
for (let frame = 0; frame < numFrames; frame++) {
|
|
39
|
+
frames.push(this.easing(frame / numFrames));
|
|
40
|
+
}
|
|
41
|
+
frames.push(this.easing(1));
|
|
42
|
+
return {
|
|
43
|
+
type: 'frames',
|
|
44
|
+
frames,
|
|
45
|
+
toValue: this.toValue,
|
|
46
|
+
iterations: this.__iterations,
|
|
47
|
+
platformConfig: this.__platformConfig,
|
|
48
|
+
debugID: this.__getDebugID(),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
start(fromValue, onUpdate, onEnd, _previousAnimation, animatedValue) {
|
|
52
|
+
this.begin(onEnd);
|
|
53
|
+
this.fromValue = fromValue;
|
|
54
|
+
this.onUpdate = onUpdate;
|
|
55
|
+
const begin = () => {
|
|
56
|
+
this.startTime = Date.now();
|
|
57
|
+
// Native took over → the JS rAF loop is skipped entirely.
|
|
58
|
+
if (this.startNativeIfNeeded(animatedValue))
|
|
59
|
+
return;
|
|
60
|
+
if (this.duration === 0) {
|
|
61
|
+
this.onUpdate(this.toValue);
|
|
62
|
+
this.__notifyAnimationEnd({ finished: true });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.animationFrame = requestFrame(() => this.onFrame());
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
if (this.delay !== 0) {
|
|
69
|
+
this.timeout = setTimer(begin, this.delay);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
begin();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
onFrame() {
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
if (now >= this.startTime + this.duration) {
|
|
78
|
+
this.onUpdate(this.fromValue + this.easing(1) * (this.toValue - this.fromValue));
|
|
79
|
+
this.__notifyAnimationEnd({ finished: true });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
this.onUpdate(this.fromValue +
|
|
83
|
+
this.easing((now - this.startTime) / this.duration) * (this.toValue - this.fromValue));
|
|
84
|
+
if (this.__active) {
|
|
85
|
+
this.animationFrame = requestFrame(() => this.onFrame());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
stop() {
|
|
89
|
+
super.stop();
|
|
90
|
+
if (this.timeout !== null) {
|
|
91
|
+
clearTimer(this.timeout);
|
|
92
|
+
this.timeout = null;
|
|
93
|
+
}
|
|
94
|
+
if (this.animationFrame !== null) {
|
|
95
|
+
cancelFrame(this.animationFrame);
|
|
96
|
+
this.animationFrame = null;
|
|
97
|
+
}
|
|
98
|
+
dlog('timing animation stopped');
|
|
99
|
+
this.__notifyAnimationEnd({ finished: false });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IAnimation, IEndCallback } from '../animation';
|
|
2
|
+
import { AnimatedNode } from '../graph';
|
|
3
|
+
import type { AnimatedValue } from '../value';
|
|
4
|
+
export declare class AnimatedTracking extends AnimatedNode {
|
|
5
|
+
private readonly value;
|
|
6
|
+
private readonly parent;
|
|
7
|
+
private readonly createAnimation;
|
|
8
|
+
private readonly endCallback?;
|
|
9
|
+
constructor(value: AnimatedValue, parent: AnimatedNode, createAnimation: (toValue: number) => IAnimation, endCallback?: IEndCallback | undefined);
|
|
10
|
+
__getValue(): number;
|
|
11
|
+
__attach(): void;
|
|
12
|
+
__detach(): void;
|
|
13
|
+
update(): void;
|
|
14
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// AnimatedTracking: drives a value toward a MOVING target. When you write
|
|
2
|
+
// `Animated.spring(value, { toValue: anotherValue })`, the target is itself an
|
|
3
|
+
// AnimatedNode; this node subscribes to it as a leaf child and, each time the
|
|
4
|
+
// target changes, re-launches the animation toward the target's new value, so the
|
|
5
|
+
// value chases the target continuously (a spring following a gesture). Ported from
|
|
6
|
+
// RN's AnimatedTracking.js, JS path; native tracking re-uses the per-launch driver.
|
|
7
|
+
import { AnimatedNode } from '../graph';
|
|
8
|
+
export class AnimatedTracking extends AnimatedNode {
|
|
9
|
+
value;
|
|
10
|
+
parent;
|
|
11
|
+
createAnimation;
|
|
12
|
+
endCallback;
|
|
13
|
+
constructor(value, parent,
|
|
14
|
+
// Builds a fresh driver aimed at a concrete target value: the config captured
|
|
15
|
+
// at call time with `toValue` resolved to the parent's current number.
|
|
16
|
+
createAnimation, endCallback) {
|
|
17
|
+
super();
|
|
18
|
+
this.value = value;
|
|
19
|
+
this.parent = parent;
|
|
20
|
+
this.createAnimation = createAnimation;
|
|
21
|
+
this.endCallback = endCallback;
|
|
22
|
+
// Subscribe to the target immediately (RN does this in the constructor), so a
|
|
23
|
+
// target change reaches update() even before the first launch.
|
|
24
|
+
this.__attach();
|
|
25
|
+
}
|
|
26
|
+
__getValue() {
|
|
27
|
+
const target = this.parent.__getValue();
|
|
28
|
+
return typeof target === 'number' ? target : 0;
|
|
29
|
+
}
|
|
30
|
+
__attach() {
|
|
31
|
+
this.parent.__addChild(this);
|
|
32
|
+
}
|
|
33
|
+
__detach() {
|
|
34
|
+
this.parent.__removeChild(this);
|
|
35
|
+
super.__detach();
|
|
36
|
+
}
|
|
37
|
+
// Leaf seam (a method, never a class field: flushValue detects leaves
|
|
38
|
+
// structurally and a field would shadow it under useDefineForClassFields). The
|
|
39
|
+
// target moved: launch a fresh animation toward its new value.
|
|
40
|
+
update() {
|
|
41
|
+
this.value.animate(this.createAnimation(this.__getValue()), this.endCallback);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function bezier(mX1: number, mY1: number, mX2: number, mY2: number): (x: number) => number;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Cubic-bezier easing solver, ported verbatim from React Native's
|
|
2
|
+
// Libraries/Animated/bezier.js (originally bezier-easing by Gaëtan Renaudeau,
|
|
3
|
+
// MIT). Pure math (no React, no native), so it lives unchanged in shared.
|
|
4
|
+
// Established by empiricism (tradeoff: performance vs precision).
|
|
5
|
+
const NEWTON_ITERATIONS = 4;
|
|
6
|
+
const NEWTON_MIN_SLOPE = 0.001;
|
|
7
|
+
const SUBDIVISION_PRECISION = 0.0000001;
|
|
8
|
+
const SUBDIVISION_MAX_ITERATIONS = 10;
|
|
9
|
+
const SPLINE_TABLE_SIZE = 11;
|
|
10
|
+
const SAMPLE_STEP_SIZE = 1.0 / (SPLINE_TABLE_SIZE - 1.0);
|
|
11
|
+
function a(a1, a2) {
|
|
12
|
+
return 1.0 - 3.0 * a2 + 3.0 * a1;
|
|
13
|
+
}
|
|
14
|
+
function b(a1, a2) {
|
|
15
|
+
return 3.0 * a2 - 6.0 * a1;
|
|
16
|
+
}
|
|
17
|
+
function c(a1) {
|
|
18
|
+
return 3.0 * a1;
|
|
19
|
+
}
|
|
20
|
+
// x(t) given t, x1, x2, or y(t) given t, y1, y2.
|
|
21
|
+
function calcBezier(t, a1, a2) {
|
|
22
|
+
return ((a(a1, a2) * t + b(a1, a2)) * t + c(a1)) * t;
|
|
23
|
+
}
|
|
24
|
+
// dx/dt given t, x1, x2, or dy/dt given t, y1, y2.
|
|
25
|
+
function getSlope(t, a1, a2) {
|
|
26
|
+
return 3.0 * a(a1, a2) * t * t + 2.0 * b(a1, a2) * t + c(a1);
|
|
27
|
+
}
|
|
28
|
+
function binarySubdivide(x, lower, upper, mX1, mX2) {
|
|
29
|
+
let currentX;
|
|
30
|
+
let currentT;
|
|
31
|
+
let lo = lower;
|
|
32
|
+
let hi = upper;
|
|
33
|
+
let i = 0;
|
|
34
|
+
do {
|
|
35
|
+
currentT = lo + (hi - lo) / 2.0;
|
|
36
|
+
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
37
|
+
if (currentX > 0.0) {
|
|
38
|
+
hi = currentT;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
lo = currentT;
|
|
42
|
+
}
|
|
43
|
+
} while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
|
|
44
|
+
return currentT;
|
|
45
|
+
}
|
|
46
|
+
function newtonRaphsonIterate(x, guess, mX1, mX2) {
|
|
47
|
+
let guessT = guess;
|
|
48
|
+
for (let i = 0; i < NEWTON_ITERATIONS; ++i) {
|
|
49
|
+
const currentSlope = getSlope(guessT, mX1, mX2);
|
|
50
|
+
if (currentSlope === 0.0) {
|
|
51
|
+
return guessT;
|
|
52
|
+
}
|
|
53
|
+
const currentX = calcBezier(guessT, mX1, mX2) - x;
|
|
54
|
+
guessT -= currentX / currentSlope;
|
|
55
|
+
}
|
|
56
|
+
return guessT;
|
|
57
|
+
}
|
|
58
|
+
export function bezier(mX1, mY1, mX2, mY2) {
|
|
59
|
+
if (!(mX1 >= 0 && mX1 <= 1 && mX2 >= 0 && mX2 <= 1)) {
|
|
60
|
+
throw new Error('bezier x values must be in [0, 1] range');
|
|
61
|
+
}
|
|
62
|
+
// Precompute the spline samples once.
|
|
63
|
+
const sampleValues = new Array(SPLINE_TABLE_SIZE);
|
|
64
|
+
if (mX1 !== mY1 || mX2 !== mY2) {
|
|
65
|
+
for (let i = 0; i < SPLINE_TABLE_SIZE; ++i) {
|
|
66
|
+
sampleValues[i] = calcBezier(i * SAMPLE_STEP_SIZE, mX1, mX2);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function getTForX(x) {
|
|
70
|
+
let intervalStart = 0.0;
|
|
71
|
+
let currentSample = 1;
|
|
72
|
+
const lastSample = SPLINE_TABLE_SIZE - 1;
|
|
73
|
+
for (; currentSample !== lastSample && sampleValues[currentSample] <= x; ++currentSample) {
|
|
74
|
+
intervalStart += SAMPLE_STEP_SIZE;
|
|
75
|
+
}
|
|
76
|
+
--currentSample;
|
|
77
|
+
// Interpolate to provide an initial guess for t.
|
|
78
|
+
const dist = (x - sampleValues[currentSample]) /
|
|
79
|
+
(sampleValues[currentSample + 1] - sampleValues[currentSample]);
|
|
80
|
+
const guessForT = intervalStart + dist * SAMPLE_STEP_SIZE;
|
|
81
|
+
const initialSlope = getSlope(guessForT, mX1, mX2);
|
|
82
|
+
if (initialSlope >= NEWTON_MIN_SLOPE) {
|
|
83
|
+
return newtonRaphsonIterate(x, guessForT, mX1, mX2);
|
|
84
|
+
}
|
|
85
|
+
if (initialSlope === 0.0) {
|
|
86
|
+
return guessForT;
|
|
87
|
+
}
|
|
88
|
+
return binarySubdivide(x, intervalStart, intervalStart + SAMPLE_STEP_SIZE, mX1, mX2);
|
|
89
|
+
}
|
|
90
|
+
return function bezierEasing(x) {
|
|
91
|
+
if (mX1 === mY1 && mX2 === mY2) {
|
|
92
|
+
return x; // linear
|
|
93
|
+
}
|
|
94
|
+
// JS numbers are imprecise; pin the extremes.
|
|
95
|
+
if (x === 0)
|
|
96
|
+
return 0;
|
|
97
|
+
if (x === 1)
|
|
98
|
+
return 1;
|
|
99
|
+
return calcBezier(getTForX(x), mY1, mY2);
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { AnimatedWithChildren } from './graph';
|
|
2
|
+
import { AnimatedValue } from './value';
|
|
3
|
+
import type { INativeNodeConfig, IPlatformConfig } from './native/native-animated';
|
|
4
|
+
export interface IRgbaValue {
|
|
5
|
+
r: number;
|
|
6
|
+
g: number;
|
|
7
|
+
b: number;
|
|
8
|
+
a: number;
|
|
9
|
+
}
|
|
10
|
+
type IChannel = number | AnimatedValue;
|
|
11
|
+
interface IRgbaInput {
|
|
12
|
+
r: IChannel;
|
|
13
|
+
g: IChannel;
|
|
14
|
+
b: IChannel;
|
|
15
|
+
a: IChannel;
|
|
16
|
+
}
|
|
17
|
+
export type IColorInput = IRgbaInput | IRgbaValue | string | number;
|
|
18
|
+
export declare function normalizeColor(color: string | number): IRgbaValue | undefined;
|
|
19
|
+
export declare class AnimatedColor extends AnimatedWithChildren {
|
|
20
|
+
readonly r: AnimatedValue;
|
|
21
|
+
readonly g: AnimatedValue;
|
|
22
|
+
readonly b: AnimatedValue;
|
|
23
|
+
readonly a: AnimatedValue;
|
|
24
|
+
constructor(value?: IColorInput);
|
|
25
|
+
__getValue(): string;
|
|
26
|
+
setValue(value: IRgbaValue | string | number): void;
|
|
27
|
+
setOffset(offset: IRgbaValue): void;
|
|
28
|
+
flattenOffset(): void;
|
|
29
|
+
extractOffset(): void;
|
|
30
|
+
stopAnimation(callback?: (value: string) => void): void;
|
|
31
|
+
__callListeners(_value: number | string): void;
|
|
32
|
+
__attach(): void;
|
|
33
|
+
__detach(): void;
|
|
34
|
+
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
35
|
+
__getNativeConfig(): INativeNodeConfig;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// AnimatedColor: animate a color by driving four channel values (r, g, b, a). Its
|
|
2
|
+
// __getValue() is an `rgba(...)` string, which the commit layer's injected color
|
|
3
|
+
// processor turns into the platform int Fabric wants. Ported from RN's
|
|
4
|
+
// AnimatedColor.js: the {r,g,b,a} and CSS-color input forms are supported; named
|
|
5
|
+
// colors and platform (Native) colors are deferred (they need RN's full
|
|
6
|
+
// normalizeColor / processColorObject, which live outside shared).
|
|
7
|
+
import { AnimatedWithChildren, flushValue } from './graph';
|
|
8
|
+
import { AnimatedValue } from './value';
|
|
9
|
+
const DEFAULT_COLOR = { r: 0, g: 0, b: 0, a: 1 };
|
|
10
|
+
function isRgbaInput(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && 'r' in value && 'g' in value;
|
|
12
|
+
}
|
|
13
|
+
function toChannel(value) {
|
|
14
|
+
return value instanceof AnimatedValue ? value : new AnimatedValue(value);
|
|
15
|
+
}
|
|
16
|
+
// Decompose a #hex (3/4/6/8), rgb()/rgba(), or 0xRRGGBBAA number into channels.
|
|
17
|
+
// undefined when unparseable (a named/platform color), so the caller falls back to
|
|
18
|
+
// the default rather than throwing inside a render. Exported so interpolation's
|
|
19
|
+
// color path parses through the same RGBA decoder (DRY) rather than duplicating it.
|
|
20
|
+
export function normalizeColor(color) {
|
|
21
|
+
if (typeof color === 'number') {
|
|
22
|
+
const c = color >>> 0;
|
|
23
|
+
return { r: (c >>> 24) & 255, g: (c >>> 16) & 255, b: (c >>> 8) & 255, a: (c & 255) / 255 };
|
|
24
|
+
}
|
|
25
|
+
const trimmed = color.trim();
|
|
26
|
+
if (trimmed.startsWith('#'))
|
|
27
|
+
return parseHex(trimmed);
|
|
28
|
+
if (/^rgba?\(/i.test(trimmed))
|
|
29
|
+
return parseRgb(trimmed);
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function parseHex(hex) {
|
|
33
|
+
let body = hex.slice(1);
|
|
34
|
+
if (body.length === 3 || body.length === 4) {
|
|
35
|
+
body = body
|
|
36
|
+
.split('')
|
|
37
|
+
.map(c => c + c)
|
|
38
|
+
.join('');
|
|
39
|
+
}
|
|
40
|
+
if (body.length !== 6 && body.length !== 8)
|
|
41
|
+
return undefined;
|
|
42
|
+
const int = Number.parseInt(body, 16);
|
|
43
|
+
if (Number.isNaN(int))
|
|
44
|
+
return undefined;
|
|
45
|
+
if (body.length === 6) {
|
|
46
|
+
return { r: (int >>> 16) & 255, g: (int >>> 8) & 255, b: int & 255, a: 1 };
|
|
47
|
+
}
|
|
48
|
+
const c = int >>> 0;
|
|
49
|
+
return { r: (c >>> 24) & 255, g: (c >>> 16) & 255, b: (c >>> 8) & 255, a: (c & 255) / 255 };
|
|
50
|
+
}
|
|
51
|
+
function parseRgb(str) {
|
|
52
|
+
const match = /^rgba?\(([^)]+)\)$/i.exec(str);
|
|
53
|
+
if (match === null)
|
|
54
|
+
return undefined;
|
|
55
|
+
const parts = match[1].split(',').map(part => Number.parseFloat(part.trim()));
|
|
56
|
+
if (parts.length < 3 || parts.some(n => Number.isNaN(n)))
|
|
57
|
+
return undefined;
|
|
58
|
+
return { r: parts[0], g: parts[1], b: parts[2], a: parts.length >= 4 ? parts[3] : 1 };
|
|
59
|
+
}
|
|
60
|
+
// Resolve any input form to four concrete channel values (numbers or pre-built
|
|
61
|
+
// AnimatedValues), so the constructor can wrap each in an AnimatedValue.
|
|
62
|
+
function resolveInput(value) {
|
|
63
|
+
if (value === undefined)
|
|
64
|
+
return DEFAULT_COLOR;
|
|
65
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
66
|
+
return normalizeColor(value) ?? DEFAULT_COLOR;
|
|
67
|
+
}
|
|
68
|
+
if (isRgbaInput(value))
|
|
69
|
+
return value;
|
|
70
|
+
return DEFAULT_COLOR;
|
|
71
|
+
}
|
|
72
|
+
export class AnimatedColor extends AnimatedWithChildren {
|
|
73
|
+
r;
|
|
74
|
+
g;
|
|
75
|
+
b;
|
|
76
|
+
a;
|
|
77
|
+
constructor(value) {
|
|
78
|
+
super();
|
|
79
|
+
const input = resolveInput(value);
|
|
80
|
+
this.r = toChannel(input.r);
|
|
81
|
+
this.g = toChannel(input.g);
|
|
82
|
+
this.b = toChannel(input.b);
|
|
83
|
+
this.a = toChannel(input.a);
|
|
84
|
+
}
|
|
85
|
+
// The CSS color string the commit layer's color processor converts to a platform
|
|
86
|
+
// int. Channels are rounded; alpha stays fractional.
|
|
87
|
+
__getValue() {
|
|
88
|
+
const r = Math.round(numericValue(this.r));
|
|
89
|
+
const g = Math.round(numericValue(this.g));
|
|
90
|
+
const b = Math.round(numericValue(this.b));
|
|
91
|
+
const a = numericValue(this.a);
|
|
92
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
93
|
+
}
|
|
94
|
+
// Each per-channel setValue/setOffset flushes bound props and walks the graph
|
|
95
|
+
// up to this color node's listeners. Driving four channels in a row would
|
|
96
|
+
// otherwise commit the bound view four times and fire color listeners four
|
|
97
|
+
// times, each with an intermediate rgba() that never logically existed. So we
|
|
98
|
+
// suspend this node's listeners across all four writes, then do ONE flush and
|
|
99
|
+
// ONE listener fire with the final composed color (RN's _withSuspendedCallbacks
|
|
100
|
+
// pattern). flushValue dedupes by leaf identity, so a single flush rebuilds
|
|
101
|
+
// every bound prop once even though four channels changed.
|
|
102
|
+
setValue(value) {
|
|
103
|
+
const rgba = typeof value === 'object' ? value : (normalizeColor(value) ?? DEFAULT_COLOR);
|
|
104
|
+
this.withSuspendedCallbacks(() => {
|
|
105
|
+
this.r.setValue(rgba.r);
|
|
106
|
+
this.g.setValue(rgba.g);
|
|
107
|
+
this.b.setValue(rgba.b);
|
|
108
|
+
this.a.setValue(rgba.a);
|
|
109
|
+
});
|
|
110
|
+
flushValue(this);
|
|
111
|
+
this.__callListeners(this.__getValue());
|
|
112
|
+
}
|
|
113
|
+
// setOffset / flattenOffset / extractOffset do NOT flush or fire listeners in
|
|
114
|
+
// symbiote's per-channel AnimatedValue (offset writes are silent), so there is
|
|
115
|
+
// no 4×-fire to suspend here, matching RN, where only setValue suspends.
|
|
116
|
+
setOffset(offset) {
|
|
117
|
+
this.r.setOffset(offset.r);
|
|
118
|
+
this.g.setOffset(offset.g);
|
|
119
|
+
this.b.setOffset(offset.b);
|
|
120
|
+
this.a.setOffset(offset.a);
|
|
121
|
+
}
|
|
122
|
+
flattenOffset() {
|
|
123
|
+
this.r.flattenOffset();
|
|
124
|
+
this.g.flattenOffset();
|
|
125
|
+
this.b.flattenOffset();
|
|
126
|
+
this.a.flattenOffset();
|
|
127
|
+
}
|
|
128
|
+
extractOffset() {
|
|
129
|
+
this.r.extractOffset();
|
|
130
|
+
this.g.extractOffset();
|
|
131
|
+
this.b.extractOffset();
|
|
132
|
+
this.a.extractOffset();
|
|
133
|
+
}
|
|
134
|
+
stopAnimation(callback) {
|
|
135
|
+
this.r.stopAnimation();
|
|
136
|
+
this.g.stopAnimation();
|
|
137
|
+
this.b.stopAnimation();
|
|
138
|
+
this.a.stopAnimation();
|
|
139
|
+
callback?.(this.__getValue());
|
|
140
|
+
}
|
|
141
|
+
// A color listener wants the composed rgba() string, not the bare channel number
|
|
142
|
+
// the child-walk arrives with. So we ignore the incoming value and re-pull
|
|
143
|
+
// __getValue(). super.__callListeners honors the suspend counter, so during
|
|
144
|
+
// setValue's four channel writes this is a no-op and the only fire is the
|
|
145
|
+
// explicit final one below.
|
|
146
|
+
__callListeners(_value) {
|
|
147
|
+
super.__callListeners(this.__getValue());
|
|
148
|
+
}
|
|
149
|
+
__attach() {
|
|
150
|
+
this.r.__addChild(this);
|
|
151
|
+
this.g.__addChild(this);
|
|
152
|
+
this.b.__addChild(this);
|
|
153
|
+
this.a.__addChild(this);
|
|
154
|
+
super.__attach();
|
|
155
|
+
}
|
|
156
|
+
__detach() {
|
|
157
|
+
this.r.__removeChild(this);
|
|
158
|
+
this.g.__removeChild(this);
|
|
159
|
+
this.b.__removeChild(this);
|
|
160
|
+
this.a.__removeChild(this);
|
|
161
|
+
super.__detach();
|
|
162
|
+
}
|
|
163
|
+
__makeNative(platformConfig) {
|
|
164
|
+
this.r.__makeNative(platformConfig);
|
|
165
|
+
this.g.__makeNative(platformConfig);
|
|
166
|
+
this.b.__makeNative(platformConfig);
|
|
167
|
+
this.a.__makeNative(platformConfig);
|
|
168
|
+
super.__makeNative(platformConfig);
|
|
169
|
+
}
|
|
170
|
+
__getNativeConfig() {
|
|
171
|
+
return {
|
|
172
|
+
type: 'color',
|
|
173
|
+
r: this.r.__getNativeTag(),
|
|
174
|
+
g: this.g.__getNativeTag(),
|
|
175
|
+
b: this.b.__getNativeTag(),
|
|
176
|
+
a: this.a.__getNativeTag(),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function numericValue(node) {
|
|
181
|
+
const value = node.__getValue();
|
|
182
|
+
return typeof value === 'number' ? value : 0;
|
|
183
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type IEasingFunction = (t: number) => number;
|
|
2
|
+
export declare const Easing: {
|
|
3
|
+
step0(n: number): number;
|
|
4
|
+
step1(n: number): number;
|
|
5
|
+
linear(t: number): number;
|
|
6
|
+
ease(t: number): number;
|
|
7
|
+
quad(t: number): number;
|
|
8
|
+
cubic(t: number): number;
|
|
9
|
+
poly(n: number): IEasingFunction;
|
|
10
|
+
sin(t: number): number;
|
|
11
|
+
circle(t: number): number;
|
|
12
|
+
exp(t: number): number;
|
|
13
|
+
elastic(bounciness?: number): IEasingFunction;
|
|
14
|
+
back(s?: number): IEasingFunction;
|
|
15
|
+
bounce(t: number): number;
|
|
16
|
+
bezier(x1: number, y1: number, x2: number, y2: number): IEasingFunction;
|
|
17
|
+
in(easing: IEasingFunction): IEasingFunction;
|
|
18
|
+
out(easing: IEasingFunction): IEasingFunction;
|
|
19
|
+
inOut(easing: IEasingFunction): IEasingFunction;
|
|
20
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Common easing functions, ported from React Native's Libraries/Animated/Easing.js.
|
|
2
|
+
// Pure math (the only dependency is the equally-pure bezier solver), so it lives
|
|
3
|
+
// unchanged in shared and every adapter re-exports it.
|
|
4
|
+
import { bezier } from './bezier';
|
|
5
|
+
let cachedEase;
|
|
6
|
+
export const Easing = {
|
|
7
|
+
// A stepping function: 1 for any positive n, else 0.
|
|
8
|
+
step0(n) {
|
|
9
|
+
return n > 0 ? 1 : 0;
|
|
10
|
+
},
|
|
11
|
+
// A stepping function: 1 once n >= 1, else 0.
|
|
12
|
+
step1(n) {
|
|
13
|
+
return n >= 1 ? 1 : 0;
|
|
14
|
+
},
|
|
15
|
+
// Linear, f(t) = t.
|
|
16
|
+
linear(t) {
|
|
17
|
+
return t;
|
|
18
|
+
},
|
|
19
|
+
// A simple inertial interaction (object slowly accelerating to speed).
|
|
20
|
+
ease(t) {
|
|
21
|
+
if (cachedEase === undefined) {
|
|
22
|
+
cachedEase = bezier(0.42, 0, 1, 1);
|
|
23
|
+
}
|
|
24
|
+
return cachedEase(t);
|
|
25
|
+
},
|
|
26
|
+
// Quadratic, f(t) = t * t.
|
|
27
|
+
quad(t) {
|
|
28
|
+
return t * t;
|
|
29
|
+
},
|
|
30
|
+
// Cubic, f(t) = t * t * t.
|
|
31
|
+
cubic(t) {
|
|
32
|
+
return t * t * t;
|
|
33
|
+
},
|
|
34
|
+
// Nth-power: position is the Nth power of elapsed time.
|
|
35
|
+
poly(n) {
|
|
36
|
+
return t => Math.pow(t, n);
|
|
37
|
+
},
|
|
38
|
+
// Sinusoidal.
|
|
39
|
+
sin(t) {
|
|
40
|
+
return 1 - Math.cos((t * Math.PI) / 2);
|
|
41
|
+
},
|
|
42
|
+
// Circular.
|
|
43
|
+
circle(t) {
|
|
44
|
+
return 1 - Math.sqrt(1 - t * t);
|
|
45
|
+
},
|
|
46
|
+
// Exponential.
|
|
47
|
+
exp(t) {
|
|
48
|
+
return Math.pow(2, 10 * (t - 1));
|
|
49
|
+
},
|
|
50
|
+
// Elastic: spring-like oscillation. bounciness 1 overshoots once; 0 not at all.
|
|
51
|
+
elastic(bounciness = 1) {
|
|
52
|
+
const p = bounciness * Math.PI;
|
|
53
|
+
return t => 1 - Math.pow(Math.cos((t * Math.PI) / 2), 3) * Math.cos(t * p);
|
|
54
|
+
},
|
|
55
|
+
// Animates back slightly before moving forward.
|
|
56
|
+
back(s = 1.70158) {
|
|
57
|
+
return t => t * t * ((s + 1) * t - s);
|
|
58
|
+
},
|
|
59
|
+
// A simple bouncing effect.
|
|
60
|
+
bounce(t) {
|
|
61
|
+
if (t < 1 / 2.75) {
|
|
62
|
+
return 7.5625 * t * t;
|
|
63
|
+
}
|
|
64
|
+
if (t < 2 / 2.75) {
|
|
65
|
+
const t2 = t - 1.5 / 2.75;
|
|
66
|
+
return 7.5625 * t2 * t2 + 0.75;
|
|
67
|
+
}
|
|
68
|
+
if (t < 2.5 / 2.75) {
|
|
69
|
+
const t2 = t - 2.25 / 2.75;
|
|
70
|
+
return 7.5625 * t2 * t2 + 0.9375;
|
|
71
|
+
}
|
|
72
|
+
const t2 = t - 2.625 / 2.75;
|
|
73
|
+
return 7.5625 * t2 * t2 + 0.984375;
|
|
74
|
+
},
|
|
75
|
+
// A cubic bezier curve, same as CSS transition-timing-function.
|
|
76
|
+
bezier(x1, y1, x2, y2) {
|
|
77
|
+
return bezier(x1, y1, x2, y2);
|
|
78
|
+
},
|
|
79
|
+
// Runs an easing function forwards.
|
|
80
|
+
in(easing) {
|
|
81
|
+
return easing;
|
|
82
|
+
},
|
|
83
|
+
// Runs an easing function backwards.
|
|
84
|
+
out(easing) {
|
|
85
|
+
return t => 1 - easing(1 - t);
|
|
86
|
+
},
|
|
87
|
+
// Makes any easing function symmetrical (forwards then backwards).
|
|
88
|
+
inOut(easing) {
|
|
89
|
+
return t => {
|
|
90
|
+
if (t < 0.5) {
|
|
91
|
+
return easing(t * 2) / 2;
|
|
92
|
+
}
|
|
93
|
+
return 1 - easing((1 - t) * 2) / 2;
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ISymbioteNode } from '../node';
|
|
2
|
+
import { AnimatedNode } from './graph';
|
|
3
|
+
type IMapping = AnimatedNode | {
|
|
4
|
+
readonly [key: string]: IMapping;
|
|
5
|
+
};
|
|
6
|
+
export interface IEventConfig {
|
|
7
|
+
readonly listener?: (...args: unknown[]) => void;
|
|
8
|
+
readonly useNativeDriver?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface IAnimatedEventHandler {
|
|
11
|
+
(...args: unknown[]): void;
|
|
12
|
+
__getEvent(): AnimatedEvent;
|
|
13
|
+
}
|
|
14
|
+
export type IEventListener = (...args: unknown[]) => void;
|
|
15
|
+
export declare class AnimatedEvent {
|
|
16
|
+
private readonly listeners;
|
|
17
|
+
private readonly mappedValues;
|
|
18
|
+
private readonly nativeDriverRequested;
|
|
19
|
+
private attachedNatively;
|
|
20
|
+
constructor(argMapping: readonly IMapping[], config?: IEventConfig);
|
|
21
|
+
__addListener(callback: IEventListener): void;
|
|
22
|
+
__removeListener(callback: IEventListener): void;
|
|
23
|
+
__isNative(): boolean;
|
|
24
|
+
__attach(viewTag: number, eventName: string): void;
|
|
25
|
+
__detach(viewTag: number, eventName: string): void;
|
|
26
|
+
__getHandler(): IAnimatedEventHandler;
|
|
27
|
+
}
|
|
28
|
+
export declare function event(argMapping: readonly IMapping[], config?: IEventConfig): IAnimatedEventHandler;
|
|
29
|
+
export interface INativeEventAttachment {
|
|
30
|
+
detach(): void;
|
|
31
|
+
}
|
|
32
|
+
export declare function attachNativeEvent(node: ISymbioteNode, eventName: string, argMapping: readonly IMapping[]): INativeEventAttachment;
|
|
33
|
+
export declare function attachNativeEventHandler(node: unknown, eventName: string, handler: unknown): INativeEventAttachment | undefined;
|
|
34
|
+
export declare function forkEvent(existing: IAnimatedEventHandler | IEventListener | undefined, listener: IEventListener): IAnimatedEventHandler | IEventListener;
|
|
35
|
+
export declare function unforkEvent(existing: IAnimatedEventHandler | IEventListener | undefined, listener: IEventListener): void;
|
|
36
|
+
export {};
|