@symbiote-native/engine 1.2.0 → 1.3.1
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/android/CMakeLists.txt +31 -1
- package/android/build.gradle +4 -1
- package/build/accessibility-info/index.android.js +21 -17
- package/build/accessibility-info/index.ios.js +2 -0
- package/build/accessibility-info/shared.d.ts +1 -1
- package/build/accessibility-props.d.ts +0 -11
- package/build/accessibility-props.js +30 -68
- package/build/alert/shared.d.ts +1 -1
- package/build/alert/shared.js +3 -7
- package/build/animated/graph.js +1 -1
- package/build/animated/leaf-lifecycle.js +2 -2
- package/build/app-state/index.d.ts +1 -1
- package/build/app-state/index.js +35 -27
- package/build/asset-source-resolver.d.ts +2 -0
- package/build/asset-source-resolver.js +13 -0
- package/build/back-handler/index.d.ts +7 -6
- package/build/back-handler/index.js +19 -16
- package/build/debug.js +8 -22
- package/build/dispatch.js +3 -9
- package/build/events/index.js +12 -3
- package/build/fabric-props.js +75 -180
- package/build/fabric.d.ts +2 -8
- package/build/fabric.js +27 -33
- package/build/host-access.d.ts +1 -128
- package/build/host-access.js +96 -205
- package/build/host-behavior.d.ts +1 -100
- package/build/host-behavior.js +125 -311
- package/build/image-loader.d.ts +4 -2
- package/build/image-loader.js +24 -48
- package/build/image-source-resolver.js +3 -7
- package/build/image-source-write.d.ts +1 -12
- package/build/image-source-write.js +28 -36
- package/build/imperative.d.ts +0 -28
- package/build/imperative.js +42 -92
- package/build/index.d.ts +3 -2
- package/build/index.js +30 -43
- package/build/invariant.d.ts +1 -0
- package/build/invariant.js +10 -0
- package/build/keyboard/index.js +11 -32
- package/build/linking/index.android.js +5 -3
- package/build/linking/shared.d.ts +1 -1
- package/build/linking/shared.js +16 -19
- package/build/mutation-buffer.d.ts +0 -177
- package/build/mutation-buffer.js +137 -308
- package/build/native-engine.d.ts +0 -102
- package/build/native-engine.js +38 -98
- package/build/native-events.d.ts +5 -0
- package/build/native-events.js +30 -18
- package/build/native-tree-host.d.ts +0 -21
- package/build/native-tree-host.js +14 -31
- package/build/node.d.ts +0 -212
- package/build/node.js +354 -774
- package/build/permissions-android/index.android.d.ts +59 -0
- package/build/permissions-android/index.android.js +47 -0
- package/build/permissions-android/index.d.ts +1 -115
- package/build/permissions-android/index.ios.d.ts +59 -0
- package/build/permissions-android/index.ios.js +31 -0
- package/build/permissions-android/index.js +3 -184
- package/build/permissions-android/shared.d.ts +63 -0
- package/build/permissions-android/shared.js +66 -0
- package/build/platform/index.android.js +3 -5
- package/build/platform/index.ios.js +3 -3
- package/build/platform/shared.d.ts +4 -0
- package/build/platform/shared.js +9 -0
- package/build/platform-color/index.android.d.ts +4 -0
- package/build/platform-color/index.android.js +7 -0
- package/build/platform-color/index.d.ts +2 -20
- package/build/platform-color/index.js +1 -45
- package/build/platform-color/shared.d.ts +21 -0
- package/build/platform-color/shared.js +41 -0
- package/build/post-commit.js +3 -8
- package/build/process-aspect-ratio.js +3 -7
- package/build/process-background-longhands.js +10 -19
- package/build/process-filter.js +11 -19
- package/build/process-font-variant.js +3 -7
- package/build/registry.d.ts +0 -33
- package/build/registry.js +22 -57
- package/build/report-error.js +4 -18
- package/build/settings/index.android.d.ts +6 -0
- package/build/settings/index.android.js +21 -0
- package/build/settings/index.d.ts +1 -8
- package/build/settings/index.ios.d.ts +8 -0
- package/build/settings/index.ios.js +122 -0
- package/build/settings/index.js +3 -122
- package/build/share/index.android.js +9 -32
- package/build/share/index.ios.js +14 -15
- package/build/share/shared.d.ts +4 -2
- package/build/share/shared.js +7 -10
- package/build/status-bar/index.android.js +1 -1
- package/build/status-bar/index.ios.js +4 -3
- package/build/structured-style.d.ts +0 -9
- package/build/structured-style.js +16 -31
- package/build/styles.js +3 -6
- package/build/surface.d.ts +0 -26
- package/build/surface.js +29 -76
- package/build/text-input-state.js +4 -8
- package/build/toast-android/index.android.d.ts +10 -0
- package/build/toast-android/index.android.js +108 -0
- package/build/toast-android/index.d.ts +1 -10
- package/build/toast-android/index.ios.d.ts +10 -0
- package/build/toast-android/index.ios.js +19 -0
- package/build/toast-android/index.js +3 -108
- package/build/touch-history.js +5 -11
- package/build/tree-host.d.ts +0 -270
- package/build/tree-host.js +63 -153
- package/build/view-config.js +17 -37
- package/cpp/SymbioteFabricProps.cpp +204 -120
- package/cpp/SymbioteFabricProps.h +5 -0
- package/cpp/SymbioteTree.cpp +20 -6
- package/package.json +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// from the PlatformConstants native module (RN spec NativePlatformConstantsAndroid.js,
|
|
4
4
|
// a different payload from iOS). Metro picks this on an Android host. The module name is
|
|
5
5
|
// the same 'PlatformConstants'; only the shape differs.
|
|
6
|
-
import { createConstantsResolver, } from './shared.js';
|
|
6
|
+
import { createConstantsResolver, gatedIsTesting, } from './shared.js';
|
|
7
7
|
// The filename already selected this host: 'android' is a literal, not a probe.
|
|
8
8
|
const OS_ANDROID = 'android';
|
|
9
9
|
// RN reads isTV off the uiMode constant.
|
|
@@ -37,14 +37,12 @@ export const Platform = {
|
|
|
37
37
|
get isVision() {
|
|
38
38
|
return false;
|
|
39
39
|
},
|
|
40
|
-
// RN gates this behind __DEV__; shared has no __DEV__ flag, so we read the native
|
|
41
|
-
// flag directly: a release build's native module reports false anyway.
|
|
42
40
|
get isTesting() {
|
|
43
|
-
return resolveConstants()
|
|
41
|
+
return gatedIsTesting(resolveConstants());
|
|
44
42
|
},
|
|
45
43
|
get isDisableAnimations() {
|
|
46
44
|
const constants = resolveConstants();
|
|
47
|
-
return constants?.isDisableAnimations ?? constants
|
|
45
|
+
return constants?.isDisableAnimations ?? gatedIsTesting(constants);
|
|
48
46
|
},
|
|
49
47
|
get isMacCatalyst() {
|
|
50
48
|
return false;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// (RN spec NativePlatformConstantsIOS.js), read lazily and cached via the shared
|
|
4
4
|
// resolver. Metro picks this on an iOS host; it is also the base re-export target
|
|
5
5
|
// (platform.ts) so tsc / tsx / web (no Metro) land here too.
|
|
6
|
-
import { createConstantsResolver, UNKNOWN_VERSION, } from './shared.js';
|
|
6
|
+
import { createConstantsResolver, gatedIsTesting, UNKNOWN_VERSION, } from './shared.js';
|
|
7
7
|
// interfaceIdiom values RN compares against for the device-class getters.
|
|
8
8
|
const IDIOM_PAD = 'pad';
|
|
9
9
|
const IDIOM_TV = 'tv';
|
|
@@ -39,13 +39,13 @@ export const Platform = {
|
|
|
39
39
|
return idiomEquals(IDIOM_VISION);
|
|
40
40
|
},
|
|
41
41
|
get isTesting() {
|
|
42
|
-
return resolveConstants()
|
|
42
|
+
return gatedIsTesting(resolveConstants());
|
|
43
43
|
},
|
|
44
44
|
// RN: isDisableAnimations ?? isTesting. The native flag wins; absent, it tracks
|
|
45
45
|
// isTesting (test runs disable animations by default).
|
|
46
46
|
get isDisableAnimations() {
|
|
47
47
|
const constants = resolveConstants();
|
|
48
|
-
return constants?.isDisableAnimations ?? constants
|
|
48
|
+
return constants?.isDisableAnimations ?? gatedIsTesting(constants);
|
|
49
49
|
},
|
|
50
50
|
get isMacCatalyst() {
|
|
51
51
|
return resolveConstants()?.isMacCatalyst ?? false;
|
|
@@ -23,3 +23,7 @@ export interface IPlatformStatic<TConstants> {
|
|
|
23
23
|
select<T>(spec: IPlatformSelectSpec<T>): T | undefined;
|
|
24
24
|
}
|
|
25
25
|
export declare function createConstantsResolver<TConstants>(guard: (value: unknown) => value is TConstants): () => TConstants | undefined;
|
|
26
|
+
export declare function isDevBuild(): boolean;
|
|
27
|
+
export declare function gatedIsTesting(constants: {
|
|
28
|
+
isTesting?: boolean;
|
|
29
|
+
} | undefined): boolean;
|
package/build/platform/shared.js
CHANGED
|
@@ -38,3 +38,12 @@ export function createConstantsResolver(guard) {
|
|
|
38
38
|
return cached;
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
// Metro's `__DEV__` global: `true` in a dev bundle, `false` in release. Read off globalThis so a
|
|
42
|
+
// host that never defines it (headless tooling) counts as release, like any unset flag.
|
|
43
|
+
export function isDevBuild() {
|
|
44
|
+
return Reflect.get(globalThis, '__DEV__') === true;
|
|
45
|
+
}
|
|
46
|
+
// RN's `isTesting`: the native flag in a dev build only (`if (__DEV__) … return false`).
|
|
47
|
+
export function gatedIsTesting(constants) {
|
|
48
|
+
return isDevBuild() && (constants?.isTesting ?? false);
|
|
49
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IDynamicColorIOSTuple, IOpaqueColorValue } from './shared';
|
|
2
|
+
export * from './shared';
|
|
3
|
+
export declare function PlatformColor(...names: string[]): IOpaqueColorValue;
|
|
4
|
+
export declare function DynamicColorIOS(_tuple: IDynamicColorIOSTuple): IOpaqueColorValue;
|
|
@@ -1,22 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
dark: IColorValue;
|
|
4
|
-
highContrastLight?: IColorValue;
|
|
5
|
-
highContrastDark?: IColorValue;
|
|
6
|
-
}
|
|
7
|
-
export interface IOpaqueColorValue {
|
|
8
|
-
readonly semantic?: readonly string[];
|
|
9
|
-
readonly dynamic?: {
|
|
10
|
-
readonly light: IColorValue;
|
|
11
|
-
readonly dark: IColorValue;
|
|
12
|
-
readonly highContrastLight?: IColorValue;
|
|
13
|
-
readonly highContrastDark?: IColorValue;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
export type IColorValue = string | number | IOpaqueColorValue;
|
|
1
|
+
import type { IDynamicColorIOSTuple, IOpaqueColorValue } from './shared';
|
|
2
|
+
export * from './shared';
|
|
17
3
|
export declare function PlatformColor(...names: string[]): IOpaqueColorValue;
|
|
18
4
|
export declare function DynamicColorIOS(tuple: IDynamicColorIOSTuple): IOpaqueColorValue;
|
|
19
|
-
export declare function isOpaqueColorValue(value: unknown): value is IOpaqueColorValue;
|
|
20
|
-
export declare function setColorProcessor(process: (value: IColorValue) => unknown): void;
|
|
21
|
-
export declare function processColor(color: IColorValue): unknown;
|
|
22
|
-
export declare function isProcessableColor(value: unknown): value is IColorValue;
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
// (iOS UIColor: semantic system colors and appearance-aware light/dark tuples).
|
|
3
|
-
// These are pure object constructors with no native dependency, so they live in
|
|
4
|
-
// shared and every adapter re-exports them. The opaque shape ({ semantic } /
|
|
5
|
-
// { dynamic }) is exactly what RN's processColor and the iOS RCTConvert UIColor
|
|
6
|
-
// path read, so our commit-time color seam routes these objects through the
|
|
7
|
-
// injected processor just like CSS-string colors (see commit.ts processValue).
|
|
1
|
+
export * from './shared.js';
|
|
8
2
|
export function PlatformColor(...names) {
|
|
9
3
|
return { semantic: names };
|
|
10
4
|
}
|
|
@@ -18,41 +12,3 @@ export function DynamicColorIOS(tuple) {
|
|
|
18
12
|
},
|
|
19
13
|
};
|
|
20
14
|
}
|
|
21
|
-
// True for the opaque objects above: the color seam uses this to route them
|
|
22
|
-
// through the platform processor alongside CSS-string colors.
|
|
23
|
-
export function isOpaqueColorValue(value) {
|
|
24
|
-
return (typeof value === 'object' &&
|
|
25
|
-
value !== null &&
|
|
26
|
-
('semantic' in value || 'dynamic' in value));
|
|
27
|
-
}
|
|
28
|
-
// Color props must reach Fabric as platform ints, not CSS strings. Fabric's C++ color
|
|
29
|
-
// parser silently drops strings. The actual conversion (processColor) is RN-platform-specific,
|
|
30
|
-
// so it is injected here rather than imported, keeping shared free of a react-native dependency
|
|
31
|
-
// (and the headless harness working). This module is the sole owner of "run a value through the
|
|
32
|
-
// platform color processor" - every color-touching consumer (commit's fabricProps,
|
|
33
|
-
// process-box-shadow, process-filter, process-background-image, StatusBar android) imports
|
|
34
|
-
// processColor/isProcessableColor from here, never from commit.ts.
|
|
35
|
-
let colorProcessor = value => value;
|
|
36
|
-
export function setColorProcessor(process) {
|
|
37
|
-
colorProcessor = process;
|
|
38
|
-
}
|
|
39
|
-
// Public mirror of RN's processColor: run a color through the injected platform processor (the
|
|
40
|
-
// canary wires RN's own). Off a real host it resolves CSS strings and opaque PlatformColor
|
|
41
|
-
// objects to the platform ints Fabric expects; headless (no processor wired) it is the identity,
|
|
42
|
-
// so smokes see the input unchanged.
|
|
43
|
-
export function processColor(color) {
|
|
44
|
-
return colorProcessor(color);
|
|
45
|
-
}
|
|
46
|
-
// A color-keyed value the platform processor must convert before Fabric: a CSS string, a numeric
|
|
47
|
-
// literal, or an opaque PlatformColor / DynamicColorIOS object. `undefined` is left untouched.
|
|
48
|
-
//
|
|
49
|
-
// A number used to be excluded here on the reasoning that it was "already a resolved platform
|
|
50
|
-
// int". Nothing in the pipeline produces one: the CSS parser emits hex STRINGS, and fabricProps
|
|
51
|
-
// builds a fresh payload object instead of writing the resolved value back into node.props, so a
|
|
52
|
-
// number reaching this guard is always the author's own literal. Excluding it committed
|
|
53
|
-
// `color: 0xff0000ff` (opaque red, rrggbbaa) unrotated, and native reads that as aarrggbb: blue.
|
|
54
|
-
export function isProcessableColor(value) {
|
|
55
|
-
return (typeof value === 'string' ||
|
|
56
|
-
typeof value === 'number' ||
|
|
57
|
-
isOpaqueColorValue(value));
|
|
58
|
-
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface IDynamicColorIOSTuple {
|
|
2
|
+
light: IColorValue;
|
|
3
|
+
dark: IColorValue;
|
|
4
|
+
highContrastLight?: IColorValue;
|
|
5
|
+
highContrastDark?: IColorValue;
|
|
6
|
+
}
|
|
7
|
+
export interface IOpaqueColorValue {
|
|
8
|
+
readonly semantic?: readonly string[];
|
|
9
|
+
readonly resource_paths?: readonly string[];
|
|
10
|
+
readonly dynamic?: {
|
|
11
|
+
readonly light: IColorValue;
|
|
12
|
+
readonly dark: IColorValue;
|
|
13
|
+
readonly highContrastLight?: IColorValue;
|
|
14
|
+
readonly highContrastDark?: IColorValue;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export type IColorValue = string | number | IOpaqueColorValue;
|
|
18
|
+
export declare function isOpaqueColorValue(value: unknown): value is IOpaqueColorValue;
|
|
19
|
+
export declare function setColorProcessor(process: (value: IColorValue) => unknown): void;
|
|
20
|
+
export declare function processColor(color: IColorValue): unknown;
|
|
21
|
+
export declare function isProcessableColor(value: unknown): value is IColorValue;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// PlatformColor / DynamicColorIOS: opaque colors native resolves. Constructors are per platform
|
|
2
|
+
// because the shapes differ: iOS reads { semantic } / { dynamic } (PlatformColorParser.mm),
|
|
3
|
+
// Android only { resource_paths } (ColorPropConverter). The C++ seam forwards the object as-is.
|
|
4
|
+
// True for the opaque objects above: the color seam uses this to route them
|
|
5
|
+
// through the platform processor alongside CSS-string colors.
|
|
6
|
+
export function isOpaqueColorValue(value) {
|
|
7
|
+
return (typeof value === 'object' &&
|
|
8
|
+
value !== null &&
|
|
9
|
+
('semantic' in value || 'dynamic' in value || 'resource_paths' in value));
|
|
10
|
+
}
|
|
11
|
+
// Color props must reach Fabric as platform ints, not CSS strings. Fabric's C++ color
|
|
12
|
+
// parser silently drops strings. The actual conversion (processColor) is RN-platform-specific,
|
|
13
|
+
// so it is injected here rather than imported, keeping shared free of a react-native dependency
|
|
14
|
+
// (and the headless harness working). This module is the sole owner of "run a value through the
|
|
15
|
+
// platform color processor" - every color-touching consumer (commit's fabricProps,
|
|
16
|
+
// process-box-shadow, process-filter, process-background-image, StatusBar android) imports
|
|
17
|
+
// processColor/isProcessableColor from here, never from commit.ts.
|
|
18
|
+
let colorProcessor = value => value;
|
|
19
|
+
export function setColorProcessor(process) {
|
|
20
|
+
colorProcessor = process;
|
|
21
|
+
}
|
|
22
|
+
// Public mirror of RN's processColor: run a color through the injected platform processor (the
|
|
23
|
+
// canary wires RN's own). Off a real host it resolves CSS strings and opaque PlatformColor
|
|
24
|
+
// objects to the platform ints Fabric expects; headless (no processor wired) it is the identity,
|
|
25
|
+
// so smokes see the input unchanged.
|
|
26
|
+
export function processColor(color) {
|
|
27
|
+
return colorProcessor(color);
|
|
28
|
+
}
|
|
29
|
+
// A color-keyed value the platform processor must convert before Fabric: a CSS string, a numeric
|
|
30
|
+
// literal, or an opaque PlatformColor / DynamicColorIOS object. `undefined` is left untouched.
|
|
31
|
+
//
|
|
32
|
+
// A number used to be excluded here on the reasoning that it was "already a resolved platform
|
|
33
|
+
// int". Nothing in the pipeline produces one: the CSS parser emits hex STRINGS, and fabricProps
|
|
34
|
+
// builds a fresh payload object instead of writing the resolved value back into node.props, so a
|
|
35
|
+
// number reaching this guard is always the author's own literal. Excluding it committed
|
|
36
|
+
// `color: 0xff0000ff` (opaque red, rrggbbaa) unrotated, and native reads that as aarrggbb: blue.
|
|
37
|
+
export function isProcessableColor(value) {
|
|
38
|
+
return (typeof value === 'string' ||
|
|
39
|
+
typeof value === 'number' ||
|
|
40
|
+
isOpaqueColorValue(value));
|
|
41
|
+
}
|
package/build/post-commit.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// which binds a props node to a view tag — can retry work that ran too early under an
|
|
5
|
-
// async-batched commit (Vue/Svelte schedule completeRoot on a microtask, so lifecycle
|
|
6
|
-
// code can reach a node before its tag exists; React commits synchronously and never
|
|
7
|
-
// queues). A neutral module so commit.ts and animated/props.ts share it without a
|
|
8
|
-
// dependency cycle.
|
|
1
|
+
// Run once after every commit that changed the tree, once fresh Fabric tags exist — lets a
|
|
2
|
+
// consumer needing a node's committed tag (the Animated native driver) retry work that ran too
|
|
3
|
+
// early under an async-batched commit. Shared by commit.ts and animated/props.ts, cycle-free.
|
|
9
4
|
const hooks = new Set();
|
|
10
5
|
export function registerPostCommit(hook) {
|
|
11
6
|
hooks.add(hook);
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
// JS-side port of RN's processAspectRatio (
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// ('16 / 9') is resolved to a number IN JS before native. A plain number (the common,
|
|
5
|
-
// already-working form) passes through untouched; this is a no-op for it.
|
|
6
|
-
//
|
|
7
|
-
// RN throws via invariant() in __DEV__ on a malformed value; we dlog and return undefined.
|
|
1
|
+
// JS-side port of RN's processAspectRatio: resolves a CSS ratio string ('16 / 9') to a number
|
|
2
|
+
// before native, same root cause as boxShadow/filter. A plain number passes through untouched.
|
|
3
|
+
// RN throws via invariant() on a malformed value; here we dlog and return undefined instead.
|
|
8
4
|
import { dlog } from './debug.js';
|
|
9
5
|
// RN processAspectRatio.js:15-63. number → number; ratio string → number; invalid → undefined.
|
|
10
6
|
export function processAspectRatio(aspectRatio) {
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
// RN's own processBackgroundSize / processBackgroundPosition / processBackgroundRepeat, imported
|
|
2
2
|
// rather than ported.
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// Why importing is free here even by this repo's strictest reading: all three upstream files
|
|
12
|
-
// contain ONLY `import type` lines. Their value-import closure is empty - no processColor, no
|
|
13
|
-
// Platform, no TurboModule floor, no renderer. There is nothing to weigh.
|
|
14
|
-
//
|
|
15
|
-
// Why no try/catch, unlike the other upstream wrappers: these three do not validate through
|
|
16
|
-
// `invariant`. They answer `[]` for anything they cannot parse, which upstream's own comment calls
|
|
17
|
-
// "do not apply any background" - so refusal is a RETURN here, not a throw.
|
|
3
|
+
// Needed because enableNativeCSSParsing() defaults to false, so RN's stock JS path parses the CSS
|
|
4
|
+
// string into the per-axis structure Fabric's C++ expects. Without it a string for any of these
|
|
5
|
+
// three reached native unparsed: dropped on iOS, cast to the wrong ReadableMap type on Android.
|
|
6
|
+
// Importing is free here: all three upstream files contain only `import type` lines, so their
|
|
7
|
+
// value-import closure is empty — no processColor, no Platform, no TurboModule floor, no renderer.
|
|
8
|
+
// No try/catch, unlike the other upstream wrappers: these three don't validate through invariant,
|
|
9
|
+
// they answer `[]` for anything unparseable — so refusal is a return here, not a throw.
|
|
18
10
|
import { dlog } from './debug.js';
|
|
19
11
|
// @ts-expect-error - untyped Flow source. Metro compiles it; vitest.config.ts strips the types.
|
|
20
12
|
import processBackgroundSizeUpstream from 'react-native/Libraries/StyleSheet/processBackgroundSize';
|
|
@@ -22,10 +14,9 @@ import processBackgroundSizeUpstream from 'react-native/Libraries/StyleSheet/pro
|
|
|
22
14
|
import processBackgroundPositionUpstream from 'react-native/Libraries/StyleSheet/processBackgroundPosition';
|
|
23
15
|
// @ts-expect-error - untyped Flow source. Metro compiles it; vitest.config.ts strips the types.
|
|
24
16
|
import processBackgroundRepeatUpstream from 'react-native/Libraries/StyleSheet/processBackgroundRepeat';
|
|
25
|
-
// An empty result
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// leaving the declaration unset.
|
|
17
|
+
// An empty result means upstream parsed nothing usable. The payload builder's rule is that a
|
|
18
|
+
// refused processor leaves the key absent — `[]` is a real value, committing it would ask native
|
|
19
|
+
// to apply "no background size" rather than leave the declaration unset.
|
|
29
20
|
function orAbsent(parsed, key, value) {
|
|
30
21
|
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
31
22
|
dlog(`${key}: RN parsed nothing usable from ${JSON.stringify(value)}`);
|
package/build/process-filter.js
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
// RN's own processFilter, imported rather than ported
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// What changed by importing: a drop-shadow's colour now goes through RN's own `processColor`
|
|
13
|
-
// (upstream imports it directly at processFilter.js:16) instead of our injected
|
|
14
|
-
// `setColorProcessor` seam. On a real host those are the same function - bootstrapHost injects
|
|
15
|
-
// exactly `processColor` - so the seam simply no longer governs the colour inside a filter.
|
|
16
|
-
//
|
|
17
|
-
// Platform caveat worth keeping in view when demoing this: on iOS RN paints only `brightness` and
|
|
18
|
-
// `opacity` unless enableSwiftUIBasedFilters is on, so grayscale/blur/saturate/contrast/hueRotate
|
|
19
|
-
// parse correctly here and still do nothing on screen.
|
|
1
|
+
// RN's own processFilter, imported rather than ported: enableNativeCSSParsing() defaults to
|
|
2
|
+
// false, so the stock path parses the CSS string / structured array in JS and native never sees
|
|
3
|
+
// the raw string.
|
|
4
|
+
// try/catch because upstream throws once (a TypeError for a non-string/array input) and a commit
|
|
5
|
+
// path must never throw; fabric-props narrows first, but processFilter is on the public barrel
|
|
6
|
+
// too, so the guard here stays reachable, not ceremonial.
|
|
7
|
+
// A drop-shadow's color goes through RN's own processColor here, not our injected
|
|
8
|
+
// setColorProcessor seam — the same function on a real host, since bootstrapHost injects exactly
|
|
9
|
+
// processColor, so the seam simply doesn't govern a filter's color.
|
|
10
|
+
// iOS caveat: RN paints only brightness/opacity unless enableSwiftUIBasedFilters is on, so
|
|
11
|
+
// grayscale/blur/saturate/contrast/hueRotate parse fine here and still paint nothing on screen.
|
|
20
12
|
import { dlog } from './debug.js';
|
|
21
13
|
// @ts-expect-error - untyped Flow source. Metro compiles it; vitest.config.ts strips the types.
|
|
22
14
|
import processFilterUpstream from 'react-native/Libraries/StyleSheet/processFilter';
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
// JS-side port of RN's processFontVariant
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// string ('small-caps tabular-nums') is split into the array native expects IN JS. An
|
|
5
|
-
// array (the common, already-working form) passes through untouched; this is a no-op
|
|
6
|
-
// for it.
|
|
7
|
-
// RN processFontVariant.js:15-28. Array → array; space-separated string → array of variants.
|
|
1
|
+
// JS-side port of RN's processFontVariant: splits a space-separated CSS string
|
|
2
|
+
// ('small-caps tabular-nums') into the array native expects, same root cause as
|
|
3
|
+
// boxShadow/filter. An array (the common, already-working form) passes through as a no-op.
|
|
8
4
|
export function processFontVariant(fontVariant) {
|
|
9
5
|
if (Array.isArray(fontVariant)) {
|
|
10
6
|
return fontVariant;
|
package/build/registry.d.ts
CHANGED
|
@@ -29,39 +29,6 @@ export declare function registerComponent(name: string, registration?: IComponen
|
|
|
29
29
|
export declare function isRegisteredEvent(component: string, listener: string): boolean;
|
|
30
30
|
export declare function registeredNativeEvent(component: string, raw: string): INativeEventBinding | undefined;
|
|
31
31
|
export declare function registeredProcessor(component: string, key: string): IPropProcessor | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* A component's ViewConfig processors, as a payload fold — or undefined when it has none.
|
|
34
|
-
*
|
|
35
|
-
* WHY A FOLD AND NOT A LOOKUP AT PAYLOAD-BUILD TIME. The payload is built in C++ on a device
|
|
36
|
-
* (`core/engine/cpp/SymbioteFabricProps.cpp`) and only in JS headless, and this registry cannot
|
|
37
|
-
* cross that boundary: it is populated lazily from an INJECTED `ReactNativeViewConfigRegistry`
|
|
38
|
-
* lookup, holding JS closures. `payloadFold` is the one seam that already runs in JS on both paths
|
|
39
|
-
* — the C++ probes it once per node and calls back — so putting the processors there is what makes
|
|
40
|
-
* a third-party view behave the same on a device as it does in a test.
|
|
41
|
-
*
|
|
42
|
-
* The alternative was a list of prop NAMES in C++, and that is what this replaces. It cost a day:
|
|
43
|
-
* `@symbiote-native/slider` declares `minimumTrackTintColor` / `maximumTrackTintColor` in its own
|
|
44
|
-
* ViewConfig, neither name was in the C++ list, both reached Fabric as CSS strings, and iOS answers
|
|
45
|
-
* a string colour with `clearColor()`. The slider dragged and reported values correctly with no
|
|
46
|
-
* track drawn at all. Any list of names is a list somebody has to extend for a component we have
|
|
47
|
-
* never seen — which would have meant editing C++ to add a native view, and that is exactly the
|
|
48
|
-
* coupling `<native_core_is_untouched>` exists to prevent.
|
|
49
|
-
*
|
|
50
|
-
* Resolved ONCE per component and cached, because `createElement` asks per node. A built-in
|
|
51
|
-
* short-circuits inside `resolve` before any of this.
|
|
52
|
-
*/
|
|
53
|
-
/**
|
|
54
|
-
* The prop names a component's OWN ViewConfig claims a processor for — i.e. exactly the keys
|
|
55
|
-
* `configPayloadFold` has already converted by the time the payload builder's own passes run.
|
|
56
|
-
*
|
|
57
|
-
* It exists so "a colour is converted exactly once" can be a stated rule rather than a lucky one.
|
|
58
|
-
* The overlap is real: `thumbTintColor` is claimed by @symbiote-native/slider's config AND by the
|
|
59
|
-
* engine's built-in COLOR_PROPS, and for a while nothing broke only because a processed colour came
|
|
60
|
-
* back as a NUMBER and the engine skipped numbers. That guard died when a numeric colour became
|
|
61
|
-
* processable in its own right — an author writing `color: 0xff0000ff` means rrggbbaa and owes the
|
|
62
|
-
* same rotation a string owes — and the second conversion then turned an already-correct int into
|
|
63
|
-
* a different colour.
|
|
64
|
-
*/
|
|
65
32
|
export declare function configProcessedKeys(component: string): ReadonlySet<string> | undefined;
|
|
66
33
|
export declare function configPayloadFold(component: string): IPayloadFold | undefined;
|
|
67
34
|
export {};
|
package/build/registry.js
CHANGED
|
@@ -1,33 +1,19 @@
|
|
|
1
|
-
// Runtime metadata for native Fabric views,
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// shared must stay react-native-free (the headless harness runs in plain Node), so
|
|
12
|
-
// the ViewConfig lookup is INJECTED, exactly like the color processor: the adapter
|
|
13
|
-
// wires `setNativeViewConfigSource(ReactNativeViewConfigRegistry.get)` on a real
|
|
14
|
-
// host, where that one source covers BOTH RN core and every library.
|
|
15
|
-
//
|
|
16
|
-
// The ONLY explicit list is OUR OWN built-in primitives (BUILTIN_COMPONENTS): a
|
|
17
|
-
// finite set we own, which keep their hand-tuned tables (view-config events, commit
|
|
18
|
-
// COLOR_PROPS) and are never read from the source, so they can't drift. Everything
|
|
19
|
-
// NOT in that set derives. The list never grows with the community; it grows only
|
|
20
|
-
// when we add a core primitive of our own.
|
|
1
|
+
// Runtime metadata for native Fabric views, derived by default. Any RN library ships its own
|
|
2
|
+
// ViewConfig via codegen, carrying everything the shared engine can't infer — which events a view
|
|
3
|
+
// emits, how to process its props. Nothing is transcribed; read from the config on first use.
|
|
4
|
+
// shared must stay react-native-free (the headless harness runs in plain Node), so the ViewConfig
|
|
5
|
+
// lookup is injected, exactly like the color processor: the adapter wires
|
|
6
|
+
// setNativeViewConfigSource(ReactNativeViewConfigRegistry.get) on a real host.
|
|
7
|
+
// The only explicit list is our own built-in primitives (BUILTIN_COMPONENTS): a finite set we own,
|
|
8
|
+
// which keep their hand-tuned tables and are never read from the source, so they can't drift. It
|
|
9
|
+
// grows only when we add a core primitive of our own, never for a community package.
|
|
21
10
|
import { isRecord } from './type-guards.js';
|
|
22
11
|
const EMPTY = {
|
|
23
12
|
listeners: new Set(),
|
|
24
13
|
byRaw: new Map(),
|
|
25
14
|
processors: new Map(),
|
|
26
15
|
};
|
|
27
|
-
//
|
|
28
|
-
// commit COLOR_PROPS). The source is never consulted for these, so they can't
|
|
29
|
-
// drift. Everything else derives. This list grows only when WE add a core
|
|
30
|
-
// primitive, never for a community package.
|
|
16
|
+
// Our own primitives — see the module header for why the source is never consulted for these.
|
|
31
17
|
const BUILTIN_COMPONENTS = new Set([
|
|
32
18
|
'RCTView',
|
|
33
19
|
'RCTText',
|
|
@@ -156,39 +142,18 @@ export function registeredNativeEvent(component, raw) {
|
|
|
156
142
|
export function registeredProcessor(component, key) {
|
|
157
143
|
return resolve(component).processors.get(key);
|
|
158
144
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
* ViewConfig, neither name was in the C++ list, both reached Fabric as CSS strings, and iOS answers
|
|
172
|
-
* a string colour with `clearColor()`. The slider dragged and reported values correctly with no
|
|
173
|
-
* track drawn at all. Any list of names is a list somebody has to extend for a component we have
|
|
174
|
-
* never seen — which would have meant editing C++ to add a native view, and that is exactly the
|
|
175
|
-
* coupling `<native_core_is_untouched>` exists to prevent.
|
|
176
|
-
*
|
|
177
|
-
* Resolved ONCE per component and cached, because `createElement` asks per node. A built-in
|
|
178
|
-
* short-circuits inside `resolve` before any of this.
|
|
179
|
-
*/
|
|
180
|
-
/**
|
|
181
|
-
* The prop names a component's OWN ViewConfig claims a processor for — i.e. exactly the keys
|
|
182
|
-
* `configPayloadFold` has already converted by the time the payload builder's own passes run.
|
|
183
|
-
*
|
|
184
|
-
* It exists so "a colour is converted exactly once" can be a stated rule rather than a lucky one.
|
|
185
|
-
* The overlap is real: `thumbTintColor` is claimed by @symbiote-native/slider's config AND by the
|
|
186
|
-
* engine's built-in COLOR_PROPS, and for a while nothing broke only because a processed colour came
|
|
187
|
-
* back as a NUMBER and the engine skipped numbers. That guard died when a numeric colour became
|
|
188
|
-
* processable in its own right — an author writing `color: 0xff0000ff` means rrggbbaa and owes the
|
|
189
|
-
* same rotation a string owes — and the second conversion then turned an already-correct int into
|
|
190
|
-
* a different colour.
|
|
191
|
-
*/
|
|
145
|
+
// A component's ViewConfig processors, as a payload fold — or undefined when it has none. Not a
|
|
146
|
+
// lookup at payload-build time: the payload is built in C++ on a device and this registry can't
|
|
147
|
+
// cross that boundary (it's populated lazily from an injected JS-closure-holding lookup).
|
|
148
|
+
// payloadFold is the one seam that already runs in JS on both paths, so putting the processors
|
|
149
|
+
// there is what makes a third-party view behave the same on device as in a test. The alternative,
|
|
150
|
+
// a list of prop names hardcoded in C++, needs editing native code for every new component we see.
|
|
151
|
+
// Resolved once per component and cached, since createElement asks per node. A built-in
|
|
152
|
+
// short-circuits inside resolve before any of this.
|
|
153
|
+
// The prop names a component's own ViewConfig claims a processor for — exactly the keys
|
|
154
|
+
// configPayloadFold has already converted by the time the payload builder's own passes run.
|
|
155
|
+
// Exists so "a colour is converted exactly once" is a stated rule, not a lucky one: an overlap
|
|
156
|
+
// between a third-party config and the engine's own COLOR_PROPS would otherwise double-convert.
|
|
192
157
|
export function configProcessedKeys(component) {
|
|
193
158
|
const cached = keysCache.get(component);
|
|
194
159
|
if (cached !== undefined)
|
package/build/report-error.js
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
// Hand an error to the host the way React Native itself does, for the seams where an adapter
|
|
2
2
|
// catches something its framework would otherwise have surfaced on its own.
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// Libraries. `global.ErrorUtils` is the same surface through the documented global that
|
|
7
|
-
// @react-native/js-polyfills installs before any module evaluates - RN's own
|
|
8
|
-
// Libraries/vendor/core/ErrorUtils.js is nothing but `export default global.ErrorUtils`. Off a
|
|
9
|
-
// native host (vitest, node smokes) the global is absent and console.error is the whole channel.
|
|
10
|
-
//
|
|
11
|
-
// This is NOT the dlog channel. dlog is DEBUG-gated and therefore the developer's; an error that
|
|
12
|
-
// blanked the screen has to reach the app whether or not anyone turned diagnostics on.
|
|
13
|
-
// Read off globalThis through Reflect rather than named as an identifier, and deliberately NOT
|
|
14
|
-
// declared in an ambient block: react-native ships its own `const ErrorUtils: ErrorUtils` in
|
|
15
|
-
// src/types/globals.d.ts, so a `declare global { var ErrorUtils }` here redeclares it (TS2451) for
|
|
16
|
-
// every package whose tsconfig pulls in RN's types - the engine's own does not, so it typechecks
|
|
17
|
-
// clean here and breaks ngc downstream. RN's declared shape also lists only the two
|
|
18
|
-
// get/setGlobalHandler members, not reportError, which the polyfill does install.
|
|
3
|
+
// Read off globalThis via Reflect, not a named identifier or an ambient declare: react-native
|
|
4
|
+
// ships its own `ErrorUtils` global type, so redeclaring it here breaks any package whose tsconfig
|
|
5
|
+
// pulls in RN's types. RN's declared shape also omits reportError, which the polyfill installs.
|
|
19
6
|
function nativeReporter() {
|
|
20
7
|
const utils = Reflect.get(globalThis, 'ErrorUtils');
|
|
21
8
|
if (typeof utils !== 'object' || utils === null)
|
|
@@ -54,8 +41,7 @@ export function reportUncaughtError(value, info) {
|
|
|
54
41
|
const report = nativeReporter();
|
|
55
42
|
if (report !== null) {
|
|
56
43
|
// Exactly one channel, never both: RN routes console.error into LogBox as well, so logging
|
|
57
|
-
// here too would double-report every error.
|
|
58
|
-
// this same reason (Libraries/Core/ReactFiberErrorDialog.js:57).
|
|
44
|
+
// here too would double-report every error.
|
|
59
45
|
report(error);
|
|
60
46
|
return;
|
|
61
47
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Settings, Android build: RN's SettingsFallback (Settings.js resolves to it off iOS). Android has
|
|
2
|
+
// no SettingsManager, so every call warns and does nothing — no JS snapshot, no watchers. The
|
|
3
|
+
// warning is RN's own user-facing one, not a diagnostic log.
|
|
4
|
+
const UNSUPPORTED = 'Settings is not yet supported on this platform.';
|
|
5
|
+
const NO_WATCH_ID = -1;
|
|
6
|
+
export const Settings = {
|
|
7
|
+
get(_key) {
|
|
8
|
+
console.warn(UNSUPPORTED);
|
|
9
|
+
return null;
|
|
10
|
+
},
|
|
11
|
+
set(_settings) {
|
|
12
|
+
console.warn(UNSUPPORTED);
|
|
13
|
+
},
|
|
14
|
+
watchKeys(_keys, _callback) {
|
|
15
|
+
console.warn(UNSUPPORTED);
|
|
16
|
+
return NO_WATCH_ID;
|
|
17
|
+
},
|
|
18
|
+
clearWatch(_watchId) {
|
|
19
|
+
console.warn(UNSUPPORTED);
|
|
20
|
+
},
|
|
21
|
+
};
|
|
@@ -1,8 +1 @@
|
|
|
1
|
-
|
|
2
|
-
get(key: string): unknown;
|
|
3
|
-
set(settings: Record<string, unknown>): void;
|
|
4
|
-
watchKeys(keys: string | string[], callback: () => void): number;
|
|
5
|
-
clearWatch(watchId: number): void;
|
|
6
|
-
}
|
|
7
|
-
export declare const Settings: SettingsImpl;
|
|
8
|
-
export {};
|
|
1
|
+
export * from './index.ios';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
declare class SettingsImpl {
|
|
2
|
+
get(key: string): unknown;
|
|
3
|
+
set(settings: Record<string, unknown>): void;
|
|
4
|
+
watchKeys(keys: string | string[], callback: () => void): number;
|
|
5
|
+
clearWatch(watchId: number): void;
|
|
6
|
+
}
|
|
7
|
+
export declare const Settings: SettingsImpl;
|
|
8
|
+
export {};
|