@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,35 @@
|
|
|
1
|
+
import { AnimatedValue } from './value';
|
|
2
|
+
export interface IValueXY {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
}
|
|
6
|
+
type IValueXYListener = (value: IValueXY) => void;
|
|
7
|
+
export declare class AnimatedValueXY {
|
|
8
|
+
readonly x: AnimatedValue;
|
|
9
|
+
readonly y: AnimatedValue;
|
|
10
|
+
private readonly jointListeners;
|
|
11
|
+
constructor(value?: {
|
|
12
|
+
x: number | AnimatedValue;
|
|
13
|
+
y: number | AnimatedValue;
|
|
14
|
+
});
|
|
15
|
+
__getValue(): IValueXY;
|
|
16
|
+
setValue(value: IValueXY): void;
|
|
17
|
+
setOffset(offset: IValueXY): void;
|
|
18
|
+
flattenOffset(): void;
|
|
19
|
+
extractOffset(): void;
|
|
20
|
+
stopAnimation(callback?: (value: IValueXY) => void): void;
|
|
21
|
+
resetAnimation(callback?: (value: IValueXY) => void): void;
|
|
22
|
+
addListener(callback: IValueXYListener): string;
|
|
23
|
+
removeListener(id: string): void;
|
|
24
|
+
removeAllListeners(): void;
|
|
25
|
+
getLayout(): {
|
|
26
|
+
left: AnimatedValue;
|
|
27
|
+
top: AnimatedValue;
|
|
28
|
+
};
|
|
29
|
+
getTranslateTransform(): [{
|
|
30
|
+
translateX: AnimatedValue;
|
|
31
|
+
}, {
|
|
32
|
+
translateY: AnimatedValue;
|
|
33
|
+
}];
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// AnimatedValueXY: a 2D value for pan-gesture-style animations. It is not a
|
|
2
|
+
// driving node itself: it multiplexes two ordinary AnimatedValues (x, y), so the
|
|
3
|
+
// same clone-on-write and listener machinery that powers AnimatedValue applies
|
|
4
|
+
// per-axis. Ported from RN's AnimatedValueXY.js with the native-driver and
|
|
5
|
+
// platform-config branches removed (ADR 0016). The two child values carry their
|
|
6
|
+
// own native state if they are ever made native.
|
|
7
|
+
import { AnimatedValue } from './value';
|
|
8
|
+
let nextListenerId = 1;
|
|
9
|
+
function isAnimatedValuePair(value) {
|
|
10
|
+
return value.x instanceof AnimatedValue && value.y instanceof AnimatedValue;
|
|
11
|
+
}
|
|
12
|
+
// Not an AnimatedNode: you bind the inner x/y (via getLayout / getTranslateTransform),
|
|
13
|
+
// never the XY object itself, so it carries no graph-node base, just the two values.
|
|
14
|
+
export class AnimatedValueXY {
|
|
15
|
+
x;
|
|
16
|
+
y;
|
|
17
|
+
// Each joint id maps to the two per-axis listener ids it registered, so
|
|
18
|
+
// removeListener can tear both down together.
|
|
19
|
+
jointListeners = new Map();
|
|
20
|
+
constructor(value = { x: 0, y: 0 }) {
|
|
21
|
+
if (typeof value.x === 'number' && typeof value.y === 'number') {
|
|
22
|
+
this.x = new AnimatedValue(value.x);
|
|
23
|
+
this.y = new AnimatedValue(value.y);
|
|
24
|
+
}
|
|
25
|
+
else if (isAnimatedValuePair(value)) {
|
|
26
|
+
this.x = value.x;
|
|
27
|
+
this.y = value.y;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
throw new Error('AnimatedValueXY must be initialized with an object of numbers or AnimatedValues.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
__getValue() {
|
|
34
|
+
return { x: this.x.__getValue(), y: this.y.__getValue() };
|
|
35
|
+
}
|
|
36
|
+
// Directly set both axes. Stops any running per-axis animation and updates
|
|
37
|
+
// every bound prop.
|
|
38
|
+
setValue(value) {
|
|
39
|
+
this.x.setValue(value.x);
|
|
40
|
+
this.y.setValue(value.y);
|
|
41
|
+
}
|
|
42
|
+
// An offset applied on top of whatever value is set, per axis.
|
|
43
|
+
setOffset(offset) {
|
|
44
|
+
this.x.setOffset(offset.x);
|
|
45
|
+
this.y.setOffset(offset.y);
|
|
46
|
+
}
|
|
47
|
+
// Fold each axis's offset into its base value; the output is unchanged.
|
|
48
|
+
flattenOffset() {
|
|
49
|
+
this.x.flattenOffset();
|
|
50
|
+
this.y.flattenOffset();
|
|
51
|
+
}
|
|
52
|
+
// Move each axis's base value into its offset; the output is unchanged.
|
|
53
|
+
extractOffset() {
|
|
54
|
+
this.x.extractOffset();
|
|
55
|
+
this.y.extractOffset();
|
|
56
|
+
}
|
|
57
|
+
// Stop any running animation on either axis. `callback` receives the final
|
|
58
|
+
// 2D value, useful for syncing state to the resting position.
|
|
59
|
+
stopAnimation(callback) {
|
|
60
|
+
this.x.stopAnimation();
|
|
61
|
+
this.y.stopAnimation();
|
|
62
|
+
callback?.(this.__getValue());
|
|
63
|
+
}
|
|
64
|
+
// Stop any animation and reset both axes to their original values.
|
|
65
|
+
resetAnimation(callback) {
|
|
66
|
+
this.x.resetAnimation();
|
|
67
|
+
this.y.resetAnimation();
|
|
68
|
+
callback?.(this.__getValue());
|
|
69
|
+
}
|
|
70
|
+
// Observe updates from either axis as a single {x, y} event. Both axes share
|
|
71
|
+
// one joint callback, so a change on either fires the listener with the
|
|
72
|
+
// current 2D value.
|
|
73
|
+
addListener(callback) {
|
|
74
|
+
const id = String(nextListenerId++);
|
|
75
|
+
const jointCallback = () => {
|
|
76
|
+
callback(this.__getValue());
|
|
77
|
+
};
|
|
78
|
+
this.jointListeners.set(id, {
|
|
79
|
+
x: this.x.addListener(jointCallback),
|
|
80
|
+
y: this.y.addListener(jointCallback),
|
|
81
|
+
});
|
|
82
|
+
return id;
|
|
83
|
+
}
|
|
84
|
+
removeListener(id) {
|
|
85
|
+
const pair = this.jointListeners.get(id);
|
|
86
|
+
if (pair === undefined) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
this.x.removeListener(pair.x);
|
|
90
|
+
this.y.removeListener(pair.y);
|
|
91
|
+
this.jointListeners.delete(id);
|
|
92
|
+
}
|
|
93
|
+
removeAllListeners() {
|
|
94
|
+
this.x.removeAllListeners();
|
|
95
|
+
this.y.removeAllListeners();
|
|
96
|
+
this.jointListeners.clear();
|
|
97
|
+
}
|
|
98
|
+
// Convert {x, y} into {left, top} for direct use in a style object.
|
|
99
|
+
getLayout() {
|
|
100
|
+
return { left: this.x, top: this.y };
|
|
101
|
+
}
|
|
102
|
+
// Convert {x, y} into a usable translation transform array.
|
|
103
|
+
getTranslateTransform() {
|
|
104
|
+
return [{ translateX: this.x }, { translateY: this.y }];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { IAnimation, IEndCallback } from './animation';
|
|
2
|
+
import { AnimatedWithChildren, type IValueListener } from './graph';
|
|
3
|
+
import type { AnimatedTracking } from './animations/tracking';
|
|
4
|
+
import { AnimatedInterpolation } from './interpolation-node';
|
|
5
|
+
import type { IInterpolationConfig } from './interpolation';
|
|
6
|
+
import { type INativeNodeConfig, type IPlatformConfig } from './native/native-animated';
|
|
7
|
+
export declare class AnimatedValue extends AnimatedWithChildren {
|
|
8
|
+
private value;
|
|
9
|
+
private readonly startingValue;
|
|
10
|
+
private offset;
|
|
11
|
+
private animation;
|
|
12
|
+
private nativeListening;
|
|
13
|
+
private tracking;
|
|
14
|
+
constructor(value: number);
|
|
15
|
+
__detach(): void;
|
|
16
|
+
addListener(callback: IValueListener): string;
|
|
17
|
+
removeListener(id: string): void;
|
|
18
|
+
removeAllListeners(): void;
|
|
19
|
+
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
20
|
+
private startListeningToNativeValueUpdates;
|
|
21
|
+
private stopListeningToNativeValueUpdates;
|
|
22
|
+
__getValue(): number;
|
|
23
|
+
setValue(value: number): void;
|
|
24
|
+
setOffset(offset: number): void;
|
|
25
|
+
flattenOffset(): void;
|
|
26
|
+
extractOffset(): void;
|
|
27
|
+
__onNativeUpdate(value: number, offset?: number): void;
|
|
28
|
+
__getNativeConfig(): INativeNodeConfig;
|
|
29
|
+
stopAnimation(callback?: (value: number) => void): void;
|
|
30
|
+
track(tracking: AnimatedTracking): void;
|
|
31
|
+
private stopTracking;
|
|
32
|
+
resetAnimation(callback?: (value: number) => void): void;
|
|
33
|
+
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
34
|
+
animate(animation: IAnimation, callback?: IEndCallback): void;
|
|
35
|
+
private updateValue;
|
|
36
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// AnimatedValue: the standard driving value. One value can drive many props in
|
|
2
|
+
// sync but is driven by one mechanism at a time: a new mechanism (a fresh
|
|
3
|
+
// animation, or setValue) stops the previous one. Ported from RN's
|
|
4
|
+
// AnimatedValue.js with the native-driver branches removed (ADR 0016); tracking
|
|
5
|
+
// (animating toward another animated node) is deferred.
|
|
6
|
+
import { AnimatedWithChildren, flushValue } from './graph';
|
|
7
|
+
import { AnimatedInterpolation } from './interpolation-node';
|
|
8
|
+
import { nativeAnimated, } from './native/native-animated';
|
|
9
|
+
export class AnimatedValue extends AnimatedWithChildren {
|
|
10
|
+
value;
|
|
11
|
+
startingValue;
|
|
12
|
+
offset;
|
|
13
|
+
animation;
|
|
14
|
+
// True while we are streaming native value updates back to JS listeners (only
|
|
15
|
+
// meaningful when the value is native-driven and has at least one JS listener).
|
|
16
|
+
nativeListening = false;
|
|
17
|
+
// Set while this value is chasing a moving target (Animated.spring toValue: node).
|
|
18
|
+
tracking = null;
|
|
19
|
+
constructor(value) {
|
|
20
|
+
super();
|
|
21
|
+
if (typeof value !== 'number') {
|
|
22
|
+
throw new Error('AnimatedValue: Attempting to set value to undefined');
|
|
23
|
+
}
|
|
24
|
+
this.startingValue = value;
|
|
25
|
+
this.value = value;
|
|
26
|
+
this.offset = 0;
|
|
27
|
+
this.animation = null;
|
|
28
|
+
}
|
|
29
|
+
__detach() {
|
|
30
|
+
this.stopAnimation();
|
|
31
|
+
this.stopListeningToNativeValueUpdates();
|
|
32
|
+
super.__detach();
|
|
33
|
+
}
|
|
34
|
+
// A JS listener on a native-driven value sees nothing per frame unless native
|
|
35
|
+
// streams updates back, so adding the first listener starts that stream and
|
|
36
|
+
// removing the last stops it. When the value isn't native, these are no-ops and
|
|
37
|
+
// the base listener machinery alone fires (JS owns the frames).
|
|
38
|
+
addListener(callback) {
|
|
39
|
+
const id = super.addListener(callback);
|
|
40
|
+
if (this.isNative)
|
|
41
|
+
this.startListeningToNativeValueUpdates();
|
|
42
|
+
return id;
|
|
43
|
+
}
|
|
44
|
+
removeListener(id) {
|
|
45
|
+
super.removeListener(id);
|
|
46
|
+
if (!this.hasListeners())
|
|
47
|
+
this.stopListeningToNativeValueUpdates();
|
|
48
|
+
}
|
|
49
|
+
removeAllListeners() {
|
|
50
|
+
super.removeAllListeners();
|
|
51
|
+
this.stopListeningToNativeValueUpdates();
|
|
52
|
+
}
|
|
53
|
+
// A value made native while listeners already exist must start streaming now.
|
|
54
|
+
__makeNative(platformConfig) {
|
|
55
|
+
super.__makeNative(platformConfig);
|
|
56
|
+
if (this.hasListeners())
|
|
57
|
+
this.startListeningToNativeValueUpdates();
|
|
58
|
+
}
|
|
59
|
+
startListeningToNativeValueUpdates() {
|
|
60
|
+
if (this.nativeListening || !this.isNative)
|
|
61
|
+
return;
|
|
62
|
+
this.nativeListening = true;
|
|
63
|
+
nativeAnimated.startListeningToValue(this.__getNativeTag(), value => {
|
|
64
|
+
// __onNativeUpdate syncs the JS value and fires our listeners (no flush:
|
|
65
|
+
// native already moved the view).
|
|
66
|
+
this.__onNativeUpdate(value);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
stopListeningToNativeValueUpdates() {
|
|
70
|
+
if (!this.nativeListening)
|
|
71
|
+
return;
|
|
72
|
+
this.nativeListening = false;
|
|
73
|
+
nativeAnimated.stopListeningToValue(this.__getNativeTag());
|
|
74
|
+
}
|
|
75
|
+
__getValue() {
|
|
76
|
+
return this.value + this.offset;
|
|
77
|
+
}
|
|
78
|
+
// Directly set the value. Stops any running animation and updates every bound
|
|
79
|
+
// prop. When the value is native-driven we skip the JS flush (native owns the
|
|
80
|
+
// view) and push the value into the native node instead.
|
|
81
|
+
setValue(value) {
|
|
82
|
+
if (this.animation) {
|
|
83
|
+
this.animation.stop();
|
|
84
|
+
this.animation = null;
|
|
85
|
+
}
|
|
86
|
+
this.updateValue(value, !this.isNative);
|
|
87
|
+
if (this.isNative) {
|
|
88
|
+
nativeAnimated.setAnimatedNodeValue(this.__getNativeTag(), value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// An offset applied on top of whatever value is set (via setValue, an
|
|
92
|
+
// animation, or Animated.event). Useful for compensating a gesture's start.
|
|
93
|
+
setOffset(offset) {
|
|
94
|
+
this.offset = offset;
|
|
95
|
+
if (this.isNative) {
|
|
96
|
+
nativeAnimated.setAnimatedNodeOffset(this.__getNativeTag(), offset);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// Fold the offset into the base value; the output is unchanged.
|
|
100
|
+
flattenOffset() {
|
|
101
|
+
this.value += this.offset;
|
|
102
|
+
this.offset = 0;
|
|
103
|
+
if (this.isNative) {
|
|
104
|
+
nativeAnimated.flattenAnimatedNodeOffset(this.__getNativeTag());
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Move the base value into the offset; the output is unchanged.
|
|
108
|
+
extractOffset() {
|
|
109
|
+
this.offset += this.value;
|
|
110
|
+
this.value = 0;
|
|
111
|
+
if (this.isNative) {
|
|
112
|
+
nativeAnimated.extractAnimatedNodeOffset(this.__getNativeTag());
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Sync the JS value from a native update (the driver's completion callback, or a
|
|
116
|
+
// native value listener) without re-flushing. Native already moved the view.
|
|
117
|
+
__onNativeUpdate(value, offset) {
|
|
118
|
+
this.updateValue(value, false);
|
|
119
|
+
if (offset !== undefined) {
|
|
120
|
+
this.offset = offset;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
__getNativeConfig() {
|
|
124
|
+
return { type: 'value', value: this.value, offset: this.offset };
|
|
125
|
+
}
|
|
126
|
+
// Stop any running animation OR tracking. `callback` receives the final value,
|
|
127
|
+
// useful for syncing state to the animation's resting position.
|
|
128
|
+
stopAnimation(callback) {
|
|
129
|
+
this.stopTracking();
|
|
130
|
+
if (this.animation) {
|
|
131
|
+
this.animation.stop();
|
|
132
|
+
}
|
|
133
|
+
this.animation = null;
|
|
134
|
+
callback?.(this.__getValue());
|
|
135
|
+
}
|
|
136
|
+
// Chase a moving target: the AnimatedTracking subscribes to the target node and
|
|
137
|
+
// re-launches the animation on every target change. Like RN, animate() itself does
|
|
138
|
+
// NOT clear tracking (the tracking node calls animate on each update); only
|
|
139
|
+
// stopAnimation / a new track tears the previous tracking down.
|
|
140
|
+
track(tracking) {
|
|
141
|
+
this.stopTracking();
|
|
142
|
+
this.tracking = tracking;
|
|
143
|
+
tracking.update();
|
|
144
|
+
}
|
|
145
|
+
stopTracking() {
|
|
146
|
+
if (this.tracking !== null) {
|
|
147
|
+
this.tracking.__detach();
|
|
148
|
+
this.tracking = null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Stop any animation and reset to the original value.
|
|
152
|
+
resetAnimation(callback) {
|
|
153
|
+
this.stopAnimation(callback);
|
|
154
|
+
this.value = this.startingValue;
|
|
155
|
+
}
|
|
156
|
+
// Map the value before it reaches a prop, e.g. 0..1 -> 0..10.
|
|
157
|
+
interpolate(config) {
|
|
158
|
+
return new AnimatedInterpolation(this, config);
|
|
159
|
+
}
|
|
160
|
+
// Drive this value with an animation. Typically called by Animated.timing /
|
|
161
|
+
// spring / decay rather than directly.
|
|
162
|
+
animate(animation, callback) {
|
|
163
|
+
const previousAnimation = this.animation;
|
|
164
|
+
if (this.animation) {
|
|
165
|
+
this.animation.stop();
|
|
166
|
+
}
|
|
167
|
+
this.animation = animation;
|
|
168
|
+
animation.start(this.value, value => {
|
|
169
|
+
this.updateValue(value, true);
|
|
170
|
+
}, result => {
|
|
171
|
+
this.animation = null;
|
|
172
|
+
callback?.(result);
|
|
173
|
+
}, previousAnimation, this);
|
|
174
|
+
}
|
|
175
|
+
updateValue(value, flush) {
|
|
176
|
+
if (value === undefined) {
|
|
177
|
+
throw new Error('AnimatedValue: Attempting to set value to undefined');
|
|
178
|
+
}
|
|
179
|
+
this.value = value;
|
|
180
|
+
if (flush) {
|
|
181
|
+
flushValue(this);
|
|
182
|
+
}
|
|
183
|
+
this.__callListeners(this.__getValue());
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { IRootTag } from '../fabric';
|
|
2
|
+
export interface IAppParameters {
|
|
3
|
+
rootTag: IRootTag;
|
|
4
|
+
initialProps?: object;
|
|
5
|
+
}
|
|
6
|
+
export type IRunnable = (appParameters: IAppParameters) => void;
|
|
7
|
+
export interface IRegistry {
|
|
8
|
+
sections: string[];
|
|
9
|
+
runnables: Record<string, IRunnable>;
|
|
10
|
+
}
|
|
11
|
+
export type IHeadlessTask = (taskData: unknown) => Promise<void>;
|
|
12
|
+
export type ITaskProvider = () => IHeadlessTask;
|
|
13
|
+
export type ITaskCanceller = () => void;
|
|
14
|
+
export type ITaskCancelProvider = () => ITaskCanceller;
|
|
15
|
+
export interface IHostRegistrar {
|
|
16
|
+
registerRunnable(appKey: string, run: IRunnable): string;
|
|
17
|
+
unmountAtRootTag?(rootTag: IRootTag): void;
|
|
18
|
+
}
|
|
19
|
+
export interface IAppRegistry<TComponentProvider, TWrapperComponentProvider> {
|
|
20
|
+
registerComponent(appKey: string, componentProvider: TComponentProvider): string;
|
|
21
|
+
registerRunnable(appKey: string, run: IRunnable): string;
|
|
22
|
+
registerSection(appKey: string, componentProvider: TComponentProvider): string;
|
|
23
|
+
runApplication(appKey: string, appParameters: IAppParameters): void;
|
|
24
|
+
unmountApplicationComponentAtRootTag(rootTag: IRootTag): void;
|
|
25
|
+
setWrapperComponentProvider(provider: TWrapperComponentProvider): void;
|
|
26
|
+
getAppKeys(): string[];
|
|
27
|
+
getRunnable(appKey: string): IRunnable | undefined;
|
|
28
|
+
getSectionKeys(): string[];
|
|
29
|
+
getSections(): Record<string, IRunnable>;
|
|
30
|
+
getRegistry(): IRegistry;
|
|
31
|
+
registerHeadlessTask(taskKey: string, taskProvider: ITaskProvider): void;
|
|
32
|
+
registerCancellableHeadlessTask(taskKey: string, taskProvider: ITaskProvider, taskCancelProvider: ITaskCancelProvider): void;
|
|
33
|
+
startHeadlessTask(taskId: number, taskKey: string, data: unknown): void;
|
|
34
|
+
cancelHeadlessTask(taskId: number, taskKey: string): void;
|
|
35
|
+
}
|
|
36
|
+
export interface ICreateAppRegistryResult<TComponentProvider, TWrapperComponentProvider> {
|
|
37
|
+
AppRegistry: IAppRegistry<TComponentProvider, TWrapperComponentProvider>;
|
|
38
|
+
setHostRegistrar(registrar: IHostRegistrar): void;
|
|
39
|
+
}
|
|
40
|
+
export declare function createAppRegistry<TComponentProvider, TWrapperComponentProvider>(runnableFor: (componentProvider: TComponentProvider, getWrapperComponentProvider: () => TWrapperComponentProvider | undefined) => IRunnable): ICreateAppRegistryResult<TComponentProvider, TWrapperComponentProvider>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// AppRegistry: the JS entry point RN apps already use — `AppRegistry.registerComponent(appKey,
|
|
2
|
+
// () => App)`. RN's version stores a runnable that calls its own React renderer; every symbiote
|
|
3
|
+
// adapter instead stores a runnable that calls ITS OWN `mount`, driving @symbiote-native/engine. That
|
|
4
|
+
// difference — building a runnable from a component provider — is the ONLY framework-specific
|
|
5
|
+
// bit (React wraps via createElement, Vue via createApp/h, Angular via createComponent), so it is
|
|
6
|
+
// the one thing each adapter supplies; everything else (registry bookkeeping, sections, the
|
|
7
|
+
// host-registrar bridge, headless tasks) is byte-identical across adapters and lives here once.
|
|
8
|
+
//
|
|
9
|
+
// The catch: the native Fabric host invokes RN's AppRegistry (a registered callable module) by
|
|
10
|
+
// app key, and it can't see ours. So registerComponent must also hand its runnable to RN's
|
|
11
|
+
// registrar. Reached the same way shared reaches processColor: a dependency-injected seam
|
|
12
|
+
// (setHostRegistrar), so the core stays react-native-free and the app glue wires the host once
|
|
13
|
+
// at startup.
|
|
14
|
+
import { getNativeModule } from '../native-modules';
|
|
15
|
+
import { dlog } from '../debug';
|
|
16
|
+
const HEADLESS_TASK_MODULE = 'HeadlessJsTaskSupport';
|
|
17
|
+
// Builds one adapter's AppRegistry. `runnableFor` is the sole framework-specific seam: given a
|
|
18
|
+
// component provider and a getter for the CURRENT wrapper-component provider (read at mount
|
|
19
|
+
// time, not registration time — setWrapperComponentProvider must affect every runnable's next
|
|
20
|
+
// run, mirroring AppRegistryImpl.js reading it live inside the runnable it returns), it returns
|
|
21
|
+
// the IRunnable that actually mounts the app for a rootTag — e.g. React's createElement + mount,
|
|
22
|
+
// Vue's createApp(component, props).mount(surface), Angular's createComponent + setInput.
|
|
23
|
+
export function createAppRegistry(runnableFor) {
|
|
24
|
+
let hostRegistrar;
|
|
25
|
+
let wrapperComponentProvider;
|
|
26
|
+
const runnables = new Map();
|
|
27
|
+
const sections = new Map();
|
|
28
|
+
const taskProviders = new Map();
|
|
29
|
+
const taskCancelProviders = new Map();
|
|
30
|
+
function register(appKey, run, isSection = false) {
|
|
31
|
+
runnables.set(appKey, run);
|
|
32
|
+
if (isSection)
|
|
33
|
+
sections.set(appKey, run);
|
|
34
|
+
// Bridge to the native registrar so the Fabric host can mount this app by key.
|
|
35
|
+
// Absent (headless / not yet wired) → registration is local only, which is what
|
|
36
|
+
// runApplication and the smokes drive directly.
|
|
37
|
+
hostRegistrar?.registerRunnable(appKey, run);
|
|
38
|
+
return appKey;
|
|
39
|
+
}
|
|
40
|
+
// Runs a registered headless task and drives the native completion/retry
|
|
41
|
+
// protocol, mirroring RN's `startHeadlessTask` (AppRegistryImpl.js:255). Native
|
|
42
|
+
// is the only caller; it must be told when the task settles so the OS can release
|
|
43
|
+
// the wakelock. Headless (no native module) → we just run the task.
|
|
44
|
+
function runHeadlessTask(taskId, taskKey, data) {
|
|
45
|
+
const native = getNativeModule(HEADLESS_TASK_MODULE);
|
|
46
|
+
dlog(`AppRegistry.startHeadlessTask: ${taskKey} (taskId=${taskId})`);
|
|
47
|
+
const provider = taskProviders.get(taskKey);
|
|
48
|
+
if (provider === undefined) {
|
|
49
|
+
dlog(`AppRegistry.startHeadlessTask: no task registered for key "${taskKey}"`);
|
|
50
|
+
native?.notifyTaskFinished?.(taskId);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
void provider()(data)
|
|
54
|
+
.then(() => {
|
|
55
|
+
native?.notifyTaskFinished?.(taskId);
|
|
56
|
+
})
|
|
57
|
+
.catch((reason) => {
|
|
58
|
+
dlog(`AppRegistry.startHeadlessTask: "${taskKey}" failed: ${String(reason)}`);
|
|
59
|
+
// RN asks native whether a retry was scheduled; if not, finish the task.
|
|
60
|
+
// Without the native module there is nothing to notify.
|
|
61
|
+
const retry = native?.notifyTaskRetry?.(taskId);
|
|
62
|
+
if (retry === undefined) {
|
|
63
|
+
native?.notifyTaskFinished?.(taskId);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
void retry.then(retryPosted => {
|
|
67
|
+
if (!retryPosted)
|
|
68
|
+
native?.notifyTaskFinished?.(taskId);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const AppRegistry = {
|
|
73
|
+
registerComponent(appKey, componentProvider) {
|
|
74
|
+
return register(appKey, runnableFor(componentProvider, () => wrapperComponentProvider));
|
|
75
|
+
},
|
|
76
|
+
registerRunnable(appKey, run) {
|
|
77
|
+
return register(appKey, run);
|
|
78
|
+
},
|
|
79
|
+
registerSection(appKey, componentProvider) {
|
|
80
|
+
return register(appKey, runnableFor(componentProvider, () => wrapperComponentProvider), true);
|
|
81
|
+
},
|
|
82
|
+
runApplication(appKey, appParameters) {
|
|
83
|
+
const run = runnables.get(appKey);
|
|
84
|
+
if (run === undefined) {
|
|
85
|
+
dlog(`AppRegistry.runApplication: no app registered for "${appKey}"`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
run(appParameters);
|
|
89
|
+
},
|
|
90
|
+
unmountApplicationComponentAtRootTag(rootTag) {
|
|
91
|
+
dlog(`AppRegistry.unmountApplicationComponentAtRootTag: rootTag ${String(rootTag)}`);
|
|
92
|
+
hostRegistrar?.unmountAtRootTag?.(rootTag);
|
|
93
|
+
},
|
|
94
|
+
setWrapperComponentProvider(provider) {
|
|
95
|
+
wrapperComponentProvider = provider;
|
|
96
|
+
},
|
|
97
|
+
getAppKeys() {
|
|
98
|
+
return [...runnables.keys()];
|
|
99
|
+
},
|
|
100
|
+
getRunnable(appKey) {
|
|
101
|
+
return runnables.get(appKey);
|
|
102
|
+
},
|
|
103
|
+
getSectionKeys() {
|
|
104
|
+
return [...sections.keys()];
|
|
105
|
+
},
|
|
106
|
+
getSections() {
|
|
107
|
+
return Object.fromEntries(sections);
|
|
108
|
+
},
|
|
109
|
+
getRegistry() {
|
|
110
|
+
return {
|
|
111
|
+
sections: [...sections.keys()],
|
|
112
|
+
runnables: Object.fromEntries(runnables),
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
registerHeadlessTask(taskKey, taskProvider) {
|
|
116
|
+
AppRegistry.registerCancellableHeadlessTask(taskKey, taskProvider, () => () => { });
|
|
117
|
+
},
|
|
118
|
+
registerCancellableHeadlessTask(taskKey, taskProvider, taskCancelProvider) {
|
|
119
|
+
if (taskProviders.has(taskKey)) {
|
|
120
|
+
dlog(`AppRegistry: headless task registered multiple times for key "${taskKey}"`);
|
|
121
|
+
}
|
|
122
|
+
taskProviders.set(taskKey, taskProvider);
|
|
123
|
+
taskCancelProviders.set(taskKey, taskCancelProvider);
|
|
124
|
+
},
|
|
125
|
+
startHeadlessTask(taskId, taskKey, data) {
|
|
126
|
+
runHeadlessTask(taskId, taskKey, data);
|
|
127
|
+
},
|
|
128
|
+
cancelHeadlessTask(taskId, taskKey) {
|
|
129
|
+
dlog(`AppRegistry.cancelHeadlessTask: ${taskKey} (taskId=${taskId})`);
|
|
130
|
+
const cancelProvider = taskCancelProviders.get(taskKey);
|
|
131
|
+
if (cancelProvider === undefined) {
|
|
132
|
+
dlog(`AppRegistry.cancelHeadlessTask: no canceller registered for key "${taskKey}"`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
cancelProvider()();
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
AppRegistry,
|
|
140
|
+
setHostRegistrar(registrar) {
|
|
141
|
+
hostRegistrar = registrar;
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type IEventSubscription } from '../native-events';
|
|
2
|
+
declare const APP_STATE_EVENT: {
|
|
3
|
+
readonly change: "change";
|
|
4
|
+
readonly memoryWarning: "memoryWarning";
|
|
5
|
+
readonly focus: "focus";
|
|
6
|
+
readonly blur: "blur";
|
|
7
|
+
};
|
|
8
|
+
export type IAppStateStatus = 'inactive' | 'background' | 'active' | 'extension' | 'unknown';
|
|
9
|
+
export type IAppStateEvent = (typeof APP_STATE_EVENT)[keyof typeof APP_STATE_EVENT];
|
|
10
|
+
declare class AppStateImpl {
|
|
11
|
+
get isAvailable(): boolean;
|
|
12
|
+
get currentState(): string | null;
|
|
13
|
+
addEventListener(type: IAppStateEvent, handler: (...args: unknown[]) => void): IEventSubscription;
|
|
14
|
+
}
|
|
15
|
+
export declare const AppState: AppStateImpl;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// AppState module: reports whether the app is foreground/background/inactive and
|
|
2
|
+
// notifies on change, memory warnings, and (iOS) focus/blur. Native emits the
|
|
3
|
+
// device events `appStateDidChange` ({ app_state }), `memoryWarning`, and
|
|
4
|
+
// `appStateFocusChange` (boolean) through the device hub; this subscribes via a
|
|
5
|
+
// NativeEventEmitter bound to the AppState native module and maps them onto the
|
|
6
|
+
// public 'change'/'memoryWarning'/'focus'/'blur' listeners, mirroring RN's
|
|
7
|
+
// Libraries/AppState/AppState.js.
|
|
8
|
+
import { getNativeModule } from '../native-modules';
|
|
9
|
+
import { installDeviceEventHub, NativeEventEmitter, } from '../native-events';
|
|
10
|
+
import { dlog } from '../debug';
|
|
11
|
+
// The native module name RN registers AppState under, confirmed from its spec
|
|
12
|
+
// (specs_DEPRECATED/modules/INativeAppState.js, `TurboModuleRegistry.getEnforcing('AppState')`).
|
|
13
|
+
const APP_STATE_MODULE = 'AppState';
|
|
14
|
+
// The device events native emits. RN's NativeAppStateEventDefinitions.
|
|
15
|
+
const NATIVE_EVENT = {
|
|
16
|
+
stateDidChange: 'appStateDidChange',
|
|
17
|
+
focusChange: 'appStateFocusChange',
|
|
18
|
+
memoryWarning: 'memoryWarning',
|
|
19
|
+
};
|
|
20
|
+
// The public event names callers subscribe to. RN's IAppStateEvent.
|
|
21
|
+
const APP_STATE_EVENT = {
|
|
22
|
+
change: 'change',
|
|
23
|
+
memoryWarning: 'memoryWarning',
|
|
24
|
+
focus: 'focus',
|
|
25
|
+
blur: 'blur',
|
|
26
|
+
};
|
|
27
|
+
function isStateChangePayload(value) {
|
|
28
|
+
return typeof value === 'object' && value !== null && 'app_state' in value;
|
|
29
|
+
}
|
|
30
|
+
// Lazily resolved so importing this module has no native side effect: a headless
|
|
31
|
+
// run without a fake __turboModuleProxy still loads it; resolution happens on first
|
|
32
|
+
// use. `null` when the module isn't linked.
|
|
33
|
+
let appStateModule;
|
|
34
|
+
let emitter;
|
|
35
|
+
let currentState = null;
|
|
36
|
+
function getModule() {
|
|
37
|
+
if (appStateModule === undefined) {
|
|
38
|
+
appStateModule = getNativeModule(APP_STATE_MODULE);
|
|
39
|
+
dlog(`AppState: module ${appStateModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
40
|
+
}
|
|
41
|
+
return appStateModule;
|
|
42
|
+
}
|
|
43
|
+
function getEmitter() {
|
|
44
|
+
if (emitter === undefined) {
|
|
45
|
+
// WHY lazy: install on first use so the hub exists before native emits, without
|
|
46
|
+
// a hard bootstrap-order dependency. Idempotent.
|
|
47
|
+
installDeviceEventHub();
|
|
48
|
+
const module = getModule();
|
|
49
|
+
if (module !== null) {
|
|
50
|
+
currentState = module.getConstants().initialAppState;
|
|
51
|
+
}
|
|
52
|
+
emitter = new NativeEventEmitter(module ?? undefined);
|
|
53
|
+
// Keep `currentState` fresh even when nobody listens, so a read after a state
|
|
54
|
+
// change returns the new value; RN registers the same always-on observer.
|
|
55
|
+
emitter.addListener(NATIVE_EVENT.stateDidChange, payload => {
|
|
56
|
+
if (!isStateChangePayload(payload))
|
|
57
|
+
return;
|
|
58
|
+
dlog(`AppState: ${NATIVE_EVENT.stateDidChange} -> ${payload.app_state}`);
|
|
59
|
+
currentState = payload.app_state;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return emitter;
|
|
63
|
+
}
|
|
64
|
+
class AppStateImpl {
|
|
65
|
+
// Feature-detect: true when the native AppState module resolved, false when it
|
|
66
|
+
// isn't linked. RN exposes the same field so callers can guard before subscribing.
|
|
67
|
+
get isAvailable() {
|
|
68
|
+
return getModule() !== null;
|
|
69
|
+
}
|
|
70
|
+
// The current foreground/background state, populated from getConstants and kept
|
|
71
|
+
// fresh by the change observer. Null until the module resolves (or never linked).
|
|
72
|
+
get currentState() {
|
|
73
|
+
getEmitter();
|
|
74
|
+
return currentState;
|
|
75
|
+
}
|
|
76
|
+
// Subscribe to an AppState event. Native delivers `appStateDidChange`,
|
|
77
|
+
// `memoryWarning`, and `appStateFocusChange`; this maps each onto the requested
|
|
78
|
+
// public event. Never throws; a missing module yields a live-but-silent
|
|
79
|
+
// subscription (the counters are no-ops without a module).
|
|
80
|
+
addEventListener(type, handler) {
|
|
81
|
+
const eventEmitter = getEmitter();
|
|
82
|
+
dlog(`AppState.addEventListener -> ${type}`);
|
|
83
|
+
switch (type) {
|
|
84
|
+
case APP_STATE_EVENT.change:
|
|
85
|
+
return eventEmitter.addListener(NATIVE_EVENT.stateDidChange, payload => {
|
|
86
|
+
if (!isStateChangePayload(payload))
|
|
87
|
+
return;
|
|
88
|
+
handler(payload.app_state);
|
|
89
|
+
});
|
|
90
|
+
case APP_STATE_EVENT.memoryWarning:
|
|
91
|
+
return eventEmitter.addListener(NATIVE_EVENT.memoryWarning, () => handler());
|
|
92
|
+
case APP_STATE_EVENT.focus:
|
|
93
|
+
return eventEmitter.addListener(NATIVE_EVENT.focusChange, hasFocus => {
|
|
94
|
+
if (hasFocus === true)
|
|
95
|
+
handler();
|
|
96
|
+
});
|
|
97
|
+
case APP_STATE_EVENT.blur:
|
|
98
|
+
return eventEmitter.addListener(NATIVE_EVENT.focusChange, hasFocus => {
|
|
99
|
+
if (hasFocus === false)
|
|
100
|
+
handler();
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export const AppState = new AppStateImpl();
|