@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/surface.js
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
// A surface is one mounted root: it owns the rootTag handed down by the native Fabric host and the
|
|
2
2
|
// top-level nodes under it. Adapters mutate it and ask it to commit.
|
|
3
|
-
//
|
|
4
|
-
// A SURFACE IS ONE ORDINARY NODE, and that is the whole implementation rather than a trick. It holds
|
|
5
|
-
// a real handle, its child ops are the ordinary append / insertBefore / removeChild, and `OP_COMMIT`
|
|
6
|
-
// names that one handle — so the host needs no `rootTag -> node` map, which is what keeps it
|
|
7
|
-
// stateless.
|
|
8
|
-
//
|
|
9
|
-
// The node is RN's AppContainer (`createSurfaceRoot` in `node.ts` — `flex: 1`, `box-none`), so what
|
|
10
|
-
// reaches the root child set is one view with the app under it. An ANCHOR in the same position
|
|
11
|
-
// hoists its children instead, and the host takes both through the same call, so nothing here is a
|
|
12
|
-
// special case.
|
|
13
3
|
import { dlog } from './debug.js';
|
|
14
4
|
import { installEventHandler } from './events/index.js';
|
|
15
5
|
import { detachAnimatedProps } from './animated/host-binding.js';
|
|
@@ -33,17 +23,10 @@ export class SymbioteSurface {
|
|
|
33
23
|
this.rootTag = rootTag;
|
|
34
24
|
this.node = createSurfaceRoot();
|
|
35
25
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* may do. One surface — the universal case — allocates nothing.
|
|
41
|
-
*
|
|
42
|
-
* `self` may already be OUT of the registry: a teardown unregisters and then commits, and that
|
|
43
|
-
* commit is the one carrying the removals. So the fast path cannot be a size check — with one
|
|
44
|
-
* live surface left, `size === 1` means either "only me" or "only the other one", and taking the
|
|
45
|
-
* shortcut on the second reading is how a surface loses the very batch that empties it.
|
|
46
|
-
*/
|
|
26
|
+
// Every other live surface, so one commit names every root — see commitSurfaceOps. Static
|
|
27
|
+
// because it reads a sibling instance's private handle, which only a member of this class may do.
|
|
28
|
+
// self may already be out of the registry: a teardown unregisters and then commits, carrying the
|
|
29
|
+
// removals — so the fast path can't be a size check, since size===1 could mean either surface.
|
|
47
30
|
static others(self) {
|
|
48
31
|
let out;
|
|
49
32
|
for (const other of surfaces.values()) {
|
|
@@ -54,13 +37,8 @@ export class SymbioteSurface {
|
|
|
54
37
|
}
|
|
55
38
|
return out ?? NO_CO_COMMITTERS;
|
|
56
39
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*
|
|
60
|
-
* A getter rather than an array this class maintains: a second copy of a child list is the thing
|
|
61
|
-
* this design removes, and `nextSiblingOf` (host-access.ts) needs the same answer the host gives
|
|
62
|
-
* for a parented node.
|
|
63
|
-
*/
|
|
40
|
+
// The top-level nodes, asked of the host. A getter rather than an array this class maintains: a
|
|
41
|
+
// second copy of a child list is the thing this design removes.
|
|
64
42
|
get children() {
|
|
65
43
|
return childrenOf(this.node);
|
|
66
44
|
}
|
|
@@ -70,10 +48,8 @@ export class SymbioteSurface {
|
|
|
70
48
|
insertBefore(child, beforeChild) {
|
|
71
49
|
insertBefore(this.node, child, beforeChild);
|
|
72
50
|
}
|
|
73
|
-
// Nomination for teardown rides on
|
|
74
|
-
//
|
|
75
|
-
// decides. The surface is one ordinary node, so it is not a second removal path that could miss
|
|
76
|
-
// the sweep and leave a behavior — its timers included — outliving the surface.
|
|
51
|
+
// Nomination for teardown rides on node.ts's removeChild, and only nominates: a framework may
|
|
52
|
+
// spell a move as remove-then-reinsert, so the commit sweep decides.
|
|
77
53
|
removeChild(child) {
|
|
78
54
|
removeChild(this.node, child);
|
|
79
55
|
}
|
|
@@ -81,63 +57,41 @@ export class SymbioteSurface {
|
|
|
81
57
|
for (const child of this.children)
|
|
82
58
|
removeChild(this.node, child);
|
|
83
59
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
* The sweep above cannot answer this: it only sees nodes a `removeChild` NOMINATED, and an
|
|
88
|
-
* unmount removes nothing — the adapter drops the whole surface. Without it every node keeps its
|
|
89
|
-
* `afterCommit` registration and its timers, and a restarted surface's commits drain the dead
|
|
90
|
-
* one's hooks forever.
|
|
91
|
-
*/
|
|
60
|
+
// Release every host behavior still standing under this surface, at unmount. The sweep above
|
|
61
|
+
// can't answer this: it only sees nodes removeChild nominated, and an unmount removes nothing —
|
|
62
|
+
// the adapter drops the whole surface.
|
|
92
63
|
teardown() {
|
|
93
|
-
// The nominations first: an adapter that empties
|
|
94
|
-
//
|
|
95
|
-
// cannot see those nodes either — they already left the tree.
|
|
64
|
+
// The nominations first: an adapter that empties and disposes the surface without a commit in
|
|
65
|
+
// between never reaches the commit sweep, and the walk below can't see those nodes either.
|
|
96
66
|
sweepDetachedBehaviors(this.children, detachAnimatedProps);
|
|
97
67
|
teardownSubtree(this.node, detachAnimatedProps);
|
|
98
68
|
}
|
|
99
69
|
// Synchronous commit: used by React's resetAfterCommit, which already batches per logical update.
|
|
100
70
|
commit() {
|
|
101
|
-
// A
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
// The teardown half of the behavior lifecycle. It runs AFTER the ops are applied — it decides
|
|
108
|
-
// what really left by asking the host for a parent, and the host does not know about a removal
|
|
109
|
-
// it has not been handed — but BEFORE the root is completed, so a behavior's parting writes
|
|
110
|
-
// (ScrollView taking its forced `scrollEventThrottle` back) ride this commit instead of owing
|
|
111
|
-
// another one. `flushOps` is that split: apply, do not publish.
|
|
112
|
-
//
|
|
113
|
-
// `removeChild` only NOMINATES — a framework spells a move as remove-then-reinsert, so tearing
|
|
114
|
-
// down at the call would kill a machine that comes back in the same batch.
|
|
71
|
+
// A superseded surface still flushes its ops and names every other root (its teardown carries
|
|
72
|
+
// the removals), but must not complete a root another surface now owns — Fast Refresh and the
|
|
73
|
+
// focus lifecycle can re-mount the same rootTag while an old teardown commit is still pending.
|
|
74
|
+
// The behavior-teardown half runs after ops are applied (asking the host for a parent needs the
|
|
75
|
+
// removal already handed over) but before the root completes, so a behavior's parting writes
|
|
76
|
+
// ride this commit instead of owing another one. flushOps is that split: apply, don't publish.
|
|
115
77
|
flushOps();
|
|
116
|
-
//
|
|
117
|
-
//
|
|
78
|
+
// Guarded at the call site, not inside the sweep — this.children is a host read that builds the
|
|
79
|
+
// whole top-level list, and it would run on every commit for a sweep with nothing to do.
|
|
118
80
|
if (hasDetachCandidates()) {
|
|
119
81
|
sweepDetachedBehaviors(this.children, detachAnimatedProps);
|
|
120
82
|
}
|
|
121
83
|
const owner = surfaces.get(this.rootTag);
|
|
122
84
|
const superseded = owner !== undefined && owner !== this;
|
|
123
85
|
commitSurfaceOps(superseded ? undefined : this.rootTag, this.node, SymbioteSurface.others(this));
|
|
124
|
-
// Fresh Fabric handles are now assigned, so the three things that
|
|
125
|
-
// existed all drain here
|
|
126
|
-
//
|
|
127
|
-
// `notifyCommitted` releases the imperative waiters (`whenCommitted`); `runPostCommitHooks` the
|
|
128
|
-
// consumers that needed a committed TAG and ran too early, which is the Animated native driver
|
|
129
|
-
// binding a props node under an async-batched commit; `runDeferredAttaches` the half of a host
|
|
130
|
-
// behavior whose setup needs a tag (a view command, an event attach). The predicate is passed in
|
|
131
|
-
// rather than imported by `host-behavior.ts`, keeping that dependency one-directional — a cycle
|
|
132
|
-
// there is a live hazard under Metro's `inlineRequires`.
|
|
86
|
+
// Fresh Fabric handles are now assigned, so the three things that couldn't run before one
|
|
87
|
+
// existed all drain here: notifyCommitted releases the imperative waiters, runPostCommitHooks
|
|
88
|
+
// the consumers that needed a committed tag, runDeferredAttaches the same for a host behavior.
|
|
133
89
|
notifyCommitted();
|
|
134
90
|
runPostCommitHooks();
|
|
135
91
|
runDeferredAttaches(isNodeCommitted);
|
|
136
|
-
// After the setup half, never before
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
// that strips a prop makes its own commit byte-identical, and the hook that must react to the
|
|
140
|
-
// flip would be the one the flip cannot wake.
|
|
92
|
+
// After the setup half, never before: a node carrying both hooks has attachAfterCommit seed the
|
|
93
|
+
// mirrors afterCommit then compares against. Unlike the two above, this asks only "props were
|
|
94
|
+
// published", so it isn't gated on the commit having made native calls.
|
|
141
95
|
runCommittedHooks(isNodeCommitted);
|
|
142
96
|
}
|
|
143
97
|
// Coalesced commit: for reactive frameworks that emit many mutations per tick. Collapses to a
|
|
@@ -152,9 +106,8 @@ export class SymbioteSurface {
|
|
|
152
106
|
});
|
|
153
107
|
}
|
|
154
108
|
}
|
|
155
|
-
// Every live surface, so the microtask flush in
|
|
156
|
-
// named. Registered from here rather than imported there
|
|
157
|
-
// reaching into it from the imperative half would put back the cycle that split exists to remove.
|
|
109
|
+
// Every live surface, so the microtask flush in imperative.ts can commit the one a queued write
|
|
110
|
+
// named. Registered from here rather than imported there, keeping that dependency one-directional.
|
|
158
111
|
const surfaces = new Map();
|
|
159
112
|
registerSurfaceCommit(rootTag => {
|
|
160
113
|
surfaces.get(rootTag)?.commit();
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
// Mirrors RN's TextInput/TextInputState: the single currently-focused input, tracked
|
|
2
|
-
//
|
|
3
|
-
// Keyboard.dismiss can blur whatever holds focus without a ref, exactly how RN's
|
|
4
|
-
// dismissKeyboard() works (blurTextInput(currentlyFocusedInput())).
|
|
1
|
+
// Mirrors RN's TextInput/TextInputState: the single currently-focused input, tracked JS-side since
|
|
2
|
+
// native exposes no focus getter. Lets Keyboard.dismiss blur whatever holds focus without a ref.
|
|
5
3
|
import { dispatchViewCommand, propOf } from './imperative.js';
|
|
6
4
|
import { dlog } from './debug.js';
|
|
7
5
|
let currentlyFocused = null;
|
|
@@ -18,10 +16,8 @@ export function setInputBlurred(node) {
|
|
|
18
16
|
if (currentlyFocused === node)
|
|
19
17
|
currentlyFocused = null;
|
|
20
18
|
}
|
|
21
|
-
// Imperative blur:
|
|
22
|
-
//
|
|
23
|
-
// currently-focused one — mirrors RN's TextInputState.blurTextInput, which guards the
|
|
24
|
-
// same way so blurring an already-unfocused input never reaches native.
|
|
19
|
+
// Imperative blur: drives the native `blur` command and drops tracked focus. A no-op if this
|
|
20
|
+
// node isn't the currently-focused one, mirroring RN's TextInputState.blurTextInput guard.
|
|
25
21
|
export function blurTextInput(node) {
|
|
26
22
|
if (node === null || currentlyFocused !== node)
|
|
27
23
|
return;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const ToastAndroid: {
|
|
2
|
+
SHORT: number;
|
|
3
|
+
LONG: number;
|
|
4
|
+
TOP: number;
|
|
5
|
+
BOTTOM: number;
|
|
6
|
+
CENTER: number;
|
|
7
|
+
show(message: string, duration: number): void;
|
|
8
|
+
showWithGravity(message: string, duration: number, gravity: number): void;
|
|
9
|
+
showWithGravityAndOffset(message: string, duration: number, gravity: number, xOffset: number, yOffset: number): void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// ToastAndroid module: pops a brief Android system toast from JS. Mirrors RN's
|
|
2
|
+
// Libraries/Components/ToastAndroid/ToastAndroid.android.js: `show` takes a message
|
|
3
|
+
// and a duration; `showWithGravity` adds a layout gravity; `showWithGravityAndOffset`
|
|
4
|
+
// adds an x/y pixel offset. No Fabric view, pure JS->native.
|
|
5
|
+
//
|
|
6
|
+
// symbiote is iOS-first and this is an Android-only module. RN's iOS fallback
|
|
7
|
+
// (ToastAndroid.ios.js) throws "not supported"; we prefer a no-op + dlog so a
|
|
8
|
+
// cross-platform smoke never crashes when the native module is absent.
|
|
9
|
+
//
|
|
10
|
+
// The native contract is confirmed from RN's TurboModule spec at
|
|
11
|
+
// specs_DEPRECATED/modules/INativeToastAndroid.js:
|
|
12
|
+
// getConstants(): { SHORT, LONG, TOP, BOTTOM, CENTER }
|
|
13
|
+
// show(message: string, duration: number)
|
|
14
|
+
// showWithGravity(message: string, duration: number, gravity: number)
|
|
15
|
+
// showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset)
|
|
16
|
+
import { dlog } from '../debug.js';
|
|
17
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
18
|
+
// The native module name RN registers this under. NOTE: this is the name the spec
|
|
19
|
+
// resolves via `TurboModuleRegistry.getEnforcing<Spec>('ToastAndroid')`, NOT the
|
|
20
|
+
// spec filename `INativeToastAndroid`. A module name is only provable on a real
|
|
21
|
+
// host (a headless fake answers to any name); this Android name is confirmed from
|
|
22
|
+
// RN source but not yet exercised on a device.
|
|
23
|
+
const TOAST_MODULE = 'ToastAndroid';
|
|
24
|
+
// Conventional RN values for SHORT/LONG/TOP/BOTTOM/CENTER. On a real device the
|
|
25
|
+
// numbers come from native getConstants() (resolved below); these are the fallbacks
|
|
26
|
+
// that keep the constants object populated headless and on a host without the module.
|
|
27
|
+
const FALLBACK_CONSTANTS = {
|
|
28
|
+
SHORT: 0,
|
|
29
|
+
LONG: 1,
|
|
30
|
+
TOP: 48,
|
|
31
|
+
BOTTOM: 80,
|
|
32
|
+
CENTER: 17,
|
|
33
|
+
};
|
|
34
|
+
// Lazily resolved so importing this module has no native side effect.
|
|
35
|
+
let toastModule;
|
|
36
|
+
function getModule() {
|
|
37
|
+
if (toastModule === undefined) {
|
|
38
|
+
toastModule = getNativeModule(TOAST_MODULE);
|
|
39
|
+
dlog(`ToastAndroid: ToastAndroid module ${toastModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
40
|
+
}
|
|
41
|
+
return toastModule;
|
|
42
|
+
}
|
|
43
|
+
// Read a single numeric constant from the native getConstants() payload, narrowing
|
|
44
|
+
// with a `typeof` guard (no cast) and falling back to the conventional RN value when
|
|
45
|
+
// the module or the key is absent.
|
|
46
|
+
function readConstant(raw, key) {
|
|
47
|
+
const value = raw[key];
|
|
48
|
+
return typeof value === 'number' ? value : FALLBACK_CONSTANTS[key];
|
|
49
|
+
}
|
|
50
|
+
// Resolve the constants once: real numbers from native on a device, fallbacks
|
|
51
|
+
// otherwise. Always returns a fully-populated object so the constants are never
|
|
52
|
+
// undefined, even headless.
|
|
53
|
+
function resolveConstants() {
|
|
54
|
+
const module = getModule();
|
|
55
|
+
if (module === null) {
|
|
56
|
+
dlog('ToastAndroid: constants from fallbacks (native module unavailable)');
|
|
57
|
+
return { ...FALLBACK_CONSTANTS };
|
|
58
|
+
}
|
|
59
|
+
const raw = module.getConstants();
|
|
60
|
+
return {
|
|
61
|
+
SHORT: readConstant(raw, 'SHORT'),
|
|
62
|
+
LONG: readConstant(raw, 'LONG'),
|
|
63
|
+
TOP: readConstant(raw, 'TOP'),
|
|
64
|
+
BOTTOM: readConstant(raw, 'BOTTOM'),
|
|
65
|
+
CENTER: readConstant(raw, 'CENTER'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const constants = resolveConstants();
|
|
69
|
+
export const ToastAndroid = {
|
|
70
|
+
// Toast duration constants.
|
|
71
|
+
SHORT: constants.SHORT,
|
|
72
|
+
LONG: constants.LONG,
|
|
73
|
+
// Toast gravity constants.
|
|
74
|
+
TOP: constants.TOP,
|
|
75
|
+
BOTTOM: constants.BOTTOM,
|
|
76
|
+
CENTER: constants.CENTER,
|
|
77
|
+
// Show a toast with the given message and duration. Degrades to a no-op (logged)
|
|
78
|
+
// when the module is absent; a missing optional native module must never throw.
|
|
79
|
+
show(message, duration) {
|
|
80
|
+
const module = getModule();
|
|
81
|
+
if (module === null) {
|
|
82
|
+
dlog('ToastAndroid.show -> ToastAndroid native module unavailable, no-op');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
dlog(`ToastAndroid.show -> "${message}" (${duration})`);
|
|
86
|
+
module.show(message, duration);
|
|
87
|
+
},
|
|
88
|
+
// Show a toast at the given layout gravity (TOP / BOTTOM / CENTER).
|
|
89
|
+
showWithGravity(message, duration, gravity) {
|
|
90
|
+
const module = getModule();
|
|
91
|
+
if (module === null) {
|
|
92
|
+
dlog('ToastAndroid.showWithGravity -> ToastAndroid native module unavailable, no-op');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
dlog(`ToastAndroid.showWithGravity -> "${message}" (${duration}, gravity=${gravity})`);
|
|
96
|
+
module.showWithGravity(message, duration, gravity);
|
|
97
|
+
},
|
|
98
|
+
// Show a toast at the given gravity, offset by xOffset/yOffset pixels.
|
|
99
|
+
showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset) {
|
|
100
|
+
const module = getModule();
|
|
101
|
+
if (module === null) {
|
|
102
|
+
dlog('ToastAndroid.showWithGravityAndOffset -> ToastAndroid native module unavailable, no-op');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
dlog(`ToastAndroid.showWithGravityAndOffset -> "${message}" (${duration}, gravity=${gravity}, ${xOffset}, ${yOffset})`);
|
|
106
|
+
module.showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
@@ -1,10 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
SHORT: number;
|
|
3
|
-
LONG: number;
|
|
4
|
-
TOP: number;
|
|
5
|
-
BOTTOM: number;
|
|
6
|
-
CENTER: number;
|
|
7
|
-
show(message: string, duration: number): void;
|
|
8
|
-
showWithGravity(message: string, duration: number, gravity: number): void;
|
|
9
|
-
showWithGravityAndOffset(message: string, duration: number, gravity: number, xOffset: number, yOffset: number): void;
|
|
10
|
-
};
|
|
1
|
+
export * from './index.ios';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const ToastAndroid: {
|
|
2
|
+
SHORT: number;
|
|
3
|
+
LONG: number;
|
|
4
|
+
TOP: number;
|
|
5
|
+
BOTTOM: number;
|
|
6
|
+
CENTER: number;
|
|
7
|
+
show(_message: string, _duration: number): void;
|
|
8
|
+
showWithGravity(_message: string, _duration: number, _gravity: number): void;
|
|
9
|
+
showWithGravityAndOffset(_message: string, _duration: number, _gravity: number, _xOffset: number, _yOffset: number): void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// ToastAndroid off Android: RN's ToastAndroidFallback (ToastAndroid.ios.js). Zeroed constants and
|
|
2
|
+
// RN's own user-facing warning on every call; nothing reaches native.
|
|
3
|
+
const UNSUPPORTED = 'ToastAndroid is not supported on this platform.';
|
|
4
|
+
export const ToastAndroid = {
|
|
5
|
+
SHORT: 0,
|
|
6
|
+
LONG: 0,
|
|
7
|
+
TOP: 0,
|
|
8
|
+
BOTTOM: 0,
|
|
9
|
+
CENTER: 0,
|
|
10
|
+
show(_message, _duration) {
|
|
11
|
+
console.warn(UNSUPPORTED);
|
|
12
|
+
},
|
|
13
|
+
showWithGravity(_message, _duration, _gravity) {
|
|
14
|
+
console.warn(UNSUPPORTED);
|
|
15
|
+
},
|
|
16
|
+
showWithGravityAndOffset(_message, _duration, _gravity, _xOffset, _yOffset) {
|
|
17
|
+
console.warn(UNSUPPORTED);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
@@ -1,108 +1,3 @@
|
|
|
1
|
-
// ToastAndroid
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// adds an x/y pixel offset. No Fabric view, pure JS->native.
|
|
5
|
-
//
|
|
6
|
-
// symbiote is iOS-first and this is an Android-only module. RN's iOS fallback
|
|
7
|
-
// (ToastAndroid.ios.js) throws "not supported"; we prefer a no-op + dlog so a
|
|
8
|
-
// cross-platform smoke never crashes when the native module is absent.
|
|
9
|
-
//
|
|
10
|
-
// The native contract is confirmed from RN's TurboModule spec at
|
|
11
|
-
// specs_DEPRECATED/modules/INativeToastAndroid.js:
|
|
12
|
-
// getConstants(): { SHORT, LONG, TOP, BOTTOM, CENTER }
|
|
13
|
-
// show(message: string, duration: number)
|
|
14
|
-
// showWithGravity(message: string, duration: number, gravity: number)
|
|
15
|
-
// showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset)
|
|
16
|
-
import { dlog } from '../debug.js';
|
|
17
|
-
import { getNativeModule } from '../native-modules/index.js';
|
|
18
|
-
// The native module name RN registers this under. NOTE: this is the name the spec
|
|
19
|
-
// resolves via `TurboModuleRegistry.getEnforcing<Spec>('ToastAndroid')`, NOT the
|
|
20
|
-
// spec filename `INativeToastAndroid`. A module name is only provable on a real
|
|
21
|
-
// host (a headless fake answers to any name); this Android name is confirmed from
|
|
22
|
-
// RN source but not yet exercised on a device.
|
|
23
|
-
const TOAST_MODULE = 'ToastAndroid';
|
|
24
|
-
// Conventional RN values for SHORT/LONG/TOP/BOTTOM/CENTER. On a real device the
|
|
25
|
-
// numbers come from native getConstants() (resolved below); these are the fallbacks
|
|
26
|
-
// that keep the constants object populated headless and on a host without the module.
|
|
27
|
-
const FALLBACK_CONSTANTS = {
|
|
28
|
-
SHORT: 0,
|
|
29
|
-
LONG: 1,
|
|
30
|
-
TOP: 48,
|
|
31
|
-
BOTTOM: 80,
|
|
32
|
-
CENTER: 17,
|
|
33
|
-
};
|
|
34
|
-
// Lazily resolved so importing this module has no native side effect.
|
|
35
|
-
let toastModule;
|
|
36
|
-
function getModule() {
|
|
37
|
-
if (toastModule === undefined) {
|
|
38
|
-
toastModule = getNativeModule(TOAST_MODULE);
|
|
39
|
-
dlog(`ToastAndroid: ToastAndroid module ${toastModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
40
|
-
}
|
|
41
|
-
return toastModule;
|
|
42
|
-
}
|
|
43
|
-
// Read a single numeric constant from the native getConstants() payload, narrowing
|
|
44
|
-
// with a `typeof` guard (no cast) and falling back to the conventional RN value when
|
|
45
|
-
// the module or the key is absent.
|
|
46
|
-
function readConstant(raw, key) {
|
|
47
|
-
const value = raw[key];
|
|
48
|
-
return typeof value === 'number' ? value : FALLBACK_CONSTANTS[key];
|
|
49
|
-
}
|
|
50
|
-
// Resolve the constants once: real numbers from native on a device, fallbacks
|
|
51
|
-
// otherwise. Always returns a fully-populated object so the constants are never
|
|
52
|
-
// undefined, even headless.
|
|
53
|
-
function resolveConstants() {
|
|
54
|
-
const module = getModule();
|
|
55
|
-
if (module === null) {
|
|
56
|
-
dlog('ToastAndroid: constants from fallbacks (native module unavailable)');
|
|
57
|
-
return { ...FALLBACK_CONSTANTS };
|
|
58
|
-
}
|
|
59
|
-
const raw = module.getConstants();
|
|
60
|
-
return {
|
|
61
|
-
SHORT: readConstant(raw, 'SHORT'),
|
|
62
|
-
LONG: readConstant(raw, 'LONG'),
|
|
63
|
-
TOP: readConstant(raw, 'TOP'),
|
|
64
|
-
BOTTOM: readConstant(raw, 'BOTTOM'),
|
|
65
|
-
CENTER: readConstant(raw, 'CENTER'),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
const constants = resolveConstants();
|
|
69
|
-
export const ToastAndroid = {
|
|
70
|
-
// Toast duration constants.
|
|
71
|
-
SHORT: constants.SHORT,
|
|
72
|
-
LONG: constants.LONG,
|
|
73
|
-
// Toast gravity constants.
|
|
74
|
-
TOP: constants.TOP,
|
|
75
|
-
BOTTOM: constants.BOTTOM,
|
|
76
|
-
CENTER: constants.CENTER,
|
|
77
|
-
// Show a toast with the given message and duration. Degrades to a no-op (logged)
|
|
78
|
-
// when the module is absent; a missing optional native module must never throw.
|
|
79
|
-
show(message, duration) {
|
|
80
|
-
const module = getModule();
|
|
81
|
-
if (module === null) {
|
|
82
|
-
dlog('ToastAndroid.show -> ToastAndroid native module unavailable, no-op');
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
dlog(`ToastAndroid.show -> "${message}" (${duration})`);
|
|
86
|
-
module.show(message, duration);
|
|
87
|
-
},
|
|
88
|
-
// Show a toast at the given layout gravity (TOP / BOTTOM / CENTER).
|
|
89
|
-
showWithGravity(message, duration, gravity) {
|
|
90
|
-
const module = getModule();
|
|
91
|
-
if (module === null) {
|
|
92
|
-
dlog('ToastAndroid.showWithGravity -> ToastAndroid native module unavailable, no-op');
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
dlog(`ToastAndroid.showWithGravity -> "${message}" (${duration}, gravity=${gravity})`);
|
|
96
|
-
module.showWithGravity(message, duration, gravity);
|
|
97
|
-
},
|
|
98
|
-
// Show a toast at the given gravity, offset by xOffset/yOffset pixels.
|
|
99
|
-
showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset) {
|
|
100
|
-
const module = getModule();
|
|
101
|
-
if (module === null) {
|
|
102
|
-
dlog('ToastAndroid.showWithGravityAndOffset -> ToastAndroid native module unavailable, no-op');
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
dlog(`ToastAndroid.showWithGravityAndOffset -> "${message}" (${duration}, gravity=${gravity}, ${xOffset}, ${yOffset})`);
|
|
106
|
-
module.showWithGravityAndOffset(message, duration, gravity, xOffset, yOffset);
|
|
107
|
-
},
|
|
108
|
-
};
|
|
1
|
+
// ToastAndroid: base / headless build. Metro picks index.android.ts / index.ios.ts on a device; off
|
|
2
|
+
// those, RN's non-Android fallback is the default, as RN's own ToastAndroid.js is.
|
|
3
|
+
export * from './index.ios.js';
|
package/build/touch-history.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
// Per-touch position/time tracking, ported from RN's
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// `touchHistory` onto the nativeEvent reaching responder handlers, exactly how
|
|
7
|
-
// ResponderEventPlugin.js sets `*.touchHistory`.
|
|
8
|
-
//
|
|
9
|
-
// events/index.ts consumes only this file's public surface (recordTouchTrack,
|
|
10
|
-
// attachTouchHistory, resetTouchHistory, touchHistory); everything else here is a
|
|
11
|
-
// private implementation detail of the bank.
|
|
1
|
+
// Per-touch position/time tracking, ported from RN's ResponderTouchHistoryStore. PanResponder's
|
|
2
|
+
// multitouch dx/vx math needs each touch's own previous->current delta, which a grant-relative
|
|
3
|
+
// centroid of all live touches can't reconstruct; the bank attaches to responder events.
|
|
4
|
+
// events/index.ts consumes only this file's public surface (recordTouchTrack, attachTouchHistory,
|
|
5
|
+
// resetTouchHistory, touchHistory); everything else here is a private implementation detail.
|
|
12
6
|
import { isRecord } from './type-guards.js';
|
|
13
7
|
// RN's bank is indexed by touch identifier and warns above 20; we never warn (headless
|
|
14
8
|
// events may carry larger or absent ids), we just skip anything out of a sane range.
|