@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.
Files changed (34) hide show
  1. package/lib/commonjs/clipboard/clipboard-impl.js +86 -10
  2. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  3. package/lib/commonjs/index.js +42 -0
  4. package/lib/commonjs/storage/devToolsStorageKeys.js +6 -1
  5. package/lib/commonjs/utils/index.js +38 -1
  6. package/lib/commonjs/utils/safeExpoRouter.js +141 -0
  7. package/lib/module/clipboard/clipboard-impl.js +85 -10
  8. package/lib/module/hooks/safe-area-impl.js +1 -1
  9. package/lib/module/index.js +3 -1
  10. package/lib/module/storage/devToolsStorageKeys.js +6 -1
  11. package/lib/module/utils/index.js +2 -1
  12. package/lib/module/utils/safeExpoRouter.js +132 -0
  13. package/lib/typescript/commonjs/clipboard/clipboard-impl.d.ts +15 -8
  14. package/lib/typescript/commonjs/clipboard/clipboard-impl.d.ts.map +1 -1
  15. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  16. package/lib/typescript/commonjs/index.d.ts +1 -1
  17. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  18. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts.map +1 -1
  19. package/lib/typescript/commonjs/utils/index.d.ts +1 -0
  20. package/lib/typescript/commonjs/utils/index.d.ts.map +1 -1
  21. package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts +17 -0
  22. package/lib/typescript/commonjs/utils/safeExpoRouter.d.ts.map +1 -0
  23. package/lib/typescript/module/clipboard/clipboard-impl.d.ts +15 -8
  24. package/lib/typescript/module/clipboard/clipboard-impl.d.ts.map +1 -1
  25. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  26. package/lib/typescript/module/index.d.ts +1 -1
  27. package/lib/typescript/module/index.d.ts.map +1 -1
  28. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts.map +1 -1
  29. package/lib/typescript/module/utils/index.d.ts +1 -0
  30. package/lib/typescript/module/utils/index.d.ts.map +1 -1
  31. package/lib/typescript/module/utils/safeExpoRouter.d.ts +17 -0
  32. package/lib/typescript/module/utils/safeExpoRouter.d.ts.map +1 -0
  33. package/package.json +4 -7
  34. 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
- * Auto-generated clipboard implementation
9
- * Detected: none
10
- * Generated at: 2026-02-03T00:33:15.804Z
8
+ * Runtime clipboard implementation
11
9
  *
12
- * DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
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
- * No clipboard library found. Install one of:
15
- * - expo-clipboard (for Expo projects)
16
- * - @react-native-clipboard/clipboard (for RN CLI projects)
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
- const clipboardType = exports.clipboardType = null;
20
- const isClipboardAvailable = () => false;
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
- console.error("[RnBetterDevTools] Copy failed: No clipboard library found.\n" + `Attempted to copy: ${text.substring(0, 50)}${text.length > 50 ? "..." : ""}\n` + "Install expo-clipboard or @react-native-clipboard/clipboard, or provide a custom onCopy function.");
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-03T00:33:15.829Z
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
  *
@@ -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
- * Auto-generated clipboard implementation
5
- * Detected: none
6
- * Generated at: 2026-02-03T00:33:15.804Z
4
+ * Runtime clipboard implementation
7
5
  *
8
- * DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
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
- * No clipboard library found. Install one of:
11
- * - expo-clipboard (for Expo projects)
12
- * - @react-native-clipboard/clipboard (for RN CLI projects)
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
- export const clipboardType = null;
16
- export const isClipboardAvailable = () => false;
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
- console.error("[RnBetterDevTools] Copy failed: No clipboard library found.\n" + `Attempted to copy: ${text.substring(0, 50)}${text.length > 50 ? "..." : ""}\n` + "Install expo-clipboard or @react-native-clipboard/clipboard, or provide a custom onCopy function.");
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
  };
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * Auto-generated safe area implementation
5
5
  * Detected: none
6
- * Generated at: 2026-02-03T00:33:15.829Z
6
+ * Generated at: 2026-02-10T20:29:38.101Z
7
7
  *
8
8
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
9
9
  *
@@ -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 } from "./utils/index.js";
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
- * Auto-generated clipboard implementation
3
- * Detected: none
4
- * Generated at: 2026-02-03T00:33:15.804Z
2
+ * Runtime clipboard implementation
5
3
  *
6
- * DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
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
- * No clipboard library found. Install one of:
9
- * - expo-clipboard (for Expo projects)
10
- * - @react-native-clipboard/clipboard (for RN CLI projects)
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;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEnE,eAAO,MAAM,aAAa,EAAE,MAAM,GAAG,cAAc,GAAG,IAAW,CAAC;AAElE,eAAO,MAAM,oBAAoB,QAAO,OAAgB,CAAC;AAEzD,eAAO,MAAM,iBAAiB,EAAE,iBAO/B,CAAC"}
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,7 +1,7 @@
1
1
  /**
2
2
  * Auto-generated safe area implementation
3
3
  * Detected: none
4
- * Generated at: 2026-02-03T00:33:15.829Z
4
+ * Generated at: 2026-02-10T20:29:38.101Z
5
5
  *
6
6
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
7
7
  *
@@ -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,GAC5B,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
+ {"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,CAgBzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE9D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,EAAE,CAsBpD"}
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
- * Auto-generated clipboard implementation
3
- * Detected: none
4
- * Generated at: 2026-02-03T00:33:15.804Z
2
+ * Runtime clipboard implementation
5
3
  *
6
- * DO NOT EDIT - This file is generated by scripts/detect-clipboard.js
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
- * No clipboard library found. Install one of:
9
- * - expo-clipboard (for Expo projects)
10
- * - @react-native-clipboard/clipboard (for RN CLI projects)
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;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEnE,eAAO,MAAM,aAAa,EAAE,MAAM,GAAG,cAAc,GAAG,IAAW,CAAC;AAElE,eAAO,MAAM,oBAAoB,QAAO,OAAgB,CAAC;AAEzD,eAAO,MAAM,iBAAiB,EAAE,iBAO/B,CAAC"}
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,7 +1,7 @@
1
1
  /**
2
2
  * Auto-generated safe area implementation
3
3
  * Detected: none
4
- * Generated at: 2026-02-03T00:33:15.829Z
4
+ * Generated at: 2026-02-10T20:29:38.101Z
5
5
  *
6
6
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
7
7
  *
@@ -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,GAC5B,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
+ {"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,CAgBzD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAE9D;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,EAAE,CAsBpD"}
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
- * This postinstall script detects which clipboard library is installed
6
- * and generates the appropriate implementation file.
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
- * This approach provides TRUE zero-config because:
9
- * 1. No metro.config.js changes needed
10
- * 2. Detection happens at install time (not bundle time)
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 OUTPUT_FILE = path.join(__dirname, "..", "src", "clipboard", "clipboard-impl.ts");
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
- // Check for explicit fallback override (used during publishing)
26
- const forceFallback = process.env.REACT_BUOY_FALLBACK === "1";
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 monorepo/project root by looking for pnpm-workspace.yaml or package.json with workspaces
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 (e) {
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 (e) {
92
- // Not found in additional paths either
93
- }
76
+ } catch {}
94
77
  }
95
-
96
78
  return false;
97
79
  }
98
80
 
99
- let content;
100
- let detectedModule;
81
+ // Detect which clipboard library the consumer has
82
+ let detectedModule = null;
83
+ let esmContent, cjsContent;
101
84
 
102
- if (!forceFallback && moduleExists("expo-clipboard")) {
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
- export const clipboardType: "expo" | "react-native" | null = "expo";
117
-
118
- export const isClipboardAvailable = (): boolean => true;
119
-
120
- export const clipboardFunction: ClipboardFunction = async (text: string): Promise<boolean> => {
121
- try {
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
- export const clipboardFunction: ClipboardFunction = async (text: string): Promise<boolean> => {
149
- try {
150
- Clipboard.setString(text);
151
- return true;
152
- } catch (error) {
153
- console.error("[RnBetterDevTools] Clipboard copy failed:", error);
154
- return false;
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
- export const isClipboardAvailable = (): boolean => false;
108
+ } else if (moduleExists("@react-native-clipboard/clipboard")) {
109
+ detectedModule = "@react-native-clipboard/clipboard";
177
110
 
178
- export const clipboardFunction: ClipboardFunction = async (text: string): Promise<boolean> => {
179
- console.error(
180
- "[RnBetterDevTools] Copy failed: No clipboard library found.\\n" +
181
- \`Attempted to copy: \${text.substring(0, 50)}\${text.length > 50 ? "..." : ""}\\n\` +
182
- "Install expo-clipboard or @react-native-clipboard/clipboard, or provide a custom onCopy function."
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
- // Ensure directory exists
190
- const dir = path.dirname(OUTPUT_FILE);
191
- if (!fs.existsSync(dir)) {
192
- fs.mkdirSync(dir, { recursive: true });
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
- fs.writeFileSync(OUTPUT_FILE, content);
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
- `[@buoy/shared-ui] Clipboard implementation configured: ${detectedModule || "none"}`
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
+ }