@symbiote-native/engine 1.3.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/build/accessibility-props.d.ts +0 -11
- package/build/accessibility-props.js +30 -68
- package/build/animated/graph.js +1 -1
- package/build/animated/leaf-lifecycle.js +2 -2
- package/build/asset-source-resolver.d.ts +2 -0
- package/build/asset-source-resolver.js +13 -0
- package/build/back-handler/index.d.ts +1 -5
- package/build/back-handler/index.js +0 -6
- package/build/debug.js +8 -22
- package/build/dispatch.js +3 -9
- package/build/events/index.js +2 -2
- package/build/fabric-props.js +74 -179
- package/build/fabric.d.ts +0 -13
- package/build/fabric.js +18 -38
- package/build/host-access.d.ts +1 -128
- package/build/host-access.js +96 -205
- package/build/host-behavior.d.ts +0 -100
- package/build/host-behavior.js +125 -311
- package/build/image-loader.js +10 -23
- package/build/image-source-resolver.js +3 -7
- package/build/image-source-write.d.ts +0 -11
- package/build/image-source-write.js +14 -34
- package/build/imperative.d.ts +0 -28
- package/build/imperative.js +42 -92
- package/build/index.d.ts +1 -0
- package/build/index.js +24 -37
- 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.js +9 -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 +338 -774
- 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/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/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/package.json +2 -2
package/build/image-loader.js
CHANGED
|
@@ -1,27 +1,16 @@
|
|
|
1
|
-
// Image static methods (RN's Image.getSize
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
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).
|
|
1
|
+
// Image static methods (RN's Image.getSize/prefetch/queryCache/etc). Both iOS and Android specs
|
|
2
|
+
// register under the same module name ('ImageLoader'), so this stays flat, non-platform-split —
|
|
3
|
+
// only the Android prefetch call signature differs (a second requestId arg), branched below.
|
|
4
|
+
// The native result crosses the I/O boundary as unknown; we never cast it, we narrow its shape.
|
|
5
|
+
// This is a stateful, native-bridge-touching imperative module with no view of its own — it
|
|
6
|
+
// belongs here alongside Alert/Share, not in a view/render-*.ts file.
|
|
16
7
|
import { dlog } from './debug.js';
|
|
17
8
|
import { resolveImageSource, } from './image-source-resolver.js';
|
|
18
9
|
import { getNativeModule } from './native-modules/index.js';
|
|
19
10
|
import { Platform } from './platform';
|
|
20
11
|
import { isNumber } from './type-guards.js';
|
|
21
|
-
// The
|
|
22
|
-
//
|
|
23
|
-
// provable on a real host - a headless fake answers to any name - so this iOS name is
|
|
24
|
-
// device-verify-pending.
|
|
12
|
+
// The native module name RN registers this under. A module name like this is only provable on a
|
|
13
|
+
// real host — a headless fake answers to any name.
|
|
25
14
|
const IMAGE_LOADER_MODULE = 'ImageLoader';
|
|
26
15
|
let imageLoaderModule;
|
|
27
16
|
function getImageLoader() {
|
|
@@ -148,10 +137,8 @@ async function queryCache(uris) {
|
|
|
148
137
|
throw error;
|
|
149
138
|
});
|
|
150
139
|
}
|
|
151
|
-
//
|
|
152
|
-
// uses via resolveImageSource).
|
|
153
|
-
// {uri, scale, ...}; the app injects the real one with setImageSourceResolver, and this exposes
|
|
154
|
-
// its output to callers directly.
|
|
140
|
+
// Pure JS: run the currently-installed source resolver (the same machinery the Image component
|
|
141
|
+
// uses via resolveImageSource). The app injects the real one with setImageSourceResolver.
|
|
155
142
|
function resolveAssetSource(source) {
|
|
156
143
|
return resolveImageSource(source);
|
|
157
144
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
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.
|
|
1
|
+
// require('./x.png') asset ids and {uri} sources resolve via RN's own resolveAssetSource, which is
|
|
2
|
+
// platform-specific and injected here rather than imported (mirrors platform-color.ts's
|
|
3
|
+
// processColor seam) so @symbiote-native/components stays free of a react-native dependency.
|
|
8
4
|
let sourceResolver = source => source;
|
|
9
5
|
export function setImageSourceResolver(resolve) {
|
|
10
6
|
sourceResolver = resolve;
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
export declare const IMAGE_SOURCE_PROPS: ReadonlySet<string>;
|
|
2
|
-
/**
|
|
3
|
-
* Resolve a source prop and normalise it to the ARRAY shape native expects.
|
|
4
|
-
*
|
|
5
|
-
* Always an array, including for the single-object and asset-id cases: a bare object reaching
|
|
6
|
-
* Fabric paints nothing and reports nothing, which is worse than an image that is simply absent.
|
|
7
|
-
* The rule downstream then has one shape to reason about instead of three.
|
|
8
|
-
*
|
|
9
|
-
* A value this cannot make sense of comes back UNTOUCHED rather than wrapped. `routeProp` writes
|
|
10
|
-
* whatever it is handed, and a tag with no image behavior must keep its props verbatim — the
|
|
11
|
-
* control case in `image-payload.itest.ts` is what holds that line.
|
|
12
|
-
*/
|
|
13
2
|
export declare function resolveImageSourceProp(value: unknown, dropsSingleSourceHeaders?: boolean): unknown;
|
|
14
3
|
export declare const IMAGE_LOAD_EVENT_NAMES: ReadonlySet<string>;
|
|
15
4
|
/** Whether at least one of the four still has a listener installed on the node. */
|
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
// Image sources, resolved on the way IN rather than
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// indexes into, populated at bundle time, in JavaScript. There is no such table in C++ and there
|
|
6
|
-
// should not be: it is the bundler's, not the platform's.
|
|
7
|
-
//
|
|
8
|
-
// This is the same seam and the same argument as `structured-style.ts`, which resolves
|
|
9
|
-
// `boxShadow`/`filter`/`transform` at write time for the identical reason — a value resolved at
|
|
10
|
-
// PAYLOAD-BUILD time is resolved HEADLESS ONLY, because the C++ builder has no JS to call, and the
|
|
11
|
-
// device then commits the raw input and Fabric drops it in silence. Moving the lookup one step
|
|
12
|
-
// earlier costs nothing and leaves the rest of the rule pure, which is what let it move at all.
|
|
13
|
-
//
|
|
14
|
-
// The three names are Image's: `source` is the real one, `defaultSource` the placeholder, and
|
|
1
|
+
// Image sources, resolved on the way IN rather than in the C++ payload builder like the rest of
|
|
2
|
+
// Image's rule: resolveImageSource asks Metro's asset registry, a JS-only, bundle-time table with
|
|
3
|
+
// no C++ side. Same seam as structured-style.ts's write-time boxShadow/filter/transform fold.
|
|
4
|
+
// The three names are Image's: `source` the real one, `defaultSource` the placeholder,
|
|
15
5
|
// `loadingIndicatorSource` Android's spinner.
|
|
16
6
|
import { resolveImageSource } from './image-source-resolver.js';
|
|
17
7
|
export const IMAGE_SOURCE_PROPS = new Set([
|
|
@@ -19,17 +9,11 @@ export const IMAGE_SOURCE_PROPS = new Set([
|
|
|
19
9
|
'defaultSource',
|
|
20
10
|
'loadingIndicatorSource',
|
|
21
11
|
]);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* The rule downstream then has one shape to reason about instead of three.
|
|
28
|
-
*
|
|
29
|
-
* A value this cannot make sense of comes back UNTOUCHED rather than wrapped. `routeProp` writes
|
|
30
|
-
* whatever it is handed, and a tag with no image behavior must keep its props verbatim — the
|
|
31
|
-
* control case in `image-payload.itest.ts` is what holds that line.
|
|
32
|
-
*/
|
|
12
|
+
// Resolve a source prop and normalize it to the array shape native expects — always an array,
|
|
13
|
+
// even for the single-object and asset-id cases, since a bare object reaching Fabric paints and
|
|
14
|
+
// reports nothing at all.
|
|
15
|
+
// A value this can't make sense of comes back untouched rather than wrapped: a tag with no image
|
|
16
|
+
// behavior must keep its props verbatim (pinned by image-payload.itest.ts).
|
|
33
17
|
export function resolveImageSourceProp(value, dropsSingleSourceHeaders = false) {
|
|
34
18
|
if (value === undefined || value === null)
|
|
35
19
|
return value;
|
|
@@ -50,15 +34,11 @@ export function resolveImageSourceProp(value, dropsSingleSourceHeaders = false)
|
|
|
50
34
|
}
|
|
51
35
|
return [resolved];
|
|
52
36
|
}
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
// `routeProp` diverts them through `setEventListener`/`node.listeners`, never through `writeProp`
|
|
59
|
-
// — unlike an ordinary function prop, they never reach the `functionProps` stash. Named here in
|
|
60
|
-
// LISTENER form (post `listenerName()`: `onLoad` -> `load`), which is what `node.listeners` keys
|
|
61
|
-
// on. Same shape `GATED_EVENT_PROPS` uses for `onLayout`, applied to a name no host behavior owns.
|
|
37
|
+
// Android's ReactImageView.setShouldNotifyLoadEvents gates on this prop: none of these four ever
|
|
38
|
+
// fire until Image.android.js sets it, because any one of them is authored; iOS has no such gate.
|
|
39
|
+
// Real Fabric events (view-config.ts's COMPONENT_EVENTS.RCTImageView), so routeProp diverts them
|
|
40
|
+
// through setEventListener/node.listeners, never writeProp — named in listener form (onLoad ->
|
|
41
|
+
// load), what node.listeners keys on.
|
|
62
42
|
export const IMAGE_LOAD_EVENT_NAMES = new Set([
|
|
63
43
|
'loadStart',
|
|
64
44
|
'load',
|
package/build/imperative.d.ts
CHANGED
|
@@ -2,47 +2,19 @@ import type { IMeasureInWindowOnSuccess, IMeasureLayoutOnSuccess, IMeasureOnSucc
|
|
|
2
2
|
import { type ISymbioteNode } from './node';
|
|
3
3
|
export declare function registerSurfaceCommit(commit: (rootTag: IRootTag) => void, forget: (rootTag: IRootTag) => void): void;
|
|
4
4
|
export declare function flushNativeProps(): void;
|
|
5
|
-
/**
|
|
6
|
-
* Publish a node whose props changed OUTSIDE any renderer mutation.
|
|
7
|
-
*
|
|
8
|
-
* Recording is not publishing. Every other write reaches Fabric because the framework's own commit
|
|
9
|
-
* follows it; a change driven by a NATIVE EVENT has no such follow-up — the press path's
|
|
10
|
-
* `setNodePressed` is the first caller that is not `setNativeProps`.
|
|
11
|
-
*
|
|
12
|
-
* Queued rather than committed on the spot: several writes in one task publish together at the
|
|
13
|
-
* microtask boundary, one commit per surface.
|
|
14
|
-
*/
|
|
15
5
|
export declare function requestCommitFor(node: ISymbioteNode): void;
|
|
16
6
|
export declare function disposeRoot(rootTag: IRootTag): void;
|
|
17
7
|
/** The committed reactTag, stable across clone-on-write — what the native Animated driver binds. */
|
|
18
8
|
export declare function getNativeTag(node: ISymbioteNode): number | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* The node's current native handle, in kind identical to React's `stateNode.node`.
|
|
21
|
-
*
|
|
22
|
-
* OPAQUE. Under the native host it is a `ShadowNode`, under a headless one whatever that host
|
|
23
|
-
* committed — see `ICommittedRecord.handle`. It used to be typed `IFabricNode`, a brand with no
|
|
24
|
-
* members, so a caller can do exactly as much with it as before.
|
|
25
|
-
*/
|
|
26
9
|
export declare function getNativeNode(node: ISymbioteNode): object | undefined;
|
|
27
10
|
/** Called by the commit path once a batch has published. */
|
|
28
11
|
export declare function notifyCommitted(): void;
|
|
29
|
-
/**
|
|
30
|
-
* Run `action` once `node` has a committed Fabric handle — immediately if it already does, else
|
|
31
|
-
* after the commit that assigns one. Returns a cancel fn (drop the retry, e.g. on unmount).
|
|
32
|
-
*/
|
|
33
12
|
export declare function whenCommitted(node: ISymbioteNode, action: () => void): () => void;
|
|
34
13
|
export declare function dispatchViewCommand(node: ISymbioteNode, commandName: string, args: readonly unknown[]): void;
|
|
35
14
|
export declare function sendAccessibilityEvent(node: ISymbioteNode, eventType: string): void;
|
|
36
15
|
export declare function measure(node: ISymbioteNode, callback: IMeasureOnSuccess): void;
|
|
37
16
|
export declare function measureInWindow(node: ISymbioteNode, callback: IMeasureInWindowOnSuccess): void;
|
|
38
17
|
export declare function measureLayout(node: ISymbioteNode, relativeTo: ISymbioteNode, onSuccess: IMeasureLayoutOnSuccess, onFail?: () => void): void;
|
|
39
|
-
/**
|
|
40
|
-
* Tell native that JS has taken the gesture, or given it up.
|
|
41
|
-
*
|
|
42
|
-
* Through the HOST like the five above it, never through the Fabric slot: under the native tree
|
|
43
|
-
* host the committed handle is our placeholder, and `nativeFabricUIManager.setIsJSResponder` unwraps
|
|
44
|
-
* only a `ShadowNode` reference it minted itself.
|
|
45
|
-
*/
|
|
46
18
|
export declare function setIsJSResponder(node: ISymbioteNode, isResponder: boolean, blockNativeResponder: boolean): void;
|
|
47
19
|
/** The node's CURRENT prop value, as the host holds it. The behaviors' one read. */
|
|
48
20
|
export declare function propOf(node: ISymbioteNode, key: string): unknown;
|
package/build/imperative.js
CHANGED
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// HOST answers now (`tree-host.ts`) — native on device, the TypeScript applier headlessly.
|
|
8
|
-
//
|
|
9
|
-
// `undefined` is the ORDINARY state here, not an error. An adapter that wires an imperative call at
|
|
10
|
-
// lifecycle time runs before `completeRoot` under an async-batched commit (Vue and Svelte schedule
|
|
11
|
-
// it on a microtask), so the node has no handle yet. Every function either defers (`whenCommitted`)
|
|
12
|
-
// or logs and returns — never throws.
|
|
1
|
+
// Everything an app or adapter reaches for outside a render: measure, view commands, accessibility
|
|
2
|
+
// events, the Animated fast path. Each is written against a Fabric handle/tag/root tag answered by
|
|
3
|
+
// the tree host (tree-host.ts): native on device, a TypeScript applier headlessly.
|
|
4
|
+
// undefined is the ordinary state here, not an error. An adapter wiring an imperative call at
|
|
5
|
+
// lifecycle time can run before completeRoot under an async-batched commit, so the node has no
|
|
6
|
+
// handle yet. Every function either defers (whenCommitted) or logs and returns — never throws.
|
|
13
7
|
import { dlog, isDebug } from './debug.js';
|
|
14
8
|
import { clearPublishedStyle, writeProp } from './node.js';
|
|
15
9
|
import { flattenStyle } from './style/index.js';
|
|
16
10
|
import { flushOps, treeHost } from './tree-host.js';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
* `undefined` is the ORDINARY state, not an error — and it is also what a WRAPPED node gets. The host
|
|
24
|
-
* keys on the handle OBJECT, so a Vue `reactive()` / deep-`ref()` Proxy around a host element misses
|
|
25
|
-
* and every function below degrades to its log. Hold host nodes with `shallowRef`.
|
|
26
|
-
*/
|
|
11
|
+
// What Fabric currently holds for `node`, or undefined before its first commit. Flushes first: an
|
|
12
|
+
// imperative call can land between a mutation and its commit, and the host can't answer about ops
|
|
13
|
+
// it hasn't been handed.
|
|
14
|
+
// undefined is also what a wrapped node gets: the host keys on the handle object, so a Vue
|
|
15
|
+
// reactive()/deep-ref() Proxy around a host element misses. Hold host nodes with shallowRef.
|
|
27
16
|
function committedRecordOf(node) {
|
|
28
17
|
flushOps();
|
|
29
18
|
return treeHost()?.committedRecordOf(node);
|
|
@@ -48,16 +37,11 @@ export function flushNativeProps() {
|
|
|
48
37
|
for (const rootTag of roots)
|
|
49
38
|
commitSurface?.(rootTag);
|
|
50
39
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
* `setNodePressed` is the first caller that is not `setNativeProps`.
|
|
57
|
-
*
|
|
58
|
-
* Queued rather than committed on the spot: several writes in one task publish together at the
|
|
59
|
-
* microtask boundary, one commit per surface.
|
|
60
|
-
*/
|
|
40
|
+
// Publish a node whose props changed outside any renderer mutation. Recording is not publishing:
|
|
41
|
+
// every other write reaches Fabric because the framework's own commit follows it, but a change
|
|
42
|
+
// driven by a native event has no such follow-up (setNodePressed is the first such caller).
|
|
43
|
+
// Queued rather than committed on the spot: several writes in one task publish together at the
|
|
44
|
+
// microtask boundary, one commit per surface.
|
|
61
45
|
export function requestCommitFor(node) {
|
|
62
46
|
const record = committedRecordOf(node);
|
|
63
47
|
if (record === undefined) {
|
|
@@ -66,14 +50,9 @@ export function requestCommitFor(node) {
|
|
|
66
50
|
}
|
|
67
51
|
requestCommitForRoot(record.rootTag);
|
|
68
52
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* `committedRecordOf` crosses the host boundary, and `setNativeProps` fetches the record two lines
|
|
73
|
-
* before it calls this — so asking again was two crossings for one fact, on the path an
|
|
74
|
-
* `AnimatedProps` leaf runs once per frame per animated node. Measured at 2 of the 3 crossings a
|
|
75
|
-
* frame made (`__tests__/animated-frame-cost.test.ts`).
|
|
76
|
-
*/
|
|
53
|
+
// The same request, for a caller that already holds the node's record. committedRecordOf crosses
|
|
54
|
+
// the host boundary, and setNativeProps fetches the record two lines before it calls this — asking
|
|
55
|
+
// again would be a second crossing for one fact, on a path an AnimatedProps leaf runs per frame.
|
|
77
56
|
function requestCommitForRoot(rootTag) {
|
|
78
57
|
pendingRoots.add(rootTag);
|
|
79
58
|
if (!flushScheduled) {
|
|
@@ -92,20 +71,15 @@ export function disposeRoot(rootTag) {
|
|
|
92
71
|
export function getNativeTag(node) {
|
|
93
72
|
return committedRecordOf(node)?.tag;
|
|
94
73
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
* OPAQUE. Under the native host it is a `ShadowNode`, under a headless one whatever that host
|
|
99
|
-
* committed — see `ICommittedRecord.handle`. It used to be typed `IFabricNode`, a brand with no
|
|
100
|
-
* members, so a caller can do exactly as much with it as before.
|
|
101
|
-
*/
|
|
74
|
+
// The node's current native handle, in kind identical to React's stateNode.node. Opaque: under the
|
|
75
|
+
// native host it's a ShadowNode, under a headless one whatever that host committed (see
|
|
76
|
+
// ICommittedRecord.handle).
|
|
102
77
|
export function getNativeNode(node) {
|
|
103
78
|
return committedRecordOf(node)?.handle;
|
|
104
79
|
}
|
|
105
|
-
// Actions waiting for their node's first commit
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
// once it runs. React commits synchronously, so its actions run inline and never land here.
|
|
80
|
+
// Actions waiting for their node's first commit — an adapter wiring a call at lifecycle time can
|
|
81
|
+
// run before completeRoot under an async-batched commit, so the node has no handle yet. Each
|
|
82
|
+
// waiter retries after a commit and is dropped once it runs; React runs its actions inline.
|
|
109
83
|
const pendingCommitWaiters = new Set();
|
|
110
84
|
/** Called by the commit path once a batch has published. */
|
|
111
85
|
export function notifyCommitted() {
|
|
@@ -114,10 +88,8 @@ export function notifyCommitted() {
|
|
|
114
88
|
pendingCommitWaiters.delete(waiter);
|
|
115
89
|
}
|
|
116
90
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
* after the commit that assigns one. Returns a cancel fn (drop the retry, e.g. on unmount).
|
|
120
|
-
*/
|
|
91
|
+
// Run `action` once `node` has a committed Fabric handle — immediately if it already does, else
|
|
92
|
+
// after the commit that assigns one. Returns a cancel fn to drop the retry (e.g. on unmount).
|
|
121
93
|
export function whenCommitted(node, action) {
|
|
122
94
|
const attempt = () => {
|
|
123
95
|
if (committedRecordOf(node) === undefined)
|
|
@@ -175,13 +147,9 @@ export function measureLayout(node, relativeTo, onSuccess, onFail = () => { }) {
|
|
|
175
147
|
}
|
|
176
148
|
treeHost()?.measureLayout(node, relativeTo, onFail, onSuccess);
|
|
177
149
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
* Through the HOST like the five above it, never through the Fabric slot: under the native tree
|
|
182
|
-
* host the committed handle is our placeholder, and `nativeFabricUIManager.setIsJSResponder` unwraps
|
|
183
|
-
* only a `ShadowNode` reference it minted itself.
|
|
184
|
-
*/
|
|
150
|
+
// Tell native that JS has taken the gesture, or given it up. Through the host like the five above
|
|
151
|
+
// it, never through the Fabric slot: under the native tree host the committed handle is our
|
|
152
|
+
// placeholder, and nativeFabricUIManager's own version unwraps only a ShadowNode it minted itself.
|
|
185
153
|
export function setIsJSResponder(node, isResponder, blockNativeResponder) {
|
|
186
154
|
if (committedRecordOf(node) === undefined) {
|
|
187
155
|
dlog('setIsJSResponder skipped: node not committed');
|
|
@@ -194,22 +162,12 @@ export function propOf(node, key) {
|
|
|
194
162
|
flushOps();
|
|
195
163
|
return treeHost()?.propOf(node, key);
|
|
196
164
|
}
|
|
197
|
-
// Per-frame prop write for the JS-driven Animated path
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
//
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
// its back or its next diff would be computed against a stale base. The write is an ordinary op now
|
|
204
|
-
// — the commit that carries it updates that record itself. Telling the host EARLY was strictly
|
|
205
|
-
// worse than not telling it: `noteNativePropsBypass` folded the values into `committedProps` before
|
|
206
|
-
// the commit ran, so the diff found nothing to send and the write never reached Fabric at all.
|
|
207
|
-
//
|
|
208
|
-
// One correction survives, because it is about the ENGINE's own state rather than the host's:
|
|
209
|
-
// `parts.published` is cleared, so `pushClassStyle`'s guard cannot turn away the re-push that
|
|
210
|
-
// RESTORES the declarative style this frame just overwrote. The guard is exact, and an app handing
|
|
211
|
-
// over a hoisted style constant (StyleSheet.create, a module-level object) would otherwise never
|
|
212
|
-
// get it back.
|
|
165
|
+
// Per-frame prop write for the JS-driven Animated path — RN flushes an animation frame with an
|
|
166
|
+
// in-place instance.setNativeProps(...); Fabric is persistent, so a frame is one scoped commit
|
|
167
|
+
// instead, an ordinary op the commit that carries it accounts for on its own.
|
|
168
|
+
// One correction survives, about the engine's own state: parts.published is cleared, so
|
|
169
|
+
// pushClassStyle's guard can't turn away the re-push that restores the declarative style this
|
|
170
|
+
// frame just overwrote — otherwise a hoisted style constant would never come back.
|
|
213
171
|
export function setNativeProps(node, partial) {
|
|
214
172
|
const record = committedRecordOf(node);
|
|
215
173
|
if (record === undefined) {
|
|
@@ -229,30 +187,22 @@ export function setNativeProps(node, partial) {
|
|
|
229
187
|
}
|
|
230
188
|
else {
|
|
231
189
|
merged[key] = value;
|
|
232
|
-
// This path used to owe the aria gate that `setProp` carried, since it bypasses it. There is
|
|
233
|
-
// no gate to owe any more: the fold is the device's rule and it recomputes presence from the
|
|
234
|
-
// bag. See `node.ts`'s note at the old choke point.
|
|
235
190
|
}
|
|
236
191
|
}
|
|
237
192
|
for (const [key, value] of Object.entries(merged)) {
|
|
238
|
-
//
|
|
239
|
-
// function reaches the wire from here and nowhere else
|
|
240
|
-
// every key its leaf holds,
|
|
193
|
+
// writeProp, not recordSetProp: this is the path with no routeProp in front of it, so a
|
|
194
|
+
// function reaches the wire from here and nowhere else (AnimatedProps.__getValue() copies
|
|
195
|
+
// every key its leaf holds, panHandlers included).
|
|
241
196
|
writeProp(node, key, value);
|
|
242
197
|
}
|
|
243
198
|
if (merged.style !== undefined)
|
|
244
199
|
clearPublishedStyle(node);
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
// string and the `Object.keys` array it builds are 60 allocations a second per node — times the
|
|
248
|
-
// list, for a list that animates its rows. F-61 dismissed 347 ungated arguments because none of
|
|
249
|
-
// them was on a path that repeats; this one is, and F-61 had it in its own in-loop list and
|
|
250
|
-
// priced it as "runs once".
|
|
200
|
+
// Gated: an AnimatedProps leaf calls this once per frame per animated node, so the template
|
|
201
|
+
// string and Object.keys array below would otherwise allocate 60 times a second per node.
|
|
251
202
|
if (isDebug()) {
|
|
252
203
|
dlog(`setNativeProps root=${record.rootTag} tag=${record.tag} keys=${Object.keys(partial)}`);
|
|
253
204
|
}
|
|
254
205
|
// Queued, not committed: every write made in this task publishes together at the microtask
|
|
255
|
-
// boundary.
|
|
256
|
-
// fact this function fetched four lines up.
|
|
206
|
+
// boundary. The record is already in hand, so this avoids a second crossing for the same fact.
|
|
257
207
|
requestCommitForRoot(record.rootTag);
|
|
258
208
|
}
|
package/build/index.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ export { imageStatics } from './image-loader';
|
|
|
65
65
|
export type { IImageStatics, IImageSize, IImageCacheStatus, } from './image-loader';
|
|
66
66
|
export { setImageSourceResolver, resolveImageSource, } from './image-source-resolver';
|
|
67
67
|
export type { IImageSource, IImageSourceProp } from './image-source-resolver';
|
|
68
|
+
export { setAssetSourceResolver, resolveAssetSource, } from './asset-source-resolver';
|
|
68
69
|
export { ActionSheetIOS } from './action-sheet-ios';
|
|
69
70
|
export type { IActionSheetIOSOptions, IShareActionSheetIOSOptions, IShareActionSheetError, } from './action-sheet-ios';
|
|
70
71
|
export { Linking } from './linking';
|
package/build/index.js
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
// @symbiote-native/engine: the retained shadow-tree + clone-on-write commit engine.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// normalization) lives behind it, in one place.
|
|
1
|
+
// @symbiote-native/engine: the retained shadow-tree + clone-on-write commit engine. Every framework
|
|
2
|
+
// adapter drives this tiny mutation API; all Fabric-specific logic (tag allocation, view-name
|
|
3
|
+
// resolution, clone-on-write, event normalization) lives behind it, in one place.
|
|
5
4
|
export { createElement, createRawText, createAnchor,
|
|
6
|
-
// The component name of a node the commit walk skips and whose children flatten into its
|
|
7
|
-
// Exported so a
|
|
8
|
-
//
|
|
9
|
-
// (TouchableNativeFeedback.js:339) — rather than being converted after the fact.
|
|
5
|
+
// The component name of a node the commit walk skips and whose children flatten into its
|
|
6
|
+
// parent. Exported so a primitive rendering no view of its own (TouchableNativeFeedback) can be
|
|
7
|
+
// born with it directly, rather than converted after the fact.
|
|
10
8
|
ANCHOR_COMPONENT, isAnchor, createVoid,
|
|
11
|
-
// The component name of a node whose
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// `input-accessory-view` on Android, `InputAccessoryView.js`'s `return null`.
|
|
9
|
+
// The component name of a node whose entire subtree the commit walk drops — unlike
|
|
10
|
+
// ANCHOR_COMPONENT, which hoists children in its place, a void node contributes neither itself
|
|
11
|
+
// nor them. For a primitive whose whole component renders nothing on this platform.
|
|
15
12
|
VOID_COMPONENT, appendChild, insertBefore, removeChild, setProp, setEventListener, routeProp, censusRetainedTree, getExplicitStyle,
|
|
16
|
-
// Exported for the
|
|
17
|
-
//
|
|
18
|
-
// recognise one it has already published.
|
|
19
|
-
// mirror shape this codebase deletes on sight — and its deliberate conservatism (a nested value
|
|
20
|
-
// reports "not the same") is exactly right for that use too.
|
|
13
|
+
// Exported for the one adapter that has to build style objects rather than receive them:
|
|
14
|
+
// Angular's ɵɵstyleMap hands over keys, so its renderer allocates a fresh object per node and
|
|
15
|
+
// needs to recognise one it has already published.
|
|
21
16
|
isSameShallowStyle, getPublishedStyle, setNodeHidden, setNodeComponent, setNodePressed, setNodeUnderlayShown, setText, isSymbioteNode, isSymbioteEvent, RAW_TEXT_COMPONENT, debugNodeId, takePropKeyTally, } from './node.js';
|
|
22
17
|
// Host access — the DOM read half Fabric does not ship. Adapters route their seam's
|
|
23
18
|
// parentNode/nextSibling/firstChild through these instead of reading a node's fields, which is
|
|
@@ -53,18 +48,12 @@ export { setTreeHost, treeHost, registerBeforeFlush, readCommitProfile, readSurf
|
|
|
53
48
|
// `installNativeTreeHost` is not on any app path: `getSlot()` already calls it, and it is here so a
|
|
54
49
|
// bring-up probe can install one explicitly against a hand-built set of bindings.
|
|
55
50
|
export { nativeTreeHost, installNativeTreeHost } from './native-tree-host.js';
|
|
56
|
-
// The
|
|
57
|
-
// package and whatever implements the tree,
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
// "A commit just reached completeRoot." The one seam that means the same thing under every
|
|
63
|
-
// adapter: React commits synchronously inside its own commit phase, while Vue / Svelte / Angular
|
|
64
|
-
// schedule completeRoot on a microtask, so each framework's own after-render hook fires at a
|
|
65
|
-
// DIFFERENT point relative to the native commit. Anything timing or comparing the commit path
|
|
66
|
-
// across adapters has to hang off this, not off a per-framework lifecycle hook, or it measures a
|
|
67
|
-
// different quantity in each one under the same name.
|
|
51
|
+
// The opcodes and the recorder are deliberately NOT here: they're the wire contract between this
|
|
52
|
+
// package and whatever implements the tree, audience a host author, not an app. They live on the
|
|
53
|
+
// mutation-buffer subpath instead, since a name on this barrel is public API on all five adapters.
|
|
54
|
+
// "A commit just reached completeRoot" — the one seam that means the same thing under every
|
|
55
|
+
// adapter: React commits synchronously, Vue/Svelte/Angular schedule it on a microtask, so each
|
|
56
|
+
// framework's after-render hook fires at a different point relative to the native commit.
|
|
68
57
|
export { registerPostCommit, unregisterPostCommit } from './post-commit.js';
|
|
69
58
|
// The aria/role -> accessibility* fold. Lives here rather than in a component wrapper because a tag
|
|
70
59
|
// has none: `fabricProps` runs it on the way to the payload, so every path gets it.
|
|
@@ -104,9 +93,8 @@ export { getSlot } from './fabric.js';
|
|
|
104
93
|
// another package (`@symbiote-native/test-utils`) and can no longer reach `./fabric` directly.
|
|
105
94
|
export { resetSlot } from './fabric.js';
|
|
106
95
|
// Imperative runtime modules: framework-agnostic native-bridge consumers (no visual, no
|
|
107
|
-
// lifecycle),
|
|
108
|
-
//
|
|
109
|
-
// real device or simulator, not headless (a headless fake resolves any module name).
|
|
96
|
+
// lifecycle), so every adapter re-exports the same module. The native module a JS API talks to is
|
|
97
|
+
// chosen per platform and can only be confirmed on a real device or simulator, not headless.
|
|
110
98
|
export { Alert } from './alert';
|
|
111
99
|
export { Share } from './share';
|
|
112
100
|
// Image statics (getSize/prefetch/queryCache/...): a stateful, native-bridge-touching module with
|
|
@@ -114,6 +102,7 @@ export { Share } from './share';
|
|
|
114
102
|
// @symbiote-native/components' renderImage lives alongside it in image-source-resolver.
|
|
115
103
|
export { imageStatics } from './image-loader.js';
|
|
116
104
|
export { setImageSourceResolver, resolveImageSource, } from './image-source-resolver.js';
|
|
105
|
+
export { setAssetSourceResolver, resolveAssetSource, } from './asset-source-resolver.js';
|
|
117
106
|
export { ActionSheetIOS } from './action-sheet-ios/index.js';
|
|
118
107
|
export { Linking } from './linking';
|
|
119
108
|
export { Vibration } from './vibration';
|
|
@@ -143,9 +132,7 @@ export { AccessibilityInfo } from './accessibility-info';
|
|
|
143
132
|
export { applyStatusBarProps, statusBarImperative, statusBarCurrentHeight, } from './status-bar';
|
|
144
133
|
export { hideTransition, STATUS_BAR_MANAGER, ANIMATED_HIDE_TRANSITION, STATIC_HIDE_TRANSITION, } from './status-bar/shared.js';
|
|
145
134
|
export { registerHostBehavior, hasHostBehaviors, hostBehaviorFor, clearHostBehaviors, appListenerFor, addDerivedNode, SLOT_DERIVED_ALL, } from './host-behavior.js';
|
|
146
|
-
//
|
|
147
|
-
// other dirtying route goes through a prop write, and a behavior
|
|
148
|
-
//
|
|
149
|
-
// prop to write. Pair it with `requestCommitFor` (exported off `./imperative` above): dirtying is
|
|
150
|
-
// not publishing.
|
|
135
|
+
// markPropsDirty is a behavior's only way to say "the fold reads state I just changed" — every
|
|
136
|
+
// other dirtying route goes through a prop write, and a derived-payload behavior has no prop to
|
|
137
|
+
// write. Pair it with requestCommitFor: dirtying is not publishing.
|
|
151
138
|
export { setBehaviorListener, markPropsDirty } from './node.js';
|