@symbiote-native/engine 1.3.1 → 1.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/build/event-value-source.d.ts +4 -0
- package/build/event-value-source.js +3 -0
- package/build/events/delivery.d.ts +9 -0
- package/build/events/delivery.js +143 -0
- package/build/events/index.js +199 -660
- package/build/events/names.d.ts +24 -0
- package/build/events/names.js +80 -0
- package/build/events/press.d.ts +20 -0
- package/build/events/press.js +89 -0
- package/build/events/responder.d.ts +6 -0
- package/build/events/responder.js +124 -0
- package/build/expo-native-view.d.ts +2 -0
- package/build/expo-native-view.js +19 -0
- package/build/imperative.d.ts +2 -0
- package/build/imperative.js +18 -1
- package/build/index.d.ts +12 -2
- package/build/index.js +8 -2
- package/build/mutation-buffer.d.ts +3 -0
- package/build/mutation-buffer.js +25 -8
- package/build/native-engine.d.ts +6 -0
- package/build/native-engine.js +27 -48
- package/build/native-tree-host.js +1 -0
- package/build/node-events.d.ts +11 -0
- package/build/node-events.js +145 -0
- package/build/node-instance.d.ts +8 -0
- package/build/node-instance.js +168 -0
- package/build/node-props.d.ts +13 -0
- package/build/node-props.js +131 -0
- package/build/node-route.d.ts +2 -0
- package/build/node-route.js +151 -0
- package/build/node-style.d.ts +15 -0
- package/build/node-style.js +214 -0
- package/build/node-tree.d.ts +6 -0
- package/build/node-tree.js +159 -0
- package/build/node-types.d.ts +70 -0
- package/build/node-types.js +36 -0
- package/build/node.d.ts +7 -97
- package/build/node.js +9 -1128
- package/build/permission-hook-runtime.d.ts +27 -0
- package/build/permission-hook-runtime.js +37 -0
- package/build/resource-controller.d.ts +6 -0
- package/build/resource-controller.js +30 -0
- package/build/tree-host.d.ts +7 -0
- package/cpp/SymbioteEngineBindings.cpp +19 -18
- package/cpp/SymbioteTree.cpp +81 -156
- package/cpp/SymbioteTree.h +6 -0
- package/package.json +2 -2
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ISymbioteNode } from '../node';
|
|
2
|
+
export declare function endsWithin(endTarget: ISymbioteNode, start: ISymbioteNode): boolean;
|
|
3
|
+
export declare function pathToRoot(from: ISymbioteNode): ISymbioteNode[];
|
|
4
|
+
export declare function lowestCommonAncestor(a: ISymbioteNode, b: ISymbioteNode): ISymbioteNode | undefined;
|
|
5
|
+
export declare function hasListenerInPath(target: ISymbioteNode, listenerName: string): boolean;
|
|
6
|
+
export declare function callOwnListener(node: ISymbioteNode, listenerName: string, nativeEvent: Record<string, unknown>): unknown;
|
|
7
|
+
export declare function bubble(target: ISymbioteNode, listenerName: string, nativeEvent: Record<string, unknown>): void;
|
|
8
|
+
/** Direct (non-bubbling) delivery: only the target's own listener fires. */
|
|
9
|
+
export declare function deliverDirect(target: ISymbioteNode, listenerName: string, nativeEvent: Record<string, unknown>): void;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Getting an event to the listeners that want it: the ancestor path, the two-phase bubble, direct
|
|
2
|
+
// delivery, and the single-node call the responder negotiation reads a boolean back from
|
|
3
|
+
import { dlog, isDebug } from '../debug.js';
|
|
4
|
+
import { ancestorsOf, parentOf } from '../host-access.js';
|
|
5
|
+
import { hasListenerFor, isAnchor, listenerFor, } from '../node.js';
|
|
6
|
+
// A press is honest only if the touch ends on the node it started on, or a descendant of it. The
|
|
7
|
+
// start node may have been unmounted mid-touch, so the walk runs out and answers false, no throw
|
|
8
|
+
export function endsWithin(endTarget, start) {
|
|
9
|
+
let node = endTarget;
|
|
10
|
+
while (node) {
|
|
11
|
+
if (node === start)
|
|
12
|
+
return true;
|
|
13
|
+
node = parentOf(node);
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
// The node chain from `from` up to the root, deepest first. The single allocation the two-phase
|
|
18
|
+
// walk indexes both ways (capture reads it reversed)
|
|
19
|
+
// ONE CROSSING, not one per level: climbing `parentOf` crossed the host boundary each step, 18
|
|
20
|
+
// questions per event on a depth-8 chain and again on every frame of every drag
|
|
21
|
+
export function pathToRoot(from) {
|
|
22
|
+
return [...ancestorsOf(from)];
|
|
23
|
+
}
|
|
24
|
+
// Depth below the root (root = 0), to align two nodes before the lockstep climb to their lowest
|
|
25
|
+
// common ancestor
|
|
26
|
+
function depthOf(node) {
|
|
27
|
+
let depth = 0;
|
|
28
|
+
for (let n = parentOf(node); n; n = parentOf(n))
|
|
29
|
+
depth++;
|
|
30
|
+
return depth;
|
|
31
|
+
}
|
|
32
|
+
// RN's `getLowestCommonAncestor` over our parent pointers: lift the deeper node to the shallower
|
|
33
|
+
// one's depth, then climb both in lockstep until they meet. Scopes the move re-negotiation
|
|
34
|
+
export function lowestCommonAncestor(a, b) {
|
|
35
|
+
let da = depthOf(a);
|
|
36
|
+
let db = depthOf(b);
|
|
37
|
+
let na = a;
|
|
38
|
+
let nb = b;
|
|
39
|
+
while (na && da > db) {
|
|
40
|
+
na = parentOf(na);
|
|
41
|
+
da--;
|
|
42
|
+
}
|
|
43
|
+
while (nb && db > da) {
|
|
44
|
+
nb = parentOf(nb);
|
|
45
|
+
db--;
|
|
46
|
+
}
|
|
47
|
+
while (na && nb) {
|
|
48
|
+
if (na === nb)
|
|
49
|
+
return na;
|
|
50
|
+
na = parentOf(na);
|
|
51
|
+
nb = parentOf(nb);
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
// Whether any node from `target` up to the root listens for `listenerName`, so the long-press
|
|
56
|
+
// timer is armed only when a handler would actually receive it
|
|
57
|
+
export function hasListenerInPath(target, listenerName) {
|
|
58
|
+
for (let node = target; node; node = parentOf(node)) {
|
|
59
|
+
if (hasListenerFor(node, listenerName))
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// Invoke one node's own listener (no bubbling) and hand back its return value, so the responder
|
|
65
|
+
// negotiation can read the boolean from `onStartShouldSetResponder`
|
|
66
|
+
export function callOwnListener(node, listenerName, nativeEvent) {
|
|
67
|
+
const listener = listenerFor(node, listenerName);
|
|
68
|
+
if (!listener)
|
|
69
|
+
return undefined;
|
|
70
|
+
return listener({
|
|
71
|
+
type: listenerName,
|
|
72
|
+
target: node,
|
|
73
|
+
currentTarget: node,
|
|
74
|
+
nativeEvent,
|
|
75
|
+
stopPropagation: () => { },
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
// Anchors (Angular's `#anchor` component hosts) never paint and have no native view. A listener on
|
|
79
|
+
// one only exists because the framework's own output binding already delivered it directly, so
|
|
80
|
+
// bubbling into it would refire the same callback twice
|
|
81
|
+
function capturedBy(node, captureName) {
|
|
82
|
+
return isAnchor(node) ? undefined : listenerFor(node, captureName);
|
|
83
|
+
}
|
|
84
|
+
// Two-phase delivery, mirroring RN's `accumulateTwoPhaseDispatches`: CAPTURE root -> target
|
|
85
|
+
// invoking each node's `<EventName>Capture` listener, then BUBBLE target -> root invoking the
|
|
86
|
+
// plain one. A `stopPropagation` in capture halts before bubble ever runs
|
|
87
|
+
export function bubble(target, listenerName, nativeEvent) {
|
|
88
|
+
let stopped = false;
|
|
89
|
+
const stopPropagation = () => {
|
|
90
|
+
stopped = true;
|
|
91
|
+
};
|
|
92
|
+
// Built target -> root once, then read in reverse for capture and forward for bubble. Re-walking
|
|
93
|
+
// `parentOf` for the second pass crossed the host boundary per level and was the expensive half
|
|
94
|
+
const captureName = `${listenerName}Capture`;
|
|
95
|
+
const path = pathToRoot(target);
|
|
96
|
+
for (let i = path.length - 1; i >= 0; i--) {
|
|
97
|
+
const node = path[i];
|
|
98
|
+
const listener = capturedBy(node, captureName);
|
|
99
|
+
if (listener) {
|
|
100
|
+
if (isDebug())
|
|
101
|
+
dlog(`event ${listenerName} capture on ${node.component}`);
|
|
102
|
+
listener({
|
|
103
|
+
type: listenerName,
|
|
104
|
+
target,
|
|
105
|
+
currentTarget: node,
|
|
106
|
+
nativeEvent,
|
|
107
|
+
stopPropagation,
|
|
108
|
+
});
|
|
109
|
+
if (stopped)
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const node of path) {
|
|
114
|
+
const listener = isAnchor(node)
|
|
115
|
+
? undefined
|
|
116
|
+
: listenerFor(node, listenerName);
|
|
117
|
+
if (listener) {
|
|
118
|
+
const event = {
|
|
119
|
+
type: listenerName,
|
|
120
|
+
target,
|
|
121
|
+
currentTarget: node,
|
|
122
|
+
nativeEvent,
|
|
123
|
+
stopPropagation,
|
|
124
|
+
};
|
|
125
|
+
listener(event);
|
|
126
|
+
if (stopped)
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Direct (non-bubbling) delivery: only the target's own listener fires. */
|
|
132
|
+
export function deliverDirect(target, listenerName, nativeEvent) {
|
|
133
|
+
const listener = listenerFor(target, listenerName);
|
|
134
|
+
if (!listener)
|
|
135
|
+
return;
|
|
136
|
+
listener({
|
|
137
|
+
type: listenerName,
|
|
138
|
+
target,
|
|
139
|
+
currentTarget: target,
|
|
140
|
+
nativeEvent,
|
|
141
|
+
stopPropagation: () => { },
|
|
142
|
+
});
|
|
143
|
+
}
|