@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.
- package/android/CMakeLists.txt +31 -1
- package/android/build.gradle +4 -1
- package/build/accessibility-info/index.android.js +21 -17
- package/build/accessibility-info/index.ios.js +2 -0
- package/build/accessibility-info/shared.d.ts +1 -1
- package/build/accessibility-props.d.ts +0 -11
- package/build/accessibility-props.js +30 -68
- package/build/alert/shared.d.ts +1 -1
- package/build/alert/shared.js +3 -7
- package/build/animated/graph.js +1 -1
- package/build/animated/leaf-lifecycle.js +2 -2
- package/build/app-state/index.d.ts +1 -1
- package/build/app-state/index.js +35 -27
- package/build/asset-source-resolver.d.ts +2 -0
- package/build/asset-source-resolver.js +13 -0
- package/build/back-handler/index.d.ts +7 -6
- package/build/back-handler/index.js +19 -16
- package/build/debug.js +8 -22
- package/build/dispatch.js +3 -9
- package/build/events/index.js +12 -3
- package/build/fabric-props.js +75 -180
- package/build/fabric.d.ts +2 -8
- package/build/fabric.js +27 -33
- package/build/host-access.d.ts +1 -128
- package/build/host-access.js +96 -205
- package/build/host-behavior.d.ts +1 -100
- package/build/host-behavior.js +125 -311
- package/build/image-loader.d.ts +4 -2
- package/build/image-loader.js +24 -48
- package/build/image-source-resolver.js +3 -7
- package/build/image-source-write.d.ts +1 -12
- package/build/image-source-write.js +28 -36
- package/build/imperative.d.ts +0 -28
- package/build/imperative.js +42 -92
- package/build/index.d.ts +3 -2
- package/build/index.js +30 -43
- package/build/invariant.d.ts +1 -0
- package/build/invariant.js +10 -0
- package/build/keyboard/index.js +11 -32
- package/build/linking/index.android.js +5 -3
- package/build/linking/shared.d.ts +1 -1
- package/build/linking/shared.js +16 -19
- package/build/mutation-buffer.d.ts +0 -177
- package/build/mutation-buffer.js +137 -308
- package/build/native-engine.d.ts +0 -102
- package/build/native-engine.js +38 -98
- package/build/native-events.d.ts +5 -0
- package/build/native-events.js +30 -18
- package/build/native-tree-host.d.ts +0 -21
- package/build/native-tree-host.js +14 -31
- package/build/node.d.ts +0 -212
- package/build/node.js +354 -774
- package/build/permissions-android/index.android.d.ts +59 -0
- package/build/permissions-android/index.android.js +47 -0
- package/build/permissions-android/index.d.ts +1 -115
- package/build/permissions-android/index.ios.d.ts +59 -0
- package/build/permissions-android/index.ios.js +31 -0
- package/build/permissions-android/index.js +3 -184
- package/build/permissions-android/shared.d.ts +63 -0
- package/build/permissions-android/shared.js +66 -0
- package/build/platform/index.android.js +3 -5
- package/build/platform/index.ios.js +3 -3
- package/build/platform/shared.d.ts +4 -0
- package/build/platform/shared.js +9 -0
- package/build/platform-color/index.android.d.ts +4 -0
- package/build/platform-color/index.android.js +7 -0
- package/build/platform-color/index.d.ts +2 -20
- package/build/platform-color/index.js +1 -45
- package/build/platform-color/shared.d.ts +21 -0
- package/build/platform-color/shared.js +41 -0
- package/build/post-commit.js +3 -8
- package/build/process-aspect-ratio.js +3 -7
- package/build/process-background-longhands.js +10 -19
- package/build/process-filter.js +11 -19
- package/build/process-font-variant.js +3 -7
- package/build/registry.d.ts +0 -33
- package/build/registry.js +22 -57
- package/build/report-error.js +4 -18
- package/build/settings/index.android.d.ts +6 -0
- package/build/settings/index.android.js +21 -0
- package/build/settings/index.d.ts +1 -8
- package/build/settings/index.ios.d.ts +8 -0
- package/build/settings/index.ios.js +122 -0
- package/build/settings/index.js +3 -122
- package/build/share/index.android.js +9 -32
- package/build/share/index.ios.js +14 -15
- package/build/share/shared.d.ts +4 -2
- package/build/share/shared.js +7 -10
- package/build/status-bar/index.android.js +1 -1
- package/build/status-bar/index.ios.js +4 -3
- package/build/structured-style.d.ts +0 -9
- package/build/structured-style.js +16 -31
- package/build/styles.js +3 -6
- package/build/surface.d.ts +0 -26
- package/build/surface.js +29 -76
- package/build/text-input-state.js +4 -8
- package/build/toast-android/index.android.d.ts +10 -0
- package/build/toast-android/index.android.js +108 -0
- package/build/toast-android/index.d.ts +1 -10
- package/build/toast-android/index.ios.d.ts +10 -0
- package/build/toast-android/index.ios.js +19 -0
- package/build/toast-android/index.js +3 -108
- package/build/touch-history.js +5 -11
- package/build/tree-host.d.ts +0 -270
- package/build/tree-host.js +63 -153
- package/build/view-config.js +17 -37
- package/cpp/SymbioteFabricProps.cpp +204 -120
- package/cpp/SymbioteFabricProps.h +5 -0
- package/cpp/SymbioteTree.cpp +20 -6
- 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
|
-
//
|
|
3
|
-
//
|
|
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
|
|
7
|
-
// Exported so a
|
|
8
|
-
//
|
|
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
|
|
12
|
-
//
|
|
13
|
-
//
|
|
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
|
|
17
|
-
//
|
|
18
|
-
// recognise one it has already published.
|
|
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
|
|
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
|
|
57
|
-
// package and whatever implements the tree,
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
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
|
|
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),
|
|
108
|
-
//
|
|
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
|
|
109
|
+
export { ToastAndroid } from './toast-android';
|
|
121
110
|
export { SoundManager } from './sound-manager/index.js';
|
|
122
|
-
export { Settings } from './settings
|
|
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
|
|
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
|
-
//
|
|
147
|
-
// other dirtying route goes through a prop write, and a behavior
|
|
148
|
-
//
|
|
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
|
+
}
|
package/build/keyboard/index.js
CHANGED
|
@@ -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
|
|
65
|
+
return getEmitter().addListener(eventType, listener);
|
|
83
66
|
},
|
|
84
|
-
//
|
|
85
|
-
//
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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(
|
|
29
|
+
sendIntent(requireModule: () => INativeLinkingModule, action: string, extras?: IIntentExtra[]): Promise<void>;
|
|
30
30
|
}
|
|
31
31
|
export declare function createLinking(platform: ILinkingPlatform): ILinkingStatic;
|
|
32
32
|
export {};
|
package/build/linking/shared.js
CHANGED
|
@@ -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
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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;
|