@symbiote-native/engine 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/build/accessibility-props.d.ts +20 -0
- package/build/accessibility-props.js +213 -0
- package/build/animated/graph.d.ts +2 -0
- package/build/animated/graph.js +14 -0
- package/build/animated/host-binding.d.ts +39 -0
- package/build/animated/host-binding.js +263 -0
- package/build/animated/leaf-lifecycle.js +10 -22
- package/build/app-registry/index.d.ts +1 -0
- package/build/app-registry/index.js +15 -5
- package/build/commit.d.ts +22 -0
- package/build/commit.js +509 -78
- package/build/debug.js +10 -4
- package/build/events/index.js +172 -87
- package/build/fabric-props.js +179 -10
- package/build/fabric.d.ts +11 -3
- package/build/fabric.js +19 -2
- package/build/host-behavior.d.ts +84 -0
- package/build/host-behavior.js +374 -0
- package/build/host-instance/index.d.ts +2 -10
- package/build/host-instance/index.js +13 -46
- package/build/index.d.ts +7 -1
- package/build/index.js +23 -4
- package/build/node.d.ts +115 -5
- package/build/node.js +737 -70
- package/build/pan-responder/index.d.ts +2 -2
- package/build/pan-responder/index.js +10 -4
- package/build/style-registry/index.d.ts +2 -0
- package/build/style-registry/index.js +79 -0
- package/build/styles.d.ts +5 -1
- package/build/surface.js +21 -4
- package/build/view-config.js +6 -0
- package/package.json +12 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The AnimatedProps leaf lifecycle every Animated.* wrapper needs: build a leaf from the current
|
|
2
|
-
// props, swap it into the value graph, bind it to the committed node, go native when asked
|
|
3
|
-
//
|
|
2
|
+
// props, swap it into the value graph, bind it to the committed node, and go native when asked.
|
|
3
|
+
// Framework-agnostic on purpose - it knows nothing about hooks,
|
|
4
4
|
// effects, change detection or reactivity, only the engine's own Animated primitives.
|
|
5
5
|
//
|
|
6
6
|
// WHY THIS LIVES IN THE ENGINE. It used to live four times, once per adapter (React's
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
// What stays in the adapter: WHEN to call reconcile (an effect, onUpdated, ngOnChanges, a $effect)
|
|
16
16
|
// and HOW to find the host node (a ref, a ViewChild, a shim). Everything below is the same for all.
|
|
17
17
|
import { AnimatedProps } from './props.js';
|
|
18
|
-
import { attachNativeEventHandler } from './event.js';
|
|
19
18
|
import { dlog } from '../debug.js';
|
|
20
19
|
// Diagnostic-only, DEBUG-gated: a process-wide sequence number so every reconcile call across
|
|
21
20
|
// every Animated.* instance in a log dump is individually identifiable and orderable.
|
|
@@ -66,7 +65,6 @@ function describeTransform(value) {
|
|
|
66
65
|
}
|
|
67
66
|
export function createAnimatedLeafLifecycle(label) {
|
|
68
67
|
let attached = null;
|
|
69
|
-
let eventDetachers = [];
|
|
70
68
|
// Diagnostic-only: the last node identity, plus a reentrancy flag to catch reconcile() being
|
|
71
69
|
// called AGAIN from inside its own call stack - the smoking-gun shape for a synchronous
|
|
72
70
|
// same-flush loop, as opposed to merely "called often".
|
|
@@ -77,11 +75,6 @@ export function createAnimatedLeafLifecycle(label) {
|
|
|
77
75
|
let lastWantsNative = false;
|
|
78
76
|
// Canceller for a native bind the caller deferred and that has not run yet.
|
|
79
77
|
let cancelPendingBind;
|
|
80
|
-
function detachEvents() {
|
|
81
|
-
for (const detach of eventDetachers)
|
|
82
|
-
detach();
|
|
83
|
-
eventDetachers = [];
|
|
84
|
-
}
|
|
85
78
|
return {
|
|
86
79
|
reconcile(props, node, wantsNative, scheduleNativeBind) {
|
|
87
80
|
const seq = ++globalReconcileSeq;
|
|
@@ -142,23 +135,19 @@ export function createAnimatedLeafLifecycle(label) {
|
|
|
142
135
|
if (attached !== null && attached !== newLeaf)
|
|
143
136
|
attached.__detach();
|
|
144
137
|
attached = newLeaf;
|
|
145
|
-
// The native half, which a caller may defer.
|
|
146
|
-
//
|
|
147
|
-
//
|
|
148
|
-
//
|
|
138
|
+
// The native half, which a caller may defer.
|
|
139
|
+
//
|
|
140
|
+
// It used to native-attach every `Animated.event` prop here as well. It must not any more:
|
|
141
|
+
// a wrapper hands those same props DOWN to a host element, so they reach `routeProp`,
|
|
142
|
+
// which binds them itself (`host-binding.ts`, `bindAnimatedEvent`) — that is what makes a
|
|
143
|
+
// bare `<scroll-view onScroll={…} />` work with no wrapper at all. Doing it here too
|
|
144
|
+
// registered the SAME mapping twice on one view tag, caught by the Vue and Svelte
|
|
145
|
+
// wrapper tests the day the engine half landed.
|
|
149
146
|
const bindNative = () => {
|
|
150
147
|
if (node !== null)
|
|
151
148
|
newLeaf.setNativeView(node);
|
|
152
149
|
if (wantsNative)
|
|
153
150
|
newLeaf.__makeNative();
|
|
154
|
-
detachEvents();
|
|
155
|
-
if (node === null)
|
|
156
|
-
return;
|
|
157
|
-
for (const key of Object.keys(props)) {
|
|
158
|
-
const attachment = attachNativeEventHandler(node, key, props[key]);
|
|
159
|
-
if (attachment !== undefined)
|
|
160
|
-
eventDetachers.push(attachment.detach);
|
|
161
|
-
}
|
|
162
151
|
};
|
|
163
152
|
cancelPendingBind?.();
|
|
164
153
|
cancelPendingBind = undefined;
|
|
@@ -175,7 +164,6 @@ export function createAnimatedLeafLifecycle(label) {
|
|
|
175
164
|
teardown() {
|
|
176
165
|
cancelPendingBind?.();
|
|
177
166
|
cancelPendingBind = undefined;
|
|
178
|
-
detachEvents();
|
|
179
167
|
if (attached !== null) {
|
|
180
168
|
attached.__detach();
|
|
181
169
|
attached = null;
|
|
@@ -14,6 +14,7 @@ export type ITaskCanceller = () => void;
|
|
|
14
14
|
export type ITaskCancelProvider = () => ITaskCanceller;
|
|
15
15
|
export interface IHostRegistrar {
|
|
16
16
|
registerRunnable(appKey: string, run: IRunnable): string;
|
|
17
|
+
registerCancellableHeadlessTask?(taskKey: string, taskProvider: ITaskProvider, taskCancelProvider: ITaskCancelProvider): void;
|
|
17
18
|
unmountAtRootTag?(rootTag: IRootTag): void;
|
|
18
19
|
}
|
|
19
20
|
export interface IAppRegistry<TComponentProvider, TWrapperComponentProvider> {
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
// the one thing each adapter supplies; everything else (registry bookkeeping, sections, the
|
|
7
7
|
// host-registrar bridge, headless tasks) is byte-identical across adapters and lives here once.
|
|
8
8
|
//
|
|
9
|
-
// The catch:
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// (setHostRegistrar), so the core stays react-native-free and the app glue wires the host once
|
|
13
|
-
// at startup.
|
|
9
|
+
// The catch: native invokes RN's registered callable AppRegistry for both surface runnables and
|
|
10
|
+
// headless tasks; it cannot see this local registry. `setHostRegistrar` mirrors those native-facing
|
|
11
|
+
// registrations there while the core remains react-native-free.
|
|
14
12
|
import { getNativeModule } from '../native-modules/index.js';
|
|
15
13
|
import { dlog } from '../debug.js';
|
|
16
14
|
const HEADLESS_TASK_MODULE = 'HeadlessJsTaskSupport';
|
|
@@ -121,6 +119,7 @@ export function createAppRegistry(runnableFor) {
|
|
|
121
119
|
}
|
|
122
120
|
taskProviders.set(taskKey, taskProvider);
|
|
123
121
|
taskCancelProviders.set(taskKey, taskCancelProvider);
|
|
122
|
+
hostRegistrar?.registerCancellableHeadlessTask?.(taskKey, taskProvider, taskCancelProvider);
|
|
124
123
|
},
|
|
125
124
|
startHeadlessTask(taskId, taskKey, data) {
|
|
126
125
|
runHeadlessTask(taskId, taskKey, data);
|
|
@@ -138,7 +137,18 @@ export function createAppRegistry(runnableFor) {
|
|
|
138
137
|
return {
|
|
139
138
|
AppRegistry,
|
|
140
139
|
setHostRegistrar(registrar) {
|
|
140
|
+
if (hostRegistrar === registrar)
|
|
141
|
+
return;
|
|
141
142
|
hostRegistrar = registrar;
|
|
143
|
+
// Headless tasks are commonly registered before adapter bootstrap attaches RN's callable
|
|
144
|
+
// AppRegistry. Replay only this missing native-facing registry; app runnables retain their
|
|
145
|
+
// existing register-after-bootstrap contract.
|
|
146
|
+
for (const [taskKey, taskProvider] of taskProviders) {
|
|
147
|
+
const taskCancelProvider = taskCancelProviders.get(taskKey);
|
|
148
|
+
if (taskCancelProvider !== undefined) {
|
|
149
|
+
registrar.registerCancellableHeadlessTask?.(taskKey, taskProvider, taskCancelProvider);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
142
152
|
},
|
|
143
153
|
};
|
|
144
154
|
}
|
package/build/commit.d.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { type IFabricNode, type IRootTag, type IMeasureOnSuccess, type IMeasureInWindowOnSuccess, type IMeasureLayoutOnSuccess } from './fabric';
|
|
2
2
|
import { type ISymbioteNode } from './node';
|
|
3
3
|
export { processColor, setColorProcessor } from './platform-color';
|
|
4
|
+
declare global {
|
|
5
|
+
var __SYMBIOTE_BATCH_CREATE__: boolean | undefined;
|
|
6
|
+
}
|
|
4
7
|
export declare function disposeRoot(rootTag: IRootTag): void;
|
|
5
8
|
export declare function commitChildren(rootTag: IRootTag, children: readonly ISymbioteNode[]): void;
|
|
6
9
|
export interface ICommitProfile {
|
|
7
10
|
commits: number;
|
|
8
11
|
walkMs: number;
|
|
9
12
|
nodesVisited: number;
|
|
13
|
+
/** Update-path nodes that rebuilt their Fabric payload and deep-compared it. */
|
|
14
|
+
propsBuilt: number;
|
|
15
|
+
/** Update-path nodes that re-cloned for a child but reused the committed payload by reference. */
|
|
16
|
+
propsReused: number;
|
|
10
17
|
propWrites: number;
|
|
11
18
|
propNoops: number;
|
|
12
19
|
childScans: number;
|
|
@@ -16,7 +23,22 @@ export interface ICommitProfile {
|
|
|
16
23
|
childFlattenWidest: number;
|
|
17
24
|
}
|
|
18
25
|
export declare function readCommitProfile(): ICommitProfile;
|
|
26
|
+
export declare function flushNativeProps(): void;
|
|
19
27
|
export declare function setNativeProps(node: ISymbioteNode, partial: Record<string, unknown>): void;
|
|
28
|
+
/**
|
|
29
|
+
* Publish a node whose props were changed OUTSIDE any renderer mutation.
|
|
30
|
+
*
|
|
31
|
+
* Dirtying is not publishing. Every other write reaches Fabric because the framework's own commit
|
|
32
|
+
* follows it; a change driven by a NATIVE EVENT has no such follow-up — `native-events.ts`
|
|
33
|
+
* requests no commit and no adapter does either, so a node marked dirty from an event handler
|
|
34
|
+
* simply stays dirty. The host-behavior press path (`setNodePressed` for `:active`) is the first
|
|
35
|
+
* caller that is not `setNativeProps`, and `setNodeHidden`'s React twin never needed it because
|
|
36
|
+
* the reconciler is already in its commit phase when it calls.
|
|
37
|
+
*
|
|
38
|
+
* Queued rather than committed on the spot, sharing `setNativeProps`' batch: several writes in one
|
|
39
|
+
* task publish together at the microtask boundary, one commit per surface.
|
|
40
|
+
*/
|
|
41
|
+
export declare function requestCommitFor(node: ISymbioteNode): void;
|
|
20
42
|
export declare function getNativeTag(node: ISymbioteNode): number | undefined;
|
|
21
43
|
export declare function whenCommitted(node: ISymbioteNode, action: () => void): () => void;
|
|
22
44
|
export declare function getNativeNode(node: ISymbioteNode): IFabricNode | undefined;
|