@symbiote-native/engine 0.1.6 → 0.1.7
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 +1 -1
- package/build/accessibility-info/index.ios.js +1 -1
- package/build/action-sheet-ios/index.js +1 -1
- package/build/alert/index.android.js +1 -1
- package/build/alert/index.ios.js +1 -1
- package/build/animated/native/native-animated.js +1 -1
- package/build/app-registry/index.js +1 -1
- package/build/app-state/index.js +1 -1
- package/build/appearance/index.js +1 -1
- package/build/back-handler/index.js +1 -1
- package/build/dimensions/index.js +1 -1
- package/build/i18n-manager/index.js +1 -1
- package/build/image-loader.js +1 -1
- package/build/index.js +1 -1
- package/build/keyboard/index.js +1 -1
- package/build/layout-animation/index.js +1 -1
- package/build/linking/shared.js +1 -1
- package/build/permissions-android/index.js +1 -1
- package/build/platform/shared.js +1 -1
- package/build/settings/index.js +1 -1
- package/build/share/index.android.js +1 -1
- package/build/share/index.ios.js +1 -1
- package/build/status-bar/index.android.js +1 -1
- package/build/status-bar/index.ios.js +1 -1
- package/build/style-sheet/index.js +1 -1
- package/build/toast-android/index.js +1 -1
- package/build/vibration/shared.js +1 -1
- package/package.json +3 -2
- package/build/image-loader/index.d.ts +0 -24
- package/build/image-loader/index.js +0 -175
- package/build/image-source-resolver/index.d.ts +0 -9
- package/build/image-source-resolver/index.js +0 -16
- package/build/native-modules.d.ts +0 -18
- package/build/native-modules.js +0 -120
|
@@ -6,7 +6,7 @@
|
|
|
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 { createDeviceEventModule } from '../native-modules.js';
|
|
9
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
10
10
|
import {} from '../native-events.js';
|
|
11
11
|
import { dlog } from '../debug.js';
|
|
12
12
|
import { isBoolean, routeSendAccessibilityEvent, } from './shared.js';
|
|
@@ -6,7 +6,7 @@
|
|
|
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 { createDeviceEventModule } from '../native-modules.js';
|
|
9
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
10
10
|
import {} from '../native-events.js';
|
|
11
11
|
import { dlog } from '../debug.js';
|
|
12
12
|
import { isBoolean, routeSendAccessibilityEvent, } from './shared.js';
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// processing in @symbiote-native/engine, so we do NOT process colors here; options pass
|
|
18
18
|
// through untouched. The canary needs no colors; revisit when wiring real colors.
|
|
19
19
|
import { dlog } from '../debug.js';
|
|
20
|
-
import { getNativeModule } from '../native-modules.js';
|
|
20
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
21
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 = {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
//
|
|
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
|
-
import { getNativeModule } from '../native-modules.js';
|
|
20
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
21
21
|
import { isRecord } from '../type-guards.js';
|
|
22
22
|
import { DEFAULT_POSITIVE_TEXT, normalizeButtons, } from './shared.js';
|
|
23
23
|
const DIALOG_MANAGER = 'DialogManagerAndroid';
|
package/build/alert/index.ios.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// Non-throwing, like StatusBar: a missing native module is a no-op, never a crash (on a
|
|
13
13
|
// device the module may be absent).
|
|
14
14
|
import { dlog } from '../debug.js';
|
|
15
|
-
import { getNativeModule } from '../native-modules.js';
|
|
15
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
16
16
|
const ALERT_MANAGER = 'AlertManager';
|
|
17
17
|
// prompt builds the native args, assigns each button its array index as id, and dispatches
|
|
18
18
|
// the matching button's onPress when the native callback returns that id. Non-throwing: no
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// module is resolved lazily on first use, so importing this file headless (no
|
|
11
11
|
// native host) is inert until a native-driven animation actually starts.
|
|
12
12
|
import { dlog } from '../../debug.js';
|
|
13
|
-
import { getNativeModule } from '../../native-modules.js';
|
|
13
|
+
import { getNativeModule } from '../../native-modules/index.js';
|
|
14
14
|
import { NativeEventEmitter } from '../../native-events.js';
|
|
15
15
|
import { isRecord } from '../../type-guards.js';
|
|
16
16
|
// iOS bridgeless registers the Turbo variant; the legacy name is the fallback.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// registrar. Reached the same way shared reaches processColor: a dependency-injected seam
|
|
12
12
|
// (setHostRegistrar), so the core stays react-native-free and the app glue wires the host once
|
|
13
13
|
// at startup.
|
|
14
|
-
import { getNativeModule } from '../native-modules.js';
|
|
14
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
15
15
|
import { dlog } from '../debug.js';
|
|
16
16
|
const HEADLESS_TASK_MODULE = 'HeadlessJsTaskSupport';
|
|
17
17
|
// Builds one adapter's AppRegistry. `runnableFor` is the sole framework-specific seam: given a
|
package/build/app-state/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// NativeEventEmitter bound to the AppState native module and maps them onto the
|
|
6
6
|
// public 'change'/'memoryWarning'/'focus'/'blur' listeners, mirroring RN's
|
|
7
7
|
// Libraries/AppState/AppState.js.
|
|
8
|
-
import { createDeviceEventModule } from '../native-modules.js';
|
|
8
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
9
9
|
import {} from '../native-events.js';
|
|
10
10
|
import { dlog } from '../debug.js';
|
|
11
11
|
// The native module name RN registers AppState under, confirmed from its spec
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// native module (which RN keys its appearance events off of) and re-broadcasts to
|
|
5
5
|
// JS listeners as a plain `{ colorScheme }` payload. Mirrors RN's
|
|
6
6
|
// Libraries/Utilities/Appearance.js, slimmed to the parts we need.
|
|
7
|
-
import { createDeviceEventModule } from '../native-modules.js';
|
|
7
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
8
8
|
import {} from '../native-events.js';
|
|
9
9
|
import { dlog } from '../debug.js';
|
|
10
10
|
// The native module name RN registers the appearance module under, confirmed from
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Android-only by intent: iOS has no hardware back button, so the whole module
|
|
7
7
|
// degrades to a no-op when the native module is absent, matching RN's
|
|
8
8
|
// BackHandler.ios.js stub. Mirrors RN's Libraries/Utilities/BackHandler.android.js.
|
|
9
|
-
import { createDeviceEventModule } from '../native-modules.js';
|
|
9
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
10
10
|
import {} from '../native-events.js';
|
|
11
11
|
import { dlog } from '../debug.js';
|
|
12
12
|
// The native module name RN registers this under. NOTE: this is the name the
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// We resolve it through the same generic native-module bridge as Platform
|
|
12
12
|
// (getNativeModule), so this module stays importable headless before a fake proxy
|
|
13
13
|
// is installed.
|
|
14
|
-
import { createDeviceEventModule } from '../native-modules.js';
|
|
14
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
15
15
|
import {} from '../native-events.js';
|
|
16
16
|
import { dlog } from '../debug.js';
|
|
17
17
|
import { isRecord } from '../type-guards.js';
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
// forceRTL(forceRTL: boolean)
|
|
14
14
|
// swapLeftAndRightInRTL(flipStyles: boolean)
|
|
15
15
|
import { dlog } from '../debug.js';
|
|
16
|
-
import { getNativeModule } from '../native-modules.js';
|
|
16
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
17
17
|
import { isBoolean } from '../type-guards.js';
|
|
18
18
|
// The iOS native module name RN registers this under (the same name on both
|
|
19
19
|
// platforms). A module name is only provable on a real host (a headless fake
|
package/build/image-loader.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// native bridge).
|
|
16
16
|
import { dlog } from './debug.js';
|
|
17
17
|
import { resolveImageSource } from './image-source-resolver.js';
|
|
18
|
-
import { getNativeModule } from './native-modules.js';
|
|
18
|
+
import { getNativeModule } from './native-modules/index.js';
|
|
19
19
|
import { Platform } from './platform';
|
|
20
20
|
import { isNumber } from './type-guards.js';
|
|
21
21
|
// The iOS native module name RN registers this under (NativeImageLoaderIOS.js resolves
|
package/build/index.js
CHANGED
|
@@ -37,7 +37,7 @@ export { registerStyles, resolveClassName, clearGlobalStyles, isClassNameValue,
|
|
|
37
37
|
export { scopeClassName } from './style-registry/scope.js';
|
|
38
38
|
export { Platform } from './platform';
|
|
39
39
|
export { dlog, isDebug } from './debug.js';
|
|
40
|
-
export { getNativeModule, getEnforcingNativeModule } from './native-modules.js';
|
|
40
|
+
export { getNativeModule, getEnforcingNativeModule } from './native-modules/index.js';
|
|
41
41
|
export { installDeviceEventHub, NativeEventEmitter, setDeviceEventSource } from './native-events.js';
|
|
42
42
|
export { AnimatedNode, AnimatedWithChildren, AnimatedValue, AnimatedValueXY, AnimatedColor, AnimatedInterpolation, AnimatedAddition, AnimatedSubtraction, AnimatedMultiplication, AnimatedDivision, AnimatedModulo, AnimatedDiffClamp, AnimatedEvent, add, subtract, multiply, divide, modulo, diffClamp, event, forkEvent, unforkEvent, attachNativeEvent, attachNativeEventHandler, flushValue, Easing, createNumericInterpolation, checkValidRanges, TimingAnimation, SpringAnimation, DecayAnimation, AnimatedTracking, timing, spring, decay, parallel, sequence, stagger, loop, delay, nativeAnimated, isNativeAnimatedAvailable, AnimatedProps, AnimatedStyle, AnimatedTransform, AnimatedMock, reduceProps, isAnimatedNode, readPassthroughStyle, resolveHostNode, } from './animated/index.js';
|
|
43
43
|
export { getSlot } from './fabric.js';
|
package/build/keyboard/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// subscribes through a NativeEventEmitter bound to the KeyboardObserver native
|
|
4
4
|
// module, which RN keys its keyboard events off of. Mirrors RN's
|
|
5
5
|
// Libraries/Components/Keyboard/Keyboard.js, slimmed to the parts we need.
|
|
6
|
-
import { createDeviceEventModule } from '../native-modules.js';
|
|
6
|
+
import { createDeviceEventModule } from '../native-modules/index.js';
|
|
7
7
|
import {} from '../native-events.js';
|
|
8
8
|
import { dlog } from '../debug.js';
|
|
9
9
|
import { blurTextInput, currentlyFocusedInput } from '../text-input-state.js';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
//
|
|
8
8
|
// It is a native-bridge consumer (RN's `Platform`/`StyleSheet` purity split puts
|
|
9
9
|
// these in the adapter, not in shared, like Keyboard / StatusBar).
|
|
10
|
-
import { getNativeModule } from '../native-modules.js';
|
|
10
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
11
11
|
import { dlog } from '../debug.js';
|
|
12
12
|
import { isRecord } from '../type-guards.js';
|
|
13
13
|
// ---- native module routing ----------------------------------------------
|
package/build/linking/shared.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// the base linking.ts re-exports the iOS build for web/headless. There is no runtime
|
|
9
9
|
// `Platform.OS` read; the filename is the selector.
|
|
10
10
|
import { installDeviceEventHub, NativeEventEmitter, } from '../native-events.js';
|
|
11
|
-
import { getNativeModule } from '../native-modules.js';
|
|
11
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
12
12
|
import { dlog } from '../debug.js';
|
|
13
13
|
// The one event symbiote observes: an incoming deep link. RN's LinkingEventDefinitions.
|
|
14
14
|
const URL_EVENT = 'url';
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
// requestPermission(permission): Promise<string>
|
|
18
18
|
// shouldShowRequestPermissionRationale(permission): Promise<boolean>
|
|
19
19
|
// requestMultiplePermissions(permissions): Promise<{[permission]: string}>
|
|
20
|
-
import { getNativeModule } from '../native-modules.js';
|
|
20
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
21
21
|
import { dlog } from '../debug.js';
|
|
22
22
|
import { isBoolean } from '../type-guards.js';
|
|
23
23
|
// The native module name RN registers this TurboModule under
|
package/build/platform/shared.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// select precedence, and the device-class getters. The filename is the selector (Metro
|
|
6
6
|
// picks platform.ios / platform.android by host); no Platform.OS read lives here.
|
|
7
7
|
import { dlog } from '../debug.js';
|
|
8
|
-
import { getNativeModule } from '../native-modules.js';
|
|
8
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
9
9
|
// The native module name RN registers PlatformConstants under, identical on both
|
|
10
10
|
// platforms; only getConstants()'s SHAPE differs, which each platform file guards.
|
|
11
11
|
export const PLATFORM_CONSTANTS = 'PlatformConstants';
|
package/build/settings/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// device event `settingsUpdated`, which feeds the same change->fire path. Mirrors
|
|
7
7
|
// RN's Libraries/Settings/Settings.ios.js, iOS surface only.
|
|
8
8
|
import { installDeviceEventHub, NativeEventEmitter, } from '../native-events.js';
|
|
9
|
-
import { getNativeModule } from '../native-modules.js';
|
|
9
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
10
10
|
import { dlog } from '../debug.js';
|
|
11
11
|
import { isRecord } from '../type-guards.js';
|
|
12
12
|
// The iOS native module name RN registers this under. NOTE: this is the name the
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// TurboModuleRegistry.get('ShareModule') from RN source, but headless fakes resolve any
|
|
9
9
|
// name, so it is only proven on a real Android host (a bridgeless resolution log there).
|
|
10
10
|
import { dlog } from '../debug.js';
|
|
11
|
-
import { getNativeModule } from '../native-modules.js';
|
|
11
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
12
12
|
import { validateContent, shareActions, SHARED_ACTION, DISMISSED_ACTION } from './shared.js';
|
|
13
13
|
const SHARE_MODULE = 'ShareModule';
|
|
14
14
|
// ShareModule.share resolves an untyped value at the native boundary; narrow it before
|
package/build/share/index.ios.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// callback. Metro picks this file on an iOS host; the base share.ts re-exports it for
|
|
6
6
|
// web/headless.
|
|
7
7
|
import { dlog } from '../debug.js';
|
|
8
|
-
import { getNativeModule } from '../native-modules.js';
|
|
8
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
9
9
|
import { ACTION_SHEET_MANAGER, } from '../action-sheet-ios/index.js';
|
|
10
10
|
import { validateContent, shareActions, SHARED_ACTION, DISMISSED_ACTION } from './shared.js';
|
|
11
11
|
export const Share = {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// replace. Now that render.ts installs RN$stopSurface and tears surfaces down cleanly, the
|
|
11
11
|
// relayout survives and the bar updates without blanking (verified on device: show/hide +
|
|
12
12
|
// light/dark text). See render.ts's installStopSurfaceGlobal.
|
|
13
|
-
import { getNativeModule } from '../native-modules.js';
|
|
13
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
14
14
|
import { dlog } from '../debug.js';
|
|
15
15
|
import { processColor } from '../platform-color/index.js';
|
|
16
16
|
import { STATUS_BAR_MANAGER } from './shared.js';
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// boundary getNativeModule<T> resolves against. Metro picks this on an iOS host; the base
|
|
9
9
|
// status-bar.ts re-exports it for tsc / tsx / headless. Each adapter wraps these with its own
|
|
10
10
|
// declarative component.
|
|
11
|
-
import { getNativeModule } from '../native-modules.js';
|
|
11
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
12
12
|
import { dlog } from '../debug.js';
|
|
13
13
|
import { STATUS_BAR_MANAGER, STATIC_HIDE_TRANSITION, hideTransition, } from './shared.js';
|
|
14
14
|
// Apply a StatusBar component's props to the native module. The adapter calls this from its
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// constants. The typed ViewStyle/TextStyle live next door in styles.ts, so `create`
|
|
6
6
|
// is typed against them like RN's, not left generic over a plain Record.
|
|
7
7
|
import { dlog } from '../debug.js';
|
|
8
|
-
import { getNativeModule } from '../native-modules.js';
|
|
8
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
9
9
|
import { flattenStyle } from '../style/index.js';
|
|
10
10
|
// RN's hairline factor: a "1 physical pixel" line is ~0.4 logical px, rounded to the
|
|
11
11
|
// nearest device pixel. Named so the 0.4 isn't a bare magic number (RN source uses
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// showWithGravity(message: string, duration: number, gravity: number)
|
|
15
15
|
// showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset)
|
|
16
16
|
import { dlog } from '../debug.js';
|
|
17
|
-
import { getNativeModule } from '../native-modules.js';
|
|
17
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
18
18
|
// The native module name RN registers this under. NOTE: this is the name the spec
|
|
19
19
|
// resolves via `TurboModuleRegistry.getEnforcing<Spec>('ToastAndroid')`, NOT the
|
|
20
20
|
// spec filename `INativeToastAndroid`. A module name is only provable on a real
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// the base vibration.ts re-exports the iOS build for web/headless. There is no runtime
|
|
17
17
|
// `Platform.OS` read; the filename is the selector. No Fabric view, pure JS->native.
|
|
18
18
|
import { dlog } from '../debug.js';
|
|
19
|
-
import { getNativeModule } from '../native-modules.js';
|
|
19
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
20
20
|
const VIBRATION_MODULE = 'Vibration';
|
|
21
21
|
// RN's _default_vibration_length: the single-buzz duration when no pattern is given,
|
|
22
22
|
// and the per-segment buzz length the iOS scheduler emits between waits.
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "SymbioteNative's retained shadow-tree engine — clone-on-write commit path + event normalization over React Native Fabric, shared by every framework adapter.",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"repository": {
|
|
6
7
|
"type": "git",
|
|
7
8
|
"url": "git+https://github.com/OneEyed1366/symbiote-native.git",
|
|
@@ -32,7 +33,7 @@
|
|
|
32
33
|
"react-native": ">=0.86"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
|
35
|
-
"@symbiote-native/test-utils": "0.1.
|
|
36
|
+
"@symbiote-native/test-utils": "0.1.6"
|
|
36
37
|
},
|
|
37
38
|
"scripts": {
|
|
38
39
|
"typecheck": "tsc --build",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type IImageSourceProp } from '../image-source-resolver';
|
|
2
|
-
export type IImageSize = {
|
|
3
|
-
width: number;
|
|
4
|
-
height: number;
|
|
5
|
-
};
|
|
6
|
-
export type IImageCacheStatus = 'memory' | 'disk' | 'disk/memory';
|
|
7
|
-
type ISizeSuccess = (width: number, height: number) => void;
|
|
8
|
-
type ISizeFailure = (error: unknown) => void;
|
|
9
|
-
declare function getSize(uri: string, success?: ISizeSuccess, failure?: ISizeFailure): Promise<IImageSize>;
|
|
10
|
-
declare function getSizeWithHeaders(uri: string, headers: Record<string, string>, success?: ISizeSuccess, failure?: ISizeFailure): Promise<IImageSize>;
|
|
11
|
-
declare function prefetch(uri: string, callback?: (requestId: number) => void): Promise<boolean>;
|
|
12
|
-
declare function abortPrefetch(requestId: number): void;
|
|
13
|
-
declare function queryCache(uris: string[]): Promise<Record<string, IImageCacheStatus>>;
|
|
14
|
-
declare function resolveAssetSource(source: IImageSourceProp): unknown;
|
|
15
|
-
export type IImageStatics = {
|
|
16
|
-
getSize: typeof getSize;
|
|
17
|
-
getSizeWithHeaders: typeof getSizeWithHeaders;
|
|
18
|
-
prefetch: typeof prefetch;
|
|
19
|
-
abortPrefetch: typeof abortPrefetch;
|
|
20
|
-
queryCache: typeof queryCache;
|
|
21
|
-
resolveAssetSource: typeof resolveAssetSource;
|
|
22
|
-
};
|
|
23
|
-
export declare const imageStatics: IImageStatics;
|
|
24
|
-
export {};
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
// Image static methods (RN's Image.getSize / prefetch / queryCache / etc).
|
|
2
|
-
//
|
|
3
|
-
// These mirror RN's iOS Image statics (Libraries/Image/Image.ios.js), which delegate to the
|
|
4
|
-
// `ImageLoader` native (Turbo)Module declared in NativeImageLoaderIOS.js. The Android spec
|
|
5
|
-
// (NativeImageLoaderAndroid.js) registers under the SAME module name ('ImageLoader'), so this
|
|
6
|
-
// stays a flat, non-platform-split module - only the Android prefetch call signature differs (a
|
|
7
|
-
// second `requestId` arg), branched on Platform.OS below, not on module name. NOTE the asymmetry
|
|
8
|
-
// in the iOS spec: `getSize` resolves a `[width, height]` ARRAY, while `getSizeWithHeaders`
|
|
9
|
-
// resolves a `{width, height}` OBJECT, both are guarded below before reading. The native result
|
|
10
|
-
// crosses the I/O boundary as `unknown`; we never cast it, we narrow its shape.
|
|
11
|
-
//
|
|
12
|
-
// This is a stateful, native-bridge-touching imperative module (module-level ImageLoader cache +
|
|
13
|
-
// prefetch requestId counter) with no view of its own - it belongs in @symbiote-native/engine
|
|
14
|
-
// alongside Alert/Share, not in a view/render-*.ts file (whose contract is zero state / zero
|
|
15
|
-
// native bridge).
|
|
16
|
-
import { dlog } from '../debug.js';
|
|
17
|
-
import { resolveImageSource } from '../image-source-resolver.js';
|
|
18
|
-
import { getNativeModule } from '../native-modules.js';
|
|
19
|
-
import { Platform } from '../platform';
|
|
20
|
-
import { isNumber } from '../type-guards.js';
|
|
21
|
-
// The iOS native module name RN registers this under (NativeImageLoaderIOS.js resolves
|
|
22
|
-
// `TurboModuleRegistry.getEnforcing<Spec>('ImageLoader')`). A module name like this is only
|
|
23
|
-
// provable on a real host - a headless fake answers to any name - so this iOS name is
|
|
24
|
-
// device-verify-pending.
|
|
25
|
-
const IMAGE_LOADER_MODULE = 'ImageLoader';
|
|
26
|
-
let imageLoaderModule;
|
|
27
|
-
function getImageLoader() {
|
|
28
|
-
if (imageLoaderModule === undefined) {
|
|
29
|
-
imageLoaderModule = getNativeModule(IMAGE_LOADER_MODULE);
|
|
30
|
-
dlog(`Image: ImageLoader module ${imageLoaderModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
31
|
-
}
|
|
32
|
-
return imageLoaderModule;
|
|
33
|
-
}
|
|
34
|
-
// Narrow native's getSize result. The spec resolves a `[width, height]` array, but tolerate a
|
|
35
|
-
// `{width, height}` object too (getSizeWithHeaders uses that shape).
|
|
36
|
-
function toImageSize(result) {
|
|
37
|
-
if (Array.isArray(result) && isNumber(result[0]) && isNumber(result[1])) {
|
|
38
|
-
return { width: result[0], height: result[1] };
|
|
39
|
-
}
|
|
40
|
-
if (typeof result === 'object' && result !== null) {
|
|
41
|
-
const width = Reflect.get(result, 'width');
|
|
42
|
-
const height = Reflect.get(result, 'height');
|
|
43
|
-
if (isNumber(width) && isNumber(height))
|
|
44
|
-
return { width, height };
|
|
45
|
-
}
|
|
46
|
-
throw new Error(`Image: unexpected size result from native: ${JSON.stringify(result)}`);
|
|
47
|
-
}
|
|
48
|
-
function requireLoader(method) {
|
|
49
|
-
const loader = getImageLoader();
|
|
50
|
-
if (loader === null) {
|
|
51
|
-
throw new Error(`Image.${method}: ImageLoader native module is not available ` +
|
|
52
|
-
'(running headless or not linked on this host).');
|
|
53
|
-
}
|
|
54
|
-
return loader;
|
|
55
|
-
}
|
|
56
|
-
// Resolve image dimensions, optionally via success/failure callbacks. Always returns the Promise
|
|
57
|
-
// too (RN returns void when a callback is passed, but a promise-and-callback shape is friendlier
|
|
58
|
-
// and a strict superset).
|
|
59
|
-
function getSize(uri, success, failure) {
|
|
60
|
-
const promise = Promise.resolve()
|
|
61
|
-
.then(() => requireLoader('getSize').getSize(uri))
|
|
62
|
-
.then(toImageSize);
|
|
63
|
-
if (typeof success === 'function') {
|
|
64
|
-
promise
|
|
65
|
-
.then(size => success(size.width, size.height))
|
|
66
|
-
.catch((error) => {
|
|
67
|
-
if (typeof failure === 'function')
|
|
68
|
-
failure(error);
|
|
69
|
-
else
|
|
70
|
-
dlog(`Image.getSize failed for ${uri}: ${String(error)}`);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
return promise;
|
|
74
|
-
}
|
|
75
|
-
function getSizeWithHeaders(uri, headers, success, failure) {
|
|
76
|
-
const promise = Promise.resolve()
|
|
77
|
-
.then(() => requireLoader('getSizeWithHeaders').getSizeWithHeaders(uri, headers))
|
|
78
|
-
.then(toImageSize);
|
|
79
|
-
if (typeof success === 'function') {
|
|
80
|
-
promise
|
|
81
|
-
.then(size => success(size.width, size.height))
|
|
82
|
-
.catch((error) => {
|
|
83
|
-
if (typeof failure === 'function')
|
|
84
|
-
failure(error);
|
|
85
|
-
else
|
|
86
|
-
dlog(`Image.getSizeWithHeaders failed for ${uri}: ${String(error)}`);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
return promise;
|
|
90
|
-
}
|
|
91
|
-
// Android keys an in-flight prefetch by a monotonic requestId (so abortRequest can cancel it);
|
|
92
|
-
// RN's Image.android.js generates the same way. iOS ignores the arg.
|
|
93
|
-
let prefetchRequestId = 0;
|
|
94
|
-
// Download a remote image into the disk cache. Resolves to whether it succeeded. `callback`
|
|
95
|
-
// receives the requestId (RN's Image.android.js shape) so the caller can later pass it to
|
|
96
|
-
// abortPrefetch.
|
|
97
|
-
async function prefetch(uri, callback) {
|
|
98
|
-
prefetchRequestId += 1;
|
|
99
|
-
const requestId = prefetchRequestId;
|
|
100
|
-
if (typeof callback === 'function')
|
|
101
|
-
callback(requestId);
|
|
102
|
-
const loader = requireLoader('prefetch');
|
|
103
|
-
return (Promise.resolve()
|
|
104
|
-
// Android's prefetchImage keys an abortable request on requestId; iOS takes ONLY the uri and
|
|
105
|
-
// throws on an extra arg (bridgeless TurboModule arg-count check). Match RN's per-platform call.
|
|
106
|
-
.then(() => Platform.OS === 'android'
|
|
107
|
-
? loader.prefetchImage(uri, requestId)
|
|
108
|
-
: loader.prefetchImage(uri))
|
|
109
|
-
.then(result => result === true)
|
|
110
|
-
.catch((error) => {
|
|
111
|
-
dlog(`Image.prefetch failed for ${uri}: ${String(error)}`);
|
|
112
|
-
throw error;
|
|
113
|
-
}));
|
|
114
|
-
}
|
|
115
|
-
// Cancel an in-flight prefetch by the requestId prefetch handed back. Android only (mirrors
|
|
116
|
-
// Image.android.js -> NativeImageLoaderAndroid.abortRequest); a missing abortRequest (iOS,
|
|
117
|
-
// headless) is a no-op rather than a throw.
|
|
118
|
-
function abortPrefetch(requestId) {
|
|
119
|
-
const loader = getImageLoader();
|
|
120
|
-
if (loader === null || typeof loader.abortRequest !== 'function') {
|
|
121
|
-
dlog(`Image.abortPrefetch(${requestId}): no abortRequest on this host, ignoring`);
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
loader.abortRequest(requestId);
|
|
125
|
-
}
|
|
126
|
-
// Narrow native's queryCache result: an object mapping each known uri to its cache status.
|
|
127
|
-
// Unknown statuses are dropped rather than trusted blindly.
|
|
128
|
-
const CACHE_STATUS = {
|
|
129
|
-
memory: 'memory',
|
|
130
|
-
disk: 'disk',
|
|
131
|
-
'disk/memory': 'disk/memory',
|
|
132
|
-
};
|
|
133
|
-
function toCacheRecord(result) {
|
|
134
|
-
const record = {};
|
|
135
|
-
if (typeof result !== 'object' || result === null)
|
|
136
|
-
return record;
|
|
137
|
-
for (const key of Object.keys(result)) {
|
|
138
|
-
const value = Reflect.get(result, key);
|
|
139
|
-
if (typeof value === 'string' && Object.hasOwn(CACHE_STATUS, value)) {
|
|
140
|
-
record[key] = CACHE_STATUS[value];
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return record;
|
|
144
|
-
}
|
|
145
|
-
async function queryCache(uris) {
|
|
146
|
-
return Promise.resolve()
|
|
147
|
-
.then(() => {
|
|
148
|
-
const loader = requireLoader('queryCache');
|
|
149
|
-
// The native queryCache never rejects (RCTImageLoader resolves getImageCacheStatus), so a
|
|
150
|
-
// rejection here is a JS/native boundary fault: log whether the method is even callable and
|
|
151
|
-
// the arg shape, to tell "not a function" (interop gap) from a marshalling reject.
|
|
152
|
-
dlog(`Image.queryCache: typeof loader.queryCache=${typeof loader.queryCache} uris=${uris.length}`);
|
|
153
|
-
return loader.queryCache(uris);
|
|
154
|
-
})
|
|
155
|
-
.then(toCacheRecord)
|
|
156
|
-
.catch((error) => {
|
|
157
|
-
dlog(`Image.queryCache failed: ${String(error)}`);
|
|
158
|
-
throw error;
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
// PURE JS: run the currently-installed source resolver (the same machinery the Image component
|
|
162
|
-
// uses via resolveImageSource). RN's resolveAssetSource turns a require() asset id into
|
|
163
|
-
// {uri, scale, ...}; the app injects the real one with setImageSourceResolver, and this exposes
|
|
164
|
-
// its output to callers directly.
|
|
165
|
-
function resolveAssetSource(source) {
|
|
166
|
-
return resolveImageSource(source);
|
|
167
|
-
}
|
|
168
|
-
export const imageStatics = {
|
|
169
|
-
getSize,
|
|
170
|
-
getSizeWithHeaders,
|
|
171
|
-
prefetch,
|
|
172
|
-
abortPrefetch,
|
|
173
|
-
queryCache,
|
|
174
|
-
resolveAssetSource,
|
|
175
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export declare function setImageSourceResolver(resolve: (source: unknown) => unknown): void;
|
|
2
|
-
export declare function resolveImageSource(source: unknown): unknown;
|
|
3
|
-
export type IImageSource = {
|
|
4
|
-
uri?: string;
|
|
5
|
-
scale?: number;
|
|
6
|
-
width?: number;
|
|
7
|
-
height?: number;
|
|
8
|
-
};
|
|
9
|
-
export type IImageSourceProp = IImageSource | IImageSource[] | number;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// Image source resolution seam: require('./x.png') asset ids and {uri} sources are resolved by
|
|
2
|
-
// RN's own resolveAssetSource before reaching the shared render fn. The actual resolution is
|
|
3
|
-
// RN-platform-specific, so it is injected here rather than imported, mirroring platform-color.ts's
|
|
4
|
-
// processColor seam - this keeps @symbiote-native/components free of a react-native dependency (and
|
|
5
|
-
// the headless harness working). BOTH the pure renderImage view (@symbiote-native/components) and
|
|
6
|
-
// this package's own image-loader statics (resolveAssetSource) call resolveImageSource; neither
|
|
7
|
-
// reaches into the mutable resolver directly.
|
|
8
|
-
let sourceResolver = source => source;
|
|
9
|
-
export function setImageSourceResolver(resolve) {
|
|
10
|
-
sourceResolver = resolve;
|
|
11
|
-
}
|
|
12
|
-
// Public mirror of RN's Image.resolveAssetSource: run a source through the injected resolver.
|
|
13
|
-
// Headless (no resolver wired) it is the identity, so smokes see the input unchanged.
|
|
14
|
-
export function resolveImageSource(source) {
|
|
15
|
-
return sourceResolver(source);
|
|
16
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { NativeEventEmitter } from './native-events';
|
|
2
|
-
declare global {
|
|
3
|
-
var __turboModuleProxy: (<T>(name: string) => T | null) | undefined;
|
|
4
|
-
var nativeModuleProxy: Record<string, unknown> | undefined;
|
|
5
|
-
}
|
|
6
|
-
export declare function getNativeModule<T>(name: string): T | null;
|
|
7
|
-
export declare function getEnforcingNativeModule<T>(name: string): T;
|
|
8
|
-
export interface IDeviceEventModuleConfig<TModule> {
|
|
9
|
-
moduleName: string;
|
|
10
|
-
moduleLogPrefix: string;
|
|
11
|
-
bindModuleToEmitter?: boolean;
|
|
12
|
-
onEmitterCreated?: (emitter: NativeEventEmitter, module: TModule | null) => void;
|
|
13
|
-
}
|
|
14
|
-
export interface IDeviceEventModule<TModule> {
|
|
15
|
-
getModule(): TModule | null;
|
|
16
|
-
getEmitter(): NativeEventEmitter;
|
|
17
|
-
}
|
|
18
|
-
export declare function createDeviceEventModule<TModule>(config: IDeviceEventModuleConfig<TModule>): IDeviceEventModule<TModule>;
|
package/build/native-modules.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
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.
|
|
11
|
-
import { dlog } from './debug.js';
|
|
12
|
-
import { installDeviceEventHub, NativeEventEmitter, } from './native-events.js';
|
|
13
|
-
import { isRecord } from './type-guards.js';
|
|
14
|
-
// The native module value crosses from an untyped HostObject into our types here;
|
|
15
|
-
// the caller vouches for its shape via T (the single trust-boundary narrowing, no
|
|
16
|
-
// per-call `as`). Native modules are always non-null objects.
|
|
17
|
-
function isNativeModule(value) {
|
|
18
|
-
return value !== null && value !== undefined;
|
|
19
|
-
}
|
|
20
|
-
// The native module `name`, typed as the caller's interface `T`, or null when no
|
|
21
|
-
// module by that name is registered in the binary (or the proxy is absent, e.g.
|
|
22
|
-
// running headless without a fake installed).
|
|
23
|
-
export function getNativeModule(name) {
|
|
24
|
-
// Non-bridgeless: the function proxy. Call it by name.
|
|
25
|
-
const turboProxy = globalThis.__turboModuleProxy;
|
|
26
|
-
if (typeof turboProxy === 'function') {
|
|
27
|
-
const module = turboProxy(name);
|
|
28
|
-
if (module !== null && module !== undefined)
|
|
29
|
-
return module;
|
|
30
|
-
}
|
|
31
|
-
// Bridgeless: the HostObject proxy, indexed by name. Guard the access: a
|
|
32
|
-
// HostObject may throw for an unlinked name, and a throw here would propagate
|
|
33
|
-
// into a render effect and blank the tree.
|
|
34
|
-
const bridgelessProxy = globalThis.nativeModuleProxy;
|
|
35
|
-
if (bridgelessProxy !== undefined) {
|
|
36
|
-
try {
|
|
37
|
-
const module = bridgelessProxy[name];
|
|
38
|
-
if (isNativeModule(module))
|
|
39
|
-
return module;
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
dlog(`nativeModuleProxy["${name}"] threw: ${String(error)}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
dlog(`native module "${name}" not found ` +
|
|
46
|
-
`(turbo=${typeof turboProxy}, bridgeless=${typeof globalThis.nativeModuleProxy})`);
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
// Same, but throws when the module is missing, for modules a feature hard-depends
|
|
50
|
-
// on (StatusBar without StatusBarManager cannot function, so failing loud beats a
|
|
51
|
-
// silent no-op).
|
|
52
|
-
export function getEnforcingNativeModule(name) {
|
|
53
|
-
const module = getNativeModule(name);
|
|
54
|
-
if (module === null) {
|
|
55
|
-
throw new Error(`Native module "${name}" is not registered in the binary. ` +
|
|
56
|
-
'Verify it is linked (New Architecture / bridgeless host with __turboModuleProxy installed).');
|
|
57
|
-
}
|
|
58
|
-
return module;
|
|
59
|
-
}
|
|
60
|
-
// ---- device-event module factory ------------------------------------------
|
|
61
|
-
//
|
|
62
|
-
// AccessibilityInfo (iOS + Android), AppState, Appearance, BackHandler, Keyboard,
|
|
63
|
-
// and Dimensions each hand-rolled the identical plumbing: lazily resolve a native
|
|
64
|
-
// module, lazily build a NativeEventEmitter bound to it, install the device-event
|
|
65
|
-
// hub on first subscribe. `createLinking` (linking/shared.ts) proved this factors
|
|
66
|
-
// out safely for Linking's iOS/Android split; this is the general form for every
|
|
67
|
-
// other lazy-module + emitter pair in the runtime-module layer.
|
|
68
|
-
//
|
|
69
|
-
// Each caller's DEGRADE POLICY stays its own, via config - the factory owns only
|
|
70
|
-
// the plumbing:
|
|
71
|
-
// - `bindModuleToEmitter` (default true): whether the resolved module is wired
|
|
72
|
-
// into the emitter so its addListener/removeListeners observe-counters get
|
|
73
|
-
// pinged. Dimensions' DeviceInfo module has no observe-counters, so it opts out
|
|
74
|
-
// (matching its original `new NativeEventEmitter(undefined)`).
|
|
75
|
-
// - `onEmitterCreated`: runs exactly once, right after the emitter is built -
|
|
76
|
-
// the hook for a caller's own permanent self-subscription (AppState/Appearance/
|
|
77
|
-
// BackHandler/Keyboard each keep a cache fresh or dispatch a chain this way) or
|
|
78
|
-
// one-time hydration from the module's constants (AppState's initial state,
|
|
79
|
-
// Dimensions' initial metrics - the latter also relies on this hook running
|
|
80
|
-
// `addListener` BEFORE the constants read, preserving the original
|
|
81
|
-
// subscribe-before-resolve ordering that guards against missing an update).
|
|
82
|
-
// A structural check, not a cast: narrows an arbitrary resolved module down to
|
|
83
|
-
// IEventEmitterModule only when it actually carries both observe-counter methods.
|
|
84
|
-
// Needed because `TModule` is unconstrained (Dimensions' INativeDeviceInfo doesn't
|
|
85
|
-
// extend IEventEmitterModule at all) - NativeEventEmitter itself re-checks the same
|
|
86
|
-
// shape internally, so this exists to satisfy the type system, not to change
|
|
87
|
-
// behavior.
|
|
88
|
-
function hasEventEmitterShape(value) {
|
|
89
|
-
return (isRecord(value) &&
|
|
90
|
-
typeof value.addListener === 'function' &&
|
|
91
|
-
typeof value.removeListeners === 'function');
|
|
92
|
-
}
|
|
93
|
-
// Build one module's lazy-resolve + lazy-emitter pair. Each call owns its own
|
|
94
|
-
// cache, so two callers (or two platform builds loaded together in one smoke) stay
|
|
95
|
-
// independent - the same guarantee `createLinking` documents.
|
|
96
|
-
export function createDeviceEventModule(config) {
|
|
97
|
-
let module;
|
|
98
|
-
let emitter;
|
|
99
|
-
function getModule() {
|
|
100
|
-
if (module === undefined) {
|
|
101
|
-
module = getNativeModule(config.moduleName);
|
|
102
|
-
dlog(`${config.moduleLogPrefix} ${module ? 'resolved' : 'NOT resolved (null)'}`);
|
|
103
|
-
}
|
|
104
|
-
return module;
|
|
105
|
-
}
|
|
106
|
-
function getEmitter() {
|
|
107
|
-
if (emitter === undefined) {
|
|
108
|
-
// WHY lazy: install on first subscribe so the hub exists before native
|
|
109
|
-
// emits, without a hard bootstrap-order dependency. Idempotent.
|
|
110
|
-
installDeviceEventHub();
|
|
111
|
-
const resolved = getModule();
|
|
112
|
-
const bindModule = config.bindModuleToEmitter ?? true;
|
|
113
|
-
const boundModule = bindModule && resolved !== null && hasEventEmitterShape(resolved) ? resolved : undefined;
|
|
114
|
-
emitter = new NativeEventEmitter(boundModule);
|
|
115
|
-
config.onEmitterCreated?.(emitter, resolved);
|
|
116
|
-
}
|
|
117
|
-
return emitter;
|
|
118
|
-
}
|
|
119
|
-
return { getModule, getEmitter };
|
|
120
|
-
}
|