@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,266 @@
|
|
|
1
|
+
// Arithmetic / operator graph nodes: add, subtract, multiply, divide, modulo,
|
|
2
|
+
// diffClamp. Each composes one or two upstream values into a derived value.
|
|
3
|
+
// Ported from RN's AnimatedAddition / AnimatedSubtraction / AnimatedMultiplication
|
|
4
|
+
// / AnimatedDivision / AnimatedModulo / AnimatedDiffClamp, numeric path only.
|
|
5
|
+
//
|
|
6
|
+
// Each node is an AnimatedWithChildren: its OWN children array holds downstream
|
|
7
|
+
// consumers (wired by the base __connectNativeChildren), while its INPUTS are held
|
|
8
|
+
// separately and wired by registering this node as a child of each input at
|
|
9
|
+
// __attach (input.__addChild(this)). __getNativeConfig is creation-only: it reads
|
|
10
|
+
// each input's native tag (creating the input node) but issues no connect.
|
|
11
|
+
import { AnimatedNode, AnimatedWithChildren } from './graph';
|
|
12
|
+
import { AnimatedValue } from './value';
|
|
13
|
+
import { AnimatedInterpolation } from './interpolation-node';
|
|
14
|
+
import { dlog } from '../debug';
|
|
15
|
+
// Wrap a bare number in an AnimatedValue so every input is a graph node.
|
|
16
|
+
function toNode(input) {
|
|
17
|
+
return typeof input === 'number' ? new AnimatedValue(input) : input;
|
|
18
|
+
}
|
|
19
|
+
function numericValue(node) {
|
|
20
|
+
const value = node.__getValue();
|
|
21
|
+
if (typeof value !== 'number') {
|
|
22
|
+
throw new Error('Animated operator input did not resolve to a number');
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
export class AnimatedAddition extends AnimatedWithChildren {
|
|
27
|
+
a;
|
|
28
|
+
b;
|
|
29
|
+
constructor(a, b) {
|
|
30
|
+
super();
|
|
31
|
+
this.a = toNode(a);
|
|
32
|
+
this.b = toNode(b);
|
|
33
|
+
}
|
|
34
|
+
__getValue() {
|
|
35
|
+
return numericValue(this.a) + numericValue(this.b);
|
|
36
|
+
}
|
|
37
|
+
interpolate(config) {
|
|
38
|
+
return new AnimatedInterpolation(this, config);
|
|
39
|
+
}
|
|
40
|
+
__attach() {
|
|
41
|
+
this.a.__addChild(this);
|
|
42
|
+
this.b.__addChild(this);
|
|
43
|
+
super.__attach();
|
|
44
|
+
}
|
|
45
|
+
__detach() {
|
|
46
|
+
this.a.__removeChild(this);
|
|
47
|
+
this.b.__removeChild(this);
|
|
48
|
+
super.__detach();
|
|
49
|
+
}
|
|
50
|
+
__makeNative(platformConfig) {
|
|
51
|
+
this.a.__makeNative(platformConfig);
|
|
52
|
+
this.b.__makeNative(platformConfig);
|
|
53
|
+
super.__makeNative(platformConfig);
|
|
54
|
+
}
|
|
55
|
+
__getNativeConfig() {
|
|
56
|
+
return { type: 'addition', input: [this.a.__getNativeTag(), this.b.__getNativeTag()] };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export class AnimatedSubtraction extends AnimatedWithChildren {
|
|
60
|
+
a;
|
|
61
|
+
b;
|
|
62
|
+
constructor(a, b) {
|
|
63
|
+
super();
|
|
64
|
+
this.a = toNode(a);
|
|
65
|
+
this.b = toNode(b);
|
|
66
|
+
}
|
|
67
|
+
__getValue() {
|
|
68
|
+
return numericValue(this.a) - numericValue(this.b);
|
|
69
|
+
}
|
|
70
|
+
interpolate(config) {
|
|
71
|
+
return new AnimatedInterpolation(this, config);
|
|
72
|
+
}
|
|
73
|
+
__attach() {
|
|
74
|
+
this.a.__addChild(this);
|
|
75
|
+
this.b.__addChild(this);
|
|
76
|
+
super.__attach();
|
|
77
|
+
}
|
|
78
|
+
__detach() {
|
|
79
|
+
this.a.__removeChild(this);
|
|
80
|
+
this.b.__removeChild(this);
|
|
81
|
+
super.__detach();
|
|
82
|
+
}
|
|
83
|
+
__makeNative(platformConfig) {
|
|
84
|
+
this.a.__makeNative(platformConfig);
|
|
85
|
+
this.b.__makeNative(platformConfig);
|
|
86
|
+
super.__makeNative(platformConfig);
|
|
87
|
+
}
|
|
88
|
+
__getNativeConfig() {
|
|
89
|
+
return { type: 'subtraction', input: [this.a.__getNativeTag(), this.b.__getNativeTag()] };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export class AnimatedMultiplication extends AnimatedWithChildren {
|
|
93
|
+
a;
|
|
94
|
+
b;
|
|
95
|
+
constructor(a, b) {
|
|
96
|
+
super();
|
|
97
|
+
this.a = toNode(a);
|
|
98
|
+
this.b = toNode(b);
|
|
99
|
+
}
|
|
100
|
+
__getValue() {
|
|
101
|
+
return numericValue(this.a) * numericValue(this.b);
|
|
102
|
+
}
|
|
103
|
+
interpolate(config) {
|
|
104
|
+
return new AnimatedInterpolation(this, config);
|
|
105
|
+
}
|
|
106
|
+
__attach() {
|
|
107
|
+
this.a.__addChild(this);
|
|
108
|
+
this.b.__addChild(this);
|
|
109
|
+
super.__attach();
|
|
110
|
+
}
|
|
111
|
+
__detach() {
|
|
112
|
+
this.a.__removeChild(this);
|
|
113
|
+
this.b.__removeChild(this);
|
|
114
|
+
super.__detach();
|
|
115
|
+
}
|
|
116
|
+
__makeNative(platformConfig) {
|
|
117
|
+
this.a.__makeNative(platformConfig);
|
|
118
|
+
this.b.__makeNative(platformConfig);
|
|
119
|
+
super.__makeNative(platformConfig);
|
|
120
|
+
}
|
|
121
|
+
__getNativeConfig() {
|
|
122
|
+
return { type: 'multiplication', input: [this.a.__getNativeTag(), this.b.__getNativeTag()] };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export class AnimatedDivision extends AnimatedWithChildren {
|
|
126
|
+
a;
|
|
127
|
+
b;
|
|
128
|
+
warnedAboutDivideByZero = false;
|
|
129
|
+
constructor(a, b) {
|
|
130
|
+
super();
|
|
131
|
+
if (b === 0 || (b instanceof AnimatedNode && b.__getValue() === 0)) {
|
|
132
|
+
dlog('AnimatedDivision: detected potential division by zero');
|
|
133
|
+
}
|
|
134
|
+
this.a = toNode(a);
|
|
135
|
+
this.b = toNode(b);
|
|
136
|
+
}
|
|
137
|
+
__getValue() {
|
|
138
|
+
const a = numericValue(this.a);
|
|
139
|
+
const b = numericValue(this.b);
|
|
140
|
+
if (b === 0) {
|
|
141
|
+
// A divide-by-zero yields Infinity/NaN, which crashes Fabric, so clamp to 0.
|
|
142
|
+
if (!this.warnedAboutDivideByZero) {
|
|
143
|
+
dlog('AnimatedDivision: detected division by zero');
|
|
144
|
+
this.warnedAboutDivideByZero = true;
|
|
145
|
+
}
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
this.warnedAboutDivideByZero = false;
|
|
149
|
+
return a / b;
|
|
150
|
+
}
|
|
151
|
+
interpolate(config) {
|
|
152
|
+
return new AnimatedInterpolation(this, config);
|
|
153
|
+
}
|
|
154
|
+
__attach() {
|
|
155
|
+
this.a.__addChild(this);
|
|
156
|
+
this.b.__addChild(this);
|
|
157
|
+
super.__attach();
|
|
158
|
+
}
|
|
159
|
+
__detach() {
|
|
160
|
+
this.a.__removeChild(this);
|
|
161
|
+
this.b.__removeChild(this);
|
|
162
|
+
super.__detach();
|
|
163
|
+
}
|
|
164
|
+
__makeNative(platformConfig) {
|
|
165
|
+
this.a.__makeNative(platformConfig);
|
|
166
|
+
this.b.__makeNative(platformConfig);
|
|
167
|
+
super.__makeNative(platformConfig);
|
|
168
|
+
}
|
|
169
|
+
__getNativeConfig() {
|
|
170
|
+
return { type: 'division', input: [this.a.__getNativeTag(), this.b.__getNativeTag()] };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
export class AnimatedModulo extends AnimatedWithChildren {
|
|
174
|
+
a;
|
|
175
|
+
modulus;
|
|
176
|
+
constructor(a, modulus) {
|
|
177
|
+
super();
|
|
178
|
+
this.a = a;
|
|
179
|
+
this.modulus = modulus;
|
|
180
|
+
}
|
|
181
|
+
// Euclidean modulo: always lands in [0, modulus), unlike JS % which keeps the
|
|
182
|
+
// dividend's sign.
|
|
183
|
+
__getValue() {
|
|
184
|
+
const a = numericValue(this.a);
|
|
185
|
+
return ((a % this.modulus) + this.modulus) % this.modulus;
|
|
186
|
+
}
|
|
187
|
+
interpolate(config) {
|
|
188
|
+
return new AnimatedInterpolation(this, config);
|
|
189
|
+
}
|
|
190
|
+
__attach() {
|
|
191
|
+
this.a.__addChild(this);
|
|
192
|
+
super.__attach();
|
|
193
|
+
}
|
|
194
|
+
__detach() {
|
|
195
|
+
this.a.__removeChild(this);
|
|
196
|
+
super.__detach();
|
|
197
|
+
}
|
|
198
|
+
__makeNative(platformConfig) {
|
|
199
|
+
this.a.__makeNative(platformConfig);
|
|
200
|
+
super.__makeNative(platformConfig);
|
|
201
|
+
}
|
|
202
|
+
__getNativeConfig() {
|
|
203
|
+
return { type: 'modulus', input: this.a.__getNativeTag(), modulus: this.modulus };
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
export class AnimatedDiffClamp extends AnimatedWithChildren {
|
|
207
|
+
a;
|
|
208
|
+
min;
|
|
209
|
+
max;
|
|
210
|
+
value;
|
|
211
|
+
lastValue;
|
|
212
|
+
constructor(a, min, max) {
|
|
213
|
+
super();
|
|
214
|
+
this.a = a;
|
|
215
|
+
this.min = min;
|
|
216
|
+
this.max = max;
|
|
217
|
+
this.value = numericValue(a);
|
|
218
|
+
this.lastValue = this.value;
|
|
219
|
+
}
|
|
220
|
+
// Accumulate the input's frame-to-frame DELTA and clamp the running total to
|
|
221
|
+
// [min, max]. The output tracks the input but never drifts past the band: the
|
|
222
|
+
// classic collapsing-header pattern.
|
|
223
|
+
__getValue() {
|
|
224
|
+
const value = numericValue(this.a);
|
|
225
|
+
const diff = value - this.lastValue;
|
|
226
|
+
this.lastValue = value;
|
|
227
|
+
this.value = Math.min(Math.max(this.value + diff, this.min), this.max);
|
|
228
|
+
return this.value;
|
|
229
|
+
}
|
|
230
|
+
interpolate(config) {
|
|
231
|
+
return new AnimatedInterpolation(this, config);
|
|
232
|
+
}
|
|
233
|
+
__attach() {
|
|
234
|
+
this.a.__addChild(this);
|
|
235
|
+
super.__attach();
|
|
236
|
+
}
|
|
237
|
+
__detach() {
|
|
238
|
+
this.a.__removeChild(this);
|
|
239
|
+
super.__detach();
|
|
240
|
+
}
|
|
241
|
+
__makeNative(platformConfig) {
|
|
242
|
+
this.a.__makeNative(platformConfig);
|
|
243
|
+
super.__makeNative(platformConfig);
|
|
244
|
+
}
|
|
245
|
+
__getNativeConfig() {
|
|
246
|
+
return { type: 'diffclamp', input: this.a.__getNativeTag(), min: this.min, max: this.max };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
export function add(a, b) {
|
|
250
|
+
return new AnimatedAddition(a, b);
|
|
251
|
+
}
|
|
252
|
+
export function subtract(a, b) {
|
|
253
|
+
return new AnimatedSubtraction(a, b);
|
|
254
|
+
}
|
|
255
|
+
export function multiply(a, b) {
|
|
256
|
+
return new AnimatedMultiplication(a, b);
|
|
257
|
+
}
|
|
258
|
+
export function divide(a, b) {
|
|
259
|
+
return new AnimatedDivision(a, b);
|
|
260
|
+
}
|
|
261
|
+
export function modulo(a, modulus) {
|
|
262
|
+
return new AnimatedModulo(a, modulus);
|
|
263
|
+
}
|
|
264
|
+
export function diffClamp(a, min, max) {
|
|
265
|
+
return new AnimatedDiffClamp(a, min, max);
|
|
266
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AnimatedWithChildren } from './graph';
|
|
2
|
+
import { type INativeNodeConfig } from './native/native-animated';
|
|
3
|
+
export declare class AnimatedProps extends AnimatedWithChildren {
|
|
4
|
+
private readonly nodes;
|
|
5
|
+
private readonly props;
|
|
6
|
+
private target;
|
|
7
|
+
private connectedViewTag;
|
|
8
|
+
constructor(inputProps: Record<string, unknown>);
|
|
9
|
+
__getValue(): Record<string, unknown>;
|
|
10
|
+
__getAnimatedValue(): Record<string, unknown>;
|
|
11
|
+
setNativeView(instance: unknown): void;
|
|
12
|
+
update(): void;
|
|
13
|
+
__attach(): void;
|
|
14
|
+
__detach(): void;
|
|
15
|
+
__makeNative(): void;
|
|
16
|
+
private connectToView;
|
|
17
|
+
retryViewConnect(): void;
|
|
18
|
+
private disconnectFromView;
|
|
19
|
+
__getNativeConfig(): INativeNodeConfig;
|
|
20
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// AnimatedProps: the leaf where the value graph meets symbiote's commit engine.
|
|
2
|
+
// It holds the host SymbioteNode (the public instance a ref handed us) and a props
|
|
3
|
+
// map whose entries may be AnimatedNodes (an animated `style` becomes an
|
|
4
|
+
// AnimatedStyle, a bare animated prop stays an AnimatedNode). Each frame, the graph
|
|
5
|
+
// flushes to this leaf via its `update()` method, which re-pulls the current values
|
|
6
|
+
// into a flat partial and pushes it through shared's scoped setNativeProps: one
|
|
7
|
+
// targeted clone-on-write commit. Ported from RN's AnimatedProps.js, JS-driven path
|
|
8
|
+
// only: native config (__makeNative / __getNativeConfig / connectAnimatedNodeToView,
|
|
9
|
+
// ADR 0017) is stripped.
|
|
10
|
+
//
|
|
11
|
+
// `update` MUST be a method, not a class field: flushValue detects a leaf by reading
|
|
12
|
+
// a `update` function off the node, and under useDefineForClassFields a field
|
|
13
|
+
// initialiser would shadow it and break subclassing. (See shared graph.ts leafUpdate.)
|
|
14
|
+
import { AnimatedNode, AnimatedWithChildren } from './graph';
|
|
15
|
+
import { setNativeProps, getNativeTag } from '../commit';
|
|
16
|
+
import { isSymbioteNode } from '../node';
|
|
17
|
+
import { registerPostCommit } from '../post-commit';
|
|
18
|
+
import { nativeAnimated } from './native/native-animated';
|
|
19
|
+
import { AnimatedStyle } from './style';
|
|
20
|
+
function isAnimatedNode(value) {
|
|
21
|
+
return value instanceof AnimatedNode;
|
|
22
|
+
}
|
|
23
|
+
// Leaves that went native before their view's Fabric tag existed. Under an async-batched
|
|
24
|
+
// commit (Vue/Svelte schedule completeRoot on a microtask) a native animation started in
|
|
25
|
+
// onMounted cascades to the leaf BEFORE the first commit assigns the tag, so connectToView
|
|
26
|
+
// finds no tag. We hold the leaf here and retry it once each commit assigns tags — the
|
|
27
|
+
// third connect trigger alongside setNativeView and __makeNative. React commits
|
|
28
|
+
// synchronously, so its leaves never land here.
|
|
29
|
+
const pendingViewConnects = new Set();
|
|
30
|
+
registerPostCommit(() => {
|
|
31
|
+
for (const leaf of pendingViewConnects)
|
|
32
|
+
leaf.retryViewConnect();
|
|
33
|
+
});
|
|
34
|
+
// Split the incoming props into (1) the AnimatedNodes to subscribe to and (2) the
|
|
35
|
+
// props map with `style` wrapped in an AnimatedStyle when it holds animated values.
|
|
36
|
+
// A fully-static style stays a plain object and contributes no node.
|
|
37
|
+
function createAnimatedProps(inputProps) {
|
|
38
|
+
const nodes = [];
|
|
39
|
+
const props = {};
|
|
40
|
+
for (const key of Object.keys(inputProps)) {
|
|
41
|
+
const value = inputProps[key];
|
|
42
|
+
// `children` is a React element (its $$typeof is a Symbol), managed by the
|
|
43
|
+
// reconciler as real Fabric child nodes, never a serializable prop. The host
|
|
44
|
+
// config strips it from every prop bag; the Animated flush must too, else each
|
|
45
|
+
// frame's setNativeProps sends the element to Fabric and folly::dynamic throws
|
|
46
|
+
// "JS Symbols are not convertible to dynamic" (Android is strict; iOS ignores it).
|
|
47
|
+
if (key === 'children')
|
|
48
|
+
continue;
|
|
49
|
+
if (key === 'style') {
|
|
50
|
+
const styleNode = AnimatedStyle.from(value);
|
|
51
|
+
if (styleNode !== undefined) {
|
|
52
|
+
props[key] = styleNode;
|
|
53
|
+
nodes.push(styleNode);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
props[key] = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else if (isAnimatedNode(value)) {
|
|
60
|
+
props[key] = value;
|
|
61
|
+
nodes.push(value);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
props[key] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { nodes, props };
|
|
68
|
+
}
|
|
69
|
+
export class AnimatedProps extends AnimatedWithChildren {
|
|
70
|
+
nodes;
|
|
71
|
+
props;
|
|
72
|
+
// The host view this leaf flushes onto. Null until a ref captures the rendered
|
|
73
|
+
// base component's public instance via setNativeView.
|
|
74
|
+
target = null;
|
|
75
|
+
// The Fabric view tag this leaf is bound to natively (null until connected).
|
|
76
|
+
// Kept so __detach can disconnect exactly what it connected (ADR 0017).
|
|
77
|
+
connectedViewTag = null;
|
|
78
|
+
constructor(inputProps) {
|
|
79
|
+
super();
|
|
80
|
+
const { nodes, props } = createAnimatedProps(inputProps);
|
|
81
|
+
this.nodes = nodes;
|
|
82
|
+
this.props = props;
|
|
83
|
+
}
|
|
84
|
+
// Rasterize the whole props map: animated entries to their current value, static
|
|
85
|
+
// entries passed through. The flat partial setNativeProps hoists onto the view.
|
|
86
|
+
__getValue() {
|
|
87
|
+
const out = {};
|
|
88
|
+
for (const key of Object.keys(this.props)) {
|
|
89
|
+
const value = this.props[key];
|
|
90
|
+
out[key] = isAnimatedNode(value) ? value.__getValue() : value;
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
__getAnimatedValue() {
|
|
95
|
+
const out = {};
|
|
96
|
+
for (const key of Object.keys(this.props)) {
|
|
97
|
+
const value = this.props[key];
|
|
98
|
+
out[key] = isAnimatedNode(value) ? value.__getAnimatedValue() : value;
|
|
99
|
+
}
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
// Bind this leaf to the host view a ref just captured. A SymbioteNode is the
|
|
103
|
+
// public instance the host config returns (getPublicInstance), so we guard
|
|
104
|
+
// structurally rather than cast.
|
|
105
|
+
setNativeView(instance) {
|
|
106
|
+
if (this.target !== null && this.target === instance)
|
|
107
|
+
return;
|
|
108
|
+
if (!isSymbioteNode(instance))
|
|
109
|
+
return;
|
|
110
|
+
this.target = instance;
|
|
111
|
+
// If a native-driven animation already made this leaf native (view attached
|
|
112
|
+
// after the animation began), connect now.
|
|
113
|
+
if (this.__isNative())
|
|
114
|
+
this.connectToView();
|
|
115
|
+
}
|
|
116
|
+
// The leaf seam (a method, never a field). flushValue calls this once per frame;
|
|
117
|
+
// re-pull the current values and push them through the scoped commit. Skipped
|
|
118
|
+
// until the view is captured and committed at least once (setNativeProps no-ops
|
|
119
|
+
// on an uncommitted node).
|
|
120
|
+
update() {
|
|
121
|
+
if (this.target === null)
|
|
122
|
+
return;
|
|
123
|
+
setNativeProps(this.target, this.__getValue());
|
|
124
|
+
}
|
|
125
|
+
__attach() {
|
|
126
|
+
for (const node of this.nodes)
|
|
127
|
+
node.__addChild(this);
|
|
128
|
+
}
|
|
129
|
+
__detach() {
|
|
130
|
+
pendingViewConnects.delete(this);
|
|
131
|
+
if (this.__isNative()) {
|
|
132
|
+
// Reset the view's animated props to their defaults (native no longer
|
|
133
|
+
// tracks them) and unbind, before the graph drops the native node.
|
|
134
|
+
nativeAnimated.restoreDefaultValues(this.__getNativeTag());
|
|
135
|
+
this.disconnectFromView();
|
|
136
|
+
}
|
|
137
|
+
for (const node of this.nodes)
|
|
138
|
+
node.__removeChild(this);
|
|
139
|
+
this.target = null;
|
|
140
|
+
super.__detach();
|
|
141
|
+
}
|
|
142
|
+
// ---- native driver (ADR 0017) -------------------------------------------
|
|
143
|
+
// Marking the leaf native binds it to the host view. The value->...->props edges
|
|
144
|
+
// are wired by the upstream walk (AnimatedWithChildren.__makeNative); the one
|
|
145
|
+
// thing only the leaf can do is attach the props node to a real view tag.
|
|
146
|
+
__makeNative() {
|
|
147
|
+
super.__makeNative();
|
|
148
|
+
if (this.target !== null)
|
|
149
|
+
this.connectToView();
|
|
150
|
+
}
|
|
151
|
+
connectToView() {
|
|
152
|
+
if (this.target === null || this.connectedViewTag !== null)
|
|
153
|
+
return;
|
|
154
|
+
const viewTag = getNativeTag(this.target);
|
|
155
|
+
if (viewTag === undefined) {
|
|
156
|
+
// The view isn't committed yet (async-batched commit): retry after the commit
|
|
157
|
+
// that assigns its tag, via the post-commit hook.
|
|
158
|
+
pendingViewConnects.add(this);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
pendingViewConnects.delete(this);
|
|
162
|
+
nativeAnimated.connectAnimatedNodeToView(this.__getNativeTag(), viewTag);
|
|
163
|
+
this.connectedViewTag = viewTag;
|
|
164
|
+
}
|
|
165
|
+
// Post-commit retry of a connect deferred because the view tag wasn't assigned yet.
|
|
166
|
+
// No-op once connected (connectToView short-circuits on connectedViewTag).
|
|
167
|
+
retryViewConnect() {
|
|
168
|
+
this.connectToView();
|
|
169
|
+
}
|
|
170
|
+
disconnectFromView() {
|
|
171
|
+
if (this.connectedViewTag === null)
|
|
172
|
+
return;
|
|
173
|
+
nativeAnimated.disconnectAnimatedNodeFromView(this.__getNativeTag(), this.connectedViewTag);
|
|
174
|
+
this.connectedViewTag = null;
|
|
175
|
+
}
|
|
176
|
+
__getNativeConfig() {
|
|
177
|
+
const propsConfig = {};
|
|
178
|
+
for (const key of Object.keys(this.props)) {
|
|
179
|
+
const value = this.props[key];
|
|
180
|
+
if (isAnimatedNode(value)) {
|
|
181
|
+
// __getNativeTag only: creation is edge-free; the connect is a later phase.
|
|
182
|
+
propsConfig[key] = value.__getNativeTag();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { type: 'props', props: propsConfig };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AnimatedNode, AnimatedWithChildren } from './graph';
|
|
2
|
+
import type { INativeNodeConfig } from './native/native-animated';
|
|
3
|
+
type ITransformEntry = Record<string, unknown>;
|
|
4
|
+
export declare class AnimatedTransform extends AnimatedWithChildren {
|
|
5
|
+
private readonly nodes;
|
|
6
|
+
private readonly transforms;
|
|
7
|
+
static from(transforms: unknown): AnimatedTransform | undefined;
|
|
8
|
+
constructor(nodes: readonly AnimatedNode[], transforms: readonly ITransformEntry[]);
|
|
9
|
+
__getValue(): ITransformEntry[];
|
|
10
|
+
__getAnimatedValue(): ITransformEntry[];
|
|
11
|
+
__attach(): void;
|
|
12
|
+
__detach(): void;
|
|
13
|
+
__getNativeConfig(): INativeNodeConfig;
|
|
14
|
+
}
|
|
15
|
+
export declare class AnimatedStyle extends AnimatedWithChildren {
|
|
16
|
+
private readonly style;
|
|
17
|
+
private readonly nodes;
|
|
18
|
+
static from(styleProp: unknown): AnimatedStyle | undefined;
|
|
19
|
+
constructor(style: Record<string, unknown>, nodes: readonly AnimatedNode[]);
|
|
20
|
+
__getValue(): Record<string, unknown>;
|
|
21
|
+
__getAnimatedValue(): Record<string, unknown>;
|
|
22
|
+
__attach(): void;
|
|
23
|
+
__detach(): void;
|
|
24
|
+
__getNativeConfig(): INativeNodeConfig;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// AnimatedStyle / AnimatedTransform: graph nodes that flatten a `style` /
|
|
2
|
+
// `transform` whose entries may themselves be AnimatedNodes. Ported from RN's
|
|
3
|
+
// AnimatedStyle.js + AnimatedTransform.js, NUMERIC path only: the native-driver
|
|
4
|
+
// config (__makeNative / __getNativeConfig / allowlist) and the web/string/color
|
|
5
|
+
// branches are stripped (ADR 0016). On __getValue() each node re-pulls its
|
|
6
|
+
// animated entries into a plain flat object the props leaf hoists onto the view.
|
|
7
|
+
import { AnimatedNode, AnimatedWithChildren } from './graph';
|
|
8
|
+
import { flattenStyle } from '../style';
|
|
9
|
+
function isAnimatedNode(value) {
|
|
10
|
+
return value instanceof AnimatedNode;
|
|
11
|
+
}
|
|
12
|
+
// Normalize an angle string to radians so native gets a plain number (RN's
|
|
13
|
+
// transformDataType). Anything else passes through untouched.
|
|
14
|
+
function transformDataType(value) {
|
|
15
|
+
if (typeof value !== 'string')
|
|
16
|
+
return value;
|
|
17
|
+
if (value.endsWith('deg'))
|
|
18
|
+
return ((parseFloat(value) || 0) * Math.PI) / 180;
|
|
19
|
+
if (value.endsWith('rad'))
|
|
20
|
+
return parseFloat(value) || 0;
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
// Collect the AnimatedNodes nested directly under a list of transform entries,
|
|
24
|
+
// so __attach can subscribe to each and a value change reaches this node.
|
|
25
|
+
function animatedNodesInTransforms(transforms) {
|
|
26
|
+
const nodes = [];
|
|
27
|
+
for (const entry of transforms) {
|
|
28
|
+
for (const key of Object.keys(entry)) {
|
|
29
|
+
const value = entry[key];
|
|
30
|
+
if (isAnimatedNode(value))
|
|
31
|
+
nodes.push(value);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return nodes;
|
|
35
|
+
}
|
|
36
|
+
export class AnimatedTransform extends AnimatedWithChildren {
|
|
37
|
+
nodes;
|
|
38
|
+
transforms;
|
|
39
|
+
// Returns an AnimatedTransform only if at least one entry is animated;
|
|
40
|
+
// otherwise the transform is fully static and needs no graph node.
|
|
41
|
+
static from(transforms) {
|
|
42
|
+
if (!Array.isArray(transforms))
|
|
43
|
+
return undefined;
|
|
44
|
+
const entries = [];
|
|
45
|
+
for (const entry of transforms) {
|
|
46
|
+
if (typeof entry === 'object' && entry !== null)
|
|
47
|
+
entries.push(entry);
|
|
48
|
+
}
|
|
49
|
+
const nodes = animatedNodesInTransforms(entries);
|
|
50
|
+
if (nodes.length === 0)
|
|
51
|
+
return undefined;
|
|
52
|
+
return new AnimatedTransform(nodes, entries);
|
|
53
|
+
}
|
|
54
|
+
constructor(nodes, transforms) {
|
|
55
|
+
super();
|
|
56
|
+
this.nodes = nodes;
|
|
57
|
+
this.transforms = transforms;
|
|
58
|
+
}
|
|
59
|
+
// Rasterize every entry: animated values pulled to their current number, static
|
|
60
|
+
// values passed through. Each result is a single-key object, order preserved.
|
|
61
|
+
__getValue() {
|
|
62
|
+
return this.transforms.map(entry => {
|
|
63
|
+
const result = {};
|
|
64
|
+
for (const key of Object.keys(entry)) {
|
|
65
|
+
const value = entry[key];
|
|
66
|
+
result[key] = isAnimatedNode(value) ? value.__getValue() : value;
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
__getAnimatedValue() {
|
|
72
|
+
return this.transforms.map(entry => {
|
|
73
|
+
const result = {};
|
|
74
|
+
for (const key of Object.keys(entry)) {
|
|
75
|
+
const value = entry[key];
|
|
76
|
+
result[key] = isAnimatedNode(value) ? value.__getAnimatedValue() : value;
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
__attach() {
|
|
82
|
+
for (const node of this.nodes)
|
|
83
|
+
node.__addChild(this);
|
|
84
|
+
}
|
|
85
|
+
__detach() {
|
|
86
|
+
for (const node of this.nodes)
|
|
87
|
+
node.__removeChild(this);
|
|
88
|
+
super.__detach();
|
|
89
|
+
}
|
|
90
|
+
// Native: one entry per transform, animated entries pointing at their value's
|
|
91
|
+
// native tag, static ones carrying the (angle-normalized) literal (ADR 0017).
|
|
92
|
+
__getNativeConfig() {
|
|
93
|
+
const transforms = [];
|
|
94
|
+
for (const entry of this.transforms) {
|
|
95
|
+
for (const key of Object.keys(entry)) {
|
|
96
|
+
const value = entry[key];
|
|
97
|
+
if (isAnimatedNode(value)) {
|
|
98
|
+
// __getNativeTag only: creation is edge-free; the connect is a later phase.
|
|
99
|
+
transforms.push({ type: 'animated', property: key, nodeTag: value.__getNativeTag() });
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
transforms.push({ type: 'static', property: key, value: transformDataType(value) });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { type: 'transform', transforms };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export class AnimatedStyle extends AnimatedWithChildren {
|
|
110
|
+
// The flat style with animated keys still pointing at their AnimatedNode (so a
|
|
111
|
+
// re-pull on __getValue reads the live value); static keys hold plain values.
|
|
112
|
+
style;
|
|
113
|
+
nodes;
|
|
114
|
+
// Returns an AnimatedStyle only if the flattened style contains AnimatedNodes
|
|
115
|
+
// (directly, or a `transform` array with animated entries). Otherwise undefined.
|
|
116
|
+
static from(styleProp) {
|
|
117
|
+
const flat = flattenStyle(styleProp);
|
|
118
|
+
const style = {};
|
|
119
|
+
const nodes = [];
|
|
120
|
+
for (const key of Object.keys(flat)) {
|
|
121
|
+
const value = Reflect.get(flat, key);
|
|
122
|
+
if (key === 'transform') {
|
|
123
|
+
const transformNode = AnimatedTransform.from(value);
|
|
124
|
+
if (transformNode !== undefined) {
|
|
125
|
+
style[key] = transformNode;
|
|
126
|
+
nodes.push(transformNode);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
style[key] = value;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else if (isAnimatedNode(value)) {
|
|
133
|
+
style[key] = value;
|
|
134
|
+
nodes.push(value);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
style[key] = value;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (nodes.length === 0)
|
|
141
|
+
return undefined;
|
|
142
|
+
return new AnimatedStyle(style, nodes);
|
|
143
|
+
}
|
|
144
|
+
constructor(style, nodes) {
|
|
145
|
+
super();
|
|
146
|
+
this.style = style;
|
|
147
|
+
this.nodes = nodes;
|
|
148
|
+
}
|
|
149
|
+
__getValue() {
|
|
150
|
+
const out = {};
|
|
151
|
+
for (const key of Object.keys(this.style)) {
|
|
152
|
+
const value = this.style[key];
|
|
153
|
+
out[key] = isAnimatedNode(value) ? value.__getValue() : value;
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
__getAnimatedValue() {
|
|
158
|
+
const out = {};
|
|
159
|
+
for (const key of Object.keys(this.style)) {
|
|
160
|
+
const value = this.style[key];
|
|
161
|
+
out[key] = isAnimatedNode(value) ? value.__getAnimatedValue() : value;
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
__attach() {
|
|
166
|
+
for (const node of this.nodes)
|
|
167
|
+
node.__addChild(this);
|
|
168
|
+
}
|
|
169
|
+
__detach() {
|
|
170
|
+
for (const node of this.nodes)
|
|
171
|
+
node.__removeChild(this);
|
|
172
|
+
super.__detach();
|
|
173
|
+
}
|
|
174
|
+
// Native: map each animated style key to its value's native tag (ADR 0017).
|
|
175
|
+
// Static keys are not in the native style node. The view already carries them.
|
|
176
|
+
__getNativeConfig() {
|
|
177
|
+
const style = {};
|
|
178
|
+
for (const key of Object.keys(this.style)) {
|
|
179
|
+
const value = this.style[key];
|
|
180
|
+
if (isAnimatedNode(value)) {
|
|
181
|
+
// __getNativeTag only: creation is edge-free; the connect is a later phase.
|
|
182
|
+
style[key] = value.__getNativeTag();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { type: 'style', style };
|
|
186
|
+
}
|
|
187
|
+
}
|