@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,9 @@
|
|
|
1
|
+
// Linking: iOS build. The native module is `LinkingManager`
|
|
2
|
+
// (RN's TurboModuleRegistry.get('LinkingManager')); iOS has no `sendIntent`, so per
|
|
3
|
+
// RN's Linking.js it rejects 'Unsupported'. Everything else is the shared core. Metro
|
|
4
|
+
// picks this file on an iOS host; the base linking.ts re-exports it for web/headless.
|
|
5
|
+
import { createLinking } from './shared';
|
|
6
|
+
export const Linking = createLinking({
|
|
7
|
+
moduleName: 'LinkingManager',
|
|
8
|
+
sendIntent: () => Promise.reject(new Error('Unsupported')),
|
|
9
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Linking: base / default build (web, headless tsx, any target without a dedicated
|
|
2
|
+
// platform file). Metro overrides this with linking.ios.ts / linking.android.ts on a
|
|
3
|
+
// real iOS/Android host; off those, the iOS build is the fallback (its LinkingManager
|
|
4
|
+
// resolves null elsewhere → graceful no-op). The barrel imports './linking', which
|
|
5
|
+
// resolves here under tsc/tsx and to the platform file under Metro. See ADR 0019.
|
|
6
|
+
export * from './index.ios';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type IEventEmitterModule, type IEventSubscription } from '../native-events';
|
|
2
|
+
declare const URL_EVENT = "url";
|
|
3
|
+
export interface IUrlEvent {
|
|
4
|
+
url: string;
|
|
5
|
+
}
|
|
6
|
+
export interface IIntentExtra {
|
|
7
|
+
key: string;
|
|
8
|
+
value: string | number | boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface INativeLinkingModule extends IEventEmitterModule {
|
|
11
|
+
getInitialURL(): Promise<string | null>;
|
|
12
|
+
canOpenURL(url: string): Promise<boolean>;
|
|
13
|
+
openURL(url: string): Promise<void>;
|
|
14
|
+
openSettings(): Promise<void>;
|
|
15
|
+
sendIntent?(action: string, extras?: IIntentExtra[]): Promise<void>;
|
|
16
|
+
addListener(eventName: string): void;
|
|
17
|
+
removeListeners(count: number): void;
|
|
18
|
+
}
|
|
19
|
+
export interface ILinkingStatic {
|
|
20
|
+
addEventListener(eventType: typeof URL_EVENT, listener: (event: IUrlEvent) => void): IEventSubscription;
|
|
21
|
+
openURL(url: string): Promise<void>;
|
|
22
|
+
canOpenURL(url: string): Promise<boolean>;
|
|
23
|
+
getInitialURL(): Promise<string | null>;
|
|
24
|
+
openSettings(): Promise<void>;
|
|
25
|
+
sendIntent(action: string, extras?: IIntentExtra[]): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export interface ILinkingPlatform {
|
|
28
|
+
moduleName: string;
|
|
29
|
+
sendIntent(module: INativeLinkingModule | null, action: string, extras?: IIntentExtra[]): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export declare function createLinking(platform: ILinkingPlatform): ILinkingStatic;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Shared core of the Linking module: everything that does NOT differ by platform:
|
|
2
|
+
// the public contract, the lazy native-module resolver, the `url` device-event
|
|
3
|
+
// subscription, URL validation, and payload narrowing. The per-platform files
|
|
4
|
+
// (linking.ios.ts / linking.android.ts) supply ONLY what genuinely diverges (the
|
|
5
|
+
// native module NAME and the `sendIntent` strategy) and hand them to `createLinking`.
|
|
6
|
+
//
|
|
7
|
+
// Metro selects the platform file on a real host (linking.android.ts > linking.ts);
|
|
8
|
+
// the base linking.ts re-exports the iOS build for web/headless. There is no runtime
|
|
9
|
+
// `Platform.OS` read; the filename is the selector. See ADR 0019.
|
|
10
|
+
import { installDeviceEventHub, NativeEventEmitter, } from '../native-events';
|
|
11
|
+
import { getNativeModule } from '../native-modules';
|
|
12
|
+
import { dlog } from '../debug';
|
|
13
|
+
// The one event symbiote observes: an incoming deep link. RN's LinkingEventDefinitions.
|
|
14
|
+
const URL_EVENT = 'url';
|
|
15
|
+
// RN's _validateURL: a typo / empty URL must fail loudly at the call, not reach native.
|
|
16
|
+
function validateUrl(url) {
|
|
17
|
+
if (typeof url !== 'string' || url.length === 0) {
|
|
18
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Narrow the native event payload to IUrlEvent at the trust boundary, no `as`.
|
|
22
|
+
function toUrlEvent(payload) {
|
|
23
|
+
if (typeof payload === 'object' && payload !== null && 'url' in payload) {
|
|
24
|
+
const { url } = payload;
|
|
25
|
+
if (typeof url === 'string')
|
|
26
|
+
return { url };
|
|
27
|
+
}
|
|
28
|
+
dlog('Linking: url event payload missing string url');
|
|
29
|
+
return { url: '' };
|
|
30
|
+
}
|
|
31
|
+
// Build a platform's Linking from its module name + sendIntent strategy. Each call owns
|
|
32
|
+
// its own lazy module/emitter cache, so importing both platform builds in a smoke keeps
|
|
33
|
+
// them independent. On a real host only one platform file is ever bundled.
|
|
34
|
+
export function createLinking(platform) {
|
|
35
|
+
let linkingModule;
|
|
36
|
+
let emitter;
|
|
37
|
+
function getModule() {
|
|
38
|
+
if (linkingModule === undefined) {
|
|
39
|
+
linkingModule = getNativeModule(platform.moduleName);
|
|
40
|
+
dlog(`Linking: ${platform.moduleName} module ${linkingModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
41
|
+
}
|
|
42
|
+
return linkingModule;
|
|
43
|
+
}
|
|
44
|
+
function getEmitter() {
|
|
45
|
+
if (emitter === undefined) {
|
|
46
|
+
// Lazy install on first subscribe: the hub exists before native emits without a
|
|
47
|
+
// hard bootstrap-order dependency. Idempotent.
|
|
48
|
+
installDeviceEventHub();
|
|
49
|
+
emitter = new NativeEventEmitter(getModule() ?? undefined);
|
|
50
|
+
}
|
|
51
|
+
return emitter;
|
|
52
|
+
}
|
|
53
|
+
function moduleUnavailable() {
|
|
54
|
+
return new Error(`Linking: ${platform.moduleName} native module unavailable`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
addEventListener(eventType, listener) {
|
|
58
|
+
dlog(`Linking.addEventListener -> ${eventType}`);
|
|
59
|
+
return getEmitter().addListener(eventType, payload => {
|
|
60
|
+
listener(toUrlEvent(payload));
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
openURL(url) {
|
|
64
|
+
validateUrl(url);
|
|
65
|
+
dlog(`Linking.openURL -> ${url}`);
|
|
66
|
+
const module = getModule();
|
|
67
|
+
if (module === null)
|
|
68
|
+
return Promise.reject(moduleUnavailable());
|
|
69
|
+
return module.openURL(url);
|
|
70
|
+
},
|
|
71
|
+
canOpenURL(url) {
|
|
72
|
+
validateUrl(url);
|
|
73
|
+
dlog(`Linking.canOpenURL -> ${url}`);
|
|
74
|
+
const module = getModule();
|
|
75
|
+
if (module === null)
|
|
76
|
+
return Promise.reject(moduleUnavailable());
|
|
77
|
+
return module.canOpenURL(url);
|
|
78
|
+
},
|
|
79
|
+
getInitialURL() {
|
|
80
|
+
dlog('Linking.getInitialURL');
|
|
81
|
+
const module = getModule();
|
|
82
|
+
if (module === null)
|
|
83
|
+
return Promise.resolve(null);
|
|
84
|
+
return module.getInitialURL();
|
|
85
|
+
},
|
|
86
|
+
openSettings() {
|
|
87
|
+
dlog('Linking.openSettings');
|
|
88
|
+
const module = getModule();
|
|
89
|
+
if (module === null)
|
|
90
|
+
return Promise.reject(moduleUnavailable());
|
|
91
|
+
return module.openSettings();
|
|
92
|
+
},
|
|
93
|
+
sendIntent(action, extras) {
|
|
94
|
+
dlog(`Linking.sendIntent -> ${action}`);
|
|
95
|
+
return platform.sendIntent(getModule(), action, extras);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
var RN$registerCallableModule: ((name: string, factory: () => {
|
|
3
|
+
emit: (eventType: string, ...args: unknown[]) => void;
|
|
4
|
+
}) => void) | undefined;
|
|
5
|
+
var RN$Bridgeless: boolean | undefined;
|
|
6
|
+
}
|
|
7
|
+
export interface IEventSubscription {
|
|
8
|
+
remove(): void;
|
|
9
|
+
}
|
|
10
|
+
export declare function installDeviceEventHub(): void;
|
|
11
|
+
export interface IDeviceEventSource {
|
|
12
|
+
addListener(eventType: string, listener: (payload: unknown) => void): IEventSubscription;
|
|
13
|
+
}
|
|
14
|
+
export declare function setDeviceEventSource(source: IDeviceEventSource): void;
|
|
15
|
+
export interface IEventEmitterModule {
|
|
16
|
+
addListener(eventType: string): void;
|
|
17
|
+
removeListeners(count: number): void;
|
|
18
|
+
}
|
|
19
|
+
export type INativeEventListener = (payload: unknown) => void;
|
|
20
|
+
export declare class NativeEventEmitter {
|
|
21
|
+
private readonly module?;
|
|
22
|
+
constructor(module?: IEventEmitterModule);
|
|
23
|
+
addListener(eventType: string, listener: INativeEventListener): IEventSubscription;
|
|
24
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// native -> JS: receiving native module events. The native side emits ALL device
|
|
2
|
+
// events by invoking ONE callable JS module under the fixed name
|
|
3
|
+
// `RCTDeviceEventEmitter`. On a real RN host that name is already owned by RN's own
|
|
4
|
+
// RCTDeviceEventEmitter, and `RN$registerCallableModule` cannot steal it: native's
|
|
5
|
+
// `callableModules_.emplace` ignores a duplicate key (ReactInstance.cpp), so a
|
|
6
|
+
// second registration is a silent no-op. So we do NOT register our own hub on a
|
|
7
|
+
// real host: the app injects RN's DeviceEventEmitter (the bus native actually
|
|
8
|
+
// calls) via `setDeviceEventSource`, exactly like setColorProcessor. The built-in
|
|
9
|
+
// hub below stays as the fallback bus for headless/non-RN runs. See .docs/decisions/0012.
|
|
10
|
+
import { dlog } from './debug';
|
|
11
|
+
import { runWrapped } from './dispatch';
|
|
12
|
+
// The single device-event bus. Native pushes into `emit`; subscribers (wrapped by
|
|
13
|
+
// NativeEventEmitter) live in `listeners`, keyed by event name.
|
|
14
|
+
const listeners = new Map();
|
|
15
|
+
function emit(eventType, ...args) {
|
|
16
|
+
const set = listeners.get(eventType);
|
|
17
|
+
// Diagnostic: proves native is calling OUR hub (vs RN's own RCTDeviceEventEmitter).
|
|
18
|
+
dlog(`device hub emit "${eventType}" -> ${set?.size ?? 0} listener(s)`);
|
|
19
|
+
if (set === undefined)
|
|
20
|
+
return;
|
|
21
|
+
// A device event arrives outside the framework's update loop; route the fan-out
|
|
22
|
+
// through the shared dispatch wrapper so a listener's setState lands on the sync
|
|
23
|
+
// lane and flushes, the same seam Fabric touch events use. Snapshot before
|
|
24
|
+
// iterating: a listener may remove itself mid-dispatch.
|
|
25
|
+
const snapshot = [...set];
|
|
26
|
+
runWrapped(() => {
|
|
27
|
+
for (const listener of snapshot)
|
|
28
|
+
listener(...args);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function addRawListener(eventType, listener) {
|
|
32
|
+
let set = listeners.get(eventType);
|
|
33
|
+
if (set === undefined) {
|
|
34
|
+
set = new Set();
|
|
35
|
+
listeners.set(eventType, set);
|
|
36
|
+
}
|
|
37
|
+
set.add(listener);
|
|
38
|
+
}
|
|
39
|
+
function removeRawListener(eventType, listener) {
|
|
40
|
+
listeners.get(eventType)?.delete(listener);
|
|
41
|
+
}
|
|
42
|
+
let installed = false;
|
|
43
|
+
// Register the hub so native can deliver events. Call once at bootstrap, after the
|
|
44
|
+
// host is up (alongside binding the Fabric slot). Idempotent.
|
|
45
|
+
export function installDeviceEventHub() {
|
|
46
|
+
// A host bus was injected: it owns delivery; the fallback hub is unused. (On a
|
|
47
|
+
// real host our registration would be a no-op anyway: native's emplace ignores
|
|
48
|
+
// the already-registered RCTDeviceEventEmitter key.)
|
|
49
|
+
if (installed || injectedSource !== undefined)
|
|
50
|
+
return;
|
|
51
|
+
const register = globalThis.RN$registerCallableModule;
|
|
52
|
+
if (register === undefined) {
|
|
53
|
+
throw new Error('RN$registerCallableModule is not installed on the global. ' +
|
|
54
|
+
'Native events need a bridgeless (New Architecture) host.');
|
|
55
|
+
}
|
|
56
|
+
register('RCTDeviceEventEmitter', () => ({ emit }));
|
|
57
|
+
installed = true;
|
|
58
|
+
dlog('device event hub installed (RCTDeviceEventEmitter)');
|
|
59
|
+
}
|
|
60
|
+
let injectedSource;
|
|
61
|
+
// Inject the host's device-event bus (e.g. RN's DeviceEventEmitter). Once set,
|
|
62
|
+
// NativeEventEmitter subscribes through it instead of the built-in fallback hub.
|
|
63
|
+
// Called by the app at bootstrap, where importing the host bus is allowed.
|
|
64
|
+
export function setDeviceEventSource(source) {
|
|
65
|
+
injectedSource = source;
|
|
66
|
+
}
|
|
67
|
+
// True only when the module actually carries both observe-counter methods. A
|
|
68
|
+
// resolved TurboModule whose spec omits addListener/removeListeners (or a host where
|
|
69
|
+
// the module isn't a real event emitter) leaves them undefined, so calling through
|
|
70
|
+
// would throw "undefined is not a function" — the `?.` guards the module, not a
|
|
71
|
+
// missing method. Mirrors RN's NativeEventEmitter constructor probe.
|
|
72
|
+
function hasObserveCounters(module) {
|
|
73
|
+
return typeof module.addListener === 'function' && typeof module.removeListeners === 'function';
|
|
74
|
+
}
|
|
75
|
+
// Subscribe to events for one native module. Mirrors RN's NativeEventEmitter: each
|
|
76
|
+
// `addListener` also pings the module's `addListener` counter, and removal pings
|
|
77
|
+
// `removeListeners`, so native observes only while someone is listening.
|
|
78
|
+
export class NativeEventEmitter {
|
|
79
|
+
module;
|
|
80
|
+
constructor(module) {
|
|
81
|
+
// Keep the module ONLY if it has both counter methods, exactly like RN: a
|
|
82
|
+
// module missing them stays unset, so the `this.module?.` calls below no-op
|
|
83
|
+
// instead of crashing on `undefined(...)`.
|
|
84
|
+
if (module !== undefined && hasObserveCounters(module)) {
|
|
85
|
+
this.module = module;
|
|
86
|
+
}
|
|
87
|
+
else if (module !== undefined) {
|
|
88
|
+
dlog('NativeEventEmitter: module lacks addListener/removeListeners; dropping it (counter pings become no-ops)');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
addListener(eventType, listener) {
|
|
92
|
+
// The module counter tells native to START observing; without it (module
|
|
93
|
+
// unresolved) native may never emit. Logged to pinpoint a silent native side.
|
|
94
|
+
const via = injectedSource !== undefined ? 'host-bus' : 'fallback-hub';
|
|
95
|
+
dlog(`NativeEventEmitter.addListener "${eventType}" ` +
|
|
96
|
+
`module-counter=${this.module ? 'pinged' : 'none'} via=${via}`);
|
|
97
|
+
this.module?.addListener(eventType);
|
|
98
|
+
if (injectedSource !== undefined) {
|
|
99
|
+
// The host bus delivers raw (no framework flush); wrap so a listener's
|
|
100
|
+
// setState lands on the sync lane and paints, like Fabric touch events.
|
|
101
|
+
const subscription = injectedSource.addListener(eventType, payload => {
|
|
102
|
+
runWrapped(() => listener(payload));
|
|
103
|
+
});
|
|
104
|
+
let removed = false;
|
|
105
|
+
return {
|
|
106
|
+
remove: () => {
|
|
107
|
+
if (removed)
|
|
108
|
+
return;
|
|
109
|
+
removed = true;
|
|
110
|
+
subscription.remove();
|
|
111
|
+
this.module?.removeListeners(1);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Fallback bus (headless / non-RN host): the internal hub. Its `emit` wraps.
|
|
116
|
+
const raw = (...args) => listener(args[0]);
|
|
117
|
+
addRawListener(eventType, raw);
|
|
118
|
+
let removed = false;
|
|
119
|
+
return {
|
|
120
|
+
remove: () => {
|
|
121
|
+
if (removed)
|
|
122
|
+
return;
|
|
123
|
+
removed = true;
|
|
124
|
+
removeRawListener(eventType, raw);
|
|
125
|
+
this.module?.removeListeners(1);
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
var __turboModuleProxy: (<T>(name: string) => T | null) | undefined;
|
|
3
|
+
var nativeModuleProxy: Record<string, unknown> | undefined;
|
|
4
|
+
}
|
|
5
|
+
export declare function getNativeModule<T>(name: string): T | null;
|
|
6
|
+
export declare function getEnforcingNativeModule<T>(name: string): T;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// JS -> native: reaching a native (Turbo)Module. The New Architecture installs
|
|
2
|
+
// `global.__turboModuleProxy(name)`: a JSI function that returns the native
|
|
3
|
+
// module registered under `name` (a HostObject whose methods call into native),
|
|
4
|
+
// or null. React Native's own `TurboModuleRegistry.get` is just this call; we are
|
|
5
|
+
// one more client of the same global, exactly as `getSlot` is for the view tree.
|
|
6
|
+
//
|
|
7
|
+
// This is first-party access, for symbiote's own modules (StatusBarManager,
|
|
8
|
+
// KeyboardObserver, …). Third-party RN packages import `TurboModuleRegistry` from
|
|
9
|
+
// `'react-native'` and read the same global themselves; they do not go through
|
|
10
|
+
// here. See .docs/decisions/0012.
|
|
11
|
+
import { dlog } from './debug';
|
|
12
|
+
// The native module value crosses from an untyped HostObject into our types here;
|
|
13
|
+
// the caller vouches for its shape via T (the single trust-boundary narrowing, no
|
|
14
|
+
// per-call `as`). Native modules are always non-null objects.
|
|
15
|
+
function isNativeModule(value) {
|
|
16
|
+
return value !== null && value !== undefined;
|
|
17
|
+
}
|
|
18
|
+
// The native module `name`, typed as the caller's interface `T`, or null when no
|
|
19
|
+
// module by that name is registered in the binary (or the proxy is absent, e.g.
|
|
20
|
+
// running headless without a fake installed).
|
|
21
|
+
export function getNativeModule(name) {
|
|
22
|
+
// Non-bridgeless: the function proxy. Call it by name.
|
|
23
|
+
const turboProxy = globalThis.__turboModuleProxy;
|
|
24
|
+
if (typeof turboProxy === 'function') {
|
|
25
|
+
const module = turboProxy(name);
|
|
26
|
+
if (module !== null && module !== undefined)
|
|
27
|
+
return module;
|
|
28
|
+
}
|
|
29
|
+
// Bridgeless: the HostObject proxy, indexed by name. Guard the access: a
|
|
30
|
+
// HostObject may throw for an unlinked name, and a throw here would propagate
|
|
31
|
+
// into a render effect and blank the tree.
|
|
32
|
+
const bridgelessProxy = globalThis.nativeModuleProxy;
|
|
33
|
+
if (bridgelessProxy !== undefined) {
|
|
34
|
+
try {
|
|
35
|
+
const module = bridgelessProxy[name];
|
|
36
|
+
if (isNativeModule(module))
|
|
37
|
+
return module;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
dlog(`nativeModuleProxy["${name}"] threw: ${String(error)}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
dlog(`native module "${name}" not found ` +
|
|
44
|
+
`(turbo=${typeof turboProxy}, bridgeless=${typeof globalThis.nativeModuleProxy})`);
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
// Same, but throws when the module is missing, for modules a feature hard-depends
|
|
48
|
+
// on (StatusBar without StatusBarManager cannot function, so failing loud beats a
|
|
49
|
+
// silent no-op).
|
|
50
|
+
export function getEnforcingNativeModule(name) {
|
|
51
|
+
const module = getNativeModule(name);
|
|
52
|
+
if (module === null) {
|
|
53
|
+
throw new Error(`Native module "${name}" is not registered in the binary. ` +
|
|
54
|
+
'Verify it is linked (New Architecture / bridgeless host with __turboModuleProxy installed).');
|
|
55
|
+
}
|
|
56
|
+
return module;
|
|
57
|
+
}
|
package/build/node.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
declare const BRAND: unique symbol;
|
|
2
|
+
export declare const RAW_TEXT_COMPONENT = "RCTRawText";
|
|
3
|
+
export declare const TEXT_COMPONENT = "RCTText";
|
|
4
|
+
export declare const VIRTUAL_TEXT_COMPONENT = "RCTVirtualText";
|
|
5
|
+
export interface ISymbioteEvent {
|
|
6
|
+
type: string;
|
|
7
|
+
target: ISymbioteNode;
|
|
8
|
+
currentTarget: ISymbioteNode;
|
|
9
|
+
nativeEvent: Record<string, unknown>;
|
|
10
|
+
stopPropagation: () => void;
|
|
11
|
+
}
|
|
12
|
+
export type IListener = (event: ISymbioteEvent) => unknown;
|
|
13
|
+
export interface ISymbioteNode {
|
|
14
|
+
readonly [BRAND]: true;
|
|
15
|
+
readonly component: string;
|
|
16
|
+
readonly isText: boolean;
|
|
17
|
+
props: Record<string, unknown>;
|
|
18
|
+
listeners: Map<string, IListener> | undefined;
|
|
19
|
+
children: ISymbioteNode[];
|
|
20
|
+
parent: ISymbioteNode | undefined;
|
|
21
|
+
}
|
|
22
|
+
export declare function createElement(component: string, isText?: boolean): ISymbioteNode;
|
|
23
|
+
export declare function createRawText(text: string): ISymbioteNode;
|
|
24
|
+
export declare function isSymbioteNode(value: unknown): value is ISymbioteNode;
|
|
25
|
+
export declare const ANCHOR_COMPONENT = "#anchor";
|
|
26
|
+
export declare function createAnchor(): ISymbioteNode;
|
|
27
|
+
export declare function isAnchor(node: ISymbioteNode): boolean;
|
|
28
|
+
export declare function setProp(node: ISymbioteNode, key: string, value: unknown): void;
|
|
29
|
+
export declare function setEventListener(node: ISymbioteNode, name: string, value: unknown): void;
|
|
30
|
+
export declare function getExplicitStyle(node: ISymbioteNode): unknown;
|
|
31
|
+
export declare function routeProp(node: ISymbioteNode, key: string, value: unknown): void;
|
|
32
|
+
export declare function setText(node: ISymbioteNode, text: string): void;
|
|
33
|
+
export declare function appendChild(parent: ISymbioteNode, child: ISymbioteNode): void;
|
|
34
|
+
export declare function insertBefore(parent: ISymbioteNode, child: ISymbioteNode, beforeChild: ISymbioteNode): void;
|
|
35
|
+
export declare function removeChild(parent: ISymbioteNode, child: ISymbioteNode): void;
|
|
36
|
+
export {};
|
package/build/node.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// The retained shadow-tree. Adapters mutate this cheap in-memory tree through a
|
|
2
|
+
// tiny API; the commit engine (commit.ts) later walks it and translates the
|
|
3
|
+
// whole thing into Fabric's clone-on-write child sets. Keeping the retained
|
|
4
|
+
// tree mutable while the Fabric mirror stays persistent is the core R2 trick,
|
|
5
|
+
// and it lives here in shared so no adapter re-implements it.
|
|
6
|
+
import { isEventFor } from './view-config';
|
|
7
|
+
import { isClassNameValue, resolveClassName } from './style-registry';
|
|
8
|
+
const BRAND = Symbol('symbiote.node');
|
|
9
|
+
// A node carries the Fabric view name directly, so adding a primitive (Image,
|
|
10
|
+
// ScrollView, TextInput) is just a new string from the adapter, no core change.
|
|
11
|
+
// The only name resolved at commit time is text: a <Text> nested inside another
|
|
12
|
+
// <Text> becomes a virtual span. `isText` marks a text container so its
|
|
13
|
+
// descendants pick the virtual variant.
|
|
14
|
+
export const RAW_TEXT_COMPONENT = 'RCTRawText';
|
|
15
|
+
export const TEXT_COMPONENT = 'RCTText';
|
|
16
|
+
export const VIRTUAL_TEXT_COMPONENT = 'RCTVirtualText';
|
|
17
|
+
export function createElement(component, isText = false) {
|
|
18
|
+
return {
|
|
19
|
+
[BRAND]: true,
|
|
20
|
+
component,
|
|
21
|
+
isText,
|
|
22
|
+
props: {},
|
|
23
|
+
listeners: undefined,
|
|
24
|
+
children: [],
|
|
25
|
+
parent: undefined,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function createRawText(text) {
|
|
29
|
+
return {
|
|
30
|
+
[BRAND]: true,
|
|
31
|
+
component: RAW_TEXT_COMPONENT,
|
|
32
|
+
isText: false,
|
|
33
|
+
props: { text },
|
|
34
|
+
listeners: undefined,
|
|
35
|
+
children: [],
|
|
36
|
+
parent: undefined,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// `instanceHandle` round-trips through Fabric unchanged: the object we pass to
|
|
40
|
+
// createNode comes back as the event target. We brand our nodes so the event
|
|
41
|
+
// handler can confirm a target is one of ours before dispatching.
|
|
42
|
+
export function isSymbioteNode(value) {
|
|
43
|
+
return typeof value === 'object' && value !== null && BRAND in value;
|
|
44
|
+
}
|
|
45
|
+
// Vue's runtime-core needs comment/anchor nodes (fragments, v-if, v-for) to track
|
|
46
|
+
// sibling order; Fabric has no such concept. An anchor is a real retained node so
|
|
47
|
+
// insert/nextSibling/parentNode ordering stays correct, but the commit walk SKIPS it
|
|
48
|
+
// (commit.ts): no native view is ever created. Marked by a sentinel component name,
|
|
49
|
+
// not a new field, so the hot SymbioteNode shape is untouched.
|
|
50
|
+
export const ANCHOR_COMPONENT = '#anchor';
|
|
51
|
+
export function createAnchor() {
|
|
52
|
+
return createElement(ANCHOR_COMPONENT);
|
|
53
|
+
}
|
|
54
|
+
export function isAnchor(node) {
|
|
55
|
+
return node.component === ANCHOR_COMPONENT;
|
|
56
|
+
}
|
|
57
|
+
// A pure prop set: no event inference. `onTintColor` is a Switch prop and reaches
|
|
58
|
+
// Fabric like any other; the event-vs-prop decision is made by routeProp, never by
|
|
59
|
+
// the key's name.
|
|
60
|
+
export function setProp(node, key, value) {
|
|
61
|
+
if (value === undefined) {
|
|
62
|
+
delete node.props[key];
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
node.props[key] = value;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Fabric gates layout events behind a boolean prop (BaseViewProps.onLayout): unlike
|
|
69
|
+
// scroll / touch / change, which the native component emits unconditionally, a
|
|
70
|
+
// layout event fires only when the shadow node is flagged. So a `layout` listener
|
|
71
|
+
// must also raise that prop, mirroring RN's `onLayout: true` validAttribute;
|
|
72
|
+
// otherwise onLayout never fires and anything measuring its own box (VirtualizedList
|
|
73
|
+
// viewport) stays at zero.
|
|
74
|
+
const LAYOUT_EVENT = 'layout';
|
|
75
|
+
const LAYOUT_FLAG_PROP = 'onLayout';
|
|
76
|
+
// The explicit event channel. Structural adapters (Svelte addEventListener, Angular
|
|
77
|
+
// Renderer2.listen) call this directly with an already-known event name; flat-bag
|
|
78
|
+
// adapters reach it through routeProp. A non-function value clears the listener.
|
|
79
|
+
export function setEventListener(node, name, value) {
|
|
80
|
+
const isHandler = typeof value === 'function';
|
|
81
|
+
if (isHandler) {
|
|
82
|
+
const handler = value;
|
|
83
|
+
const listeners = (node.listeners ??= new Map());
|
|
84
|
+
listeners.set(name, (event) => handler(event));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
node.listeners?.delete(name);
|
|
88
|
+
}
|
|
89
|
+
if (name === LAYOUT_EVENT)
|
|
90
|
+
setProp(node, LAYOUT_FLAG_PROP, isHandler ? true : undefined);
|
|
91
|
+
}
|
|
92
|
+
const ON_PREFIX = /^on[A-Z]/;
|
|
93
|
+
// onChange -> change
|
|
94
|
+
function listenerName(propName) {
|
|
95
|
+
return propName.charAt(2).toLowerCase() + propName.slice(3);
|
|
96
|
+
}
|
|
97
|
+
// The responder-negotiation events (PanResponder's panHandlers). They are a
|
|
98
|
+
// JS-side protocol the event layer synthesizes from raw touches, NOT Fabric
|
|
99
|
+
// ViewConfig events, so isEventFor never reports them. Treat them as listeners on
|
|
100
|
+
// any node so PanResponder's handlers actually attach (rather than routing to
|
|
101
|
+
// setProp and reaching Fabric as dead props). Names are post-listenerName.
|
|
102
|
+
const RESPONDER_EVENTS = new Set([
|
|
103
|
+
'startShouldSetResponder',
|
|
104
|
+
'startShouldSetResponderCapture',
|
|
105
|
+
'moveShouldSetResponder',
|
|
106
|
+
'moveShouldSetResponderCapture',
|
|
107
|
+
'responderGrant',
|
|
108
|
+
'responderReject',
|
|
109
|
+
'responderStart',
|
|
110
|
+
'responderMove',
|
|
111
|
+
'responderEnd',
|
|
112
|
+
'responderRelease',
|
|
113
|
+
'responderTerminate',
|
|
114
|
+
'responderTerminationRequest',
|
|
115
|
+
]);
|
|
116
|
+
// React's JSX dev transform (transform-react-jsx-self / -source, injected by RN's babel
|
|
117
|
+
// preset whenever dev=true) annotates every element with __self (the component instance)
|
|
118
|
+
// and __source ({ fileName, lineNumber, columnNumber }). React's own Fabric host config
|
|
119
|
+
// consumes both and never forwards them. A JSX-based adapter (Vue JSX, Solid JSX) instead
|
|
120
|
+
// carries them onto the vnode as ordinary props, so they reach setProp and then Fabric,
|
|
121
|
+
// where Android's folly::dynamic rejects __self with "JS Functions are not convertible to
|
|
122
|
+
// dynamic" (the instance holds functions) and the surface paints black, while iOS silently
|
|
123
|
+
// drops it. SFC/template authoring never produces them. Strip them here, once, so no
|
|
124
|
+
// adapter leaks React JSX dev metadata to the host, mirroring React's host config.
|
|
125
|
+
const REACT_JSX_DEV_PROPS = new Set(['__self', '__source']);
|
|
126
|
+
const classStyleParts = new WeakMap();
|
|
127
|
+
function commitClassStyle(node, patch) {
|
|
128
|
+
const entry = { ...classStyleParts.get(node), ...patch };
|
|
129
|
+
classStyleParts.set(node, entry);
|
|
130
|
+
setProp(node, 'style', [entry.classStyle, entry.explicitStyle]);
|
|
131
|
+
}
|
|
132
|
+
// The explicit (non-class-derived) style half, for an adapter that builds its style prop up
|
|
133
|
+
// key-by-key (Angular's Ivy ɵɵstyleProp/setStyle) instead of handing over one whole object —
|
|
134
|
+
// it must merge onto this, not onto node.props.style directly, which may be the
|
|
135
|
+
// [classStyle, explicitStyle] array commitClassStyle writes above.
|
|
136
|
+
export function getExplicitStyle(node) {
|
|
137
|
+
return classStyleParts.get(node)?.explicitStyle;
|
|
138
|
+
}
|
|
139
|
+
const CLASS_PROP_KEYS = new Set(['class', 'className']);
|
|
140
|
+
// The flat-bag split (React / Vue / Solid): an `onX` prop becomes an event listener
|
|
141
|
+
// ONLY when the node's component actually declares `x` as an event (per the shared
|
|
142
|
+
// ViewConfig). Otherwise it is a plain prop, so `onTintColor` on a Switch, whose
|
|
143
|
+
// only event is `change`, routes to setProp and reaches Fabric.
|
|
144
|
+
export function routeProp(node, key, value) {
|
|
145
|
+
if (REACT_JSX_DEV_PROPS.has(key))
|
|
146
|
+
return;
|
|
147
|
+
if (CLASS_PROP_KEYS.has(key)) {
|
|
148
|
+
commitClassStyle(node, {
|
|
149
|
+
classStyle: resolveClassName(isClassNameValue(value) ? value : undefined),
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (key === 'style') {
|
|
154
|
+
commitClassStyle(node, { explicitStyle: value });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (ON_PREFIX.test(key)) {
|
|
158
|
+
const name = listenerName(key);
|
|
159
|
+
if (RESPONDER_EVENTS.has(name) || isEventFor(node.component, name)) {
|
|
160
|
+
setEventListener(node, name, value);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
setProp(node, key, value);
|
|
165
|
+
}
|
|
166
|
+
export function setText(node, text) {
|
|
167
|
+
node.props.text = text;
|
|
168
|
+
}
|
|
169
|
+
function detach(child) {
|
|
170
|
+
const parent = child.parent;
|
|
171
|
+
if (!parent)
|
|
172
|
+
return;
|
|
173
|
+
const index = parent.children.indexOf(child);
|
|
174
|
+
if (index >= 0)
|
|
175
|
+
parent.children.splice(index, 1);
|
|
176
|
+
child.parent = undefined;
|
|
177
|
+
}
|
|
178
|
+
export function appendChild(parent, child) {
|
|
179
|
+
detach(child);
|
|
180
|
+
child.parent = parent;
|
|
181
|
+
parent.children.push(child);
|
|
182
|
+
}
|
|
183
|
+
export function insertBefore(parent, child, beforeChild) {
|
|
184
|
+
detach(child);
|
|
185
|
+
child.parent = parent;
|
|
186
|
+
const index = parent.children.indexOf(beforeChild);
|
|
187
|
+
parent.children.splice(index < 0 ? parent.children.length : index, 0, child);
|
|
188
|
+
}
|
|
189
|
+
export function removeChild(parent, child) {
|
|
190
|
+
const index = parent.children.indexOf(child);
|
|
191
|
+
if (index >= 0)
|
|
192
|
+
parent.children.splice(index, 1);
|
|
193
|
+
child.parent = undefined;
|
|
194
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ISymbioteEvent } from '../node';
|
|
2
|
+
export interface IPanResponderGestureState {
|
|
3
|
+
stateID: number;
|
|
4
|
+
moveX: number;
|
|
5
|
+
moveY: number;
|
|
6
|
+
x0: number;
|
|
7
|
+
y0: number;
|
|
8
|
+
dx: number;
|
|
9
|
+
dy: number;
|
|
10
|
+
vx: number;
|
|
11
|
+
vy: number;
|
|
12
|
+
numberActiveTouches: number;
|
|
13
|
+
_accountsForMovesUpTo: number;
|
|
14
|
+
}
|
|
15
|
+
type IActiveCallback = (event: ISymbioteEvent, gestureState: IPanResponderGestureState) => boolean;
|
|
16
|
+
type IPassiveCallback = (event: ISymbioteEvent, gestureState: IPanResponderGestureState) => void;
|
|
17
|
+
export interface IPanResponderCallbacks {
|
|
18
|
+
onStartShouldSetPanResponder?: IActiveCallback;
|
|
19
|
+
onStartShouldSetPanResponderCapture?: IActiveCallback;
|
|
20
|
+
onMoveShouldSetPanResponder?: IActiveCallback;
|
|
21
|
+
onMoveShouldSetPanResponderCapture?: IActiveCallback;
|
|
22
|
+
onPanResponderGrant?: IPassiveCallback;
|
|
23
|
+
onPanResponderStart?: IPassiveCallback;
|
|
24
|
+
onPanResponderMove?: IPassiveCallback;
|
|
25
|
+
onPanResponderEnd?: IPassiveCallback;
|
|
26
|
+
onPanResponderRelease?: IPassiveCallback;
|
|
27
|
+
onPanResponderReject?: IPassiveCallback;
|
|
28
|
+
onPanResponderTerminate?: IPassiveCallback;
|
|
29
|
+
onPanResponderTerminationRequest?: IActiveCallback;
|
|
30
|
+
onShouldBlockNativeResponder?: IActiveCallback;
|
|
31
|
+
}
|
|
32
|
+
export interface IGestureResponderHandlers {
|
|
33
|
+
onStartShouldSetResponder: (event: ISymbioteEvent) => boolean;
|
|
34
|
+
onStartShouldSetResponderCapture: (event: ISymbioteEvent) => boolean;
|
|
35
|
+
onMoveShouldSetResponder: (event: ISymbioteEvent) => boolean;
|
|
36
|
+
onMoveShouldSetResponderCapture: (event: ISymbioteEvent) => boolean;
|
|
37
|
+
onResponderGrant: (event: ISymbioteEvent) => boolean;
|
|
38
|
+
onResponderReject: (event: ISymbioteEvent) => void;
|
|
39
|
+
onResponderStart: (event: ISymbioteEvent) => void;
|
|
40
|
+
onResponderMove: (event: ISymbioteEvent) => void;
|
|
41
|
+
onResponderEnd: (event: ISymbioteEvent) => void;
|
|
42
|
+
onResponderRelease: (event: ISymbioteEvent) => void;
|
|
43
|
+
onResponderTerminate: (event: ISymbioteEvent) => void;
|
|
44
|
+
onResponderTerminationRequest: (event: ISymbioteEvent) => boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface IPanResponderInstance {
|
|
47
|
+
panHandlers: IGestureResponderHandlers;
|
|
48
|
+
getInteractionHandle: () => number | null;
|
|
49
|
+
}
|
|
50
|
+
declare const PanResponder: {
|
|
51
|
+
create(config: IPanResponderCallbacks): IPanResponderInstance;
|
|
52
|
+
};
|
|
53
|
+
export default PanResponder;
|