@buoy-gg/shared-ui 2.1.3 → 2.1.4-beta.3
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/lib/commonjs/clipboard/clipboard-impl.js +86 -10
- package/lib/commonjs/hooks/safe-area-impl.js +1 -1
- package/lib/commonjs/index.js +42 -0
- package/lib/commonjs/storage/devToolsStorageKeys.js +6 -1
- package/lib/commonjs/utils/index.js +38 -1
- package/lib/commonjs/utils/safeExpoRouter.js +141 -0
- package/lib/module/clipboard/clipboard-impl.js +85 -10
- package/lib/module/hooks/safe-area-impl.js +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/storage/devToolsStorageKeys.js +6 -1
- package/lib/module/utils/index.js +2 -1
- package/lib/module/utils/safeExpoRouter.js +132 -0
- package/lib/typescript/commonjs/clipboard/clipboard-impl.d.ts +15 -8
- package/lib/typescript/commonjs/clipboard/clipboard-impl.d.ts.map +1 -1
- package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/index.d.ts +1 -0
- package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts +17 -0
- package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts.map +1 -0
- package/lib/typescript/module/clipboard/clipboard-impl.d.ts +15 -8
- package/lib/typescript/module/clipboard/clipboard-impl.d.ts.map +1 -1
- package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
- package/lib/typescript/module/index.d.ts +1 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
- package/lib/typescript/module/utils/index.d.ts +1 -0
- package/lib/typescript/module/utils/index.d.ts.map +1 -1
- package/lib/typescript/module/utils/safeExpoRouter.d.ts +17 -0
- package/lib/typescript/module/utils/safeExpoRouter.d.ts.map +1 -0
- package/package.json +4 -7
- package/scripts/detect-clipboard.js +78 -126
|
@@ -5,22 +5,98 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.isClipboardAvailable = exports.clipboardType = exports.clipboardFunction = void 0;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* Detected: none
|
|
10
|
-
* Generated at: 2026-02-03T00:33:15.804Z
|
|
8
|
+
* Runtime clipboard implementation
|
|
11
9
|
*
|
|
12
|
-
*
|
|
10
|
+
* Uses Metro's allowOptionalDependencies with top-level try-catch
|
|
11
|
+
* so Metro marks these requires as optional (skipped if not installed).
|
|
13
12
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* We grab module references eagerly (for Metro), but detect which one
|
|
14
|
+
* actually works lazily on first use — by trying to call it. This avoids
|
|
15
|
+
* NativeModules checks which don't work with TurboModules/new architecture.
|
|
16
|
+
*
|
|
17
|
+
* Consumers must set `transformer.allowOptionalDependencies = true`
|
|
18
|
+
* in their metro.config.js for this to work.
|
|
19
|
+
*
|
|
20
|
+
* Fallback chain:
|
|
21
|
+
* 1. expo-clipboard
|
|
22
|
+
* 2. @react-native-clipboard/clipboard
|
|
23
|
+
* 3. Graceful failure
|
|
17
24
|
*/
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
// Grab module references at load time (top-level try-catch for Metro)
|
|
27
|
+
// Always require both — we decide which actually works at call time
|
|
28
|
+
let _expoClipboard = null;
|
|
29
|
+
try {
|
|
30
|
+
_expoClipboard = require("expo-clipboard");
|
|
31
|
+
} catch {}
|
|
32
|
+
let _rnClipboard = null;
|
|
33
|
+
try {
|
|
34
|
+
const mod = require("@react-native-clipboard/clipboard");
|
|
35
|
+
_rnClipboard = mod.default || mod;
|
|
36
|
+
} catch {}
|
|
37
|
+
|
|
38
|
+
// Lazy detection: resolved on first clipboardFunction() call
|
|
39
|
+
let _detectedType = null;
|
|
40
|
+
let _clipboardFn = null;
|
|
41
|
+
let _detected = false;
|
|
42
|
+
async function detect(text) {
|
|
43
|
+
// 1. Try expo-clipboard by actually calling it
|
|
44
|
+
if (_expoClipboard && typeof _expoClipboard.setStringAsync === "function") {
|
|
45
|
+
try {
|
|
46
|
+
await _expoClipboard.setStringAsync(text);
|
|
47
|
+
_detectedType = "expo";
|
|
48
|
+
_clipboardFn = async t => {
|
|
49
|
+
await _expoClipboard.setStringAsync(t);
|
|
50
|
+
return true;
|
|
51
|
+
};
|
|
52
|
+
_detected = true;
|
|
53
|
+
return true;
|
|
54
|
+
} catch {}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 2. Try @react-native-clipboard/clipboard
|
|
58
|
+
if (_rnClipboard && typeof _rnClipboard.setString === "function") {
|
|
59
|
+
try {
|
|
60
|
+
_rnClipboard.setString(text);
|
|
61
|
+
_detectedType = "react-native";
|
|
62
|
+
_clipboardFn = async t => {
|
|
63
|
+
_rnClipboard.setString(t);
|
|
64
|
+
return true;
|
|
65
|
+
};
|
|
66
|
+
_detected = true;
|
|
67
|
+
return true;
|
|
68
|
+
} catch {}
|
|
69
|
+
}
|
|
70
|
+
_detected = true;
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const clipboardType = () => {
|
|
74
|
+
return _detectedType;
|
|
75
|
+
};
|
|
76
|
+
exports.clipboardType = clipboardType;
|
|
77
|
+
const isClipboardAvailable = () => {
|
|
78
|
+
// Before first use, optimistically return true if we have a module ref
|
|
79
|
+
if (!_detected) return _expoClipboard != null || _rnClipboard != null;
|
|
80
|
+
return _clipboardFn != null;
|
|
81
|
+
};
|
|
21
82
|
exports.isClipboardAvailable = isClipboardAvailable;
|
|
22
83
|
const clipboardFunction = async text => {
|
|
23
|
-
|
|
84
|
+
// If already detected, use the cached function
|
|
85
|
+
if (_detected && _clipboardFn) {
|
|
86
|
+
try {
|
|
87
|
+
return await _clipboardFn(text);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("[buoy] Clipboard copy failed:", error);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// First call: detect which clipboard works by actually trying it
|
|
95
|
+
if (!_detected) {
|
|
96
|
+
const result = await detect(text);
|
|
97
|
+
if (result) return true;
|
|
98
|
+
}
|
|
99
|
+
console.warn("[buoy] No clipboard library available. Install expo-clipboard or @react-native-clipboard/clipboard.");
|
|
24
100
|
return false;
|
|
25
101
|
};
|
|
26
102
|
exports.clipboardFunction = clipboardFunction;
|
|
@@ -7,7 +7,7 @@ exports.useNativeSafeAreaInsets = exports.safeAreaType = exports.hasSafeAreaPack
|
|
|
7
7
|
/**
|
|
8
8
|
* Auto-generated safe area implementation
|
|
9
9
|
* Detected: none
|
|
10
|
-
* Generated at: 2026-02-
|
|
10
|
+
* Generated at: 2026-02-10T20:29:38.101Z
|
|
11
11
|
*
|
|
12
12
|
* DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
|
|
13
13
|
*
|
package/lib/commonjs/index.js
CHANGED
|
@@ -30,6 +30,12 @@ var _exportNames = {
|
|
|
30
30
|
subscriberCountNotifier: true,
|
|
31
31
|
subscribeToSubscriberCountChanges: true,
|
|
32
32
|
notifySubscriberCountChange: true,
|
|
33
|
+
useSafeRouter: true,
|
|
34
|
+
useSafePathname: true,
|
|
35
|
+
useSafeSegments: true,
|
|
36
|
+
useSafeGlobalSearchParams: true,
|
|
37
|
+
getSafeRouter: true,
|
|
38
|
+
isExpoRouterAvailable: true,
|
|
33
39
|
isPlainObjectUtil: true,
|
|
34
40
|
useSafeAreaInsets: true,
|
|
35
41
|
useFilterManager: true,
|
|
@@ -202,6 +208,12 @@ Object.defineProperty(exports, "getSafeAreaInsets", {
|
|
|
202
208
|
return _index3.getSafeAreaInsets;
|
|
203
209
|
}
|
|
204
210
|
});
|
|
211
|
+
Object.defineProperty(exports, "getSafeRouter", {
|
|
212
|
+
enumerable: true,
|
|
213
|
+
get: function () {
|
|
214
|
+
return _index3.getSafeRouter;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
205
217
|
Object.defineProperty(exports, "getStorageBackendType", {
|
|
206
218
|
enumerable: true,
|
|
207
219
|
get: function () {
|
|
@@ -244,6 +256,12 @@ Object.defineProperty(exports, "isEmpty", {
|
|
|
244
256
|
return _index3.isEmpty;
|
|
245
257
|
}
|
|
246
258
|
});
|
|
259
|
+
Object.defineProperty(exports, "isExpoRouterAvailable", {
|
|
260
|
+
enumerable: true,
|
|
261
|
+
get: function () {
|
|
262
|
+
return _index3.isExpoRouterAvailable;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
247
265
|
Object.defineProperty(exports, "isJsonSerializable", {
|
|
248
266
|
enumerable: true,
|
|
249
267
|
get: function () {
|
|
@@ -376,6 +394,30 @@ Object.defineProperty(exports, "useSafeAreaInsets", {
|
|
|
376
394
|
return _index1.useSafeAreaInsets;
|
|
377
395
|
}
|
|
378
396
|
});
|
|
397
|
+
Object.defineProperty(exports, "useSafeGlobalSearchParams", {
|
|
398
|
+
enumerable: true,
|
|
399
|
+
get: function () {
|
|
400
|
+
return _index3.useSafeGlobalSearchParams;
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
Object.defineProperty(exports, "useSafePathname", {
|
|
404
|
+
enumerable: true,
|
|
405
|
+
get: function () {
|
|
406
|
+
return _index3.useSafePathname;
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
Object.defineProperty(exports, "useSafeRouter", {
|
|
410
|
+
enumerable: true,
|
|
411
|
+
get: function () {
|
|
412
|
+
return _index3.useSafeRouter;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
Object.defineProperty(exports, "useSafeSegments", {
|
|
416
|
+
enumerable: true,
|
|
417
|
+
get: function () {
|
|
418
|
+
return _index3.useSafeSegments;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
379
421
|
var _index = require("./ui/index.js");
|
|
380
422
|
Object.keys(_index).forEach(function (key) {
|
|
381
423
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -197,11 +197,16 @@ const LEGACY_DEV_TOOL_PATTERNS = ["@devtools", "@dev_tools_", "@modal_state_",
|
|
|
197
197
|
function isDevToolsStorageKey(key) {
|
|
198
198
|
if (!key) return false;
|
|
199
199
|
|
|
200
|
-
// Check if it starts with our base prefix
|
|
200
|
+
// Check if it starts with our base prefix (@react_buoy)
|
|
201
201
|
if (key.startsWith(devToolsStorageKeys.base)) {
|
|
202
202
|
return true;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
// Check for buoy- prefixed keys (modal persistence, license, etc.)
|
|
206
|
+
if (key.startsWith("buoy-")) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
205
210
|
// Check for legacy dev tool keys that need cleanup
|
|
206
211
|
for (const pattern of LEGACY_DEV_TOOL_PATTERNS) {
|
|
207
212
|
if (key.startsWith(pattern)) {
|
|
@@ -51,6 +51,12 @@ Object.defineProperty(exports, "getSafeAreaInsets", {
|
|
|
51
51
|
return _getSafeAreaInsets.getSafeAreaInsets;
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
+
Object.defineProperty(exports, "getSafeRouter", {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _safeExpoRouter.getSafeRouter;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
54
60
|
Object.defineProperty(exports, "getStorageBackendType", {
|
|
55
61
|
enumerable: true,
|
|
56
62
|
get: function () {
|
|
@@ -81,6 +87,12 @@ Object.defineProperty(exports, "isEmpty", {
|
|
|
81
87
|
return _typeHelpers.isEmpty;
|
|
82
88
|
}
|
|
83
89
|
});
|
|
90
|
+
Object.defineProperty(exports, "isExpoRouterAvailable", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
get: function () {
|
|
93
|
+
return _safeExpoRouter.isExpoRouterAvailable;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
84
96
|
Object.defineProperty(exports, "isJsonSerializable", {
|
|
85
97
|
enumerable: true,
|
|
86
98
|
get: function () {
|
|
@@ -159,6 +171,30 @@ Object.defineProperty(exports, "truncateText", {
|
|
|
159
171
|
return _valueFormatting.truncateText;
|
|
160
172
|
}
|
|
161
173
|
});
|
|
174
|
+
Object.defineProperty(exports, "useSafeGlobalSearchParams", {
|
|
175
|
+
enumerable: true,
|
|
176
|
+
get: function () {
|
|
177
|
+
return _safeExpoRouter.useSafeGlobalSearchParams;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
Object.defineProperty(exports, "useSafePathname", {
|
|
181
|
+
enumerable: true,
|
|
182
|
+
get: function () {
|
|
183
|
+
return _safeExpoRouter.useSafePathname;
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
Object.defineProperty(exports, "useSafeRouter", {
|
|
187
|
+
enumerable: true,
|
|
188
|
+
get: function () {
|
|
189
|
+
return _safeExpoRouter.useSafeRouter;
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
Object.defineProperty(exports, "useSafeSegments", {
|
|
193
|
+
enumerable: true,
|
|
194
|
+
get: function () {
|
|
195
|
+
return _safeExpoRouter.useSafeSegments;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
162
198
|
var _displayValue = require("./displayValue.js");
|
|
163
199
|
var _getSafeAreaInsets = require("./getSafeAreaInsets.js");
|
|
164
200
|
var _persistentStorage = require("./persistentStorage.js");
|
|
@@ -167,4 +203,5 @@ var _typeHelpers = require("./typeHelpers.js");
|
|
|
167
203
|
var _valueFormatting = require("./valueFormatting.js");
|
|
168
204
|
var _loadOptionalModule = require("./loadOptionalModule.js");
|
|
169
205
|
var _subscribable = require("./subscribable.js");
|
|
170
|
-
var _subscriberCountNotifier = require("./subscriberCountNotifier.js");
|
|
206
|
+
var _subscriberCountNotifier = require("./subscriberCountNotifier.js");
|
|
207
|
+
var _safeExpoRouter = require("./safeExpoRouter.js");
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.getSafeRouter = getSafeRouter;
|
|
7
|
+
exports.isExpoRouterAvailable = isExpoRouterAvailable;
|
|
8
|
+
exports.useSafeGlobalSearchParams = useSafeGlobalSearchParams;
|
|
9
|
+
exports.useSafePathname = useSafePathname;
|
|
10
|
+
exports.useSafeRouter = useSafeRouter;
|
|
11
|
+
exports.useSafeSegments = useSafeSegments;
|
|
12
|
+
var _reactNative = require("react-native");
|
|
13
|
+
/**
|
|
14
|
+
* Safe wrapper for expo-router
|
|
15
|
+
*
|
|
16
|
+
* Provides optional imports for expo-router hooks and utilities.
|
|
17
|
+
* Falls back to no-op implementations when expo-router is not installed.
|
|
18
|
+
*
|
|
19
|
+
* On RN CLI (without Expo native modules), expo-router's JS is bundled but
|
|
20
|
+
* its hooks crash at runtime because the ExpoLinking native module is missing.
|
|
21
|
+
* We check for the native module BEFORE attempting to use any expo-router hooks.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
let expoRouter = null;
|
|
25
|
+
let isAvailable = false;
|
|
26
|
+
let checkedAvailability = false;
|
|
27
|
+
function checkExpoRouterAvailability() {
|
|
28
|
+
if (checkedAvailability) return isAvailable;
|
|
29
|
+
try {
|
|
30
|
+
// expo-router depends on ExpoLinking native module.
|
|
31
|
+
// On RN CLI the JS is bundled but the native module isn't registered,
|
|
32
|
+
// so require() succeeds but hooks crash at runtime. Check native side first.
|
|
33
|
+
if (!_reactNative.NativeModules.ExpoLinking) {
|
|
34
|
+
checkedAvailability = true;
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
expoRouter = require("expo-router");
|
|
38
|
+
isAvailable = expoRouter != null;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
isAvailable = false;
|
|
41
|
+
expoRouter = null;
|
|
42
|
+
}
|
|
43
|
+
checkedAvailability = true;
|
|
44
|
+
return isAvailable;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// No-op implementations when expo-router is not available
|
|
49
|
+
// ============================================================================
|
|
50
|
+
|
|
51
|
+
function noOpUseRouter() {
|
|
52
|
+
return {
|
|
53
|
+
push: () => console.warn("[buoy] expo-router not installed: push() unavailable"),
|
|
54
|
+
replace: () => console.warn("[buoy] expo-router not installed: replace() unavailable"),
|
|
55
|
+
back: () => console.warn("[buoy] expo-router not installed: back() unavailable"),
|
|
56
|
+
canGoBack: () => false,
|
|
57
|
+
setParams: () => console.warn("[buoy] expo-router not installed: setParams() unavailable"),
|
|
58
|
+
navigate: () => console.warn("[buoy] expo-router not installed: navigate() unavailable")
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function noOpUsePathname() {
|
|
62
|
+
return "/";
|
|
63
|
+
}
|
|
64
|
+
function noOpUseSegments() {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
function noOpUseGlobalSearchParams() {
|
|
68
|
+
return {};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ============================================================================
|
|
72
|
+
// Safe hook exports
|
|
73
|
+
// ============================================================================
|
|
74
|
+
|
|
75
|
+
function useSafeRouter() {
|
|
76
|
+
if (!checkExpoRouterAvailability()) {
|
|
77
|
+
return noOpUseRouter();
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
return expoRouter.useRouter();
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.warn("[buoy] Failed to use expo-router.useRouter:", error);
|
|
83
|
+
return noOpUseRouter();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function useSafePathname() {
|
|
87
|
+
if (!checkExpoRouterAvailability()) {
|
|
88
|
+
return noOpUsePathname();
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
return expoRouter.usePathname();
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.warn("[buoy] Failed to use expo-router.usePathname:", error);
|
|
94
|
+
return noOpUsePathname();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function useSafeSegments() {
|
|
98
|
+
if (!checkExpoRouterAvailability()) {
|
|
99
|
+
return noOpUseSegments();
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
return expoRouter.useSegments();
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.warn("[buoy] Failed to use expo-router.useSegments:", error);
|
|
105
|
+
return noOpUseSegments();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function useSafeGlobalSearchParams() {
|
|
109
|
+
if (!checkExpoRouterAvailability()) {
|
|
110
|
+
return noOpUseGlobalSearchParams();
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
return expoRouter.useGlobalSearchParams();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.warn("[buoy] Failed to use expo-router.useGlobalSearchParams:", error);
|
|
116
|
+
return noOpUseGlobalSearchParams();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ============================================================================
|
|
121
|
+
// Router instance getter (for imperative navigation)
|
|
122
|
+
// ============================================================================
|
|
123
|
+
|
|
124
|
+
function getSafeRouter() {
|
|
125
|
+
if (!checkExpoRouterAvailability()) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
return expoRouter.router || null;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Availability check
|
|
137
|
+
// ============================================================================
|
|
138
|
+
|
|
139
|
+
function isExpoRouterAvailable() {
|
|
140
|
+
return checkExpoRouterAvailability();
|
|
141
|
+
}
|
|
@@ -1,20 +1,95 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* Detected: none
|
|
6
|
-
* Generated at: 2026-02-03T00:33:15.804Z
|
|
4
|
+
* Runtime clipboard implementation
|
|
7
5
|
*
|
|
8
|
-
*
|
|
6
|
+
* Uses Metro's allowOptionalDependencies with top-level try-catch
|
|
7
|
+
* so Metro marks these requires as optional (skipped if not installed).
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* We grab module references eagerly (for Metro), but detect which one
|
|
10
|
+
* actually works lazily on first use — by trying to call it. This avoids
|
|
11
|
+
* NativeModules checks which don't work with TurboModules/new architecture.
|
|
12
|
+
*
|
|
13
|
+
* Consumers must set `transformer.allowOptionalDependencies = true`
|
|
14
|
+
* in their metro.config.js for this to work.
|
|
15
|
+
*
|
|
16
|
+
* Fallback chain:
|
|
17
|
+
* 1. expo-clipboard
|
|
18
|
+
* 2. @react-native-clipboard/clipboard
|
|
19
|
+
* 3. Graceful failure
|
|
13
20
|
*/
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
// Grab module references at load time (top-level try-catch for Metro)
|
|
23
|
+
// Always require both — we decide which actually works at call time
|
|
24
|
+
let _expoClipboard = null;
|
|
25
|
+
try {
|
|
26
|
+
_expoClipboard = require("expo-clipboard");
|
|
27
|
+
} catch {}
|
|
28
|
+
let _rnClipboard = null;
|
|
29
|
+
try {
|
|
30
|
+
const mod = require("@react-native-clipboard/clipboard");
|
|
31
|
+
_rnClipboard = mod.default || mod;
|
|
32
|
+
} catch {}
|
|
33
|
+
|
|
34
|
+
// Lazy detection: resolved on first clipboardFunction() call
|
|
35
|
+
let _detectedType = null;
|
|
36
|
+
let _clipboardFn = null;
|
|
37
|
+
let _detected = false;
|
|
38
|
+
async function detect(text) {
|
|
39
|
+
// 1. Try expo-clipboard by actually calling it
|
|
40
|
+
if (_expoClipboard && typeof _expoClipboard.setStringAsync === "function") {
|
|
41
|
+
try {
|
|
42
|
+
await _expoClipboard.setStringAsync(text);
|
|
43
|
+
_detectedType = "expo";
|
|
44
|
+
_clipboardFn = async t => {
|
|
45
|
+
await _expoClipboard.setStringAsync(t);
|
|
46
|
+
return true;
|
|
47
|
+
};
|
|
48
|
+
_detected = true;
|
|
49
|
+
return true;
|
|
50
|
+
} catch {}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 2. Try @react-native-clipboard/clipboard
|
|
54
|
+
if (_rnClipboard && typeof _rnClipboard.setString === "function") {
|
|
55
|
+
try {
|
|
56
|
+
_rnClipboard.setString(text);
|
|
57
|
+
_detectedType = "react-native";
|
|
58
|
+
_clipboardFn = async t => {
|
|
59
|
+
_rnClipboard.setString(t);
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
62
|
+
_detected = true;
|
|
63
|
+
return true;
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
_detected = true;
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
export const clipboardType = () => {
|
|
70
|
+
return _detectedType;
|
|
71
|
+
};
|
|
72
|
+
export const isClipboardAvailable = () => {
|
|
73
|
+
// Before first use, optimistically return true if we have a module ref
|
|
74
|
+
if (!_detected) return _expoClipboard != null || _rnClipboard != null;
|
|
75
|
+
return _clipboardFn != null;
|
|
76
|
+
};
|
|
17
77
|
export const clipboardFunction = async text => {
|
|
18
|
-
|
|
78
|
+
// If already detected, use the cached function
|
|
79
|
+
if (_detected && _clipboardFn) {
|
|
80
|
+
try {
|
|
81
|
+
return await _clipboardFn(text);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("[buoy] Clipboard copy failed:", error);
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// First call: detect which clipboard works by actually trying it
|
|
89
|
+
if (!_detected) {
|
|
90
|
+
const result = await detect(text);
|
|
91
|
+
if (result) return true;
|
|
92
|
+
}
|
|
93
|
+
console.warn("[buoy] No clipboard library available. Install expo-clipboard or @react-native-clipboard/clipboard.");
|
|
19
94
|
return false;
|
|
20
95
|
};
|
package/lib/module/index.js
CHANGED
|
@@ -25,7 +25,9 @@ loadOptionalModule, getCachedOptionalModule,
|
|
|
25
25
|
// Subscribable base class for self-managing listeners
|
|
26
26
|
Subscribable,
|
|
27
27
|
// Subscriber count notifier for cross-package notifications
|
|
28
|
-
subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange
|
|
28
|
+
subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange,
|
|
29
|
+
// Safe expo-router wrappers (falls back to no-ops on RN CLI)
|
|
30
|
+
useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, isExpoRouterAvailable } from "./utils/index.js";
|
|
29
31
|
|
|
30
32
|
// Also export formatting utils
|
|
31
33
|
export * from "./utils/formatting/index.js";
|
|
@@ -190,11 +190,16 @@ const LEGACY_DEV_TOOL_PATTERNS = ["@devtools", "@dev_tools_", "@modal_state_",
|
|
|
190
190
|
export function isDevToolsStorageKey(key) {
|
|
191
191
|
if (!key) return false;
|
|
192
192
|
|
|
193
|
-
// Check if it starts with our base prefix
|
|
193
|
+
// Check if it starts with our base prefix (@react_buoy)
|
|
194
194
|
if (key.startsWith(devToolsStorageKeys.base)) {
|
|
195
195
|
return true;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
// Check for buoy- prefixed keys (modal persistence, license, etc.)
|
|
199
|
+
if (key.startsWith("buoy-")) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
|
|
198
203
|
// Check for legacy dev tool keys that need cleanup
|
|
199
204
|
for (const pattern of LEGACY_DEV_TOOL_PATTERNS) {
|
|
200
205
|
if (key.startsWith(pattern)) {
|
|
@@ -8,4 +8,5 @@ export { getValueType, isPrimitive, isJsonSerializable, isValidJson, getConstruc
|
|
|
8
8
|
export { parseValue, formatValue, getTypeColor, truncateText, flattenObject, formatPath } from "./valueFormatting.js";
|
|
9
9
|
export { loadOptionalModule, getCachedOptionalModule } from "./loadOptionalModule.js";
|
|
10
10
|
export { Subscribable } from "./subscribable.js";
|
|
11
|
-
export { subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange } from "./subscriberCountNotifier.js";
|
|
11
|
+
export { subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange } from "./subscriberCountNotifier.js";
|
|
12
|
+
export { useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, isExpoRouterAvailable } from "./safeExpoRouter.js";
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Safe wrapper for expo-router
|
|
5
|
+
*
|
|
6
|
+
* Provides optional imports for expo-router hooks and utilities.
|
|
7
|
+
* Falls back to no-op implementations when expo-router is not installed.
|
|
8
|
+
*
|
|
9
|
+
* On RN CLI (without Expo native modules), expo-router's JS is bundled but
|
|
10
|
+
* its hooks crash at runtime because the ExpoLinking native module is missing.
|
|
11
|
+
* We check for the native module BEFORE attempting to use any expo-router hooks.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { NativeModules } from "react-native";
|
|
15
|
+
let expoRouter = null;
|
|
16
|
+
let isAvailable = false;
|
|
17
|
+
let checkedAvailability = false;
|
|
18
|
+
function checkExpoRouterAvailability() {
|
|
19
|
+
if (checkedAvailability) return isAvailable;
|
|
20
|
+
try {
|
|
21
|
+
// expo-router depends on ExpoLinking native module.
|
|
22
|
+
// On RN CLI the JS is bundled but the native module isn't registered,
|
|
23
|
+
// so require() succeeds but hooks crash at runtime. Check native side first.
|
|
24
|
+
if (!NativeModules.ExpoLinking) {
|
|
25
|
+
checkedAvailability = true;
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
expoRouter = require("expo-router");
|
|
29
|
+
isAvailable = expoRouter != null;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
isAvailable = false;
|
|
32
|
+
expoRouter = null;
|
|
33
|
+
}
|
|
34
|
+
checkedAvailability = true;
|
|
35
|
+
return isAvailable;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// No-op implementations when expo-router is not available
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
function noOpUseRouter() {
|
|
43
|
+
return {
|
|
44
|
+
push: () => console.warn("[buoy] expo-router not installed: push() unavailable"),
|
|
45
|
+
replace: () => console.warn("[buoy] expo-router not installed: replace() unavailable"),
|
|
46
|
+
back: () => console.warn("[buoy] expo-router not installed: back() unavailable"),
|
|
47
|
+
canGoBack: () => false,
|
|
48
|
+
setParams: () => console.warn("[buoy] expo-router not installed: setParams() unavailable"),
|
|
49
|
+
navigate: () => console.warn("[buoy] expo-router not installed: navigate() unavailable")
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function noOpUsePathname() {
|
|
53
|
+
return "/";
|
|
54
|
+
}
|
|
55
|
+
function noOpUseSegments() {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
function noOpUseGlobalSearchParams() {
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Safe hook exports
|
|
64
|
+
// ============================================================================
|
|
65
|
+
|
|
66
|
+
export function useSafeRouter() {
|
|
67
|
+
if (!checkExpoRouterAvailability()) {
|
|
68
|
+
return noOpUseRouter();
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
return expoRouter.useRouter();
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.warn("[buoy] Failed to use expo-router.useRouter:", error);
|
|
74
|
+
return noOpUseRouter();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export function useSafePathname() {
|
|
78
|
+
if (!checkExpoRouterAvailability()) {
|
|
79
|
+
return noOpUsePathname();
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
return expoRouter.usePathname();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.warn("[buoy] Failed to use expo-router.usePathname:", error);
|
|
85
|
+
return noOpUsePathname();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function useSafeSegments() {
|
|
89
|
+
if (!checkExpoRouterAvailability()) {
|
|
90
|
+
return noOpUseSegments();
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
return expoRouter.useSegments();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
console.warn("[buoy] Failed to use expo-router.useSegments:", error);
|
|
96
|
+
return noOpUseSegments();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export function useSafeGlobalSearchParams() {
|
|
100
|
+
if (!checkExpoRouterAvailability()) {
|
|
101
|
+
return noOpUseGlobalSearchParams();
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
return expoRouter.useGlobalSearchParams();
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.warn("[buoy] Failed to use expo-router.useGlobalSearchParams:", error);
|
|
107
|
+
return noOpUseGlobalSearchParams();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// Router instance getter (for imperative navigation)
|
|
113
|
+
// ============================================================================
|
|
114
|
+
|
|
115
|
+
export function getSafeRouter() {
|
|
116
|
+
if (!checkExpoRouterAvailability()) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
return expoRouter.router || null;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Availability check
|
|
128
|
+
// ============================================================================
|
|
129
|
+
|
|
130
|
+
export function isExpoRouterAvailable() {
|
|
131
|
+
return checkExpoRouterAvailability();
|
|
132
|
+
}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Detected: none
|
|
4
|
-
* Generated at: 2026-02-03T00:33:15.804Z
|
|
2
|
+
* Runtime clipboard implementation
|
|
5
3
|
*
|
|
6
|
-
*
|
|
4
|
+
* Uses Metro's allowOptionalDependencies with top-level try-catch
|
|
5
|
+
* so Metro marks these requires as optional (skipped if not installed).
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* We grab module references eagerly (for Metro), but detect which one
|
|
8
|
+
* actually works lazily on first use — by trying to call it. This avoids
|
|
9
|
+
* NativeModules checks which don't work with TurboModules/new architecture.
|
|
10
|
+
*
|
|
11
|
+
* Consumers must set `transformer.allowOptionalDependencies = true`
|
|
12
|
+
* in their metro.config.js for this to work.
|
|
13
|
+
*
|
|
14
|
+
* Fallback chain:
|
|
15
|
+
* 1. expo-clipboard
|
|
16
|
+
* 2. @react-native-clipboard/clipboard
|
|
17
|
+
* 3. Graceful failure
|
|
11
18
|
*/
|
|
12
19
|
export type ClipboardFunction = (text: string) => Promise<boolean>;
|
|
13
|
-
export declare const clipboardType: "expo" | "react-native" | null;
|
|
20
|
+
export declare const clipboardType: () => "expo" | "react-native" | null;
|
|
14
21
|
export declare const isClipboardAvailable: () => boolean;
|
|
15
22
|
export declare const clipboardFunction: ClipboardFunction;
|
|
16
23
|
//# sourceMappingURL=clipboard-impl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard-impl.d.ts","sourceRoot":"","sources":["../../../../src/clipboard/clipboard-impl.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"clipboard-impl.d.ts","sourceRoot":"","sources":["../../../../src/clipboard/clipboard-impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAqDnE,eAAO,MAAM,aAAa,QAAO,MAAM,GAAG,cAAc,GAAG,IAE1D,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAO,OAIvC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,iBAmB/B,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./ui";
|
|
2
2
|
export * from "./stores";
|
|
3
|
-
export { displayValue, parseDisplayValue, getSafeAreaInsets, persistentStorage, isUsingPersistentStorage, getStorageBackendType, safeStringify, getValueType, isPrimitive, isJsonSerializable, isValidJson, getConstructorName, isEmpty, getValueSize, parseValue, formatValue, getTypeColor, truncateText, flattenObject, formatPath, loadOptionalModule, getCachedOptionalModule, Subscribable, type SubscribableListener, subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange, } from "./utils";
|
|
3
|
+
export { displayValue, parseDisplayValue, getSafeAreaInsets, persistentStorage, isUsingPersistentStorage, getStorageBackendType, safeStringify, getValueType, isPrimitive, isJsonSerializable, isValidJson, getConstructorName, isEmpty, getValueSize, parseValue, formatValue, getTypeColor, truncateText, flattenObject, formatPath, loadOptionalModule, getCachedOptionalModule, Subscribable, type SubscribableListener, subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange, useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, isExpoRouterAvailable, } from "./utils";
|
|
4
4
|
export * from "./utils/formatting";
|
|
5
5
|
export * from "./utils/time";
|
|
6
6
|
export { isPlainObject as isPlainObjectUtil } from "./utils/typeHelpers";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,MAAM,CAAC;AAGrB,cAAc,UAAU,CAAC;AAGzB,OAAO,EAEL,YAAY,EACZ,iBAAiB,EAEjB,iBAAiB,EAEjB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EAErB,aAAa,EAEb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,EAEZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EAEV,kBAAkB,EAClB,uBAAuB,EAEvB,YAAY,EACZ,KAAK,oBAAoB,EAEzB,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,MAAM,CAAC;AAGrB,cAAc,UAAU,CAAC;AAGzB,OAAO,EAEL,YAAY,EACZ,iBAAiB,EAEjB,iBAAiB,EAEjB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EAErB,aAAa,EAEb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,EAEZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EAEV,kBAAkB,EAClB,uBAAuB,EAEvB,YAAY,EACZ,KAAK,oBAAoB,EAEzB,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,EAE3B,aAAa,EACb,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAGjB,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,cAAc,SAAS,CAAC;AAGxB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,EACb,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,+CAA+C,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,YAAY,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,YAAY,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACtF,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG7E,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACjL,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devToolsStorageKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/devToolsStorageKeys.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;IAC9B;;OAEG;;IAGH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;IAUH;;OAEG;;;;;;QAQD,kDAAkD;;QAElD,gCAAgC;;QAGhC,gCAAgC;;;IAKlC;;OAEG;;;QAGD,mCAAmC;;;IAIrC;;OAEG;;;;;IAOH;;OAEG;;;;;;;IAQH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;;;;;;;IAuBH;;OAEG;;;;;;;;;;;IAiBH;;OAEG;;;;;;;;;;;IAgBH;;OAEG;;;;;;;;;;IAgBH;;OAEG;;;;;;;;IAYH;;OAEG;;;;;;;;;IAcH;;OAEG;;;;QAID,oCAAoC;;QAGpC,wCAAwC;;QAGxC,2BAA2B;;;CAIrB,CAAC;AAwBX;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"devToolsStorageKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/devToolsStorageKeys.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;IAC9B;;OAEG;;IAGH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;IAUH;;OAEG;;;;;;QAQD,kDAAkD;;QAElD,gCAAgC;;QAGhC,gCAAgC;;;IAKlC;;OAEG;;;QAGD,mCAAmC;;;IAIrC;;OAEG;;;;;IAOH;;OAEG;;;;;;;IAQH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;;;;;;;IAuBH;;OAEG;;;;;;;;;;;IAiBH;;OAEG;;;;;;;;;;;IAgBH;;OAEG;;;;;;;;;;IAgBH;;OAEG;;;;;;;;IAYH;;OAEG;;;;;;;;;IAcH;;OAEG;;;;QAID,oCAAoC;;QAGpC,wCAAwC;;QAGxC,2BAA2B;;;CAIrB,CAAC;AAwBX;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAqBzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE9D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,EAAE,CAsBpD"}
|
|
@@ -7,4 +7,5 @@ export { parseValue, formatValue, getTypeColor, truncateText, flattenObject, for
|
|
|
7
7
|
export { loadOptionalModule, getCachedOptionalModule } from "./loadOptionalModule";
|
|
8
8
|
export { Subscribable, type SubscribableListener } from "./subscribable";
|
|
9
9
|
export { subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange, } from "./subscriberCountNotifier";
|
|
10
|
+
export { useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, isExpoRouterAvailable, } from "./safeExpoRouter";
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,aAAa,EACb,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,qBAAqB,GACtB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe wrapper for expo-router
|
|
3
|
+
*
|
|
4
|
+
* Provides optional imports for expo-router hooks and utilities.
|
|
5
|
+
* Falls back to no-op implementations when expo-router is not installed.
|
|
6
|
+
*
|
|
7
|
+
* On RN CLI (without Expo native modules), expo-router's JS is bundled but
|
|
8
|
+
* its hooks crash at runtime because the ExpoLinking native module is missing.
|
|
9
|
+
* We check for the native module BEFORE attempting to use any expo-router hooks.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSafeRouter(): any;
|
|
12
|
+
export declare function useSafePathname(): string;
|
|
13
|
+
export declare function useSafeSegments(): string[];
|
|
14
|
+
export declare function useSafeGlobalSearchParams(): Record<string, string | string[]>;
|
|
15
|
+
export declare function getSafeRouter(): any;
|
|
16
|
+
export declare function isExpoRouterAvailable(): boolean;
|
|
17
|
+
//# sourceMappingURL=safeExpoRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safeExpoRouter.d.ts","sourceRoot":"","sources":["../../../../src/utils/safeExpoRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA8DH,wBAAgB,aAAa,QAW5B;AAED,wBAAgB,eAAe,IAAI,MAAM,CAWxC;AAED,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAW1C;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAW7E;AAMD,wBAAgB,aAAa,QAU5B;AAMD,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C"}
|
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Detected: none
|
|
4
|
-
* Generated at: 2026-02-03T00:33:15.804Z
|
|
2
|
+
* Runtime clipboard implementation
|
|
5
3
|
*
|
|
6
|
-
*
|
|
4
|
+
* Uses Metro's allowOptionalDependencies with top-level try-catch
|
|
5
|
+
* so Metro marks these requires as optional (skipped if not installed).
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* We grab module references eagerly (for Metro), but detect which one
|
|
8
|
+
* actually works lazily on first use — by trying to call it. This avoids
|
|
9
|
+
* NativeModules checks which don't work with TurboModules/new architecture.
|
|
10
|
+
*
|
|
11
|
+
* Consumers must set `transformer.allowOptionalDependencies = true`
|
|
12
|
+
* in their metro.config.js for this to work.
|
|
13
|
+
*
|
|
14
|
+
* Fallback chain:
|
|
15
|
+
* 1. expo-clipboard
|
|
16
|
+
* 2. @react-native-clipboard/clipboard
|
|
17
|
+
* 3. Graceful failure
|
|
11
18
|
*/
|
|
12
19
|
export type ClipboardFunction = (text: string) => Promise<boolean>;
|
|
13
|
-
export declare const clipboardType: "expo" | "react-native" | null;
|
|
20
|
+
export declare const clipboardType: () => "expo" | "react-native" | null;
|
|
14
21
|
export declare const isClipboardAvailable: () => boolean;
|
|
15
22
|
export declare const clipboardFunction: ClipboardFunction;
|
|
16
23
|
//# sourceMappingURL=clipboard-impl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard-impl.d.ts","sourceRoot":"","sources":["../../../../src/clipboard/clipboard-impl.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"clipboard-impl.d.ts","sourceRoot":"","sources":["../../../../src/clipboard/clipboard-impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAqDnE,eAAO,MAAM,aAAa,QAAO,MAAM,GAAG,cAAc,GAAG,IAE1D,CAAC;AAEF,eAAO,MAAM,oBAAoB,QAAO,OAIvC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,iBAmB/B,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./ui";
|
|
2
2
|
export * from "./stores";
|
|
3
|
-
export { displayValue, parseDisplayValue, getSafeAreaInsets, persistentStorage, isUsingPersistentStorage, getStorageBackendType, safeStringify, getValueType, isPrimitive, isJsonSerializable, isValidJson, getConstructorName, isEmpty, getValueSize, parseValue, formatValue, getTypeColor, truncateText, flattenObject, formatPath, loadOptionalModule, getCachedOptionalModule, Subscribable, type SubscribableListener, subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange, } from "./utils";
|
|
3
|
+
export { displayValue, parseDisplayValue, getSafeAreaInsets, persistentStorage, isUsingPersistentStorage, getStorageBackendType, safeStringify, getValueType, isPrimitive, isJsonSerializable, isValidJson, getConstructorName, isEmpty, getValueSize, parseValue, formatValue, getTypeColor, truncateText, flattenObject, formatPath, loadOptionalModule, getCachedOptionalModule, Subscribable, type SubscribableListener, subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange, useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, isExpoRouterAvailable, } from "./utils";
|
|
4
4
|
export * from "./utils/formatting";
|
|
5
5
|
export * from "./utils/time";
|
|
6
6
|
export { isPlainObject as isPlainObjectUtil } from "./utils/typeHelpers";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,MAAM,CAAC;AAGrB,cAAc,UAAU,CAAC;AAGzB,OAAO,EAEL,YAAY,EACZ,iBAAiB,EAEjB,iBAAiB,EAEjB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EAErB,aAAa,EAEb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,EAEZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EAEV,kBAAkB,EAClB,uBAAuB,EAEvB,YAAY,EACZ,KAAK,oBAAoB,EAEzB,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,MAAM,CAAC;AAGrB,cAAc,UAAU,CAAC;AAGzB,OAAO,EAEL,YAAY,EACZ,iBAAiB,EAEjB,iBAAiB,EAEjB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EAErB,aAAa,EAEb,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,EAEZ,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,EAEV,kBAAkB,EAClB,uBAAuB,EAEvB,YAAY,EACZ,KAAK,oBAAoB,EAEzB,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,EAE3B,aAAa,EACb,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,qBAAqB,GACtB,MAAM,SAAS,CAAC;AAGjB,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGzE,cAAc,SAAS,CAAC;AAGxB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,EACb,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,+CAA+C,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAEvF,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,YAAY,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAE1E,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,YAAY,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACtF,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG7E,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACjL,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devToolsStorageKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/devToolsStorageKeys.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;IAC9B;;OAEG;;IAGH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;IAUH;;OAEG;;;;;;QAQD,kDAAkD;;QAElD,gCAAgC;;QAGhC,gCAAgC;;;IAKlC;;OAEG;;;QAGD,mCAAmC;;;IAIrC;;OAEG;;;;;IAOH;;OAEG;;;;;;;IAQH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;;;;;;;IAuBH;;OAEG;;;;;;;;;;;IAiBH;;OAEG;;;;;;;;;;;IAgBH;;OAEG;;;;;;;;;;IAgBH;;OAEG;;;;;;;;IAYH;;OAEG;;;;;;;;;IAcH;;OAEG;;;;QAID,oCAAoC;;QAGpC,wCAAwC;;QAGxC,2BAA2B;;;CAIrB,CAAC;AAwBX;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"devToolsStorageKeys.d.ts","sourceRoot":"","sources":["../../../../src/storage/devToolsStorageKeys.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;IAC9B;;OAEG;;IAGH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;IAUH;;OAEG;;;;;;QAQD,kDAAkD;;QAElD,gCAAgC;;QAGhC,gCAAgC;;;IAKlC;;OAEG;;;QAGD,mCAAmC;;;IAIrC;;OAEG;;;;;IAOH;;OAEG;;;;;;;IAQH;;OAEG;;;;;;;IASH;;OAEG;;;;;;;;;;;;;;IAuBH;;OAEG;;;;;;;;;;;IAiBH;;OAEG;;;;;;;;;;;IAgBH;;OAEG;;;;;;;;;;IAgBH;;OAEG;;;;;;;;IAYH;;OAEG;;;;;;;;;IAcH;;OAEG;;;;QAID,oCAAoC;;QAGpC,wCAAwC;;QAGxC,2BAA2B;;;CAIrB,CAAC;AAwBX;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAqBzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE9D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,EAAE,CAsBpD"}
|
|
@@ -7,4 +7,5 @@ export { parseValue, formatValue, getTypeColor, truncateText, flattenObject, for
|
|
|
7
7
|
export { loadOptionalModule, getCachedOptionalModule } from "./loadOptionalModule";
|
|
8
8
|
export { Subscribable, type SubscribableListener } from "./subscribable";
|
|
9
9
|
export { subscriberCountNotifier, subscribeToSubscriberCountChanges, notifySubscriberCountChange, } from "./subscriberCountNotifier";
|
|
10
|
+
export { useSafeRouter, useSafePathname, useSafeSegments, useSafeGlobalSearchParams, getSafeRouter, isExpoRouterAvailable, } from "./safeExpoRouter";
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,OAAO,EACP,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,iCAAiC,EACjC,2BAA2B,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,aAAa,EACb,eAAe,EACf,eAAe,EACf,yBAAyB,EACzB,aAAa,EACb,qBAAqB,GACtB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe wrapper for expo-router
|
|
3
|
+
*
|
|
4
|
+
* Provides optional imports for expo-router hooks and utilities.
|
|
5
|
+
* Falls back to no-op implementations when expo-router is not installed.
|
|
6
|
+
*
|
|
7
|
+
* On RN CLI (without Expo native modules), expo-router's JS is bundled but
|
|
8
|
+
* its hooks crash at runtime because the ExpoLinking native module is missing.
|
|
9
|
+
* We check for the native module BEFORE attempting to use any expo-router hooks.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSafeRouter(): any;
|
|
12
|
+
export declare function useSafePathname(): string;
|
|
13
|
+
export declare function useSafeSegments(): string[];
|
|
14
|
+
export declare function useSafeGlobalSearchParams(): Record<string, string | string[]>;
|
|
15
|
+
export declare function getSafeRouter(): any;
|
|
16
|
+
export declare function isExpoRouterAvailable(): boolean;
|
|
17
|
+
//# sourceMappingURL=safeExpoRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safeExpoRouter.d.ts","sourceRoot":"","sources":["../../../../src/utils/safeExpoRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA8DH,wBAAgB,aAAa,QAW5B;AAED,wBAAgB,eAAe,IAAI,MAAM,CAWxC;AAED,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAW1C;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAW7E;AAMD,wBAAgB,aAAa,QAU5B;AAMD,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buoy-gg/shared-ui",
|
|
3
|
-
"version": "2.1.3",
|
|
3
|
+
"version": "2.1.4-beta.3",
|
|
4
4
|
"description": "Shared UI components, hooks, and utilities",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -115,10 +115,10 @@
|
|
|
115
115
|
],
|
|
116
116
|
"sideEffects": false,
|
|
117
117
|
"dependencies": {
|
|
118
|
-
"@buoy-gg/floating-tools-core": "2.1.3"
|
|
118
|
+
"@buoy-gg/floating-tools-core": "2.1.4-beta.3"
|
|
119
119
|
},
|
|
120
120
|
"peerDependencies": {
|
|
121
|
-
"@buoy-gg/license": "
|
|
121
|
+
"@buoy-gg/license": "2.1.4-beta.3",
|
|
122
122
|
"@react-native-clipboard/clipboard": "*",
|
|
123
123
|
"expo-clipboard": "*",
|
|
124
124
|
"expo-file-system": "*",
|
|
@@ -127,9 +127,6 @@
|
|
|
127
127
|
"react-native-safe-area-context": "*"
|
|
128
128
|
},
|
|
129
129
|
"peerDependenciesMeta": {
|
|
130
|
-
"@buoy-gg/license": {
|
|
131
|
-
"optional": true
|
|
132
|
-
},
|
|
133
130
|
"expo-clipboard": {
|
|
134
131
|
"optional": true
|
|
135
132
|
},
|
|
@@ -149,7 +146,7 @@
|
|
|
149
146
|
"expo-clipboard": "~7.1.5",
|
|
150
147
|
"react-native-safe-area-context": "^5.6.2",
|
|
151
148
|
"typescript": "~5.8.3",
|
|
152
|
-
"@buoy-gg/license": "2.1.3"
|
|
149
|
+
"@buoy-gg/license": "2.1.4-beta.3"
|
|
153
150
|
},
|
|
154
151
|
"react-native-builder-bob": {
|
|
155
152
|
"source": "src",
|
|
@@ -1,32 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Clipboard Detection Script
|
|
3
|
+
* Clipboard Detection Script (postinstall)
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* and
|
|
5
|
+
* For PUBLISHED npm consumers only. Detects which clipboard library
|
|
6
|
+
* is installed and overwrites the built lib/ files with a static import.
|
|
7
|
+
* This means npm consumers need ZERO metro.config.js changes.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* 3. Metro sees static imports only
|
|
12
|
-
* 4. Works with any Metro version
|
|
13
|
-
*
|
|
14
|
-
* IMPORTANT: During npm publish (prepublishOnly), REACT_BUOY_FALLBACK=1 is set
|
|
15
|
-
* to ensure the published package contains the fallback implementation.
|
|
16
|
-
* This ensures the package works out of the box even if postinstall doesn't run.
|
|
17
|
-
* When users install the package, postinstall runs and upgrades to native if available.
|
|
9
|
+
* For workspace/link consumers (monorepo dev), this script is a no-op.
|
|
10
|
+
* They use the runtime detection code in src/clipboard/clipboard-impl.ts
|
|
11
|
+
* which handles both clipboard libraries via try-catch + allowOptionalDependencies.
|
|
18
12
|
*/
|
|
19
13
|
|
|
20
14
|
const fs = require("fs");
|
|
21
15
|
const path = require("path");
|
|
22
16
|
|
|
23
|
-
const
|
|
17
|
+
const pkgRoot = path.join(__dirname, "..");
|
|
18
|
+
|
|
19
|
+
// Only run for published consumers (lib/ exists, src/ doesn't).
|
|
20
|
+
// In the monorepo, src/ exists and we want to preserve the runtime detection code.
|
|
21
|
+
const hasLib = fs.existsSync(path.join(pkgRoot, "lib"));
|
|
22
|
+
const hasSrc = fs.existsSync(path.join(pkgRoot, "src"));
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
if (!hasLib || hasSrc) {
|
|
25
|
+
// Monorepo / workspace context — skip, runtime detection handles it
|
|
26
|
+
console.log("[@buoy/shared-ui] Clipboard: skipping postinstall (workspace mode)");
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
|
-
* Find the
|
|
31
|
+
* Find the consumer's project root
|
|
30
32
|
*/
|
|
31
33
|
function findProjectRoot(startDir) {
|
|
32
34
|
let dir = startDir;
|
|
@@ -49,151 +51,101 @@ function findProjectRoot(startDir) {
|
|
|
49
51
|
return null;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
/**
|
|
53
|
-
* Get additional search paths for pnpm monorepos
|
|
54
|
-
*/
|
|
55
54
|
function getAdditionalSearchPaths() {
|
|
56
55
|
const paths = [];
|
|
57
56
|
const projectRoot = findProjectRoot(__dirname);
|
|
58
|
-
|
|
59
57
|
if (projectRoot) {
|
|
60
|
-
// pnpm virtual store - where hoisted packages live
|
|
61
58
|
const pnpmVirtualStore = path.join(projectRoot, "node_modules", ".pnpm", "node_modules");
|
|
62
|
-
if (fs.existsSync(pnpmVirtualStore))
|
|
63
|
-
paths.push(pnpmVirtualStore);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Also check root node_modules directly
|
|
59
|
+
if (fs.existsSync(pnpmVirtualStore)) paths.push(pnpmVirtualStore);
|
|
67
60
|
const rootNodeModules = path.join(projectRoot, "node_modules");
|
|
68
|
-
if (fs.existsSync(rootNodeModules))
|
|
69
|
-
paths.push(rootNodeModules);
|
|
70
|
-
}
|
|
61
|
+
if (fs.existsSync(rootNodeModules)) paths.push(rootNodeModules);
|
|
71
62
|
}
|
|
72
|
-
|
|
73
63
|
return paths;
|
|
74
64
|
}
|
|
75
65
|
|
|
76
66
|
function moduleExists(name) {
|
|
77
|
-
// First try standard resolution
|
|
78
67
|
try {
|
|
79
68
|
require.resolve(name);
|
|
80
69
|
return true;
|
|
81
|
-
} catch
|
|
82
|
-
// Standard resolution failed, try additional paths (for pnpm monorepos)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Try with additional search paths
|
|
70
|
+
} catch {}
|
|
86
71
|
const additionalPaths = getAdditionalSearchPaths();
|
|
87
72
|
if (additionalPaths.length > 0) {
|
|
88
73
|
try {
|
|
89
74
|
require.resolve(name, { paths: additionalPaths });
|
|
90
75
|
return true;
|
|
91
|
-
} catch
|
|
92
|
-
// Not found in additional paths either
|
|
93
|
-
}
|
|
76
|
+
} catch {}
|
|
94
77
|
}
|
|
95
|
-
|
|
96
78
|
return false;
|
|
97
79
|
}
|
|
98
80
|
|
|
99
|
-
|
|
100
|
-
let detectedModule;
|
|
81
|
+
// Detect which clipboard library the consumer has
|
|
82
|
+
let detectedModule = null;
|
|
83
|
+
let esmContent, cjsContent;
|
|
101
84
|
|
|
102
|
-
if (
|
|
85
|
+
if (moduleExists("expo-clipboard")) {
|
|
103
86
|
detectedModule = "expo-clipboard";
|
|
104
|
-
content = `/**
|
|
105
|
-
* Auto-generated clipboard implementation
|
|
106
|
-
* Detected: expo-clipboard
|
|
107
|
-
* Generated at: ${new Date().toISOString()}
|
|
108
|
-
*
|
|
109
|
-
* DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
|
|
110
|
-
*/
|
|
111
|
-
|
|
112
|
-
import { setStringAsync } from "expo-clipboard";
|
|
113
|
-
|
|
114
|
-
export type ClipboardFunction = (text: string) => Promise<boolean>;
|
|
115
87
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
export const isClipboardAvailable = ()
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
await setStringAsync(text);
|
|
123
|
-
return true;
|
|
124
|
-
} catch (error) {
|
|
125
|
-
console.error("[RnBetterDevTools] Clipboard copy failed:", error);
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
88
|
+
esmContent = `import { setStringAsync } from "expo-clipboard";
|
|
89
|
+
export const clipboardType = () => "expo";
|
|
90
|
+
export const isClipboardAvailable = () => true;
|
|
91
|
+
export const clipboardFunction = async (text) => {
|
|
92
|
+
try { await setStringAsync(text); return true; }
|
|
93
|
+
catch (e) { console.error("[buoy] Clipboard copy failed:", e); return false; }
|
|
128
94
|
};
|
|
129
95
|
`;
|
|
130
|
-
} else if (!forceFallback && moduleExists("@react-native-clipboard/clipboard")) {
|
|
131
|
-
detectedModule = "@react-native-clipboard/clipboard";
|
|
132
|
-
content = `/**
|
|
133
|
-
* Auto-generated clipboard implementation
|
|
134
|
-
* Detected: @react-native-clipboard/clipboard
|
|
135
|
-
* Generated at: ${new Date().toISOString()}
|
|
136
|
-
*
|
|
137
|
-
* DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
|
|
138
|
-
*/
|
|
139
|
-
|
|
140
|
-
import Clipboard from "@react-native-clipboard/clipboard";
|
|
141
|
-
|
|
142
|
-
export type ClipboardFunction = (text: string) => Promise<boolean>;
|
|
143
|
-
|
|
144
|
-
export const clipboardType: "expo" | "react-native" | null = "react-native";
|
|
145
|
-
|
|
146
|
-
export const isClipboardAvailable = (): boolean => true;
|
|
147
96
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
97
|
+
cjsContent = `"use strict";
|
|
98
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
99
|
+
const expo = require("expo-clipboard");
|
|
100
|
+
exports.clipboardType = () => "expo";
|
|
101
|
+
exports.isClipboardAvailable = () => true;
|
|
102
|
+
exports.clipboardFunction = async (text) => {
|
|
103
|
+
try { await expo.setStringAsync(text); return true; }
|
|
104
|
+
catch (e) { console.error("[buoy] Clipboard copy failed:", e); return false; }
|
|
156
105
|
};
|
|
157
106
|
`;
|
|
158
|
-
} else {
|
|
159
|
-
detectedModule = null;
|
|
160
|
-
content = `/**
|
|
161
|
-
* Auto-generated clipboard implementation
|
|
162
|
-
* Detected: none
|
|
163
|
-
* Generated at: ${new Date().toISOString()}
|
|
164
|
-
*
|
|
165
|
-
* DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
|
|
166
|
-
*
|
|
167
|
-
* No clipboard library found. Install one of:
|
|
168
|
-
* - expo-clipboard (for Expo projects)
|
|
169
|
-
* - @react-native-clipboard/clipboard (for RN CLI projects)
|
|
170
|
-
*/
|
|
171
|
-
|
|
172
|
-
export type ClipboardFunction = (text: string) => Promise<boolean>;
|
|
173
|
-
|
|
174
|
-
export const clipboardType: "expo" | "react-native" | null = null;
|
|
175
107
|
|
|
176
|
-
|
|
108
|
+
} else if (moduleExists("@react-native-clipboard/clipboard")) {
|
|
109
|
+
detectedModule = "@react-native-clipboard/clipboard";
|
|
177
110
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
);
|
|
184
|
-
return false;
|
|
111
|
+
esmContent = `import Clipboard from "@react-native-clipboard/clipboard";
|
|
112
|
+
export const clipboardType = () => "react-native";
|
|
113
|
+
export const isClipboardAvailable = () => true;
|
|
114
|
+
export const clipboardFunction = async (text) => {
|
|
115
|
+
try { Clipboard.setString(text); return true; }
|
|
116
|
+
catch (e) { console.error("[buoy] Clipboard copy failed:", e); return false; }
|
|
185
117
|
};
|
|
186
118
|
`;
|
|
187
|
-
}
|
|
188
119
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
120
|
+
cjsContent = `"use strict";
|
|
121
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
122
|
+
const rnClipboard = require("@react-native-clipboard/clipboard");
|
|
123
|
+
const Clipboard = rnClipboard.default || rnClipboard;
|
|
124
|
+
exports.clipboardType = () => "react-native";
|
|
125
|
+
exports.isClipboardAvailable = () => true;
|
|
126
|
+
exports.clipboardFunction = async (text) => {
|
|
127
|
+
try { Clipboard.setString(text); return true; }
|
|
128
|
+
catch (e) { console.error("[buoy] Clipboard copy failed:", e); return false; }
|
|
129
|
+
};
|
|
130
|
+
`;
|
|
193
131
|
}
|
|
194
132
|
|
|
195
|
-
|
|
133
|
+
if (detectedModule && esmContent && cjsContent) {
|
|
134
|
+
// Write to both module and commonjs output directories
|
|
135
|
+
const targets = [
|
|
136
|
+
path.join(pkgRoot, "lib", "module", "clipboard", "clipboard-impl.js"),
|
|
137
|
+
path.join(pkgRoot, "lib", "commonjs", "clipboard", "clipboard-impl.js"),
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
for (const target of targets) {
|
|
141
|
+
if (fs.existsSync(path.dirname(target))) {
|
|
142
|
+
const isCommonjs = target.includes("commonjs");
|
|
143
|
+
fs.writeFileSync(target, isCommonjs ? cjsContent : esmContent);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
196
146
|
|
|
197
|
-
console.log(
|
|
198
|
-
|
|
199
|
-
|
|
147
|
+
console.log(`[@buoy/shared-ui] Clipboard configured: ${detectedModule}`);
|
|
148
|
+
} else {
|
|
149
|
+
// No clipboard found — keep the runtime detection fallback from the build
|
|
150
|
+
console.log("[@buoy/shared-ui] Clipboard: no library detected, using fallback");
|
|
151
|
+
}
|