@symbiote-native/engine 1.2.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.
Files changed (110) hide show
  1. package/android/CMakeLists.txt +31 -1
  2. package/android/build.gradle +4 -1
  3. package/build/accessibility-info/index.android.js +21 -17
  4. package/build/accessibility-info/index.ios.js +2 -0
  5. package/build/accessibility-info/shared.d.ts +1 -1
  6. package/build/accessibility-props.d.ts +0 -11
  7. package/build/accessibility-props.js +30 -68
  8. package/build/alert/shared.d.ts +1 -1
  9. package/build/alert/shared.js +3 -7
  10. package/build/animated/graph.js +1 -1
  11. package/build/animated/leaf-lifecycle.js +2 -2
  12. package/build/app-state/index.d.ts +1 -1
  13. package/build/app-state/index.js +35 -27
  14. package/build/asset-source-resolver.d.ts +2 -0
  15. package/build/asset-source-resolver.js +13 -0
  16. package/build/back-handler/index.d.ts +7 -6
  17. package/build/back-handler/index.js +19 -16
  18. package/build/debug.js +8 -22
  19. package/build/dispatch.js +3 -9
  20. package/build/events/index.js +12 -3
  21. package/build/fabric-props.js +75 -180
  22. package/build/fabric.d.ts +2 -8
  23. package/build/fabric.js +27 -33
  24. package/build/host-access.d.ts +1 -128
  25. package/build/host-access.js +96 -205
  26. package/build/host-behavior.d.ts +1 -100
  27. package/build/host-behavior.js +125 -311
  28. package/build/image-loader.d.ts +4 -2
  29. package/build/image-loader.js +24 -48
  30. package/build/image-source-resolver.js +3 -7
  31. package/build/image-source-write.d.ts +1 -12
  32. package/build/image-source-write.js +28 -36
  33. package/build/imperative.d.ts +0 -28
  34. package/build/imperative.js +42 -92
  35. package/build/index.d.ts +3 -2
  36. package/build/index.js +30 -43
  37. package/build/invariant.d.ts +1 -0
  38. package/build/invariant.js +10 -0
  39. package/build/keyboard/index.js +11 -32
  40. package/build/linking/index.android.js +5 -3
  41. package/build/linking/shared.d.ts +1 -1
  42. package/build/linking/shared.js +16 -19
  43. package/build/mutation-buffer.d.ts +0 -177
  44. package/build/mutation-buffer.js +137 -308
  45. package/build/native-engine.d.ts +0 -102
  46. package/build/native-engine.js +38 -98
  47. package/build/native-events.d.ts +5 -0
  48. package/build/native-events.js +30 -18
  49. package/build/native-tree-host.d.ts +0 -21
  50. package/build/native-tree-host.js +14 -31
  51. package/build/node.d.ts +0 -212
  52. package/build/node.js +354 -774
  53. package/build/permissions-android/index.android.d.ts +59 -0
  54. package/build/permissions-android/index.android.js +47 -0
  55. package/build/permissions-android/index.d.ts +1 -115
  56. package/build/permissions-android/index.ios.d.ts +59 -0
  57. package/build/permissions-android/index.ios.js +31 -0
  58. package/build/permissions-android/index.js +3 -184
  59. package/build/permissions-android/shared.d.ts +63 -0
  60. package/build/permissions-android/shared.js +66 -0
  61. package/build/platform/index.android.js +3 -5
  62. package/build/platform/index.ios.js +3 -3
  63. package/build/platform/shared.d.ts +4 -0
  64. package/build/platform/shared.js +9 -0
  65. package/build/platform-color/index.android.d.ts +4 -0
  66. package/build/platform-color/index.android.js +7 -0
  67. package/build/platform-color/index.d.ts +2 -20
  68. package/build/platform-color/index.js +1 -45
  69. package/build/platform-color/shared.d.ts +21 -0
  70. package/build/platform-color/shared.js +41 -0
  71. package/build/post-commit.js +3 -8
  72. package/build/process-aspect-ratio.js +3 -7
  73. package/build/process-background-longhands.js +10 -19
  74. package/build/process-filter.js +11 -19
  75. package/build/process-font-variant.js +3 -7
  76. package/build/registry.d.ts +0 -33
  77. package/build/registry.js +22 -57
  78. package/build/report-error.js +4 -18
  79. package/build/settings/index.android.d.ts +6 -0
  80. package/build/settings/index.android.js +21 -0
  81. package/build/settings/index.d.ts +1 -8
  82. package/build/settings/index.ios.d.ts +8 -0
  83. package/build/settings/index.ios.js +122 -0
  84. package/build/settings/index.js +3 -122
  85. package/build/share/index.android.js +9 -32
  86. package/build/share/index.ios.js +14 -15
  87. package/build/share/shared.d.ts +4 -2
  88. package/build/share/shared.js +7 -10
  89. package/build/status-bar/index.android.js +1 -1
  90. package/build/status-bar/index.ios.js +4 -3
  91. package/build/structured-style.d.ts +0 -9
  92. package/build/structured-style.js +16 -31
  93. package/build/styles.js +3 -6
  94. package/build/surface.d.ts +0 -26
  95. package/build/surface.js +29 -76
  96. package/build/text-input-state.js +4 -8
  97. package/build/toast-android/index.android.d.ts +10 -0
  98. package/build/toast-android/index.android.js +108 -0
  99. package/build/toast-android/index.d.ts +1 -10
  100. package/build/toast-android/index.ios.d.ts +10 -0
  101. package/build/toast-android/index.ios.js +19 -0
  102. package/build/toast-android/index.js +3 -108
  103. package/build/touch-history.js +5 -11
  104. package/build/tree-host.d.ts +0 -270
  105. package/build/tree-host.js +63 -153
  106. package/build/view-config.js +17 -37
  107. package/cpp/SymbioteFabricProps.cpp +204 -120
  108. package/cpp/SymbioteFabricProps.h +5 -0
  109. package/cpp/SymbioteTree.cpp +20 -6
  110. package/package.json +2 -2
package/build/index.js CHANGED
@@ -1,23 +1,18 @@
1
- // @symbiote-native/engine: the retained shadow-tree + clone-on-write commit engine.
2
- // Every framework adapter drives this tiny mutation API; all Fabric-specific
3
- // logic (tag allocation, view-name resolution, clone-on-write, event
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 parent.
7
- // Exported so a PRIMITIVE that renders no view of its own can be born with it — RN's
8
- // TouchableNativeFeedback clones onto its single child and commits nothing
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 ENTIRE subtree the commit walk drops — unlike
12
- // `ANCHOR_COMPONENT`, which hoists its children up in its place, a void node contributes neither
13
- // itself nor them. For a primitive whose whole component renders nothing on this platform —
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 ONE adapter that has to build style objects rather than receive them: Angular's
17
- // `ɵɵstyleMap` hands over keys, so its renderer allocates a fresh object per node and needs to
18
- // recognise one it has already published. A second copy of this comparator in the adapter is the
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
@@ -44,7 +39,7 @@ export { SymbioteSurface, createSurface } from './surface.js';
44
39
  export { setEventDispatcher } from './dispatch.js';
45
40
  // `setColorProcessor` / `processColor` were only RE-exported by the old `commit.ts`; they point at
46
41
  // their real home now.
47
- export { setColorProcessor, processColor } from './platform-color/index.js';
42
+ export { setColorProcessor, processColor } from './platform-color';
48
43
  export { dispatchViewCommand, sendAccessibilityEvent, setNativeProps, getNativeTag, getNativeNode, whenCommitted, measure, measureInWindow, measureLayout, disposeRoot, requestCommitFor, } from './imperative.js';
49
44
  // The tree host: the seam a runtime installs to answer about the tree JS does not hold. `setTreeHost`
50
45
  // is what `installFabric()` (@symbiote-native/test-utils) calls with the TypeScript applier.
@@ -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 OPCODES and the recorder are deliberately NOT here. They are the wire contract between this
57
- // package and whatever implements the tree, so their audience is a HOST author — the C++ and the
58
- // TypeScript applier — not an app. They live on the `@symbiote-native/engine/mutation-buffer`
59
- // subpath, for the same reason `state-style` does: a name on this barrel is public API on all five
60
- // adapters at once, with no edit to any of them
61
- // (`.claude/rules/adapter-parity-audit.md`, "A build-tool-facing symbol belongs on a SUBPATH").
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.
@@ -78,7 +67,7 @@ export { fabricProps } from './fabric-props.js';
78
67
  // createElement): the imperative measure/setNativeProps/focus API, on the shared node prototype.
79
68
  // toPublicInstance is the identity that names the seam — see ./host-instance.
80
69
  export { toPublicInstance } from './host-instance/index.js';
81
- export { PlatformColor, DynamicColorIOS, isOpaqueColorValue, } from './platform-color/index.js';
70
+ export { PlatformColor, DynamicColorIOS, isOpaqueColorValue, } from './platform-color';
82
71
  // CSS-style processors (boxShadow/filter): RN parses these in JS before native because
83
72
  // enableNativeCSSParsing() defaults to false. Exported so an adapter / test can reuse them.
84
73
  export { processBoxShadow } from './process-box-shadow/index.js';
@@ -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), moved here from @symbiote-native/react so every adapter re-exports the SAME module.
108
- // The native module a JS API talks to is chosen per platform and can only be confirmed on a
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,12 +102,13 @@ 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';
120
- export { ToastAndroid } from './toast-android/index.js';
109
+ export { ToastAndroid } from './toast-android';
121
110
  export { SoundManager } from './sound-manager/index.js';
122
- export { Settings } from './settings/index.js';
111
+ export { Settings } from './settings';
123
112
  export { I18nManager } from './i18n-manager/index.js';
124
113
  // Device-state / event modules (Dimensions, Appearance, AppState, Keyboard, …).
125
114
  export { Dimensions } from './dimensions/index.js';
@@ -135,17 +124,15 @@ export { createAppRegistry } from './app-registry/index.js';
135
124
  export { Keyboard, KEYBOARD_EVENT } from './keyboard/index.js';
136
125
  export { currentlyFocusedInput, setInputFocused, setInputBlurred, blurTextInput, focusTextInput, } from './text-input-state.js';
137
126
  export { LayoutAnimation } from './layout-animation/index.js';
138
- export { BackHandler } from './back-handler/index.js';
139
- export { PermissionsAndroid, PERMISSIONS, RESULTS, } from './permissions-android/index.js';
127
+ export { BackHandler, installBackHandler } from './back-handler/index.js';
128
+ export { PermissionsAndroid, PERMISSIONS, RESULTS, } from './permissions-android';
140
129
  export { AccessibilityInfo } from './accessibility-info';
141
130
  // StatusBar: values from the platform-selected './status-bar', types from '-shared' (the
142
131
  // .ios re-export would otherwise duplicate-export the type symbols).
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
- // `markPropsDirty` is a behavior's only way to say "the fold reads state I just changed". Every
147
- // other dirtying route goes through a prop write, and a behavior whose payload is DERIVED — the
148
- // sticky header's debounced translateY lives in its own runtime, not in the node's props — has no
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';
@@ -0,0 +1 @@
1
+ export declare function invariant(condition: boolean, message: string): asserts condition;
@@ -0,0 +1,10 @@
1
+ // RN's `invariant(condition, message)` (the `invariant` package): a synchronous throw named
2
+ // 'Invariant Violation' carrying the message verbatim. Ports use it where RN does, so a failure is
3
+ // the same exception at the same moment.
4
+ export function invariant(condition, message) {
5
+ if (condition)
6
+ return;
7
+ const error = new Error(message);
8
+ error.name = 'Invariant Violation';
9
+ throw error;
10
+ }
@@ -33,25 +33,6 @@ function isKeyboardEvent(payload) {
33
33
  // Keyboard listens to its OWN show/hide events and caches the event so the synchronous
34
34
  // isVisible() / metrics() reads need no native round-trip.
35
35
  let currentlyShowing = null;
36
- // Every live subscription this module handed out, grouped by event type, so
37
- // removeAllListeners(eventType) can tear them all down. The shared NativeEventEmitter
38
- // exposes only per-listener remove(), so Keyboard tracks the set itself (mirrors RN's
39
- // _emitter.removeAllListeners, which we cannot reach through the shared emitter).
40
- const subscriptions = new Map();
41
- function trackSubscription(eventType, subscription) {
42
- let set = subscriptions.get(eventType);
43
- if (set === undefined) {
44
- set = new Set();
45
- subscriptions.set(eventType, set);
46
- }
47
- set.add(subscription);
48
- return {
49
- remove() {
50
- subscription.remove();
51
- set.delete(subscription);
52
- },
53
- };
54
- }
55
36
  // Lazily resolved so importing this module has no native side effect: a headless
56
37
  // run without a fake __turboModuleProxy still loads it; resolution happens on the
57
38
  // first addListener. Null when the module isn't linked.
@@ -73,42 +54,40 @@ const deviceEventModule = createDeviceEventModule({
73
54
  });
74
55
  },
75
56
  });
57
+ // RN builds KeyboardImpl, and with it the didShow/didHide tracking, the first time Keyboard is
58
+ // touched. Every method goes through here so the tracking starts at that same moment.
76
59
  function getEmitter() {
77
60
  return deviceEventModule.getEmitter();
78
61
  }
79
62
  export const Keyboard = {
80
63
  addListener(eventType, listener) {
81
64
  dlog(`Keyboard.addListener -> ${eventType}`);
82
- return trackSubscription(eventType, getEmitter().addListener(eventType, listener));
65
+ return getEmitter().addListener(eventType, listener);
83
66
  },
84
- // Tear down every listener this module added for one event type. The self-subscription
85
- // that feeds the cache is untracked, so it survives (RN parity: removeAllListeners only
86
- // clears caller subscriptions). No-op when nobody's listening for that event.
67
+ // RN's `_emitter.removeAllListeners(eventType)`: every listener of the event on the device bus,
68
+ // Keyboard's own show/hide tracking included — a later show is then no longer cached.
87
69
  removeAllListeners(eventType) {
88
70
  dlog(`Keyboard.removeAllListeners -> ${eventType}`);
89
- const set = subscriptions.get(eventType);
90
- if (set === undefined)
91
- return;
92
- for (const subscription of set)
93
- subscription.remove();
94
- set.clear();
71
+ getEmitter().removeAllListeners(eventType);
95
72
  },
96
73
  // Whether the keyboard is last known to be visible. Reads the cached show event.
97
74
  isVisible() {
75
+ getEmitter();
98
76
  return currentlyShowing !== null;
99
77
  },
100
78
  // The soft-keyboard frame if visible (the cached event's endCoordinates), else
101
79
  // undefined. RN's metrics().
102
80
  metrics() {
81
+ getEmitter();
103
82
  return currentlyShowing?.endCoordinates;
104
83
  },
105
84
  // Syncs an accessory view's layout with the keyboard transition: configure the next
106
85
  // commit to animate over the keyboard's own duration/easing. RN's
107
- // scheduleLayoutAnimation (Keyboard.js:193). Skipped when duration is absent or 0,
108
- // since a zero-length animation is a no-op.
86
+ // scheduleLayoutAnimation (Keyboard.js:193): only when `duration != null && duration !== 0`.
109
87
  scheduleLayoutAnimation(event) {
88
+ getEmitter();
110
89
  const { duration, easing } = event;
111
- if (duration === 0)
90
+ if (duration == null || duration === 0)
112
91
  return;
113
92
  dlog(`Keyboard.scheduleLayoutAnimation -> duration ${duration}, easing ${easing}`);
114
93
  LayoutAnimation.configureNext({
@@ -9,9 +9,11 @@
9
9
  import { createLinking } from './shared.js';
10
10
  export const Linking = createLinking({
11
11
  moduleName: 'IntentAndroid',
12
- sendIntent: (module, action, extras) => {
13
- if (module === null || module.sendIntent === undefined) {
14
- return Promise.reject(new Error('Linking: IntentAndroid native module unavailable'));
12
+ // RN: `nullthrows(NativeIntentAndroid).sendIntent(action, extras)`.
13
+ sendIntent: (requireModule, action, extras) => {
14
+ const module = requireModule();
15
+ if (module.sendIntent === undefined) {
16
+ throw new TypeError('NativeIntentAndroid.sendIntent is not a function');
15
17
  }
16
18
  return module.sendIntent(action, extras);
17
19
  },
@@ -26,7 +26,7 @@ export interface ILinkingStatic {
26
26
  }
27
27
  export interface ILinkingPlatform {
28
28
  moduleName: string;
29
- sendIntent(module: INativeLinkingModule | null, action: string, extras?: IIntentExtra[]): Promise<void>;
29
+ sendIntent(requireModule: () => INativeLinkingModule, action: string, extras?: IIntentExtra[]): Promise<void>;
30
30
  }
31
31
  export declare function createLinking(platform: ILinkingPlatform): ILinkingStatic;
32
32
  export {};
@@ -12,6 +12,8 @@ import { getNativeModule } from '../native-modules/index.js';
12
12
  import { dlog } from '../debug.js';
13
13
  // The one event symbiote observes: an incoming deep link. RN's LinkingEventDefinitions.
14
14
  const URL_EVENT = 'url';
15
+ // The `nullthrows` package's message, which RN's Linking surfaces for a missing native module.
16
+ const NULLTHROWS_MESSAGE = 'Got unexpected null or undefined';
15
17
  // RN's _validateURL: a typo / empty URL must fail loudly at the call, not reach native.
16
18
  function validateUrl(url) {
17
19
  if (typeof url !== 'string' || url.length === 0) {
@@ -50,8 +52,15 @@ export function createLinking(platform) {
50
52
  }
51
53
  return emitter;
52
54
  }
53
- function moduleUnavailable() {
54
- return new Error(`Linking: ${platform.moduleName} native module unavailable`);
55
+ // RN's `nullthrows(NativeModule)`: a missing module throws SYNCHRONOUSLY, with that package's
56
+ // message, from every method (Linking.js).
57
+ function requireModule() {
58
+ const module = getModule();
59
+ if (module === null) {
60
+ dlog(`Linking: ${platform.moduleName} unavailable -> throw`);
61
+ throw new Error(NULLTHROWS_MESSAGE);
62
+ }
63
+ return module;
55
64
  }
56
65
  return {
57
66
  addEventListener(eventType, listener) {
@@ -63,36 +72,24 @@ export function createLinking(platform) {
63
72
  openURL(url) {
64
73
  validateUrl(url);
65
74
  dlog(`Linking.openURL -> ${url}`);
66
- const module = getModule();
67
- if (module === null)
68
- return Promise.reject(moduleUnavailable());
69
- return module.openURL(url);
75
+ return requireModule().openURL(url);
70
76
  },
71
77
  canOpenURL(url) {
72
78
  validateUrl(url);
73
79
  dlog(`Linking.canOpenURL -> ${url}`);
74
- const module = getModule();
75
- if (module === null)
76
- return Promise.reject(moduleUnavailable());
77
- return module.canOpenURL(url);
80
+ return requireModule().canOpenURL(url);
78
81
  },
79
82
  getInitialURL() {
80
83
  dlog('Linking.getInitialURL');
81
- const module = getModule();
82
- if (module === null)
83
- return Promise.resolve(null);
84
- return module.getInitialURL();
84
+ return requireModule().getInitialURL();
85
85
  },
86
86
  openSettings() {
87
87
  dlog('Linking.openSettings');
88
- const module = getModule();
89
- if (module === null)
90
- return Promise.reject(moduleUnavailable());
91
- return module.openSettings();
88
+ return requireModule().openSettings();
92
89
  },
93
90
  sendIntent(action, extras) {
94
91
  dlog(`Linking.sendIntent -> ${action}`);
95
- return platform.sendIntent(getModule(), action, extras);
92
+ return platform.sendIntent(requireModule, action, extras);
96
93
  },
97
94
  };
98
95
  }
@@ -1,10 +1,3 @@
1
- /**
2
- * The opcodes. These numbers ARE the contract: renumbering here without renumbering the C++ commits
3
- * a different tree, silently, and no test in either language can see across the boundary.
4
- *
5
- * Stride is fixed so the ops array is addressable as memory rather than parsed. Operands are either
6
- * a SLOT (an index into the batch's `handles` array — see below) or an index into a side table.
7
- */
8
1
  export declare const OP_STRIDE = 6;
9
2
  export declare const OP_CREATE_ELEMENT = 0;
10
3
  export declare const OP_CREATE_RAW_TEXT = 1;
@@ -16,120 +9,14 @@ export declare const OP_SET_PROP = 6;
16
9
  export declare const OP_SET_TEXT = 7;
17
10
  export declare const OP_COMMIT = 8;
18
11
  export declare const OP_SET_COMPONENT = 9;
19
- /**
20
- * The INTRINSIC TAG this node came from — `pressable`, not `RCTView`. `[slot, tag]`.
21
- *
22
- * Emitted only for a node a host behavior actually attached to, from `attachHostBehavior`, which is
23
- * where the tag is already in hand and already matched. Every other node pays nothing.
24
- *
25
- * WHY THE TAG HAS TO CROSS AT ALL. A tag's platform props are resolved natively now, and the native
26
- * side keys them off what it knows the node IS. For `<text-input>` the Fabric view name answers
27
- * that by itself (`RCTSinglelineTextInputView` names nothing else); for `<pressable>` it does not —
28
- * it commits as `RCTView`, byte-identical to a plain view. The tag is the only fact that separates
29
- * them, and it is the same fact a browser keys user-agent behavior off.
30
- */
31
12
  export declare const OP_SET_TAG = 10;
32
- /**
33
- * An app callback appeared on, or disappeared from, an event name the behavior OWNS.
34
- * `[slot, name, present]`. See `recordSetOwnedListener` for why the bit crosses and the closure
35
- * does not.
36
- */
37
13
  export declare const OP_SET_OWNED_LISTENER = 11;
38
- /**
39
- * A behavior's FEEDBACK state flipped — TouchableHighlight's underlay is showing, or stopped.
40
- * `[slot, shown]`.
41
- *
42
- * The second bit to cross for the same reason the first did. `OP_SET_OWNED_LISTENER` carries whether
43
- * the app wired a handler; this carries whether the control is currently giving feedback, which is
44
- * the platform's own `:active` in everything but the timing. `setNodePressed`'s header already calls
45
- * the press state "the engine-owned half of what `:active` is on the web", and this is its twin for
46
- * the one control whose feedback does NOT track the press exactly: RN holds the underlay past
47
- * release so a fast tap still flashes (`TouchableHighlight.js:270-293`).
48
- *
49
- * THE TIMER STAYS IN JS and that is the boundary, not an omission. WHEN the bit flips is Pressability
50
- * plus a `delayPressOut` hold, running at gesture rate and calling back into app code
51
- * (`onShowUnderlay` / `onHideUnderlay`). WHAT a showing underlay looks like — a background colour and
52
- * a dimmed child, from two props no ViewConfig declares — is the platform's, and it is
53
- * `foldTouchableHighlightUnderlay` now.
54
- *
55
- * A flip is a GESTURE-rate event rather than a per-render one: twice a tap, against a `payloadFold`
56
- * that was charged on every commit the node was dirty in for the life of the screen.
57
- */
58
14
  export declare const OP_SET_UNDERLAY_SHOWN = 12;
59
- /**
60
- * A VOID node: commits nothing of its own AND does not hoist its children into Fabric either —
61
- * unlike an anchor, which hoists. `[slot]`.
62
- *
63
- * `InputAccessoryView.js` renders `null` on Android: the whole component, children included,
64
- * contributes nothing to the host tree. An anchor cannot express that — it exists precisely to hand
65
- * its children up in its own place — so a node whose entire subtree must vanish from Fabric needs
66
- * its own kind. Everything else about it (the retained JS tree, `appendChild`, adapter bookkeeping)
67
- * is unaffected; only the commit walk treats it as contributing zero Fabric nodes, recursively.
68
- */
69
15
  export declare const OP_CREATE_VOID = 13;
70
- /**
71
- * A `setProp` whose value slot is this DELETES the key.
72
- *
73
- * `undefined` cannot carry it: `null` is a legitimate Fabric prop value meaning "reset to the
74
- * default", and the two must stay distinguishable — `cloneNodeWithNewProps` merges, so a removed
75
- * key has to be sent as an explicit `null` while a key that was never there must not be sent at
76
- * all. The JS `setProp` already collapses `undefined` to a delete before anything is encoded.
77
- */
78
16
  export declare const NO_VALUE = -1;
79
- /**
80
- * A node kind. Native needs it because two of the three never become a Fabric node the same way,
81
- * and both rules are decided at INSERT or at child-set build — never by a walk:
82
- *
83
- * ELEMENT an ordinary view. Its Fabric view name is fixed at creation, with ONE exception:
84
- * a text element inside another text element commits as `RCTVirtualText` instead of
85
- * `RCTText`. Native resolves that when the node acquires a parent, because that is when
86
- * it first knows the answer, and re-resolves it on a reparent.
87
- * RAW_TEXT an `RCTRawText` leaf. Skipped from its parent's child set when its text is empty —
88
- * an empty one would paint.
89
- * ANCHOR a position marker the frameworks insert (`{#if}`, a fragment, a `{@render}` slot).
90
- * It never becomes a Fabric node at all: native keeps it in ITS OWN structure so
91
- * `insertBefore(parent, node, anchor)` resolves, and hoists its children into its
92
- * parent's child list when building the child set. This is why our own store cannot BE
93
- * the Fabric tree — there is no Fabric node to hold an anchor, which is the one thing
94
- * `IMirror` was genuinely for.
95
- *
96
- * A SURFACE is an anchor too, and that is not a trick: an anchor is a node whose children belong to
97
- * its parent's list, and a surface is a node whose children belong to the root's child set. Same
98
- * shape, so `OP_COMMIT` names one and the native side needs no `rootTag -> node` map — which keeps
99
- * the applier stateless, the property the whole lifetime design rests on.
100
- */
101
17
  export declare const KIND_ELEMENT = 0;
102
18
  export declare const KIND_RAW_TEXT = 1;
103
19
  export declare const KIND_ANCHOR = 2;
104
- /**
105
- * One recorded batch, flat.
106
- *
107
- * `handles` is the load-bearing table and it travels OUT rather than back: it holds the placeholder
108
- * object for every slot the ops address, and native attaches each created node to the object at
109
- * that slot as JSI `NativeState`. So the objects the adapter is already holding become the handles
110
- * in place, their lifetime is the nodes' lifetime, and nothing has to be freed explicitly.
111
- *
112
- * A slot is an index into THIS batch and is meaningless outside it. That is deliberate: an id that
113
- * outlives a batch forces a table on the far side, and a table is a second owner with nothing to
114
- * tell it when the first one let go — which is exactly the leak that took the previous applier from
115
- * 792 to 1492 MB.
116
- *
117
- * `values` carries whatever a prop is: a string, a number, a boolean, `null`, a style object, an
118
- * array. Native converts each to `folly::dynamic` ONCE, when the op is applied — never again per
119
- * commit, which is the half that ships today.
120
- */
121
- /**
122
- * What the buffer needs a handle to BE.
123
- *
124
- * Still an identity and nothing else as far as the ops are concerned — no parent, no children, no
125
- * order. The two fields are the buffer's own scratch space for `slotOf`, written by this file and
126
- * read by nobody else; `ISymbioteNode` declares them from its constructor so every real handle
127
- * carries the pair on one hidden class.
128
- *
129
- * Spelled as a requirement rather than as optional fields on purpose: a handle that cannot hold its
130
- * slot would fall back to nothing, and the failure would be a silently re-pushed node rather than a
131
- * type error.
132
- */
133
20
  export type IMutationHandle = {
134
21
  slot: number;
135
22
  slotBatch: number;
@@ -141,35 +28,13 @@ export type IMutationBatch = {
141
28
  readonly instanceHandles: readonly unknown[];
142
29
  readonly handles: readonly object[];
143
30
  };
144
- /**
145
- * What native answers back, for the four things JS still asks.
146
- *
147
- * All four are per-node and none of them is structural — no parent, no children, no order. They
148
- * exist because a host behavior runs in JS and has to see the props it reacts to, and because an
149
- * app can measure a ref.
150
- *
151
- * Called at GESTURE rate, not commit rate, which is what makes the crossing cost irrelevant: ~10
152
- * reads per touch against the 19 009 per commit this whole design exists to remove.
153
- */
154
31
  export type INativeTree = {
155
32
  applyOps: (batch: IMutationBatch) => void;
156
33
  getProp: (handle: IMutationHandle, key: string) => unknown;
157
- /** The resolved Fabric view name, which native may have changed at insert (see `KIND_ELEMENT`). */
158
34
  getViewName: (handle: IMutationHandle) => string;
159
35
  };
160
- /** Whether a commit would publish anything. See `changedSinceCommit`. */
161
36
  export declare function hasChangedSinceCommit(): boolean;
162
- /**
163
- * Called by `commitSurfaceOps` once it has drained. Separate from `takeBatch` because a READ drains
164
- * too, and a read is not a commit — clearing there would make the next commit believe its work had
165
- * already been published.
166
- */
167
37
  export declare function noteCommitDrained(): void;
168
- /**
169
- * The one dirtying route that writes no op: a behavior with a DERIVED payload asks the host to
170
- * rebuild a node the buffer never named. Without this the commit that follows would look idle and
171
- * be skipped, and the derived payload would sit unpublished until something unrelated changed.
172
- */
173
38
  export declare function noteHostSideChange(): void;
174
39
  /** Does the pending batch hold anything that could change what the host says this node's parent is? */
175
40
  export declare function hasPendingPlacement(handle: IMutationHandle): boolean;
@@ -183,56 +48,14 @@ export declare function recordRemoveChild(parent: IMutationHandle, child: IMutat
183
48
  /** `undefined` DELETES the key — the collapse `setProp` has always performed, spelled on the wire. */
184
49
  export declare function recordSetProp(handle: IMutationHandle, key: string, value: unknown): void;
185
50
  export declare function recordSetText(handle: IMutationHandle, text: string): void;
186
- /**
187
- * Change a node's Fabric view name after creation.
188
- *
189
- * It exists for exactly one thing and would not otherwise: `TextInput`'s `multiline` decides between
190
- * `RCTSinglelineTextInputView` and `RCTMultilineTextInputView`, and an app can flip it. No prop write
191
- * moves a node between native views, so the host has to RE-CREATE the node under the new name and
192
- * re-parent its children — which is the same path a reparent already takes, and why this needs no
193
- * new machinery on the far side beyond honouring the name.
194
- *
195
- * A JS-only workaround was the alternative and it is the one thing this design rules out: to know
196
- * what to rebuild, JS would have to hold the tree.
197
- */
198
51
  export declare function recordSetComponent(handle: IMutationHandle, viewName: string): void;
199
52
  export declare function recordSetTag(handle: IMutationHandle, tag: string): void;
200
- /**
201
- * Whether an app callback is currently wired to an event name the BEHAVIOR owns. `[slot, name,
202
- * present]`, `present` being 1 or 0.
203
- *
204
- * The EXISTENCE, never the function. A name a behavior owns is diverted into a JS stash by
205
- * `setEventListener` and never becomes a prop, so the payload builder sees no trace of it — and
206
- * `focusable` on a touchable is `focusable !== false && onPress !== undefined && !disabled`
207
- * (`TouchableOpacity.js:336-339`), two props and one thing only JS knew. This is the one bit that
208
- * closes that gap.
209
- *
210
- * The browser is the argument rather than convenience: a UA computes focusability itself and CAN,
211
- * because `addEventListener` is its own API — it knows which elements carry a click handler, while
212
- * the handler's body stays the application's. Same split.
213
- *
214
- * Emitted on a FLIP only, from `setEventListener`, which already refuses to notify on listener
215
- * identity because a framework hands a fresh closure nearly every render. So this is a mount-time
216
- * op, not a per-render one — against the per-commit fold it replaces.
217
- */
218
53
  export declare function recordSetOwnedListener(handle: IMutationHandle, name: string, isPresent: boolean): void;
219
54
  /** See `OP_SET_UNDERLAY_SHOWN`. Emitted on a flip only, from the behavior that owns the timer. */
220
55
  export declare function recordSetUnderlayShown(handle: IMutationHandle, shown: boolean): void;
221
56
  export declare function recordCommit(rootTag: number, surface: IMutationHandle): void;
222
57
  /** Whether anything is pending. The commit path asks before paying for a drain. */
223
58
  export declare function hasPendingOps(): boolean;
224
- /**
225
- * Drain the buffer.
226
- *
227
- * Fresh arrays rather than reused ones: the batch outlives this call on the native path (`applyOps`
228
- * reads `handles` while attaching state), and a recycled array would be mutated under it by the next
229
- * mutation the adapter makes.
230
- *
231
- * `slice` for the ops and not `subarray` for exactly that reason — a subarray would share the
232
- * backing store the very next `push` writes into. It is a typed-array copy rather than the
233
- * element-by-element iterator walk this used to be, and the ops buffer itself is KEPT so its
234
- * capacity survives the drain.
235
- */
236
59
  export declare function takeBatch(): IMutationBatch;
237
60
  /** Test seam. Drops everything pending without applying it. */
238
61
  export declare function resetMutationBuffer(): void;