@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.
Files changed (47) hide show
  1. package/build/event-value-source.d.ts +4 -0
  2. package/build/event-value-source.js +3 -0
  3. package/build/events/delivery.d.ts +9 -0
  4. package/build/events/delivery.js +143 -0
  5. package/build/events/index.js +199 -660
  6. package/build/events/names.d.ts +24 -0
  7. package/build/events/names.js +80 -0
  8. package/build/events/press.d.ts +20 -0
  9. package/build/events/press.js +89 -0
  10. package/build/events/responder.d.ts +6 -0
  11. package/build/events/responder.js +124 -0
  12. package/build/expo-native-view.d.ts +2 -0
  13. package/build/expo-native-view.js +19 -0
  14. package/build/imperative.d.ts +2 -0
  15. package/build/imperative.js +18 -1
  16. package/build/index.d.ts +12 -2
  17. package/build/index.js +8 -2
  18. package/build/mutation-buffer.d.ts +3 -0
  19. package/build/mutation-buffer.js +25 -8
  20. package/build/native-engine.d.ts +6 -0
  21. package/build/native-engine.js +27 -48
  22. package/build/native-tree-host.js +1 -0
  23. package/build/node-events.d.ts +11 -0
  24. package/build/node-events.js +145 -0
  25. package/build/node-instance.d.ts +8 -0
  26. package/build/node-instance.js +168 -0
  27. package/build/node-props.d.ts +13 -0
  28. package/build/node-props.js +131 -0
  29. package/build/node-route.d.ts +2 -0
  30. package/build/node-route.js +151 -0
  31. package/build/node-style.d.ts +15 -0
  32. package/build/node-style.js +214 -0
  33. package/build/node-tree.d.ts +6 -0
  34. package/build/node-tree.js +159 -0
  35. package/build/node-types.d.ts +70 -0
  36. package/build/node-types.js +36 -0
  37. package/build/node.d.ts +7 -97
  38. package/build/node.js +9 -1128
  39. package/build/permission-hook-runtime.d.ts +27 -0
  40. package/build/permission-hook-runtime.js +37 -0
  41. package/build/resource-controller.d.ts +6 -0
  42. package/build/resource-controller.js +30 -0
  43. package/build/tree-host.d.ts +7 -0
  44. package/cpp/SymbioteEngineBindings.cpp +19 -18
  45. package/cpp/SymbioteTree.cpp +81 -156
  46. package/cpp/SymbioteTree.h +6 -0
  47. package/package.json +2 -2
@@ -0,0 +1,4 @@
1
+ import type { IEventSubscription } from './native-events';
2
+ export type IEventValueSource<TValue, TEvent extends string = string> = {
3
+ addListener: (event: TEvent, listener: (value: TValue) => void) => IEventSubscription;
4
+ };
@@ -0,0 +1,3 @@
1
+ // A source that emits a named event carrying its own next value (`useAudioPlayerStatus`, ...)
2
+ // `TEvent` generic so a `SharedObject`'s own literal-keyed `addListener` structurally matches
3
+ export {};
@@ -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
+ }