@symbiote-native/engine 1.3.0 → 1.4.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 (79) hide show
  1. package/build/accessibility-props.d.ts +0 -11
  2. package/build/accessibility-props.js +30 -68
  3. package/build/animated/graph.js +1 -1
  4. package/build/animated/leaf-lifecycle.js +2 -2
  5. package/build/asset-source-resolver.d.ts +2 -0
  6. package/build/asset-source-resolver.js +13 -0
  7. package/build/back-handler/index.d.ts +1 -5
  8. package/build/back-handler/index.js +0 -6
  9. package/build/debug.js +8 -22
  10. package/build/dispatch.js +3 -9
  11. package/build/events/delivery.d.ts +9 -0
  12. package/build/events/delivery.js +143 -0
  13. package/build/events/index.js +199 -660
  14. package/build/events/names.d.ts +24 -0
  15. package/build/events/names.js +80 -0
  16. package/build/events/press.d.ts +20 -0
  17. package/build/events/press.js +89 -0
  18. package/build/events/responder.d.ts +6 -0
  19. package/build/events/responder.js +124 -0
  20. package/build/fabric-props.js +74 -179
  21. package/build/fabric.d.ts +0 -13
  22. package/build/fabric.js +18 -38
  23. package/build/host-access.d.ts +1 -128
  24. package/build/host-access.js +96 -205
  25. package/build/host-behavior.d.ts +0 -100
  26. package/build/host-behavior.js +125 -311
  27. package/build/image-loader.js +10 -23
  28. package/build/image-source-resolver.js +3 -7
  29. package/build/image-source-write.d.ts +0 -11
  30. package/build/image-source-write.js +14 -34
  31. package/build/imperative.d.ts +2 -28
  32. package/build/imperative.js +60 -93
  33. package/build/index.d.ts +6 -2
  34. package/build/index.js +29 -39
  35. package/build/mutation-buffer.d.ts +3 -177
  36. package/build/mutation-buffer.js +162 -316
  37. package/build/native-engine.d.ts +6 -102
  38. package/build/native-engine.js +60 -141
  39. package/build/native-events.js +9 -18
  40. package/build/native-tree-host.d.ts +0 -21
  41. package/build/native-tree-host.js +15 -31
  42. package/build/node-events.d.ts +11 -0
  43. package/build/node-events.js +145 -0
  44. package/build/node-instance.d.ts +8 -0
  45. package/build/node-instance.js +168 -0
  46. package/build/node-props.d.ts +13 -0
  47. package/build/node-props.js +131 -0
  48. package/build/node-route.d.ts +2 -0
  49. package/build/node-route.js +151 -0
  50. package/build/node-style.d.ts +15 -0
  51. package/build/node-style.js +214 -0
  52. package/build/node-tree.d.ts +6 -0
  53. package/build/node-tree.js +159 -0
  54. package/build/node-types.d.ts +70 -0
  55. package/build/node-types.js +36 -0
  56. package/build/node.d.ts +7 -309
  57. package/build/node.js +9 -1564
  58. package/build/post-commit.js +3 -8
  59. package/build/process-aspect-ratio.js +3 -7
  60. package/build/process-background-longhands.js +10 -19
  61. package/build/process-filter.js +11 -19
  62. package/build/process-font-variant.js +3 -7
  63. package/build/registry.d.ts +0 -33
  64. package/build/registry.js +22 -57
  65. package/build/report-error.js +4 -18
  66. package/build/structured-style.d.ts +0 -9
  67. package/build/structured-style.js +16 -31
  68. package/build/styles.js +3 -6
  69. package/build/surface.d.ts +0 -26
  70. package/build/surface.js +29 -76
  71. package/build/text-input-state.js +4 -8
  72. package/build/touch-history.js +5 -11
  73. package/build/tree-host.d.ts +7 -270
  74. package/build/tree-host.js +63 -153
  75. package/build/view-config.js +17 -37
  76. package/cpp/SymbioteEngineBindings.cpp +19 -18
  77. package/cpp/SymbioteTree.cpp +81 -156
  78. package/cpp/SymbioteTree.h +6 -0
  79. package/package.json +2 -2
package/build/node.d.ts CHANGED
@@ -1,310 +1,8 @@
1
- import type { IMeasureOnSuccess, IMeasureInWindowOnSuccess, IMeasureLayoutOnSuccess } from './fabric';
2
- import { type IClassNameValue } from './style-registry';
3
- import { type IHostBehavior, type IPayloadFold } from './host-behavior';
4
- import { type ITreeCensus } from './tree-host';
5
- declare const BRAND: unique symbol;
6
- export declare const RAW_TEXT_COMPONENT = "RCTRawText";
7
- export declare const TEXT_COMPONENT = "RCTText";
8
- export declare const VIRTUAL_TEXT_COMPONENT = "RCTVirtualText";
9
- export interface ISymbioteEvent {
10
- type: string;
11
- target: ISymbioteNode;
12
- currentTarget: ISymbioteNode;
13
- nativeEvent: Record<string, unknown>;
14
- stopPropagation: () => void;
15
- }
16
- export type IListener = (event: ISymbioteEvent) => unknown;
17
- export declare function isSymbioteEvent(value: unknown): value is ISymbioteEvent;
18
- export interface ISymbioteNode {
19
- readonly [BRAND]: true;
20
- component: string;
21
- readonly isText: boolean;
22
- listeners: Map<string, IListener> | undefined;
23
- /**
24
- * Whether this node's host behavior declared `afterCommit`.
25
- *
26
- * Read on every prop write, exactly as `hasAriaAlias` beside it is and for the same reason: the
27
- * alternative is a Set lookup per write, on the hottest path in the engine. What it gates is the
28
- * NARROWING of the post-commit beat — the hook runs for nodes whose props moved rather than for
29
- * every mounted behavior, which is what took TextInput's `propOf` off every commit (F-67).
30
- *
31
- * Set once at `createElement`, by `attachHostBehavior`. Not sticky in the `hasAriaAlias` sense:
32
- * it describes the behavior's shape, and a behavior is attached once and detached whole.
33
- */
34
- hasCommitHook: boolean;
35
- /**
36
- * Whether this node's three image-source props are resolved on the way IN — see
37
- * `image-source-write.ts` for why the asset lookup happens at write time and not in the payload.
38
- *
39
- * A boolean read per write, same shape and same reason as `hasCommitHook` above. It has to be
40
- * gated on the NODE rather than applied to the key everywhere, because the resolution normalises
41
- * to Image's ARRAY shape: a `WebView` or a third-party video view also spells `source`, and
42
- * wrapping theirs would hand native a shape it does not read.
43
- *
44
- * Set once at `createElement`, by `attachHostBehavior`, for the behavior that declares it.
45
- */
46
- resolvesImageSources: boolean;
47
- nativeIdWinsOverId: boolean;
48
- payloadFold: IPayloadFold | undefined;
49
- /**
50
- * The behavior that attached to this node, or `undefined` for the vast majority that have none.
51
- *
52
- * A field for the same reason `payloadFold` above it is one, and set on the same line: every
53
- * reader is a per-node path at list scale — the teardown sweep touches every node of a removed
54
- * subtree, and `routeProp`'s slot/owned-listener questions run per prop write. A `WeakMap` probe
55
- * is the dearest way to ask a question whose answer is almost always "none".
56
- *
57
- * Owned by `host-behavior.ts`; `attachHostBehavior` is the only writer.
58
- */
59
- hostBehavior: IHostBehavior | undefined;
60
- styleParts: IClassStyleParts | undefined;
61
- childHost: ISymbioteNode | undefined;
62
- wrapper: ISymbioteNode | undefined;
63
- mayHaveChildren: boolean;
64
- /**
65
- * Whether the teardown sweep has released this node and not seen it come back.
66
- *
67
- * Owned by `host-behavior.ts` — see `detachOne` / `reattachHostBehaviors`. A field rather than
68
- * the `WeakSet` it was, because the sweep reads and writes it for EVERY node of a removed
69
- * subtree (ten thousand on a thousand-row clear) and every insert reads it to decide whether to
70
- * walk at all, which is the ~9 000-call path of a create.
71
- */
72
- isTornDown: boolean;
73
- slot: number;
74
- slotBatch: number;
75
- measure(callback: IMeasureOnSuccess): void;
76
- measureInWindow(callback: IMeasureInWindowOnSuccess): void;
77
- measureLayout(relativeToNativeNode: ISymbioteNode | number, onSuccess: IMeasureLayoutOnSuccess, onFail?: () => void): void;
78
- setNativeProps(nativeProps: Record<string, unknown>): void;
79
- focus(): void;
80
- blur(): void;
81
- scrollTo(options?: {
82
- x?: number;
83
- y?: number;
84
- animated?: boolean;
85
- }): void;
86
- scrollToEnd(options?: {
87
- animated?: boolean;
88
- }): void;
89
- flashScrollIndicators(): void;
90
- }
91
- /**
92
- * Mint an element and record its creation.
93
- *
94
- * The node object IS the handle: it is what the ops address, what the host attaches its native node
95
- * to, and what Fabric hands back as an event target. Nothing else is allocated.
96
- */
97
- export declare function createElement(component: string, isText?: boolean, tag?: string): ISymbioteNode;
98
- /**
99
- * `tag` mirrors `createElement`'s, and a raw text needs it for the same reason an element does: the
100
- * behavior registry is keyed by tag, so a node that does not hand one over cannot have a rule.
101
- *
102
- * A raw text carrying a tag looks odd and is not. It has no props an app can write — its whole
103
- * payload is `text` — but its CONTENT can still be a function of the platform rather than of the
104
- * app: Button renders its title uppercased on Android (`Button.js:352-353`), which is a user-agent
105
- * decision about a control, not anything the app asked for. That rule needs the node to be
106
- * identifiable, and a tag is how this codebase identifies one.
107
- *
108
- * Defaulted to the raw-text component, so every existing caller is unchanged and pays the same
109
- * lookup miss `createElement` already pays for a node nobody registered.
110
- */
111
- export declare function createRawText(text: string, tag?: string): ISymbioteNode;
112
- export declare function isSymbioteNode(value: unknown): value is ISymbioteNode;
113
- export declare function debugNodeId(node: ISymbioteNode): number;
114
- export declare const ANCHOR_COMPONENT = "#anchor";
115
- export declare function createAnchor(): ISymbioteNode;
116
- export declare const VOID_COMPONENT = "#void";
117
- export declare function createVoid(): ISymbioteNode;
118
- /**
119
- * The sentinel a SURFACE's own root node carries, so `parentOf` can stop there.
120
- *
121
- * A top-level node must answer `undefined` for its parent, and adapters depend on the exact miss:
122
- * Angular reads `null` as "defer, `<ng-content>` will place this" (answering the surface once
123
- * mounted every FlatList cell at top level), while Vue and Solid spell `?? surface` at their call
124
- * sites and would be handed an object that is not the `SymbioteSurface` they compare against. One
125
- * component name, read in JS, keeps all three right without a second structure.
126
- *
127
- * It is a JS-side name only. What goes over the wire is `RCTView`, because this node is REAL.
128
- */
129
- export declare const SURFACE_COMPONENT = "#surface";
130
- /**
131
- * One persistent root view per surface, mirroring RN's own AppContainer — `renderApplication` wraps
132
- * the app in `<View style={{flex:1}} pointerEvents="box-none">`.
133
- *
134
- * It is not decoration. Without `flex: 1` a non-flex root collapses to content height, and without
135
- * `box-none` a touch landing outside the app's own children has no escape. Living here rather than
136
- * in each adapter's `mount()` gives every framework a full-screen root for free and keeps layout in
137
- * the shared layer (`<adapters_stay_thin>`).
138
- *
139
- * The surface therefore commits as ONE node rather than hoisting its children into the child set —
140
- * which is why the host materializes the node `OP_COMMIT` names instead of walking its children. An
141
- * anchor in that position still hoists, so the host handles both without a special case.
142
- */
143
- export declare function createSurfaceRoot(): ISymbioteNode;
144
- export declare function isAnchor(node: ISymbioteNode): boolean;
145
- /**
146
- * Change which Fabric view a node commits as, keeping the node's identity.
147
- *
148
- * The POLICY stays out of the engine: which prop decides, and which view it decides between, lives
149
- * in `HOST_PRIMITIVES` and is read by `resolveIntrinsicTag` in `@symbiote-native/components`. The
150
- * engine only knows how to swap the name — the same split every other spec-driven fold has here.
151
- *
152
- * A no-op when the name is unchanged, so a renderer may call it on every update without comparing
153
- * first.
154
- *
155
- * The JS field and the op BOTH move, and both are load-bearing. `node.component` is what the aria
156
- * fold, the behavior registry and `fabricProps` key on; the op is what makes the host re-create the
157
- * node under the new name, since no prop write moves a node between native views.
158
- */
159
- export declare function setNodeComponent(node: ISymbioteNode, component: string): void;
160
- export declare function takePropStats(): {
161
- writes: number;
162
- };
163
- export declare function takePropKeyTally(): ReadonlyMap<string, number>;
164
- export declare function setProp(node: ISymbioteNode, key: string, value: unknown): void;
165
- /**
166
- * The one place a prop reaches the wire, and the only place that can keep a function off it.
167
- *
168
- * `setNativeProps` calls this rather than `recordSetProp` for that reason — it is the path that has
169
- * no `routeProp` in front of it.
170
- */
171
- export declare function writeProp(node: ISymbioteNode, key: string, value: unknown): void;
172
- /** What `propOf` consults before asking the host. `undefined` when nothing was stashed. */
173
- export declare function functionPropOf(node: ISymbioteNode, key: string): unknown;
174
- /**
175
- * The same stash, whole — what `propsOf` layers over the host's answer.
176
- *
177
- * `undefined` rather than an empty Map for a node that stashed nothing, which is nearly every node:
178
- * the caller then hands back the host's own object instead of copying it.
179
- */
180
- export declare function functionPropsOf(node: ISymbioteNode): ReadonlyMap<string, unknown> | undefined;
181
- /**
182
- * "Rebuild this node's payload — the fold reads state I just changed."
183
- *
184
- * A behavior whose payload is DERIVED has no prop to write: the sticky header's debounced
185
- * translateY lives in its own runtime, not on the node, so nothing names the node and the host
186
- * never marks it. This is the one route that says so directly.
187
- *
188
- * Dirtying is not publishing — pair it with `requestCommitFor` (imperative.ts).
189
- */
190
- export declare function markPropsDirty(node: ISymbioteNode): void;
191
- /**
192
- * Install a listener the BEHAVIOR owns, bypassing the ownership check.
193
- *
194
- * `setEventListener` diverts an owned name into the stash, which is right for an app listener and
195
- * circular for the behavior's own dispatcher — it would stash itself and never occupy the slot it
196
- * exists to hold. This is the one writer allowed past that gate.
197
- *
198
- * `undefined` removes it, gate flag included. A behavior whose dispatcher is conditional needs
199
- * that as much as it needs the install: ScrollView takes the owner's `layout` only while the app
200
- * or an inverted sticky header wants it, and a one-way installer leaves `onLayout: true` standing
201
- * in the payload of a ScrollView that no longer reads the event.
202
- */
203
- export declare function setBehaviorListener(node: ISymbioteNode, name: string, listener: IListener | undefined): void;
204
- export declare function setEventListener(node: ISymbioteNode, name: string, value: unknown): void;
205
- export interface IClassStyleParts {
206
- classStyle: unknown;
207
- explicitStyle: unknown;
208
- hiddenStyle: unknown;
209
- className: IClassNameValue | undefined;
210
- isPressed: boolean;
211
- activeStyle: unknown;
212
- activeStyleFromCallback: boolean;
213
- published: readonly unknown[] | undefined;
214
- }
215
- /**
216
- * Is this rebuilt style the same style, key for key?
217
- *
218
- * A component body that writes its style inline hands over a FRESH object every render, equal to
219
- * the one already standing — the commonest shape any app produces, and one `Object.is` cannot see.
220
- * Without this the write crosses into the host, becomes a `folly::dynamic`, and is only THEN found
221
- * to be unchanged. Measured on `build-release` (`no-op-rerender-cost.itest.ts`), 1 000 rows
222
- * re-rendered with nothing changed: 9.7 ms against 0.3 ms for the same app with its style hoisted,
223
- * and 5.2 ms of that was the conversion. The cheapest place to refuse a write is the earliest place
224
- * that can see it is a no-op.
225
- *
226
- * SHALLOW AND CONSERVATIVE, both deliberately. A nested value (a transform list, a shadow, a style
227
- * array) reports "not the same" rather than being compared deeply, because a deep compare makes this
228
- * guard cost the size of the style — which is the cost it exists to avoid. Those keep crossing and
229
- * the host's own `diffProps` refuses them exactly as before, so being wrong here is slow, never
230
- * incorrect.
231
- *
232
- * `undefined` on either side also reports "not the same", which is what lets the key COUNT stand in
233
- * for a key-set comparison: equal counts plus every key of `next` matching a defined value in
234
- * `standing` cannot leave a key unaccounted for.
235
- */
236
- export declare function isSameShallowStyle(next: unknown, standing: unknown): boolean;
237
- /**
238
- * Stop a node painting without unmounting it, or let it paint again.
239
- *
240
- * The seam React's `Activity`/`Suspense` reach for through `hideInstance`/`unhideInstance`. It
241
- * lives in the engine rather than an adapter because the reversibility problem — restoring the
242
- * author's style byte for byte — belongs to whoever owns the style merge, and that is here.
243
- */
244
- export declare function setNodeHidden(node: ISymbioteNode, hidden: boolean): void;
245
- /**
246
- * Put a node into (or out of) its pressed state, so `.x:active` rules apply.
247
- *
248
- * The engine-owned half of what `:active` is on the web: the press state resolves BELOW the
249
- * framework and never crosses into it, which is what lets a pressable be an intrinsic tag rather
250
- * than a component (`.claude/rules/host-primitive-tier.md`, tier 2). A component is forced only
251
- * when the TEMPLATE must read the state — `v-slot="{ pressed }"` and the function form of `style`
252
- * — and this exists so the common case does not have to.
253
- *
254
- * Costs nothing when no `:active` rule is registered anywhere: `resolveActiveClassName` hands back
255
- * the very same object the unpressed path returns, so `isAlreadyPublished` turns the re-push away
256
- * and the node is never dirtied.
257
- */
258
- export declare function setNodePressed(node: ISymbioteNode, pressed: boolean): void;
259
- /**
260
- * Tell the host a behavior's FEEDBACK is showing — TouchableHighlight's underlay, and only that.
261
- *
262
- * The sibling of `setNodePressed` and deliberately NOT the same bit. Press state drives `:active`
263
- * class resolution, which happens in JS because a class name resolves against a JS registry; this
264
- * drives a rule that lives in C++ (`foldTouchableHighlightUnderlay`), so it crosses as one op rather
265
- * than resolving to a style here. And the two are genuinely different facts: RN holds the underlay
266
- * past release so a fast tap still flashes, so `shown` LAGS `pressed` by a `delayPressOut` timer.
267
- *
268
- * No style is computed on this side at all, which is the whole point — the two props the rule reads
269
- * (`underlayColor`, `activeOpacity`) are ones the engine already strips from the payload, so the
270
- * values and their defaults live in one place instead of being erased in C++ and reached around for
271
- * in JS.
272
- */
273
- export declare function setNodeUnderlayShown(node: ISymbioteNode, shown: boolean): void;
274
- /**
275
- * Forget what was last published, so the next `pushClassStyle` cannot be turned away.
276
- *
277
- * The one caller is `setNativeProps` (imperative.ts), which writes the style slot past this file —
278
- * see the note on `IClassStyleParts.published` for why the restore path depends on this. A no-op for
279
- * a node nobody has styled, which is why it is not `stylePartsOf(node).published = undefined`: that
280
- * would allocate the parts on a node that has none.
281
- */
282
- export declare function clearPublishedStyle(node: ISymbioteNode): void;
283
- export declare function getExplicitStyle(node: ISymbioteNode): unknown;
284
- /**
285
- * The `[classStyle, explicitStyle]` pair the node currently PUBLISHES — the same value
286
- * `commitClassStyle` writes, in the same order, so `flattenStyle` collapses it the way Fabric will.
287
- *
288
- * For a caller that wants the merged answer without a host: the pair reaches the payload as an op,
289
- * and only a host holds ops. A test that has not installed one — `core/css-parser` reaches into the
290
- * engine by relative path and depends on neither package — can read it here instead of reaching
291
- * into `styleParts`, which is engine-owned and not a shape anything outside may bind to.
292
- */
293
- export declare function getPublishedStyle(node: ISymbioteNode): readonly unknown[];
294
- export declare function routeProp(node: ISymbioteNode, key: string, value: unknown): void;
295
- export declare function setText(node: ISymbioteNode, text: string): void;
296
- export declare function appendChild(requestedParent: ISymbioteNode, child: ISymbioteNode): void;
297
- export declare function insertBefore(requestedParent: ISymbioteNode, child: ISymbioteNode, beforeChild: ISymbioteNode | null | undefined): void;
298
- export declare function removeChild(requestedParent: ISymbioteNode, child: ISymbioteNode): void;
1
+ export { ANCHOR_COMPONENT, RAW_TEXT_COMPONENT, SURFACE_COMPONENT, TEXT_COMPONENT, VIRTUAL_TEXT_COMPONENT, VOID_COMPONENT, isAnchor, isSymbioteEvent, isSymbioteNode, type IClassStyleParts, type IEventDispatch, type IListener, type ISymbioteEvent, type ISymbioteNode, } from './node-types';
2
+ export { createAnchor, createElement, createRawText, createSurfaceRoot, createVoid, debugNodeId, setNodeComponent, } from './node-instance';
3
+ export { functionPropOf, functionPropsOf, markPropsDirty, setProp, setText, takePropKeyTally, takePropStats, writeProp, } from './node-props';
4
+ export { clearPublishedStyle, getExplicitStyle, getPublishedStyle, isSameShallowStyle, setNodeHidden, setNodePressed, setNodeUnderlayShown, } from './node-style';
5
+ export { hasListenerFor, listenerFor, setBehaviorListener, setEventListener, setNodeDispatch, } from './node-events';
6
+ export { routeProp } from './node-route';
7
+ export { appendChild, censusRetainedTree, insertBefore, removeChild, } from './node-tree';
299
8
  export type { ITreeCensus } from './tree-host';
300
- /**
301
- * A structural census of the tree the HOST holds — see `ITreeCensus` (tree-host.ts) for what each
302
- * number is for and why the anchor count says more about the adapter than about the app.
303
- *
304
- * It walks nothing here: the walk needs `props.text` to tell an empty raw text from a real one, and
305
- * a child list to measure a flatten width, and JS has neither. `undefined` from `treeHost()` means
306
- * nothing is installed, and the empty census is the honest answer — every probe that reads this
307
- * asserts against a mounted tree, so a zero from an uninstalled host cannot be mistaken for one from
308
- * an empty one.
309
- */
310
- export declare function censusRetainedTree(roots: readonly ISymbioteNode[]): ITreeCensus;