@symbiote-native/engine 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/alert/shared.d.ts +1 -1
- package/build/alert/shared.js +3 -7
- package/build/app-state/index.d.ts +1 -1
- package/build/app-state/index.js +35 -27
- package/build/back-handler/index.d.ts +7 -2
- package/build/back-handler/index.js +19 -10
- package/build/events/index.js +10 -1
- package/build/fabric-props.js +1 -1
- package/build/fabric.d.ts +7 -0
- package/build/fabric.js +14 -0
- package/build/host-behavior.d.ts +1 -0
- package/build/image-loader.d.ts +4 -2
- package/build/image-loader.js +14 -25
- package/build/image-source-write.d.ts +1 -1
- package/build/image-source-write.js +14 -2
- package/build/index.d.ts +2 -2
- package/build/index.js +6 -6
- 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/native-events.d.ts +5 -0
- package/build/native-events.js +21 -0
- package/build/node.js +18 -2
- 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/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/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/cpp/SymbioteFabricProps.cpp +204 -120
- package/cpp/SymbioteFabricProps.h +5 -0
- package/cpp/SymbioteTree.cpp +20 -6
- package/package.json +2 -2
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Settings module: reads/writes the app's persisted defaults (iOS NSUserDefaults
|
|
2
|
+
// via the native SettingsManager). A JS-side snapshot seeded from the native module
|
|
3
|
+
// constants answers `get`; `set` writes through to native and updates the snapshot;
|
|
4
|
+
// `watchKeys`/`clearWatch` are a pure-JS subscription registry that fires when a
|
|
5
|
+
// watched key's value changes. Native re-broadcasts external edits through the
|
|
6
|
+
// device event `settingsUpdated`, which feeds the same change->fire path. Mirrors
|
|
7
|
+
// RN's Libraries/Settings/Settings.ios.js, iOS surface only.
|
|
8
|
+
import { installDeviceEventHub, NativeEventEmitter, } from '../native-events.js';
|
|
9
|
+
import { getNativeModule } from '../native-modules/index.js';
|
|
10
|
+
import { dlog } from '../debug.js';
|
|
11
|
+
import { isRecord } from '../type-guards.js';
|
|
12
|
+
// The iOS native module name RN registers this under. NOTE: this is the name the
|
|
13
|
+
// iOS JS wrapper resolves via `TurboModuleRegistry.getEnforcing('SettingsManager')`.
|
|
14
|
+
// The spec filename is `INativeSettingsManager`. A module name is only provable on a
|
|
15
|
+
// real host (a headless fake answers to any name); this iOS name is device-verify-pending.
|
|
16
|
+
const SETTINGS_MODULE = 'SettingsManager';
|
|
17
|
+
// The device event native emits when the app's defaults change out from under JS
|
|
18
|
+
// (e.g. a Settings.bundle edit). Its payload is a record of changed key->value.
|
|
19
|
+
const SETTINGS_UPDATED_EVENT = 'settingsUpdated';
|
|
20
|
+
// watchIds are handed out as the registry index, so the first watcher is 0. A
|
|
21
|
+
// cleared slot keeps its index (the array never shrinks) so later ids stay stable.
|
|
22
|
+
const FIRST_WATCH_ID = 0;
|
|
23
|
+
// Lazily resolved so importing this module has no native side effect. `null` when
|
|
24
|
+
// the module isn't linked (headless): the snapshot then starts empty and `set`
|
|
25
|
+
// updates only JS state + fires watchers.
|
|
26
|
+
let settingsModule;
|
|
27
|
+
function getModule() {
|
|
28
|
+
if (settingsModule === undefined) {
|
|
29
|
+
settingsModule = getNativeModule(SETTINGS_MODULE);
|
|
30
|
+
dlog(`Settings: module ${settingsModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
31
|
+
}
|
|
32
|
+
return settingsModule;
|
|
33
|
+
}
|
|
34
|
+
// The JS-side mirror of native defaults: seeded once from the module constants,
|
|
35
|
+
// kept in sync by `set` and by the `settingsUpdated` device event.
|
|
36
|
+
let snapshot;
|
|
37
|
+
function getSnapshot() {
|
|
38
|
+
if (snapshot === undefined) {
|
|
39
|
+
const module = getModule();
|
|
40
|
+
const constants = module?.getConstants().settings;
|
|
41
|
+
snapshot = isRecord(constants) ? { ...constants } : {};
|
|
42
|
+
dlog(`Settings: snapshot seeded with ${Object.keys(snapshot).length} key(s)`);
|
|
43
|
+
}
|
|
44
|
+
return snapshot;
|
|
45
|
+
}
|
|
46
|
+
const subscriptions = [];
|
|
47
|
+
// Fire every watcher whose key set covers `key`. Called only for keys that changed.
|
|
48
|
+
function fireWatchers(key) {
|
|
49
|
+
for (const sub of subscriptions) {
|
|
50
|
+
if (sub.callback !== null && sub.keys.includes(key))
|
|
51
|
+
sub.callback();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Fold a batch of new values into the snapshot, firing watchers for each key whose
|
|
55
|
+
// value actually changed. Shared by `set` (JS-originated) and the device event
|
|
56
|
+
// (native-originated), matching RN's `_sendObservations`.
|
|
57
|
+
function applyChanges(values) {
|
|
58
|
+
const current = getSnapshot();
|
|
59
|
+
for (const key of Object.keys(values)) {
|
|
60
|
+
const next = values[key];
|
|
61
|
+
const didChange = current[key] !== next;
|
|
62
|
+
current[key] = next;
|
|
63
|
+
if (didChange)
|
|
64
|
+
fireWatchers(key);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
let emitter;
|
|
68
|
+
// Subscribe to native's `settingsUpdated` so external edits flow into the snapshot.
|
|
69
|
+
// WHY lazy + module-gated: importing this file must have no native side effect, and
|
|
70
|
+
// with no native module there is nothing native to observe, so a headless run that
|
|
71
|
+
// never installs the device hub doesn't crash. Idempotent.
|
|
72
|
+
function subscribeToNative() {
|
|
73
|
+
if (emitter !== undefined)
|
|
74
|
+
return;
|
|
75
|
+
const module = getModule();
|
|
76
|
+
if (module === null)
|
|
77
|
+
return;
|
|
78
|
+
installDeviceEventHub();
|
|
79
|
+
emitter = new NativeEventEmitter(module);
|
|
80
|
+
emitter.addListener(SETTINGS_UPDATED_EVENT, payload => {
|
|
81
|
+
if (!isRecord(payload))
|
|
82
|
+
return;
|
|
83
|
+
applyChanges(payload);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
class SettingsImpl {
|
|
87
|
+
// Read the current value for `key` from the JS snapshot. `undefined` if unset.
|
|
88
|
+
get(key) {
|
|
89
|
+
subscribeToNative();
|
|
90
|
+
return getSnapshot()[key];
|
|
91
|
+
}
|
|
92
|
+
// Persist `settings` to native, update the snapshot, and fire watchers for the
|
|
93
|
+
// keys that changed. Without a native module (headless) only JS state updates.
|
|
94
|
+
set(settings) {
|
|
95
|
+
subscribeToNative();
|
|
96
|
+
const module = getModule();
|
|
97
|
+
if (module === null) {
|
|
98
|
+
dlog('Settings.set -> no module (JS snapshot + watchers only)');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
module.setValues(settings);
|
|
102
|
+
}
|
|
103
|
+
applyChanges(settings);
|
|
104
|
+
}
|
|
105
|
+
// Register a watcher for one or more keys. Returns a numeric watchId (the registry
|
|
106
|
+
// index) to pass to `clearWatch`.
|
|
107
|
+
watchKeys(keys, callback) {
|
|
108
|
+
subscribeToNative();
|
|
109
|
+
const watched = typeof keys === 'string' ? [keys] : keys;
|
|
110
|
+
const watchId = subscriptions.length + FIRST_WATCH_ID;
|
|
111
|
+
subscriptions.push({ keys: watched, callback });
|
|
112
|
+
return watchId;
|
|
113
|
+
}
|
|
114
|
+
// Disarm the watcher with the given id. Its slot is emptied (kept, not removed) so
|
|
115
|
+
// every other watchId stays valid.
|
|
116
|
+
clearWatch(watchId) {
|
|
117
|
+
if (watchId >= FIRST_WATCH_ID && watchId < subscriptions.length) {
|
|
118
|
+
subscriptions[watchId] = { keys: [], callback: null };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
export const Settings = new SettingsImpl();
|
package/build/settings/index.js
CHANGED
|
@@ -1,122 +1,3 @@
|
|
|
1
|
-
// Settings
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// `watchKeys`/`clearWatch` are a pure-JS subscription registry that fires when a
|
|
5
|
-
// watched key's value changes. Native re-broadcasts external edits through the
|
|
6
|
-
// device event `settingsUpdated`, which feeds the same change->fire path. Mirrors
|
|
7
|
-
// RN's Libraries/Settings/Settings.ios.js, iOS surface only.
|
|
8
|
-
import { installDeviceEventHub, NativeEventEmitter, } from '../native-events.js';
|
|
9
|
-
import { getNativeModule } from '../native-modules/index.js';
|
|
10
|
-
import { dlog } from '../debug.js';
|
|
11
|
-
import { isRecord } from '../type-guards.js';
|
|
12
|
-
// The iOS native module name RN registers this under. NOTE: this is the name the
|
|
13
|
-
// iOS JS wrapper resolves via `TurboModuleRegistry.getEnforcing('SettingsManager')`.
|
|
14
|
-
// The spec filename is `INativeSettingsManager`. A module name is only provable on a
|
|
15
|
-
// real host (a headless fake answers to any name); this iOS name is device-verify-pending.
|
|
16
|
-
const SETTINGS_MODULE = 'SettingsManager';
|
|
17
|
-
// The device event native emits when the app's defaults change out from under JS
|
|
18
|
-
// (e.g. a Settings.bundle edit). Its payload is a record of changed key->value.
|
|
19
|
-
const SETTINGS_UPDATED_EVENT = 'settingsUpdated';
|
|
20
|
-
// watchIds are handed out as the registry index, so the first watcher is 0. A
|
|
21
|
-
// cleared slot keeps its index (the array never shrinks) so later ids stay stable.
|
|
22
|
-
const FIRST_WATCH_ID = 0;
|
|
23
|
-
// Lazily resolved so importing this module has no native side effect. `null` when
|
|
24
|
-
// the module isn't linked (headless): the snapshot then starts empty and `set`
|
|
25
|
-
// updates only JS state + fires watchers.
|
|
26
|
-
let settingsModule;
|
|
27
|
-
function getModule() {
|
|
28
|
-
if (settingsModule === undefined) {
|
|
29
|
-
settingsModule = getNativeModule(SETTINGS_MODULE);
|
|
30
|
-
dlog(`Settings: module ${settingsModule ? 'resolved' : 'NOT resolved (null)'}`);
|
|
31
|
-
}
|
|
32
|
-
return settingsModule;
|
|
33
|
-
}
|
|
34
|
-
// The JS-side mirror of native defaults: seeded once from the module constants,
|
|
35
|
-
// kept in sync by `set` and by the `settingsUpdated` device event.
|
|
36
|
-
let snapshot;
|
|
37
|
-
function getSnapshot() {
|
|
38
|
-
if (snapshot === undefined) {
|
|
39
|
-
const module = getModule();
|
|
40
|
-
const constants = module?.getConstants().settings;
|
|
41
|
-
snapshot = isRecord(constants) ? { ...constants } : {};
|
|
42
|
-
dlog(`Settings: snapshot seeded with ${Object.keys(snapshot).length} key(s)`);
|
|
43
|
-
}
|
|
44
|
-
return snapshot;
|
|
45
|
-
}
|
|
46
|
-
const subscriptions = [];
|
|
47
|
-
// Fire every watcher whose key set covers `key`. Called only for keys that changed.
|
|
48
|
-
function fireWatchers(key) {
|
|
49
|
-
for (const sub of subscriptions) {
|
|
50
|
-
if (sub.callback !== null && sub.keys.includes(key))
|
|
51
|
-
sub.callback();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
// Fold a batch of new values into the snapshot, firing watchers for each key whose
|
|
55
|
-
// value actually changed. Shared by `set` (JS-originated) and the device event
|
|
56
|
-
// (native-originated), matching RN's `_sendObservations`.
|
|
57
|
-
function applyChanges(values) {
|
|
58
|
-
const current = getSnapshot();
|
|
59
|
-
for (const key of Object.keys(values)) {
|
|
60
|
-
const next = values[key];
|
|
61
|
-
const didChange = current[key] !== next;
|
|
62
|
-
current[key] = next;
|
|
63
|
-
if (didChange)
|
|
64
|
-
fireWatchers(key);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
let emitter;
|
|
68
|
-
// Subscribe to native's `settingsUpdated` so external edits flow into the snapshot.
|
|
69
|
-
// WHY lazy + module-gated: importing this file must have no native side effect, and
|
|
70
|
-
// with no native module there is nothing native to observe, so a headless run that
|
|
71
|
-
// never installs the device hub doesn't crash. Idempotent.
|
|
72
|
-
function subscribeToNative() {
|
|
73
|
-
if (emitter !== undefined)
|
|
74
|
-
return;
|
|
75
|
-
const module = getModule();
|
|
76
|
-
if (module === null)
|
|
77
|
-
return;
|
|
78
|
-
installDeviceEventHub();
|
|
79
|
-
emitter = new NativeEventEmitter(module);
|
|
80
|
-
emitter.addListener(SETTINGS_UPDATED_EVENT, payload => {
|
|
81
|
-
if (!isRecord(payload))
|
|
82
|
-
return;
|
|
83
|
-
applyChanges(payload);
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
class SettingsImpl {
|
|
87
|
-
// Read the current value for `key` from the JS snapshot. `undefined` if unset.
|
|
88
|
-
get(key) {
|
|
89
|
-
subscribeToNative();
|
|
90
|
-
return getSnapshot()[key];
|
|
91
|
-
}
|
|
92
|
-
// Persist `settings` to native, update the snapshot, and fire watchers for the
|
|
93
|
-
// keys that changed. Without a native module (headless) only JS state updates.
|
|
94
|
-
set(settings) {
|
|
95
|
-
subscribeToNative();
|
|
96
|
-
const module = getModule();
|
|
97
|
-
if (module === null) {
|
|
98
|
-
dlog('Settings.set -> no module (JS snapshot + watchers only)');
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
module.setValues(settings);
|
|
102
|
-
}
|
|
103
|
-
applyChanges(settings);
|
|
104
|
-
}
|
|
105
|
-
// Register a watcher for one or more keys. Returns a numeric watchId (the registry
|
|
106
|
-
// index) to pass to `clearWatch`.
|
|
107
|
-
watchKeys(keys, callback) {
|
|
108
|
-
subscribeToNative();
|
|
109
|
-
const watched = typeof keys === 'string' ? [keys] : keys;
|
|
110
|
-
const watchId = subscriptions.length + FIRST_WATCH_ID;
|
|
111
|
-
subscriptions.push({ keys: watched, callback });
|
|
112
|
-
return watchId;
|
|
113
|
-
}
|
|
114
|
-
// Disarm the watcher with the given id. Its slot is emptied (kept, not removed) so
|
|
115
|
-
// every other watchId stays valid.
|
|
116
|
-
clearWatch(watchId) {
|
|
117
|
-
if (watchId >= FIRST_WATCH_ID && watchId < subscriptions.length) {
|
|
118
|
-
subscriptions[watchId] = { keys: [], callback: null };
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
export const Settings = new SettingsImpl();
|
|
1
|
+
// Settings: base / headless build. Metro picks index.ios.ts / index.android.ts on a device; off
|
|
2
|
+
// those, the iOS build (the SettingsManager-backed one) is the default.
|
|
3
|
+
export * from './index.ios.js';
|
|
@@ -9,47 +9,24 @@
|
|
|
9
9
|
// name, so it is only proven on a real Android host (a bridgeless resolution log there).
|
|
10
10
|
import { dlog } from '../debug.js';
|
|
11
11
|
import { getNativeModule } from '../native-modules/index.js';
|
|
12
|
-
import {
|
|
12
|
+
import { assertShareArgs, invariant, shareActions } from './shared.js';
|
|
13
13
|
const SHARE_MODULE = 'ShareModule';
|
|
14
|
-
// ShareModule.share resolves an untyped value at the native boundary; narrow it before
|
|
15
|
-
// reading `action` (no `as`).
|
|
16
|
-
function isShareResult(value) {
|
|
17
|
-
return (typeof value === 'object' &&
|
|
18
|
-
value !== null &&
|
|
19
|
-
'action' in value &&
|
|
20
|
-
typeof value.action === 'string');
|
|
21
|
-
}
|
|
22
14
|
export const Share = {
|
|
23
15
|
...shareActions,
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
// native result, or a missing module (explicit reject, never a hung Promise).
|
|
16
|
+
// Share.js's Android branch: every check is a synchronous invariant, and the native result
|
|
17
|
+
// passes through untouched under `activityType: null`.
|
|
27
18
|
share(content, options = {}) {
|
|
28
|
-
|
|
29
|
-
if (invalid !== null) {
|
|
30
|
-
dlog(`Share.share -> invalid content: ${invalid.message}`);
|
|
31
|
-
return Promise.reject(invalid);
|
|
32
|
-
}
|
|
19
|
+
assertShareArgs(content, options);
|
|
33
20
|
dlog('Share.share (android)');
|
|
34
21
|
const shareModule = getNativeModule(SHARE_MODULE);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return Promise.reject(new Error('Share: ShareModule native module unavailable'));
|
|
38
|
-
}
|
|
22
|
+
invariant(shareModule !== null, 'ShareModule should be registered on Android.');
|
|
23
|
+
invariant(content.title == null || typeof content.title === 'string', 'Invalid title: title should be a string.');
|
|
39
24
|
const newContent = {
|
|
40
25
|
title: content.title,
|
|
41
26
|
message: typeof content.message === 'string' ? content.message : undefined,
|
|
42
27
|
};
|
|
43
|
-
return shareModule
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
throw new Error('Share: ShareModule returned an unexpected result');
|
|
47
|
-
}
|
|
48
|
-
dlog(`Share.share -> android action=${result.action}`);
|
|
49
|
-
return {
|
|
50
|
-
action: result.action === DISMISSED_ACTION ? DISMISSED_ACTION : SHARED_ACTION,
|
|
51
|
-
activityType: null,
|
|
52
|
-
};
|
|
53
|
-
});
|
|
28
|
+
return shareModule
|
|
29
|
+
.share(newContent, options.dialogTitle)
|
|
30
|
+
.then(result => ({ activityType: null, ...result }));
|
|
54
31
|
},
|
|
55
32
|
};
|
package/build/share/index.ios.js
CHANGED
|
@@ -7,39 +7,38 @@
|
|
|
7
7
|
import { dlog } from '../debug.js';
|
|
8
8
|
import { getNativeModule } from '../native-modules/index.js';
|
|
9
9
|
import { ACTION_SHEET_MANAGER, } from '../action-sheet-ios/index.js';
|
|
10
|
-
import {
|
|
10
|
+
import { isProcessableColor, processColor } from '../platform-color';
|
|
11
|
+
import { assertShareArgs, invariant, shareActions, SHARED_ACTION, DISMISSED_ACTION, } from './shared.js';
|
|
11
12
|
export const Share = {
|
|
12
13
|
...shareActions,
|
|
13
14
|
// Open the iOS share sheet for `content`. Resolves with the user's action
|
|
14
15
|
// (sharedAction / dismissedAction); rejects on invalid content, a native failure,
|
|
15
16
|
// or a missing module (explicit reject rather than a Promise that never settles).
|
|
16
17
|
share(content, options = {}) {
|
|
17
|
-
|
|
18
|
-
if (invalid !== null) {
|
|
19
|
-
dlog(`Share.share -> invalid content: ${invalid.message}`);
|
|
20
|
-
return Promise.reject(invalid);
|
|
21
|
-
}
|
|
18
|
+
assertShareArgs(content, options);
|
|
22
19
|
dlog('Share.share (ios)');
|
|
23
|
-
|
|
24
|
-
if (manager === null) {
|
|
25
|
-
dlog(`Share: "${ACTION_SHEET_MANAGER}" unresolved`);
|
|
26
|
-
return Promise.reject(new Error('Share: ActionSheetManager native module unavailable'));
|
|
27
|
-
}
|
|
20
|
+
// Share.js's iOS branch: both invariants run INSIDE the executor, so they reject.
|
|
28
21
|
return new Promise((resolve, reject) => {
|
|
22
|
+
const tintColor = isProcessableColor(options.tintColor)
|
|
23
|
+
? processColor(options.tintColor)
|
|
24
|
+
: undefined;
|
|
25
|
+
invariant(tintColor == null || typeof tintColor === 'number', 'Unexpected color given for options.tintColor');
|
|
26
|
+
const manager = getNativeModule(ACTION_SHEET_MANAGER);
|
|
27
|
+
invariant(manager !== null, 'NativeActionSheetManager is not registered on iOS, but it should be.');
|
|
29
28
|
manager.showShareActionSheetWithOptions({
|
|
30
29
|
message: typeof content.message === 'string' ? content.message : undefined,
|
|
31
30
|
url: typeof content.url === 'string' ? content.url : undefined,
|
|
32
31
|
subject: options.subject,
|
|
33
|
-
tintColor:
|
|
34
|
-
anchor: options.anchor,
|
|
32
|
+
tintColor: typeof tintColor === 'number' ? tintColor : undefined,
|
|
33
|
+
anchor: typeof options.anchor === 'number' ? options.anchor : undefined,
|
|
35
34
|
excludedActivityTypes: options.excludedActivityTypes,
|
|
36
35
|
}, error => {
|
|
37
36
|
dlog('Share.share -> failure');
|
|
38
|
-
reject(
|
|
37
|
+
reject(error);
|
|
39
38
|
}, (completed, activityType) => {
|
|
40
39
|
dlog(`Share.share -> success completed=${completed}`);
|
|
41
40
|
resolve(completed
|
|
42
|
-
? { action: SHARED_ACTION, activityType
|
|
41
|
+
? { action: SHARED_ACTION, activityType }
|
|
43
42
|
: { action: DISMISSED_ACTION, activityType: null });
|
|
44
43
|
});
|
|
45
44
|
});
|
package/build/share/shared.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { invariant } from '../invariant';
|
|
2
|
+
export { invariant };
|
|
1
3
|
export type IShareContent = {
|
|
2
4
|
title?: string;
|
|
3
5
|
url: string;
|
|
@@ -17,7 +19,7 @@ export interface IShareOptions {
|
|
|
17
19
|
export declare const SHARED_ACTION = "sharedAction";
|
|
18
20
|
export declare const DISMISSED_ACTION = "dismissedAction";
|
|
19
21
|
export interface IShareAction {
|
|
20
|
-
action:
|
|
22
|
+
action: string;
|
|
21
23
|
activityType?: string | null;
|
|
22
24
|
}
|
|
23
25
|
export interface IShareStatic {
|
|
@@ -29,4 +31,4 @@ export declare const shareActions: {
|
|
|
29
31
|
sharedAction: typeof SHARED_ACTION;
|
|
30
32
|
dismissedAction: typeof DISMISSED_ACTION;
|
|
31
33
|
};
|
|
32
|
-
export declare function
|
|
34
|
+
export declare function assertShareArgs(content: IShareContent, options: IShareOptions): void;
|
package/build/share/shared.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
// Metro selects the platform file on a real host (share.android.ts > share.ts); the base
|
|
8
8
|
// share.ts re-exports the iOS build for web/headless. There is no runtime `Platform.OS`
|
|
9
9
|
// read: the filename is the selector.
|
|
10
|
+
import { invariant } from '../invariant.js';
|
|
11
|
+
export { invariant };
|
|
10
12
|
// RN's Share action constants (RN Share.js ~173/179). These back the documented
|
|
11
13
|
// `result.action === Share.dismissedAction` pattern. True statically-known literals,
|
|
12
14
|
// so CONSTANT_CASE; the public fields (Share.sharedAction / Share.dismissedAction) are
|
|
@@ -19,14 +21,9 @@ export const shareActions = {
|
|
|
19
21
|
sharedAction: SHARED_ACTION,
|
|
20
22
|
dismissedAction: DISMISSED_ACTION,
|
|
21
23
|
};
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
if (typeof content.url !== 'string' && typeof content.message !== 'string') {
|
|
29
|
-
return new Error('At least one of URL or message is required');
|
|
30
|
-
}
|
|
31
|
-
return null;
|
|
24
|
+
// Share.js's three shared invariants, checked before any promise exists on both platforms.
|
|
25
|
+
export function assertShareArgs(content, options) {
|
|
26
|
+
invariant(typeof content === 'object' && content !== null, 'Content to share must be a valid object');
|
|
27
|
+
invariant(typeof content.url === 'string' || typeof content.message === 'string', 'At least one of URL or message is required');
|
|
28
|
+
invariant(typeof options === 'object' && options !== null, 'Options must be a valid object');
|
|
32
29
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// on device: show/hide + light/dark text survive the relayout without blanking.
|
|
12
12
|
import { getNativeModule } from '../native-modules/index.js';
|
|
13
13
|
import { dlog } from '../debug.js';
|
|
14
|
-
import { processColor } from '../platform-color
|
|
14
|
+
import { processColor } from '../platform-color';
|
|
15
15
|
import { STATUS_BAR_MANAGER, } from './shared.js';
|
|
16
16
|
// processColor returns `unknown` (its result is platform-dependent); narrow to the
|
|
17
17
|
// number Fabric/native expects, like RN's invariant before setColor. A non-number
|
|
@@ -17,9 +17,10 @@ import { STATUS_BAR_MANAGER, STATIC_HIDE_TRANSITION, hideTransition, } from './s
|
|
|
17
17
|
// __turboModuleProxy is installed. Non-enforcing: a declarative StatusBar must NOT crash the
|
|
18
18
|
// whole render if the module can't resolve.
|
|
19
19
|
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
20
|
+
// TODO(rn-parity): each StatusBar applies its props directly. RN keeps a stack instead:
|
|
21
|
+
// `_propsStack` over `_defaultProps`, unmount restores the previous entry, one batched native
|
|
22
|
+
// update, public push/pop/replaceStackEntry, `showHideTransition`, and static setters that warn
|
|
23
|
+
// on the wrong platform. Port it for both platforms and all 5 adapters.
|
|
23
24
|
export function applyStatusBarProps(props) {
|
|
24
25
|
const { barStyle, hidden, animated = false, networkActivityIndicatorVisible, } = props;
|
|
25
26
|
const manager = getNativeModule(STATUS_BAR_MANAGER);
|
|
@@ -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
|
+
};
|