@symbiote-native/engine 0.1.4 → 0.1.5
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/build/accessibility-info/index.android.js +17 -29
- package/build/accessibility-info/index.ios.js +23 -37
- package/build/accessibility-info/shared.d.ts +3 -2
- package/build/accessibility-info/shared.js +25 -2
- package/build/action-sheet-ios/index.d.ts +6 -0
- package/build/action-sheet-ios/index.js +1 -1
- package/build/alert/index.android.js +1 -3
- package/build/animated/animations/base.js +5 -14
- package/build/animated/event.js +7 -9
- package/build/animated/graph.d.ts +6 -0
- package/build/animated/graph.js +14 -0
- package/build/animated/interpolation-node.d.ts +0 -1
- package/build/animated/interpolation-node.js +5 -4
- package/build/animated/native/native-animated.js +1 -3
- package/build/animated/operators.d.ts +14 -34
- package/build/animated/operators.js +19 -95
- package/build/animated/value.d.ts +2 -4
- package/build/animated/value.js +17 -5
- package/build/app-state/index.js +17 -22
- package/build/appearance/index.js +17 -25
- package/build/back-handler/index.js +15 -18
- package/build/commit.d.ts +1 -3
- package/build/commit.js +10 -207
- package/build/dimensions/index.js +25 -20
- package/build/events/index.js +6 -151
- package/build/fabric-props.d.ts +3 -0
- package/build/fabric-props.js +186 -0
- package/build/i18n-manager/index.js +3 -5
- package/build/image-loader.d.ts +24 -0
- package/build/image-loader.js +175 -0
- package/build/image-source-resolver.d.ts +9 -0
- package/build/image-source-resolver.js +16 -0
- package/build/index.d.ts +10 -3
- package/build/index.js +11 -2
- package/build/keyboard/index.js +19 -34
- package/build/layout-animation/index.d.ts +1 -0
- package/build/layout-animation/index.js +53 -35
- package/build/native-modules.d.ts +12 -0
- package/build/native-modules.js +64 -1
- package/build/node.d.ts +1 -0
- package/build/node.js +9 -0
- package/build/pan-responder/index.js +1 -3
- package/build/permissions-android/index.js +1 -3
- package/build/platform-color.d.ts +3 -0
- package/build/platform-color.js +24 -0
- package/build/process-background-image/index.js +7 -14
- package/build/process-box-shadow/index.js +1 -5
- package/build/process-filter.js +2 -8
- package/build/registry.js +3 -5
- package/build/settings/index.js +1 -3
- package/build/share/index.ios.js +1 -1
- package/build/status-bar/index.android.js +1 -1
- package/build/style/index.js +2 -4
- package/build/style-registry/index.d.ts +1 -3
- package/build/style-registry/index.js +15 -48
- package/build/style-registry/scope.d.ts +3 -0
- package/build/style-registry/scope.js +41 -0
- package/build/touch-history.d.ts +23 -0
- package/build/touch-history.js +150 -0
- package/build/type-guards.d.ts +4 -0
- package/build/type-guards.js +15 -0
- package/package.json +1 -1
|
@@ -6,12 +6,10 @@
|
|
|
6
6
|
// device-event NAMES also differ from iOS (e.g. screen-reader is `touchExplorationDidChange`,
|
|
7
7
|
// reduce-motion is `reduceMotionDidChange`). Metro picks this on an Android host. Mirrors
|
|
8
8
|
// RN's AccessibilityInfo.js Android branches.
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { isSymbioteNode } from '../node.js';
|
|
12
|
-
import { sendAccessibilityEvent as sharedSendAccessibilityEvent } from '../commit.js';
|
|
9
|
+
import { createDeviceEventModule } from '../native-modules.js';
|
|
10
|
+
import {} from '../native-events.js';
|
|
13
11
|
import { dlog } from '../debug.js';
|
|
14
|
-
import { isBoolean, } from './shared.js';
|
|
12
|
+
import { isBoolean, routeSendAccessibilityEvent, } from './shared.js';
|
|
15
13
|
// The Android native module name. This is the module the Android JS wrapper
|
|
16
14
|
// (INativeAccessibilityInfoAndroid) resolves: the stock RN `AccessibilityInfo` Turbo/legacy
|
|
17
15
|
// module. A module name is only provable on a real host (a headless fake answers to any
|
|
@@ -28,22 +26,18 @@ const ANDROID_DEVICE_EVENT = {
|
|
|
28
26
|
invertColorsChanged: 'invertColorDidChange',
|
|
29
27
|
grayscaleChanged: 'grayscaleModeDidChange',
|
|
30
28
|
};
|
|
31
|
-
// Lazily resolved so importing this module has no native side effect. `null` when
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
// Lazily resolved so importing this module has no native side effect. `null` when
|
|
30
|
+
// unlinked. The lazy-resolve + lazy-emitter shape lives in `createDeviceEventModule`
|
|
31
|
+
// (native-modules.ts); Android adds no self-subscription on top of it.
|
|
32
|
+
const deviceEventModule = createDeviceEventModule({
|
|
33
|
+
moduleName: ACCESSIBILITY_MODULE,
|
|
34
|
+
moduleLogPrefix: 'AccessibilityInfo(android): module',
|
|
35
|
+
});
|
|
34
36
|
function getModule() {
|
|
35
|
-
|
|
36
|
-
accessibilityModule = getNativeModule(ACCESSIBILITY_MODULE);
|
|
37
|
-
dlog(`AccessibilityInfo(android): module ${accessibilityModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
38
|
-
}
|
|
39
|
-
return accessibilityModule;
|
|
37
|
+
return deviceEventModule.getModule();
|
|
40
38
|
}
|
|
41
39
|
function getEmitter() {
|
|
42
|
-
|
|
43
|
-
installDeviceEventHub();
|
|
44
|
-
emitter = new NativeEventEmitter(getModule() ?? undefined);
|
|
45
|
-
}
|
|
46
|
-
return emitter;
|
|
40
|
+
return deviceEventModule.getEmitter();
|
|
47
41
|
}
|
|
48
42
|
// Run a single-callback Android getter as a Promise. Resolves false when the module is
|
|
49
43
|
// unlinked OR the optional method is absent on this host; mirrors RN's "missing query ->
|
|
@@ -132,18 +126,12 @@ class AccessibilityInfoAndroid {
|
|
|
132
126
|
query.call(module, originalTimeout, timeout => resolve(timeout));
|
|
133
127
|
});
|
|
134
128
|
}
|
|
135
|
-
// Emit a named accessibility event at a view through the Fabric slot.
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
// instance), so resolve it with the runtime guard and route through shared.
|
|
129
|
+
// Emit a named accessibility event at a view through the Fabric slot. The shared
|
|
130
|
+
// routing (isSymbioteNode guard + dispatch) lives in shared.ts, identical on both
|
|
131
|
+
// platforms; Android has no early-return special case, so it passes no shouldSkip
|
|
132
|
+
// hook - every event reaches the slot.
|
|
140
133
|
sendAccessibilityEvent(handle, eventType) {
|
|
141
|
-
|
|
142
|
-
dlog(`AccessibilityInfo(android).sendAccessibilityEvent("${eventType}") -> handle is not a node (no-op)`);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
dlog(`AccessibilityInfo(android).sendAccessibilityEvent("${eventType}") -> slot`);
|
|
146
|
-
sharedSendAccessibilityEvent(handle, eventType);
|
|
134
|
+
routeSendAccessibilityEvent('android', handle, eventType);
|
|
147
135
|
}
|
|
148
136
|
// Subscribe to an accessibility-state change. Android events all carry a bare boolean.
|
|
149
137
|
// Never throws: a public event with no Android device mapping yields an inert
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
// based state getters (VoiceOver / reduce-motion / bold-text / grayscale / invert-colors /
|
|
3
3
|
// reduce-transparency / darker-system-colors), announce + focus side effects, and the
|
|
4
4
|
// observe-counters for the device-event subscription. Subscribes to iOS device events
|
|
5
|
-
// (`screenReaderChanged` / `reduceMotionChanged` / `boldTextChanged` /
|
|
5
|
+
// (`screenReaderChanged` / `reduceMotionChanged` / `boldTextChanged` / ...) via a
|
|
6
6
|
// NativeEventEmitter and re-broadcasts to JS listeners. Metro picks this on an iOS host;
|
|
7
7
|
// the bare accessibility-info.ts re-exports it as the default for tsc / tsx / headless.
|
|
8
8
|
// Mirrors RN's AccessibilityInfo.js iOS branches.
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { isSymbioteNode } from '../node.js';
|
|
12
|
-
import { sendAccessibilityEvent as sharedSendAccessibilityEvent } from '../commit.js';
|
|
9
|
+
import { createDeviceEventModule } from '../native-modules.js';
|
|
10
|
+
import {} from '../native-events.js';
|
|
13
11
|
import { dlog } from '../debug.js';
|
|
14
|
-
import { isBoolean, } from './shared.js';
|
|
12
|
+
import { isBoolean, routeSendAccessibilityEvent, } from './shared.js';
|
|
15
13
|
// The iOS native module name RN registers this under. NOTE: this is the name the iOS JS
|
|
16
14
|
// wrapper (INativeAccessibilityManagerIOS) resolves via
|
|
17
15
|
// `TurboModuleRegistry.get('AccessibilityManager')`, NOT the spec filename
|
|
@@ -32,24 +30,18 @@ const IOS_DEVICE_EVENT = {
|
|
|
32
30
|
};
|
|
33
31
|
// Lazily resolved so importing this module has no native side effect: a headless run
|
|
34
32
|
// without a fake __turboModuleProxy still loads it; resolution happens on first use.
|
|
35
|
-
// `null` when the module isn't linked.
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
// `null` when the module isn't linked. The lazy-resolve + lazy-emitter shape itself
|
|
34
|
+
// lives in `createDeviceEventModule` (native-modules.ts); iOS adds no self-subscription
|
|
35
|
+
// on top of it, unlike app-state/appearance/back-handler/keyboard.
|
|
36
|
+
const deviceEventModule = createDeviceEventModule({
|
|
37
|
+
moduleName: ACCESSIBILITY_MODULE,
|
|
38
|
+
moduleLogPrefix: 'AccessibilityInfo(ios): module',
|
|
39
|
+
});
|
|
38
40
|
function getModule() {
|
|
39
|
-
|
|
40
|
-
accessibilityModule = getNativeModule(ACCESSIBILITY_MODULE);
|
|
41
|
-
dlog(`AccessibilityInfo(ios): module ${accessibilityModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
42
|
-
}
|
|
43
|
-
return accessibilityModule;
|
|
41
|
+
return deviceEventModule.getModule();
|
|
44
42
|
}
|
|
45
43
|
function getEmitter() {
|
|
46
|
-
|
|
47
|
-
// WHY lazy: install on first subscribe so the hub exists before native emits,
|
|
48
|
-
// without a hard bootstrap-order dependency. Idempotent.
|
|
49
|
-
installDeviceEventHub();
|
|
50
|
-
emitter = new NativeEventEmitter(getModule() ?? undefined);
|
|
51
|
-
}
|
|
52
|
-
return emitter;
|
|
44
|
+
return deviceEventModule.getEmitter();
|
|
53
45
|
}
|
|
54
46
|
// Run a callback-based native getter as a Promise; resolves false when the module is
|
|
55
47
|
// unlinked, mirroring RN's "unavailable query -> false" contract for the cross-platform
|
|
@@ -162,24 +154,18 @@ class AccessibilityInfoIOS {
|
|
|
162
154
|
getRecommendedTimeoutMillis(originalTimeout) {
|
|
163
155
|
return Promise.resolve(originalTimeout);
|
|
164
156
|
}
|
|
165
|
-
// Emit an accessibility event at a view through the Fabric slot.
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
// RN early-returns 'click' on iOS only (AccessibilityInfo.js) because VoiceOver has no click
|
|
171
|
-
// producer, so preserve that one no-op; every other event reaches the slot.
|
|
157
|
+
// Emit an accessibility event at a view through the Fabric slot. The shared routing
|
|
158
|
+
// (isSymbioteNode guard + dispatch) lives in shared.ts, identical on both platforms;
|
|
159
|
+
// the ONE thing iOS adds is its own early return on 'click' (VoiceOver has no click
|
|
160
|
+
// producer, AccessibilityInfo.js), passed as the shouldSkip hook so it keeps its
|
|
161
|
+
// exact log text.
|
|
172
162
|
sendAccessibilityEvent(handle, eventType) {
|
|
173
|
-
|
|
163
|
+
routeSendAccessibilityEvent('ios', handle, eventType, () => {
|
|
164
|
+
if (eventType !== 'click')
|
|
165
|
+
return false;
|
|
174
166
|
dlog('AccessibilityInfo(ios).sendAccessibilityEvent("click") -> iOS no-op (RN parity)');
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
if (!isSymbioteNode(handle)) {
|
|
178
|
-
dlog(`AccessibilityInfo(ios).sendAccessibilityEvent("${eventType}") -> handle is not a node (no-op)`);
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
dlog(`AccessibilityInfo(ios).sendAccessibilityEvent("${eventType}") -> slot`);
|
|
182
|
-
sharedSendAccessibilityEvent(handle, eventType);
|
|
167
|
+
return true;
|
|
168
|
+
});
|
|
183
169
|
}
|
|
184
170
|
// Subscribe to an accessibility-state change. A handler for a boolean event receives a
|
|
185
171
|
// boolean; the iOS-only `announcementFinished` carries the announcement payload. Never
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ISymbioteNode } from '../node';
|
|
2
2
|
import type { IEventSubscription } from '../native-events';
|
|
3
|
+
export { isBoolean } from '../type-guards';
|
|
3
4
|
export type IAccessibilityChangeEventName = 'screenReaderChanged' | 'reduceMotionChanged' | 'boldTextChanged' | 'grayscaleChanged' | 'invertColorsChanged' | 'reduceTransparencyChanged' | 'darkerSystemColorsChanged' | 'announcementFinished' | 'accessibilityServiceChanged' | 'highTextContrastChanged';
|
|
4
5
|
export type IAccessibilityChangeEvent = IAccessibilityChangeEventName;
|
|
5
6
|
export type IAccessibilityHandle = ISymbioteNode | number | null | undefined;
|
|
@@ -31,4 +32,4 @@ export interface IAccessibilityInfoStatic {
|
|
|
31
32
|
addEventListener(eventName: IAccessibilityChangeEventName, handler: IAccessibilityChangeEventHandler): IEventSubscription;
|
|
32
33
|
}
|
|
33
34
|
export type IAccessibilityEventType = 'click' | 'focus' | 'viewHoverEnter' | 'windowStateChange';
|
|
34
|
-
export declare function
|
|
35
|
+
export declare function routeSendAccessibilityEvent(platformLabel: string, handle: IAccessibilityHandle, eventType: IAccessibilityEventType, shouldSkip?: () => boolean): void;
|
|
@@ -9,6 +9,29 @@
|
|
|
9
9
|
// Platform.OS read: the native module name is resolved per platform inside those
|
|
10
10
|
// files, not derived from this file's name. Mirrors
|
|
11
11
|
// RN's Libraries/Components/AccessibilityInfo/AccessibilityInfo.js.
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
import { isSymbioteNode } from '../node.js';
|
|
13
|
+
import { sendAccessibilityEvent as dispatchAccessibilityEvent } from '../commit.js';
|
|
14
|
+
import { dlog } from '../debug.js';
|
|
15
|
+
export { isBoolean } from '../type-guards.js';
|
|
16
|
+
// The routing behind IAccessibilityInfoStatic.sendAccessibilityEvent, shared by both
|
|
17
|
+
// platforms: resolve the handle to a real SymbioteNode and dispatch through the Fabric
|
|
18
|
+
// slot. RN's Fabric path hands the public-instance handle straight to
|
|
19
|
+
// nativeFabricUIManager.sendAccessibilityEvent with the STRING eventType, and the C++
|
|
20
|
+
// side maps it; the handle here IS the SymbioteNode (symbiote augments the node in
|
|
21
|
+
// place as its public instance).
|
|
22
|
+
//
|
|
23
|
+
// The one thing that genuinely diverges by platform - iOS's early return on 'click'
|
|
24
|
+
// (VoiceOver has no click producer, AccessibilityInfo.js) - is NOT decided here: a
|
|
25
|
+
// platform passes `shouldSkip`, which both decides AND logs its own skip (so iOS keeps
|
|
26
|
+
// its exact "iOS no-op (RN parity)" message); Android omits it and every event reaches
|
|
27
|
+
// the slot.
|
|
28
|
+
export function routeSendAccessibilityEvent(platformLabel, handle, eventType, shouldSkip) {
|
|
29
|
+
if (shouldSkip?.() === true)
|
|
30
|
+
return;
|
|
31
|
+
if (!isSymbioteNode(handle)) {
|
|
32
|
+
dlog(`AccessibilityInfo(${platformLabel}).sendAccessibilityEvent("${eventType}") -> handle is not a node (no-op)`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
dlog(`AccessibilityInfo(${platformLabel}).sendAccessibilityEvent("${eventType}") -> slot`);
|
|
36
|
+
dispatchAccessibilityEvent(handle, eventType);
|
|
14
37
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export declare const ACTION_SHEET_MANAGER = "ActionSheetManager";
|
|
1
2
|
export interface IActionSheetIOSOptions {
|
|
2
3
|
title?: string;
|
|
3
4
|
message?: string;
|
|
@@ -29,6 +30,11 @@ export interface IShareActionSheetError {
|
|
|
29
30
|
userInfo?: Record<string, unknown>;
|
|
30
31
|
message: string;
|
|
31
32
|
}
|
|
33
|
+
export interface INativeActionSheetManager {
|
|
34
|
+
showActionSheetWithOptions(options: IActionSheetIOSOptions, callback: (buttonIndex: number) => void): void;
|
|
35
|
+
showShareActionSheetWithOptions(options: IShareActionSheetIOSOptions, failureCallback: (error: IShareActionSheetError) => void, successCallback: (completed: boolean, activityType?: string) => void): void;
|
|
36
|
+
dismissActionSheet?(): void;
|
|
37
|
+
}
|
|
32
38
|
export declare const ActionSheetIOS: {
|
|
33
39
|
showActionSheetWithOptions(options: IActionSheetIOSOptions, callback: (buttonIndex: number) => void): void;
|
|
34
40
|
showShareActionSheetWithOptions(options: IShareActionSheetIOSOptions, failureCallback: (error: IShareActionSheetError) => void, successCallback: (completed: boolean, activityType?: string) => void): void;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// through untouched. The canary needs no colors; revisit when wiring real colors.
|
|
19
19
|
import { dlog } from '../debug.js';
|
|
20
20
|
import { getNativeModule } from '../native-modules.js';
|
|
21
|
-
const ACTION_SHEET_MANAGER = 'ActionSheetManager';
|
|
21
|
+
export const ACTION_SHEET_MANAGER = 'ActionSheetManager';
|
|
22
22
|
// The static imperative API RN exposes, mirrored as a static-method object.
|
|
23
23
|
export const ActionSheetIOS = {
|
|
24
24
|
showActionSheetWithOptions(options, callback) {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
// Non-throwing, like StatusBar: a missing native module is a no-op, never a crash.
|
|
19
19
|
import { dlog } from '../debug.js';
|
|
20
20
|
import { getNativeModule } from '../native-modules.js';
|
|
21
|
+
import { isRecord } from '../type-guards.js';
|
|
21
22
|
import { DEFAULT_POSITIVE_TEXT, normalizeButtons, } from './shared.js';
|
|
22
23
|
const DIALOG_MANAGER = 'DialogManagerAndroid';
|
|
23
24
|
// RN's hardwired Android fallbacks for the button-key constants (NativeDialogManager-
|
|
@@ -32,9 +33,6 @@ const ANDROID_DIALOG_CONSTANTS = {
|
|
|
32
33
|
};
|
|
33
34
|
// The trust boundary for getConstants(): native sends an untyped HostObject. Read each key
|
|
34
35
|
// with a typeof guard and fall back to RN's documented default when it's missing.
|
|
35
|
-
function isRecord(value) {
|
|
36
|
-
return typeof value === 'object' && value !== null;
|
|
37
|
-
}
|
|
38
36
|
function readDialogConstants(raw) {
|
|
39
37
|
if (!isRecord(raw)) {
|
|
40
38
|
dlog('Alert: DialogManagerAndroid.getConstants() returned a non-object — using defaults');
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
// owns its own requestAnimationFrame loop. They are declared as methods (not
|
|
9
9
|
// class fields) so a subclass override is not shadowed under
|
|
10
10
|
// useDefineForClassFields.
|
|
11
|
-
import { flushValue } from '../graph.js';
|
|
12
11
|
import { dlog, isDebug } from '../../debug.js';
|
|
13
12
|
import { generateNativeAnimationId, isNativeAnimatedAvailable, nativeAnimated, } from '../native/native-animated.js';
|
|
14
13
|
export class BaseAnimation {
|
|
@@ -41,7 +40,7 @@ export class BaseAnimation {
|
|
|
41
40
|
this.onEndCallback = onEnd;
|
|
42
41
|
this.__active = true;
|
|
43
42
|
}
|
|
44
|
-
// A native driver overrides this with its curve config (`{type:'frames'|'spring'|'decay',
|
|
43
|
+
// A native driver overrides this with its curve config (`{type:'frames'|'spring'|'decay', ...}`).
|
|
45
44
|
getNativeAnimationConfig() {
|
|
46
45
|
throw new Error('This animation type cannot be offloaded to the native driver');
|
|
47
46
|
}
|
|
@@ -57,19 +56,11 @@ export class BaseAnimation {
|
|
|
57
56
|
dlog('useNativeDriver requested but native animated module is missing; using JS driver');
|
|
58
57
|
return false;
|
|
59
58
|
}
|
|
60
|
-
const config = this.getNativeAnimationConfig();
|
|
61
|
-
// RN hands the curve's platform bag down to the value node (Animation.js:137)
|
|
62
|
-
// so the node's create config carries it too.
|
|
63
|
-
animatedValue.__makeNative(this.__platformConfig);
|
|
64
59
|
this.nativeId = generateNativeAnimationId();
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
animatedValue.__onNativeUpdate(result.value, result.offset);
|
|
70
|
-
flushValue(animatedValue);
|
|
71
|
-
}
|
|
72
|
-
});
|
|
60
|
+
// The value owns the native handshake (make native, mint tag, sync back on
|
|
61
|
+
// completion); we hand over only what THIS driver owns: the curve, RN's
|
|
62
|
+
// Animation.js:137 platform bag, this animation's id, and its own end callback.
|
|
63
|
+
animatedValue.__startNativeAnimation(this.getNativeAnimationConfig(), this.nativeId, finished => this.__notifyAnimationEnd({ finished }), this.__platformConfig);
|
|
73
64
|
return true;
|
|
74
65
|
}
|
|
75
66
|
stop() {
|
package/build/animated/event.js
CHANGED
|
@@ -18,9 +18,7 @@ import { getNativeTag, whenCommitted } from '../commit.js';
|
|
|
18
18
|
import { isSymbioteNode } from '../node.js';
|
|
19
19
|
import { AnimatedNode, flushValue } from './graph.js';
|
|
20
20
|
import { isNativeAnimatedAvailable, nativeAnimated } from './native/native-animated.js';
|
|
21
|
-
|
|
22
|
-
return typeof value === 'object' && value !== null;
|
|
23
|
-
}
|
|
21
|
+
import { isRecord } from '../type-guards.js';
|
|
24
22
|
// A value node settable from an event field. AnimatedValue carries setValue; we
|
|
25
23
|
// duck-type it (rather than importing AnimatedValue) to keep this leaf-agnostic
|
|
26
24
|
// and avoid a value<->event import cycle.
|
|
@@ -68,9 +66,9 @@ export class AnimatedEvent {
|
|
|
68
66
|
// RN parity: the event remembers whether useNativeDriver was requested. Honored only
|
|
69
67
|
// when a native module is present (__isNative); otherwise the JS path drives values.
|
|
70
68
|
nativeDriverRequested;
|
|
71
|
-
// Flipped once a host view native-attaches this event
|
|
72
|
-
// setting values (native owns them on the UI thread) and only forwards listeners
|
|
73
|
-
//
|
|
69
|
+
// Flipped once a host view native-attaches this event: the JS handler then stops
|
|
70
|
+
// setting values (native owns them on the UI thread) and only forwards listeners,
|
|
71
|
+
// avoiding a double drive and a redundant per-tick commit.
|
|
74
72
|
attachedNatively = false;
|
|
75
73
|
constructor(argMapping, config) {
|
|
76
74
|
if (config?.listener !== undefined)
|
|
@@ -165,8 +163,8 @@ export function attachNativeEvent(node, eventName, argMapping) {
|
|
|
165
163
|
const animatedEvent = new AnimatedEvent(argMapping);
|
|
166
164
|
let attachedTag;
|
|
167
165
|
// Bind once the node is committed: now if it already has a Fabric tag, else after the commit that
|
|
168
|
-
// assigns it. Vue/Svelte batch commits on a microtask, so the adapter can wire this
|
|
169
|
-
// sticky-header scroll
|
|
166
|
+
// assigns it. Vue/Svelte batch commits on a microtask, so the adapter can wire this (e.g. the
|
|
167
|
+
// sticky-header scroll) before the tag exists; whenCommitted defers instead of silently binding
|
|
170
168
|
// nothing. React commits synchronously and binds on the first try.
|
|
171
169
|
const cancel = whenCommitted(node, () => {
|
|
172
170
|
const viewTag = getNativeTag(node);
|
|
@@ -187,7 +185,7 @@ export function attachNativeEvent(node, eventName, argMapping) {
|
|
|
187
185
|
// Native-attach the AnimatedEvent already behind a handler from `event(...)`, binding it
|
|
188
186
|
// to a committed host node. Unlike attachNativeEvent (which builds a fresh event from a
|
|
189
187
|
// raw mapping for ScrollView's internal sticky value), this REUSES the caller's handler,
|
|
190
|
-
// so createAnimatedComponent can offload `onScroll={Animated.event(
|
|
188
|
+
// so createAnimatedComponent can offload `onScroll={Animated.event(..., {useNativeDriver})}`
|
|
191
189
|
// to the UI thread, and the __makeNative cascade carries the bound interpolations/props
|
|
192
190
|
// native with it. Returns undefined (caller keeps the JS path) when the prop is not a native
|
|
193
191
|
// event handler; if it IS but the node has no tag yet, the bind defers to the commit (same race).
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { type INativeNodeConfig, type IPlatformConfig } from './native/native-animated';
|
|
2
|
+
import type { IInterpolationConfig } from './interpolation';
|
|
3
|
+
import type { AnimatedInterpolation } from './interpolation-node';
|
|
2
4
|
export type IValueListener = (state: {
|
|
3
5
|
value: number | string;
|
|
4
6
|
}) => void;
|
|
7
|
+
type IInterpolationFactory = (parent: AnimatedNode, config: IInterpolationConfig) => AnimatedInterpolation;
|
|
8
|
+
export declare function registerInterpolationFactory(factory: IInterpolationFactory): void;
|
|
5
9
|
export declare class AnimatedNode {
|
|
6
10
|
private readonly listeners;
|
|
7
11
|
private suspendCallbacks;
|
|
@@ -17,6 +21,7 @@ export declare class AnimatedNode {
|
|
|
17
21
|
__getNativeConfig(): INativeNodeConfig;
|
|
18
22
|
__getValue(): unknown;
|
|
19
23
|
__getAnimatedValue(): unknown;
|
|
24
|
+
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
20
25
|
__addChild(_child: AnimatedNode): void;
|
|
21
26
|
__removeChild(_child: AnimatedNode): void;
|
|
22
27
|
__getChildren(): readonly AnimatedNode[];
|
|
@@ -36,3 +41,4 @@ export declare class AnimatedWithChildren extends AnimatedNode {
|
|
|
36
41
|
__callListeners(value: number | string): void;
|
|
37
42
|
}
|
|
38
43
|
export declare function flushValue(rootNode: AnimatedNode): void;
|
|
44
|
+
export {};
|
package/build/animated/graph.js
CHANGED
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
// to rebuild composite props (e.g. transform from many parents).
|
|
12
12
|
import { generateNativeNodeTag, nativeAnimated, } from './native/native-animated.js';
|
|
13
13
|
let nextListenerId = 1;
|
|
14
|
+
let createInterpolationNode;
|
|
15
|
+
export function registerInterpolationFactory(factory) {
|
|
16
|
+
createInterpolationNode = factory;
|
|
17
|
+
}
|
|
14
18
|
// Depth of the currently-active withSuspendedCallbacks blocks. While > 0, a
|
|
15
19
|
// composite setter (AnimatedColor.setValue) is driving several channels in a row;
|
|
16
20
|
// each channel's own flushValue is suppressed so the bound leaf commits ONCE (at
|
|
@@ -98,6 +102,16 @@ export class AnimatedNode {
|
|
|
98
102
|
__getAnimatedValue() {
|
|
99
103
|
return this.__getValue();
|
|
100
104
|
}
|
|
105
|
+
// Map this node's value before it reaches a prop, e.g. 0..1 -> 0..10. Defined once
|
|
106
|
+
// here (Information Expert: every node subclass wants the identical one-liner)
|
|
107
|
+
// instead of duplicated per subclass; see registerInterpolationFactory above for
|
|
108
|
+
// why the concrete constructor is injected rather than imported directly.
|
|
109
|
+
interpolate(config) {
|
|
110
|
+
if (createInterpolationNode === undefined) {
|
|
111
|
+
throw new Error('AnimatedNode.interpolate: interpolation factory not registered');
|
|
112
|
+
}
|
|
113
|
+
return createInterpolationNode(this, config);
|
|
114
|
+
}
|
|
101
115
|
__addChild(_child) { }
|
|
102
116
|
__removeChild(_child) { }
|
|
103
117
|
__getChildren() {
|
|
@@ -8,7 +8,6 @@ export declare class AnimatedInterpolation extends AnimatedWithChildren {
|
|
|
8
8
|
constructor(parent: AnimatedNode, config: IInterpolationConfig);
|
|
9
9
|
private getInterpolation;
|
|
10
10
|
__getValue(): number | string;
|
|
11
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
12
11
|
__attach(): void;
|
|
13
12
|
__detach(): void;
|
|
14
13
|
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// through an interpolation. Ported from RN's AnimatedInterpolation.js: numeric,
|
|
3
3
|
// string-with-units, and color output ranges (the value graph; native config
|
|
4
4
|
// removed). Platform (Native) colors stay out of scope, color.ts defers them.
|
|
5
|
-
import { AnimatedNode, AnimatedWithChildren } from './graph.js';
|
|
5
|
+
import { AnimatedNode, AnimatedWithChildren, registerInterpolationFactory } from './graph.js';
|
|
6
6
|
import { checkValidRanges, createInterpolation } from './interpolation.js';
|
|
7
7
|
export class AnimatedInterpolation extends AnimatedWithChildren {
|
|
8
8
|
parent;
|
|
@@ -28,9 +28,6 @@ export class AnimatedInterpolation extends AnimatedWithChildren {
|
|
|
28
28
|
}
|
|
29
29
|
return this.getInterpolation()(parentValue);
|
|
30
30
|
}
|
|
31
|
-
interpolate(config) {
|
|
32
|
-
return new AnimatedInterpolation(this, config);
|
|
33
|
-
}
|
|
34
31
|
__attach() {
|
|
35
32
|
this.parent.__addChild(this);
|
|
36
33
|
super.__attach();
|
|
@@ -55,3 +52,7 @@ export class AnimatedInterpolation extends AnimatedWithChildren {
|
|
|
55
52
|
};
|
|
56
53
|
}
|
|
57
54
|
}
|
|
55
|
+
// Hand graph.ts's AnimatedNode.interpolate() the real constructor at module load,
|
|
56
|
+
// so every node subclass's base-class interpolate() produces an actual
|
|
57
|
+
// AnimatedInterpolation without graph.ts ever value-importing this module.
|
|
58
|
+
registerInterpolationFactory((parent, config) => new AnimatedInterpolation(parent, config));
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { dlog } from '../../debug.js';
|
|
13
13
|
import { getNativeModule } from '../../native-modules.js';
|
|
14
14
|
import { NativeEventEmitter } from '../../native-events.js';
|
|
15
|
+
import { isRecord } from '../../type-guards.js';
|
|
15
16
|
// iOS bridgeless registers the Turbo variant; the legacy name is the fallback.
|
|
16
17
|
const TURBO_MODULE_NAME = 'NativeAnimatedTurboModule';
|
|
17
18
|
const LEGACY_MODULE_NAME = 'NativeAnimatedModule';
|
|
@@ -50,9 +51,6 @@ export function generateNativeAnimationId() {
|
|
|
50
51
|
const VALUE_UPDATE_EVENT = 'onAnimatedValueUpdate';
|
|
51
52
|
const valueListeners = new Map();
|
|
52
53
|
let valueUpdateSubscription;
|
|
53
|
-
function isRecord(value) {
|
|
54
|
-
return typeof value === 'object' && value !== null;
|
|
55
|
-
}
|
|
56
54
|
function ensureValueUpdateSubscription() {
|
|
57
55
|
if (valueUpdateSubscription !== undefined)
|
|
58
56
|
return;
|
|
@@ -1,50 +1,31 @@
|
|
|
1
1
|
import { AnimatedNode, AnimatedWithChildren } from './graph';
|
|
2
|
-
import { AnimatedInterpolation } from './interpolation-node';
|
|
3
|
-
import type { IInterpolationConfig } from './interpolation';
|
|
4
2
|
import type { INativeNodeConfig, IPlatformConfig } from './native/native-animated';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
declare abstract class AnimatedBinaryOp extends AnimatedWithChildren {
|
|
4
|
+
protected readonly a: AnimatedNode;
|
|
5
|
+
protected readonly b: AnimatedNode;
|
|
8
6
|
constructor(a: AnimatedNode | number, b: AnimatedNode | number);
|
|
7
|
+
protected abstract compute(a: number, b: number): number;
|
|
9
8
|
__getValue(): number;
|
|
10
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
11
9
|
__attach(): void;
|
|
12
10
|
__detach(): void;
|
|
13
11
|
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
12
|
+
}
|
|
13
|
+
export declare class AnimatedAddition extends AnimatedBinaryOp {
|
|
14
|
+
protected compute(a: number, b: number): number;
|
|
14
15
|
__getNativeConfig(): INativeNodeConfig;
|
|
15
16
|
}
|
|
16
|
-
export declare class AnimatedSubtraction extends
|
|
17
|
-
|
|
18
|
-
private readonly b;
|
|
19
|
-
constructor(a: AnimatedNode | number, b: AnimatedNode | number);
|
|
20
|
-
__getValue(): number;
|
|
21
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
22
|
-
__attach(): void;
|
|
23
|
-
__detach(): void;
|
|
24
|
-
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
17
|
+
export declare class AnimatedSubtraction extends AnimatedBinaryOp {
|
|
18
|
+
protected compute(a: number, b: number): number;
|
|
25
19
|
__getNativeConfig(): INativeNodeConfig;
|
|
26
20
|
}
|
|
27
|
-
export declare class AnimatedMultiplication extends
|
|
28
|
-
|
|
29
|
-
private readonly b;
|
|
30
|
-
constructor(a: AnimatedNode | number, b: AnimatedNode | number);
|
|
31
|
-
__getValue(): number;
|
|
32
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
33
|
-
__attach(): void;
|
|
34
|
-
__detach(): void;
|
|
35
|
-
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
21
|
+
export declare class AnimatedMultiplication extends AnimatedBinaryOp {
|
|
22
|
+
protected compute(a: number, b: number): number;
|
|
36
23
|
__getNativeConfig(): INativeNodeConfig;
|
|
37
24
|
}
|
|
38
|
-
export declare class AnimatedDivision extends
|
|
39
|
-
private readonly a;
|
|
40
|
-
private readonly b;
|
|
25
|
+
export declare class AnimatedDivision extends AnimatedBinaryOp {
|
|
41
26
|
private warnedAboutDivideByZero;
|
|
42
27
|
constructor(a: AnimatedNode | number, b: AnimatedNode | number);
|
|
43
|
-
|
|
44
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
45
|
-
__attach(): void;
|
|
46
|
-
__detach(): void;
|
|
47
|
-
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
28
|
+
protected compute(a: number, b: number): number;
|
|
48
29
|
__getNativeConfig(): INativeNodeConfig;
|
|
49
30
|
}
|
|
50
31
|
export declare class AnimatedModulo extends AnimatedWithChildren {
|
|
@@ -52,7 +33,6 @@ export declare class AnimatedModulo extends AnimatedWithChildren {
|
|
|
52
33
|
private readonly modulus;
|
|
53
34
|
constructor(a: AnimatedNode, modulus: number);
|
|
54
35
|
__getValue(): number;
|
|
55
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
56
36
|
__attach(): void;
|
|
57
37
|
__detach(): void;
|
|
58
38
|
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
@@ -66,7 +46,6 @@ export declare class AnimatedDiffClamp extends AnimatedWithChildren {
|
|
|
66
46
|
private lastValue;
|
|
67
47
|
constructor(a: AnimatedNode, min: number, max: number);
|
|
68
48
|
__getValue(): number;
|
|
69
|
-
interpolate(config: IInterpolationConfig): AnimatedInterpolation;
|
|
70
49
|
__attach(): void;
|
|
71
50
|
__detach(): void;
|
|
72
51
|
__makeNative(platformConfig?: IPlatformConfig): void;
|
|
@@ -78,3 +57,4 @@ export declare function multiply(a: AnimatedNode | number, b: AnimatedNode | num
|
|
|
78
57
|
export declare function divide(a: AnimatedNode | number, b: AnimatedNode | number): AnimatedDivision;
|
|
79
58
|
export declare function modulo(a: AnimatedNode, modulus: number): AnimatedModulo;
|
|
80
59
|
export declare function diffClamp(a: AnimatedNode, min: number, max: number): AnimatedDiffClamp;
|
|
60
|
+
export {};
|