@buoy-gg/route-events 7.0.41 → 7.0.43
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/README.md +11 -64
- package/lib/commonjs/RouteObserver.js +1 -54
- package/lib/commonjs/RouteParser.js +1 -314
- package/lib/commonjs/RouteTracker.js +1 -112
- package/lib/commonjs/RouteTracker.web.js +1 -12
- package/lib/commonjs/browserRouteRegistry.js +1 -30
- package/lib/commonjs/browserRoutes.js +1 -96
- package/lib/commonjs/components/NavigationStack.js +2 -572
- package/lib/commonjs/components/ReactNavigationRoutes.js +1 -836
- package/lib/commonjs/components/ReactNavigationRoutes.web.js +1 -12
- package/lib/commonjs/components/RouteEventDetail.js +1 -97
- package/lib/commonjs/components/RouteEventExpandedContent.js +1 -204
- package/lib/commonjs/components/RouteEventItemCompact.js +1 -191
- package/lib/commonjs/components/RouteEventsModalWithTabs.js +1 -734
- package/lib/commonjs/components/RouteEventsTimeline.js +1 -107
- package/lib/commonjs/components/RouteFilterViewV2.js +1 -42
- package/lib/commonjs/components/RoutesSitemap.js +2 -1035
- package/lib/commonjs/expoRouterStore.js +1 -121
- package/lib/commonjs/expoRouterStore.web.js +1 -44
- package/lib/commonjs/hooks/useRouteEvents.js +1 -57
- package/lib/commonjs/index.js +1 -168
- package/lib/commonjs/preset.js +1 -69
- package/lib/commonjs/stores/navigationStackStore.js +1 -45
- package/lib/commonjs/stores/routeEventStore.js +1 -136
- package/lib/commonjs/sync/routeEventsSyncAdapter.js +1 -275
- package/lib/commonjs/useNavigationStack.js +1 -408
- package/lib/commonjs/useNavigationStack.web.js +1 -32
- package/lib/commonjs/useRouteObserver.js +1 -73
- package/lib/commonjs/useRouteObserverReactNavigation.js +1 -109
- package/lib/commonjs/useRouteSitemap.js +1 -255
- package/lib/commonjs/utils/routeTemplate.js +1 -79
- package/lib/commonjs/utils/safeReactNavigation.js +1 -194
- package/lib/commonjs/utils/safeReactNavigation.web.js +1 -36
- package/lib/commonjs/utils/testIDs.js +1 -63
- package/lib/module/RouteObserver.js +1 -49
- package/lib/module/RouteParser.js +1 -309
- package/lib/module/RouteTracker.js +1 -109
- package/lib/module/RouteTracker.web.js +1 -8
- package/lib/module/browserRouteRegistry.js +1 -24
- package/lib/module/browserRoutes.js +1 -92
- package/lib/module/components/NavigationStack.js +2 -568
- package/lib/module/components/ReactNavigationRoutes.js +1 -832
- package/lib/module/components/ReactNavigationRoutes.web.js +1 -3
- package/lib/module/components/RouteEventDetail.js +1 -93
- package/lib/module/components/RouteEventExpandedContent.js +1 -200
- package/lib/module/components/RouteEventItemCompact.js +1 -187
- package/lib/module/components/RouteEventsModalWithTabs.js +1 -731
- package/lib/module/components/RouteEventsTimeline.js +1 -103
- package/lib/module/components/RouteFilterViewV2.js +1 -38
- package/lib/module/components/RoutesSitemap.js +2 -1033
- package/lib/module/expoRouterStore.js +1 -114
- package/lib/module/expoRouterStore.web.js +1 -37
- package/lib/module/hooks/useRouteEvents.js +1 -54
- package/lib/module/index.js +1 -70
- package/lib/module/preset.js +1 -66
- package/lib/module/stores/navigationStackStore.js +1 -41
- package/lib/module/stores/routeEventStore.js +1 -128
- package/lib/module/sync/routeEventsSyncAdapter.js +1 -273
- package/lib/module/useNavigationStack.js +1 -404
- package/lib/module/useNavigationStack.web.js +1 -28
- package/lib/module/useRouteObserver.js +1 -70
- package/lib/module/useRouteObserverReactNavigation.js +1 -106
- package/lib/module/useRouteSitemap.js +1 -250
- package/lib/module/utils/routeTemplate.js +1 -73
- package/lib/module/utils/safeReactNavigation.js +1 -185
- package/lib/module/utils/safeReactNavigation.web.js +1 -27
- package/lib/module/utils/testIDs.js +1 -55
- package/lib/web/index.mjs +4 -5
- package/package.json +6 -11
- package/lib/typescript/RouteObserver.d.ts.map +0 -1
- package/lib/typescript/RouteParser.d.ts.map +0 -1
- package/lib/typescript/RouteTracker.d.ts.map +0 -1
- package/lib/typescript/RouteTracker.web.d.ts.map +0 -1
- package/lib/typescript/browserRouteRegistry.d.ts.map +0 -1
- package/lib/typescript/browserRoutes.d.ts.map +0 -1
- package/lib/typescript/components/NavigationStack.d.ts.map +0 -1
- package/lib/typescript/components/ReactNavigationRoutes.d.ts.map +0 -1
- package/lib/typescript/components/ReactNavigationRoutes.web.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventDetail.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventExpandedContent.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventItemCompact.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventsModalWithTabs.d.ts.map +0 -1
- package/lib/typescript/components/RouteEventsTimeline.d.ts.map +0 -1
- package/lib/typescript/components/RouteFilterViewV2.d.ts.map +0 -1
- package/lib/typescript/components/RoutesSitemap.d.ts.map +0 -1
- package/lib/typescript/expoRouterStore.d.ts.map +0 -1
- package/lib/typescript/expoRouterStore.web.d.ts.map +0 -1
- package/lib/typescript/hooks/useRouteEvents.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/stores/navigationStackStore.d.ts.map +0 -1
- package/lib/typescript/stores/routeEventStore.d.ts.map +0 -1
- package/lib/typescript/sync/routeEventsSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/useNavigationStack.d.ts.map +0 -1
- package/lib/typescript/useNavigationStack.web.d.ts.map +0 -1
- package/lib/typescript/useRouteObserver.d.ts.map +0 -1
- package/lib/typescript/useRouteObserverReactNavigation.d.ts.map +0 -1
- package/lib/typescript/useRouteSitemap.d.ts.map +0 -1
- package/lib/typescript/utils/routeTemplate.d.ts.map +0 -1
- package/lib/typescript/utils/safeReactNavigation.d.ts.map +0 -1
- package/lib/typescript/utils/safeReactNavigation.web.d.ts.map +0 -1
- package/lib/typescript/utils/testIDs.d.ts.map +0 -1
|
@@ -1,255 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.useParentRoutes = useParentRoutes;
|
|
7
|
-
exports.useRoute = useRoute;
|
|
8
|
-
exports.useRouteSitemap = useRouteSitemap;
|
|
9
|
-
var _react = require("react");
|
|
10
|
-
var _RouteParser = require("./RouteParser");
|
|
11
|
-
var _expoRouterStore = require("./expoRouterStore");
|
|
12
|
-
/**
|
|
13
|
-
* useRouteSitemap - React hooks for accessing parsed route information
|
|
14
|
-
*
|
|
15
|
-
* Provides access to the Expo Router route tree with parsing, filtering,
|
|
16
|
-
* and search capabilities.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
// Type-only definition to avoid Metro resolution issues
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Extract all routes from the navigation state recursively
|
|
23
|
-
* This builds a RouteNode-like structure from React Navigation's state
|
|
24
|
-
*/
|
|
25
|
-
function buildRouteNodeFromNavigationState(state) {
|
|
26
|
-
if (!state || !state.routes) return null;
|
|
27
|
-
|
|
28
|
-
// Find the app directory structure from the navigation state
|
|
29
|
-
// The root route usually contains the file-based routing structure
|
|
30
|
-
const rootRoute = state.routes?.[0];
|
|
31
|
-
if (!rootRoute) return null;
|
|
32
|
-
|
|
33
|
-
// Build a simple route node structure
|
|
34
|
-
// This will work with the RouteParser
|
|
35
|
-
const routeNode = {
|
|
36
|
-
type: 'route',
|
|
37
|
-
route: '',
|
|
38
|
-
dynamic: null,
|
|
39
|
-
children: [],
|
|
40
|
-
contextKey: '_app'
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// Recursively collect all routes from the state
|
|
44
|
-
function collectRoutes(navState, parent, pathPrefix = '') {
|
|
45
|
-
if (!navState || !navState.routes) return;
|
|
46
|
-
navState.routes.forEach(route => {
|
|
47
|
-
const routeName = route.name;
|
|
48
|
-
|
|
49
|
-
// Skip internal routes
|
|
50
|
-
if (routeName.startsWith('__') || routeName.includes('_layout') || routeName.startsWith('+not-found')) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Create a route node
|
|
55
|
-
const node = {
|
|
56
|
-
type: routeName === 'index' ? 'route' : 'route',
|
|
57
|
-
route: routeName === 'index' ? '' : routeName,
|
|
58
|
-
dynamic: routeName.includes('[') ? [routeName.match(/\[([^\]]+)\]/)?.[1] || ''] : null,
|
|
59
|
-
children: [],
|
|
60
|
-
contextKey: `app/${routeName}`
|
|
61
|
-
};
|
|
62
|
-
parent.children.push(node);
|
|
63
|
-
|
|
64
|
-
// If this route has nested state, recurse
|
|
65
|
-
if (route.state) {
|
|
66
|
-
collectRoutes(route.state, node, `${pathPrefix}/${routeName}`);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
collectRoutes(state, routeNode);
|
|
71
|
-
return routeNode.children.length > 0 ? routeNode : null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// ============================================================================
|
|
75
|
-
// Hook Options & Return Types
|
|
76
|
-
// ============================================================================
|
|
77
|
-
|
|
78
|
-
// ============================================================================
|
|
79
|
-
// Main Hook
|
|
80
|
-
// ============================================================================
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Hook to access and parse Expo Router's route tree
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```tsx
|
|
87
|
-
* const { routes, groups, stats, filteredRoutes } = useRouteSitemap({
|
|
88
|
-
* searchQuery: 'pokemon',
|
|
89
|
-
* sortBy: 'path',
|
|
90
|
-
* autoRefresh: true
|
|
91
|
-
* });
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
function useRouteSitemap(options = {}) {
|
|
95
|
-
const {
|
|
96
|
-
searchQuery = "",
|
|
97
|
-
sortBy = "path",
|
|
98
|
-
autoRefresh = false,
|
|
99
|
-
refreshInterval = 1000,
|
|
100
|
-
injectedRoutes,
|
|
101
|
-
injectedSource = null,
|
|
102
|
-
injectedLastUpdatedAt = null
|
|
103
|
-
} = options;
|
|
104
|
-
const hasInjectedRoutes = injectedRoutes != null;
|
|
105
|
-
const [routeTreeState, setRouteTreeState] = (0, _react.useState)(() => {
|
|
106
|
-
const node = (0, _expoRouterStore.loadRouteNode)();
|
|
107
|
-
const metadata = (0, _expoRouterStore.getRouteNodeMetadata)();
|
|
108
|
-
return {
|
|
109
|
-
node,
|
|
110
|
-
version: 0,
|
|
111
|
-
lastUpdatedAt: metadata.lastLoadedAt,
|
|
112
|
-
source: metadata.source
|
|
113
|
-
};
|
|
114
|
-
});
|
|
115
|
-
const routeNode = routeTreeState.node;
|
|
116
|
-
const routeNodeVersion = routeTreeState.version;
|
|
117
|
-
const lastUpdatedAt = routeTreeState.lastUpdatedAt;
|
|
118
|
-
const source = routeTreeState.source;
|
|
119
|
-
const refresh = (0, _react.useCallback)(() => {
|
|
120
|
-
setRouteTreeState(previous => {
|
|
121
|
-
const node = (0, _expoRouterStore.loadRouteNode)();
|
|
122
|
-
const metadata = (0, _expoRouterStore.getRouteNodeMetadata)();
|
|
123
|
-
return {
|
|
124
|
-
node,
|
|
125
|
-
version: previous.version + 1,
|
|
126
|
-
lastUpdatedAt: metadata.lastLoadedAt,
|
|
127
|
-
source: metadata.source
|
|
128
|
-
};
|
|
129
|
-
});
|
|
130
|
-
}, []);
|
|
131
|
-
|
|
132
|
-
// When the route tree isn't available yet (e.g., Expo Router still mounting),
|
|
133
|
-
// poll until it becomes ready. Use a more aggressive retry since the store
|
|
134
|
-
// is a singleton that gets populated asynchronously.
|
|
135
|
-
(0, _react.useEffect)(() => {
|
|
136
|
-
if (routeNode) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Routes injected from outside (dashboard) don't come from the local store.
|
|
141
|
-
if (hasInjectedRoutes) {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// On web (no expo-router) the tree will never load — don't poll forever.
|
|
146
|
-
if (!(0, _expoRouterStore.isExpoRouterStoreSupported)()) {
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
let retryCount = 0;
|
|
150
|
-
const maxRetries = 100; // 10 seconds max
|
|
151
|
-
|
|
152
|
-
const poll = () => {
|
|
153
|
-
retryCount++;
|
|
154
|
-
refresh();
|
|
155
|
-
if (retryCount < maxRetries) {
|
|
156
|
-
timeoutRef = setTimeout(poll, 100);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
let timeoutRef = setTimeout(poll, 100);
|
|
160
|
-
return () => clearTimeout(timeoutRef);
|
|
161
|
-
}, [routeNode, refresh, hasInjectedRoutes]);
|
|
162
|
-
|
|
163
|
-
// Optional auto-refresh hook for callers that want periodic updates
|
|
164
|
-
(0, _react.useEffect)(() => {
|
|
165
|
-
if (!autoRefresh) return;
|
|
166
|
-
const interval = setInterval(refresh, refreshInterval);
|
|
167
|
-
return () => clearInterval(interval);
|
|
168
|
-
}, [autoRefresh, refreshInterval, refresh]);
|
|
169
|
-
|
|
170
|
-
// With injected routes we're "supported" regardless of the local runtime, and
|
|
171
|
-
// "loaded" once the device has actually sent a non-empty tree (an empty array
|
|
172
|
-
// means the device is still booting expo-router → keep showing "Loading...").
|
|
173
|
-
const isLoaded = hasInjectedRoutes ? injectedRoutes.length > 0 : !!routeNode;
|
|
174
|
-
const isSupported = hasInjectedRoutes ? true : (0, _expoRouterStore.isExpoRouterStoreSupported)();
|
|
175
|
-
|
|
176
|
-
// Parse routes (or use the pre-parsed routes injected from the dashboard).
|
|
177
|
-
const routes = (0, _react.useMemo)(() => {
|
|
178
|
-
if (hasInjectedRoutes) return injectedRoutes;
|
|
179
|
-
if (!routeNode) return [];
|
|
180
|
-
return _RouteParser.RouteParser.parseRouteTree(routeNode);
|
|
181
|
-
}, [routeNode, routeNodeVersion, hasInjectedRoutes, injectedRoutes]);
|
|
182
|
-
|
|
183
|
-
// Sort routes
|
|
184
|
-
const sortedRoutes = (0, _react.useMemo)(() => {
|
|
185
|
-
return _RouteParser.RouteParser.sortRoutes(routes, sortBy);
|
|
186
|
-
}, [routes, sortBy]);
|
|
187
|
-
|
|
188
|
-
// Filter routes by search query
|
|
189
|
-
const filteredRoutes = (0, _react.useMemo)(() => {
|
|
190
|
-
if (!searchQuery) return sortedRoutes;
|
|
191
|
-
return _RouteParser.RouteParser.filterRoutes(sortedRoutes, searchQuery);
|
|
192
|
-
}, [sortedRoutes, searchQuery]);
|
|
193
|
-
|
|
194
|
-
// Organize into groups
|
|
195
|
-
const groups = (0, _react.useMemo)(() => {
|
|
196
|
-
return _RouteParser.RouteParser.organizeRoutes(filteredRoutes);
|
|
197
|
-
}, [filteredRoutes]);
|
|
198
|
-
|
|
199
|
-
// Calculate stats
|
|
200
|
-
const stats = (0, _react.useMemo)(() => {
|
|
201
|
-
return _RouteParser.RouteParser.getRouteStats(routes);
|
|
202
|
-
}, [routes]);
|
|
203
|
-
|
|
204
|
-
// Helper functions
|
|
205
|
-
const findRoute = path => _RouteParser.RouteParser.findRouteByPath(routes, path);
|
|
206
|
-
const getParents = path => _RouteParser.RouteParser.getParentRoutes(routes, path);
|
|
207
|
-
return {
|
|
208
|
-
routes: sortedRoutes,
|
|
209
|
-
groups,
|
|
210
|
-
stats,
|
|
211
|
-
filteredRoutes,
|
|
212
|
-
isLoaded,
|
|
213
|
-
isSupported,
|
|
214
|
-
refresh,
|
|
215
|
-
findRoute,
|
|
216
|
-
getParents,
|
|
217
|
-
lastUpdatedAt: hasInjectedRoutes ? injectedLastUpdatedAt : lastUpdatedAt,
|
|
218
|
-
source: hasInjectedRoutes ? injectedSource : source
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// ============================================================================
|
|
223
|
-
// Helper Hooks
|
|
224
|
-
// ============================================================================
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Get a specific route by path
|
|
228
|
-
*
|
|
229
|
-
* @example
|
|
230
|
-
* ```tsx
|
|
231
|
-
* const pokemonRoute = useRoute('/pokemon/[id]');
|
|
232
|
-
* ```
|
|
233
|
-
*/
|
|
234
|
-
function useRoute(path) {
|
|
235
|
-
const {
|
|
236
|
-
findRoute
|
|
237
|
-
} = useRouteSitemap();
|
|
238
|
-
return (0, _react.useMemo)(() => findRoute(path), [findRoute, path]);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Get all parent routes for a given path
|
|
243
|
-
*
|
|
244
|
-
* @example
|
|
245
|
-
* ```tsx
|
|
246
|
-
* const parents = useParentRoutes('/pokemon/[id]');
|
|
247
|
-
* // Returns: [{ path: '/pokemon', ... }]
|
|
248
|
-
* ```
|
|
249
|
-
*/
|
|
250
|
-
function useParentRoutes(path) {
|
|
251
|
-
const {
|
|
252
|
-
getParents
|
|
253
|
-
} = useRouteSitemap();
|
|
254
|
-
return (0, _react.useMemo)(() => getParents(path), [getParents, path]);
|
|
255
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useParentRoutes=useParentRoutes;exports.useRoute=useRoute;exports.useRouteSitemap=useRouteSitemap;var _react=require("react");var _RouteParser=require("./RouteParser");var _expoRouterStore=require("./expoRouterStore");function buildRouteNodeFromNavigationState(t){if(!t||!t.routes)return null;const r=t.routes?.[0];if(!r)return null;const s={type:"route",route:"",dynamic:null,children:[],contextKey:"_app"};function l(n,a,h=""){if(!n||!n.routes)return;n.routes.forEach(R=>{const e=R.name;if(e.startsWith("__")||e.includes("_layout")||e.startsWith("+not-found")){return}const u={type:e==="index"?"route":"route",route:e==="index"?"":e,dynamic:e.includes("[")?[e.match(/\[([^\]]+)\]/)?.[1]||""]:null,children:[],contextKey:`app/${e}`};a.children.push(u);if(R.state){l(R.state,u,`${h}/${e}`)}})}l(t,s);return s.children.length>0?s:null}function useRouteSitemap(t={}){const{searchQuery:r="",sortBy:s="path",autoRefresh:l=false,refreshInterval:n=1e3,injectedRoutes:a,injectedSource:h=null,injectedLastUpdatedAt:R=null}=t;const e=a!=null;const[u,S]=(0,_react.useState)(()=>{const o=(0,_expoRouterStore.loadRouteNode)();const d=(0,_expoRouterStore.getRouteNodeMetadata)();return{node:o,version:0,lastUpdatedAt:d.lastLoadedAt,source:d.source}});const c=u.node;const y=u.version;const g=u.lastUpdatedAt;const v=u.source;const f=(0,_react.useCallback)(()=>{S(o=>{const d=(0,_expoRouterStore.loadRouteNode)();const p=(0,_expoRouterStore.getRouteNodeMetadata)();return{node:d,version:o.version+1,lastUpdatedAt:p.lastLoadedAt,source:p.source}})},[]);(0,_react.useEffect)(()=>{if(c){return}if(e){return}if(!(0,_expoRouterStore.isExpoRouterStoreSupported)()){return}let o=0;const d=100;const p=()=>{o++;f();if(o<d){x=setTimeout(p,100)}};let x=setTimeout(p,100);return()=>clearTimeout(x)},[c,f,e]);(0,_react.useEffect)(()=>{if(!l)return;const o=setInterval(f,n);return()=>clearInterval(o)},[l,n,f]);const M=e?a.length>0:!!c;const N=e?true:(0,_expoRouterStore.isExpoRouterStoreSupported)();const i=(0,_react.useMemo)(()=>{if(e)return a;if(!c)return[];return _RouteParser.RouteParser.parseRouteTree(c)},[c,y,e,a]);const m=(0,_react.useMemo)(()=>{return _RouteParser.RouteParser.sortRoutes(i,s)},[i,s]);const P=(0,_react.useMemo)(()=>{if(!r)return m;return _RouteParser.RouteParser.filterRoutes(m,r)},[m,r]);const _=(0,_react.useMemo)(()=>{return _RouteParser.RouteParser.organizeRoutes(P)},[P]);const A=(0,_react.useMemo)(()=>{return _RouteParser.RouteParser.getRouteStats(i)},[i]);const T=o=>_RouteParser.RouteParser.findRouteByPath(i,o);const U=o=>_RouteParser.RouteParser.getParentRoutes(i,o);return{routes:m,groups:_,stats:A,filteredRoutes:P,isLoaded:M,isSupported:N,refresh:f,findRoute:T,getParents:U,lastUpdatedAt:e?R:g,source:e?h:v}}function useRoute(t){const{findRoute:r}=useRouteSitemap();return(0,_react.useMemo)(()=>r(t),[r,t])}function useParentRoutes(t){const{getParents:r}=useRouteSitemap();return(0,_react.useMemo)(()=>r(t),[r,t])}
|
|
@@ -1,79 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.getRouteTemplate = getRouteTemplate;
|
|
7
|
-
exports.routeHref = routeHref;
|
|
8
|
-
exports.splitRouteHref = splitRouteHref;
|
|
9
|
-
/**
|
|
10
|
-
* Infer a route template from a concrete pathname and its segments.
|
|
11
|
-
* Dynamic segments (numeric ids, UUIDs) collapse to `[id]`, so
|
|
12
|
-
* `/products/42` becomes `/products/[id]`. Returns null when the template
|
|
13
|
-
* matches the pathname (i.e. the route is fully static).
|
|
14
|
-
*/
|
|
15
|
-
function getRouteTemplate(pathname, segments) {
|
|
16
|
-
if (!segments || segments.length === 0) return null;
|
|
17
|
-
const templateParts = segments.map(segment => {
|
|
18
|
-
// Numeric ids
|
|
19
|
-
if (/^\d+$/.test(segment)) {
|
|
20
|
-
return "[id]";
|
|
21
|
-
}
|
|
22
|
-
// UUIDs
|
|
23
|
-
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(segment)) {
|
|
24
|
-
return "[id]";
|
|
25
|
-
}
|
|
26
|
-
return segment;
|
|
27
|
-
});
|
|
28
|
-
const template = "/" + templateParts.join("/");
|
|
29
|
-
return template !== pathname ? template : null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* The href that reopens a recorded route: its pathname plus the params that are
|
|
34
|
-
* not already in the path, as a query string. Expo Router reports dynamic
|
|
35
|
-
* segment values (`/order/42` → `{ id: "42" }`) and search params (`?menu=1`)
|
|
36
|
-
* in one `params` object; only the second kind needs to be carried, because the
|
|
37
|
-
* first is already in the pathname.
|
|
38
|
-
*/
|
|
39
|
-
function routeHref(pathname, params) {
|
|
40
|
-
if (!params) return pathname;
|
|
41
|
-
const inPath = new Set(pathname.split("/").filter(Boolean).map(seg => {
|
|
42
|
-
try {
|
|
43
|
-
return decodeURIComponent(seg);
|
|
44
|
-
} catch {
|
|
45
|
-
return seg;
|
|
46
|
-
}
|
|
47
|
-
}));
|
|
48
|
-
const query = [];
|
|
49
|
-
for (const [key, raw] of Object.entries(params)) {
|
|
50
|
-
const values = Array.isArray(raw) ? raw : [raw];
|
|
51
|
-
// A catch-all segment's values, or one dynamic segment's value.
|
|
52
|
-
if (values.length > 0 && values.every(v => inPath.has(String(v)))) continue;
|
|
53
|
-
for (const v of values) query.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(v))}`);
|
|
54
|
-
}
|
|
55
|
-
return query.length ? `${pathname}?${query.join("&")}` : pathname;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Split an href from {@link routeHref} back into its path and params. */
|
|
59
|
-
function splitRouteHref(href) {
|
|
60
|
-
const q = href.indexOf("?");
|
|
61
|
-
if (q < 0) return {
|
|
62
|
-
pathname: href,
|
|
63
|
-
params: {}
|
|
64
|
-
};
|
|
65
|
-
const params = {};
|
|
66
|
-
for (const pair of href.slice(q + 1).split("&")) {
|
|
67
|
-
if (!pair) continue;
|
|
68
|
-
const [k, v = ""] = pair.split("=");
|
|
69
|
-
try {
|
|
70
|
-
params[decodeURIComponent(k)] = decodeURIComponent(v);
|
|
71
|
-
} catch {
|
|
72
|
-
params[k] = v;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
pathname: href.slice(0, q),
|
|
77
|
-
params
|
|
78
|
-
};
|
|
79
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.getRouteTemplate=getRouteTemplate;exports.routeHref=routeHref;exports.splitRouteHref=splitRouteHref;function getRouteTemplate(t,n){if(!n||n.length===0)return null;const r=n.map(e=>{if(/^\d+$/.test(e)){return"[id]"}if(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(e)){return"[id]"}return e});const o="/"+r.join("/");return o!==t?o:null}function routeHref(t,n){if(!n)return t;const r=new Set(t.split("/").filter(Boolean).map(e=>{try{return decodeURIComponent(e)}catch{return e}}));const o=[];for(const[e,i]of Object.entries(n)){const u=Array.isArray(i)?i:[i];if(u.length>0&&u.every(c=>r.has(String(c))))continue;for(const c of u)o.push(`${encodeURIComponent(e)}=${encodeURIComponent(String(c))}`)}return o.length?`${t}?${o.join("&")}`:t}function splitRouteHref(t){const n=t.indexOf("?");if(n<0)return{pathname:t,params:{}};const r={};for(const o of t.slice(n+1).split("&")){if(!o)continue;const[e,i=""]=o.split("=");try{r[decodeURIComponent(e)]=decodeURIComponent(i)}catch{r[e]=i}}return{pathname:t.slice(0,n),params:r}}
|
|
@@ -1,194 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.getCommonActions = getCommonActions;
|
|
7
|
-
exports.getStackActions = getStackActions;
|
|
8
|
-
exports.isReactNavigationAvailable = isReactNavigationAvailable;
|
|
9
|
-
exports.useSafeNavigation = useSafeNavigation;
|
|
10
|
-
exports.useSafeNavigationContainerRef = useSafeNavigationContainerRef;
|
|
11
|
-
exports.useSafeNavigationState = useSafeNavigationState;
|
|
12
|
-
var _react = require("react");
|
|
13
|
-
/**
|
|
14
|
-
* Safe wrapper for @react-navigation/native
|
|
15
|
-
*
|
|
16
|
-
* Provides optional imports for React Navigation hooks.
|
|
17
|
-
* Falls back to no-op implementations when @react-navigation/native is not installed.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
let reactNavigation = null;
|
|
21
|
-
let isAvailable = false;
|
|
22
|
-
let checkedAvailability = false;
|
|
23
|
-
|
|
24
|
-
// Expo Router (SDK 54+) VENDORS React Navigation: its NavigationContainer
|
|
25
|
-
// provides the vendored NavigationContainerRefContext from
|
|
26
|
-
// expo-router/build/react-navigation, NOT the one exported by the
|
|
27
|
-
// @react-navigation/native package (which may not even be installed, or is a
|
|
28
|
-
// second module instance whose context nobody provides). Reading only the npm
|
|
29
|
-
// context in such apps yields undefined forever — the Stack tab then hangs on
|
|
30
|
-
// "Loading navigation stack...". So we load both copies and consult both
|
|
31
|
-
// contexts.
|
|
32
|
-
let vendoredReactNavigation = null;
|
|
33
|
-
let checkedVendored = false;
|
|
34
|
-
function getVendoredReactNavigation() {
|
|
35
|
-
if (checkedVendored) return vendoredReactNavigation;
|
|
36
|
-
checkedVendored = true;
|
|
37
|
-
try {
|
|
38
|
-
// Compat entry re-exporting the vendored native/core/routers modules.
|
|
39
|
-
// Older expo-router versions (and RN CLI apps) don't have it — the
|
|
40
|
-
// require throws and we stay on @react-navigation/native.
|
|
41
|
-
const vendored = require("expo-router/react-navigation");
|
|
42
|
-
vendoredReactNavigation = vendored?.NavigationContainerRefContext ? vendored : null;
|
|
43
|
-
} catch {
|
|
44
|
-
vendoredReactNavigation = null;
|
|
45
|
-
}
|
|
46
|
-
return vendoredReactNavigation;
|
|
47
|
-
}
|
|
48
|
-
function checkReactNavigationAvailability() {
|
|
49
|
-
if (checkedAvailability) return isAvailable;
|
|
50
|
-
try {
|
|
51
|
-
reactNavigation = require("@react-navigation/native");
|
|
52
|
-
isAvailable = reactNavigation != null;
|
|
53
|
-
} catch (error) {
|
|
54
|
-
isAvailable = false;
|
|
55
|
-
reactNavigation = null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Expo Router apps don't necessarily install @react-navigation/native at
|
|
59
|
-
// all — the vendored copy then supplies CommonActions/StackActions/hooks
|
|
60
|
-
// (actions are plain serializable objects, so either copy's work).
|
|
61
|
-
if (!isAvailable) {
|
|
62
|
-
const vendored = getVendoredReactNavigation();
|
|
63
|
-
if (vendored) {
|
|
64
|
-
reactNavigation = vendored;
|
|
65
|
-
isAvailable = true;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
checkedAvailability = true;
|
|
69
|
-
return isAvailable;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// ============================================================================
|
|
73
|
-
// No-op implementations when @react-navigation/native is not available
|
|
74
|
-
// ============================================================================
|
|
75
|
-
|
|
76
|
-
function noOpUseNavigation() {
|
|
77
|
-
return (0, _react.useMemo)(() => ({
|
|
78
|
-
navigate: () => console.warn("[route-events] @react-navigation/native not installed: navigate() unavailable"),
|
|
79
|
-
goBack: () => console.warn("[route-events] @react-navigation/native not installed: goBack() unavailable"),
|
|
80
|
-
canGoBack: () => false,
|
|
81
|
-
reset: () => console.warn("[route-events] @react-navigation/native not installed: reset() unavailable"),
|
|
82
|
-
setParams: () => console.warn("[route-events] @react-navigation/native not installed: setParams() unavailable"),
|
|
83
|
-
dispatch: () => console.warn("[route-events] @react-navigation/native not installed: dispatch() unavailable"),
|
|
84
|
-
isFocused: () => true,
|
|
85
|
-
addListener: () => () => {},
|
|
86
|
-
removeListener: () => {},
|
|
87
|
-
getParent: () => undefined,
|
|
88
|
-
getState: () => undefined,
|
|
89
|
-
getId: () => undefined
|
|
90
|
-
}), []);
|
|
91
|
-
}
|
|
92
|
-
function noOpUseNavigationState(selector) {
|
|
93
|
-
return (0, _react.useMemo)(() => {
|
|
94
|
-
// Return a minimal state structure
|
|
95
|
-
const emptyState = {
|
|
96
|
-
key: "default",
|
|
97
|
-
index: 0,
|
|
98
|
-
routeNames: [],
|
|
99
|
-
routes: [],
|
|
100
|
-
type: "stack"
|
|
101
|
-
};
|
|
102
|
-
try {
|
|
103
|
-
return selector ? selector(emptyState) : emptyState;
|
|
104
|
-
} catch {
|
|
105
|
-
return emptyState;
|
|
106
|
-
}
|
|
107
|
-
}, [selector]);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ============================================================================
|
|
111
|
-
// Safe hook exports
|
|
112
|
-
// ============================================================================
|
|
113
|
-
|
|
114
|
-
function useSafeNavigation() {
|
|
115
|
-
if (!checkReactNavigationAvailability()) {
|
|
116
|
-
return noOpUseNavigation();
|
|
117
|
-
}
|
|
118
|
-
try {
|
|
119
|
-
return reactNavigation.useNavigation();
|
|
120
|
-
} catch (error) {
|
|
121
|
-
console.warn("[route-events] Failed to use @react-navigation/native.useNavigation:", error);
|
|
122
|
-
return noOpUseNavigation();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
function useSafeNavigationState(selector) {
|
|
126
|
-
if (!checkReactNavigationAvailability()) {
|
|
127
|
-
return noOpUseNavigationState(selector);
|
|
128
|
-
}
|
|
129
|
-
try {
|
|
130
|
-
return reactNavigation.useNavigationState(selector);
|
|
131
|
-
} catch (error) {
|
|
132
|
-
console.warn("[route-events] Failed to use @react-navigation/native.useNavigationState:", error);
|
|
133
|
-
return noOpUseNavigationState(selector);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// ============================================================================
|
|
138
|
-
// Guarded module accessors
|
|
139
|
-
// ============================================================================
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Fallback for useContext when @react-navigation/native is absent: a stable
|
|
143
|
-
* context that always yields undefined, so callers' `if (!containerRef)`
|
|
144
|
-
* guards skip every dispatch path. Module presence is constant for the app
|
|
145
|
-
* lifetime, so hook order stays stable either way.
|
|
146
|
-
*/
|
|
147
|
-
const FallbackNavigationContainerRefContext = /*#__PURE__*/(0, _react.createContext)(undefined);
|
|
148
|
-
|
|
149
|
-
/** CommonActions from @react-navigation/native, or null when absent. */
|
|
150
|
-
function getCommonActions() {
|
|
151
|
-
return checkReactNavigationAvailability() ? reactNavigation.CommonActions : null;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** StackActions from @react-navigation/native, or null when absent. */
|
|
155
|
-
function getStackActions() {
|
|
156
|
-
return checkReactNavigationAvailability() ? reactNavigation.StackActions : null;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Both contexts are resolved ONCE and cached so hook identity/order stays
|
|
160
|
-
// stable for the app lifetime (module presence is constant).
|
|
161
|
-
let npmContainerRefContext = null;
|
|
162
|
-
let vendoredContainerRefContext = null;
|
|
163
|
-
function getContainerRefContexts() {
|
|
164
|
-
if (npmContainerRefContext == null) {
|
|
165
|
-
npmContainerRefContext = checkReactNavigationAvailability() && reactNavigation.NavigationContainerRefContext ? reactNavigation.NavigationContainerRefContext : FallbackNavigationContainerRefContext;
|
|
166
|
-
}
|
|
167
|
-
if (vendoredContainerRefContext == null) {
|
|
168
|
-
const vendored = getVendoredReactNavigation();
|
|
169
|
-
vendoredContainerRefContext = vendored?.NavigationContainerRefContext ?? FallbackNavigationContainerRefContext;
|
|
170
|
-
}
|
|
171
|
-
return [npmContainerRefContext, vendoredContainerRefContext];
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* The navigation container ref for THIS app, whichever module instance
|
|
176
|
-
* provides it: @react-navigation/native's NavigationContainerRefContext
|
|
177
|
-
* (RN CLI, older expo-router) or Expo Router's vendored copy (SDK 54+).
|
|
178
|
-
* Returns undefined when rendered outside any NavigationContainer or when
|
|
179
|
-
* React Navigation is absent entirely.
|
|
180
|
-
*/
|
|
181
|
-
function useSafeNavigationContainerRef() {
|
|
182
|
-
const [npmCtx, vendoredCtx] = getContainerRefContexts();
|
|
183
|
-
const npmRef = (0, _react.useContext)(npmCtx);
|
|
184
|
-
const vendoredRef = (0, _react.useContext)(vendoredCtx);
|
|
185
|
-
return npmRef ?? vendoredRef;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// ============================================================================
|
|
189
|
-
// Availability check
|
|
190
|
-
// ============================================================================
|
|
191
|
-
|
|
192
|
-
function isReactNavigationAvailable() {
|
|
193
|
-
return checkReactNavigationAvailability();
|
|
194
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.getCommonActions=getCommonActions;exports.getStackActions=getStackActions;exports.isReactNavigationAvailable=isReactNavigationAvailable;exports.useSafeNavigation=useSafeNavigation;exports.useSafeNavigationContainerRef=useSafeNavigationContainerRef;exports.useSafeNavigationState=useSafeNavigationState;var _react=require("react");let reactNavigation=null;let isAvailable=false;let checkedAvailability=false;let vendoredReactNavigation=null;let checkedVendored=false;function getVendoredReactNavigation(){if(checkedVendored)return vendoredReactNavigation;checkedVendored=true;try{const e=require("expo-router/react-navigation");vendoredReactNavigation=e?.NavigationContainerRefContext?e:null}catch{vendoredReactNavigation=null}return vendoredReactNavigation}function checkReactNavigationAvailability(){if(checkedAvailability)return isAvailable;try{reactNavigation=require("@react-navigation/native");isAvailable=reactNavigation!=null}catch(e){isAvailable=false;reactNavigation=null}if(!isAvailable){const e=getVendoredReactNavigation();if(e){reactNavigation=e;isAvailable=true}}checkedAvailability=true;return isAvailable}function noOpUseNavigation(){return(0,_react.useMemo)(()=>({navigate:()=>console.warn("[route-events] @react-navigation/native not installed: navigate() unavailable"),goBack:()=>console.warn("[route-events] @react-navigation/native not installed: goBack() unavailable"),canGoBack:()=>false,reset:()=>console.warn("[route-events] @react-navigation/native not installed: reset() unavailable"),setParams:()=>console.warn("[route-events] @react-navigation/native not installed: setParams() unavailable"),dispatch:()=>console.warn("[route-events] @react-navigation/native not installed: dispatch() unavailable"),isFocused:()=>true,addListener:()=>()=>{},removeListener:()=>{},getParent:()=>void 0,getState:()=>void 0,getId:()=>void 0}),[])}function noOpUseNavigationState(e){return(0,_react.useMemo)(()=>{const t={key:"default",index:0,routeNames:[],routes:[],type:"stack"};try{return e?e(t):t}catch{return t}},[e])}function useSafeNavigation(){if(!checkReactNavigationAvailability()){return noOpUseNavigation()}try{return reactNavigation.useNavigation()}catch(e){console.warn("[route-events] Failed to use @react-navigation/native.useNavigation:",e);return noOpUseNavigation()}}function useSafeNavigationState(e){if(!checkReactNavigationAvailability()){return noOpUseNavigationState(e)}try{return reactNavigation.useNavigationState(e)}catch(t){console.warn("[route-events] Failed to use @react-navigation/native.useNavigationState:",t);return noOpUseNavigationState(e)}}const FallbackNavigationContainerRefContext=(0,_react.createContext)(void 0);function getCommonActions(){return checkReactNavigationAvailability()?reactNavigation.CommonActions:null}function getStackActions(){return checkReactNavigationAvailability()?reactNavigation.StackActions:null}let npmContainerRefContext=null;let vendoredContainerRefContext=null;function getContainerRefContexts(){if(npmContainerRefContext==null){npmContainerRefContext=checkReactNavigationAvailability()&&reactNavigation.NavigationContainerRefContext?reactNavigation.NavigationContainerRefContext:FallbackNavigationContainerRefContext}if(vendoredContainerRefContext==null){const e=getVendoredReactNavigation();vendoredContainerRefContext=e?.NavigationContainerRefContext??FallbackNavigationContainerRefContext}return[npmContainerRefContext,vendoredContainerRefContext]}function useSafeNavigationContainerRef(){const[e,t]=getContainerRefContexts();const n=(0,_react.useContext)(e);const a=(0,_react.useContext)(t);return n??a}function isReactNavigationAvailable(){return checkReactNavigationAvailability()}
|
|
@@ -1,36 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.getCommonActions = getCommonActions;
|
|
7
|
-
exports.getStackActions = getStackActions;
|
|
8
|
-
exports.isReactNavigationAvailable = isReactNavigationAvailable;
|
|
9
|
-
exports.useSafeNavigation = useSafeNavigation;
|
|
10
|
-
exports.useSafeNavigationContainerRef = useSafeNavigationContainerRef;
|
|
11
|
-
exports.useSafeNavigationState = useSafeNavigationState;
|
|
12
|
-
var _utils = require("@buoy-gg/shared-ui/utils");
|
|
13
|
-
function useSafeNavigation() {
|
|
14
|
-
return _utils.browserRouter;
|
|
15
|
-
}
|
|
16
|
-
function useSafeNavigationState(selector) {
|
|
17
|
-
return selector({
|
|
18
|
-
routes: [],
|
|
19
|
-
routeNames: [],
|
|
20
|
-
index: 0,
|
|
21
|
-
key: 'browser',
|
|
22
|
-
type: 'stack'
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
function useSafeNavigationContainerRef() {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
function getCommonActions() {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
function getStackActions() {
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
function isReactNavigationAvailable() {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.getCommonActions=getCommonActions;exports.getStackActions=getStackActions;exports.isReactNavigationAvailable=isReactNavigationAvailable;exports.useSafeNavigation=useSafeNavigation;exports.useSafeNavigationContainerRef=useSafeNavigationContainerRef;exports.useSafeNavigationState=useSafeNavigationState;var _utils=require("@buoy-gg/shared-ui/utils");function useSafeNavigation(){return _utils.browserRouter}function useSafeNavigationState(e){return e({routes:[],routeNames:[],index:0,key:"browser",type:"stack"})}function useSafeNavigationContainerRef(){return void 0}function getCommonActions(){return null}function getStackActions(){return null}function isReactNavigationAvailable(){return false}
|
|
@@ -1,63 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.eventRowTestID = eventRowTestID;
|
|
7
|
-
exports.pathSlug = pathSlug;
|
|
8
|
-
exports.sitemapGroupTestID = sitemapGroupTestID;
|
|
9
|
-
exports.sitemapRouteTestID = sitemapRouteTestID;
|
|
10
|
-
exports.stackItemTestID = stackItemTestID;
|
|
11
|
-
/**
|
|
12
|
-
* Stable e2e handles for the routes tool.
|
|
13
|
-
*
|
|
14
|
-
* Everything in this tool is addressed by its PATH, never by a list index or a
|
|
15
|
-
* per-session id. Route events are a prepend-list whose indices shift on every
|
|
16
|
-
* navigation, the sitemap re-sorts and regroups as you search, and the stack
|
|
17
|
-
* renumbers itself on every push — the pathname is the one thing that means the
|
|
18
|
-
* same screen on the next launch, and the only thing a test can name up front.
|
|
19
|
-
*
|
|
20
|
-
* A pathname is not testID-safe as it stands (`/blog/2024/react-native-tips`,
|
|
21
|
-
* `/pokemon/[id]`), so it is slugged the way the rest of Buoy's handles read:
|
|
22
|
-
* `buoy-routes-route-blog-year-slug`.
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/** Any path-ish string → a testID-safe slug (`/` → `-`, brackets dropped). */
|
|
26
|
-
function pathSlug(path) {
|
|
27
|
-
return String(path).toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "root";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* `buoy-routes-event-row-<slug>-<visit>` for one row of the events timeline.
|
|
32
|
-
*
|
|
33
|
-
* The visit number is part of the handle because revisiting a screen is the
|
|
34
|
-
* normal case here: three trips to `/about` would otherwise be three views
|
|
35
|
-
* sharing one testID, which Detox reports as "multiple elements found" — an
|
|
36
|
-
* ambiguity error where the test meant "the second visit". It also makes the
|
|
37
|
-
* tool's own visit counting addressable rather than merely visible.
|
|
38
|
-
*/
|
|
39
|
-
function eventRowTestID(pathname, visitNumber) {
|
|
40
|
-
return `buoy-routes-event-row-${pathSlug(pathname)}-${visitNumber}`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** `buoy-routes-route-<slug>` for one row of the sitemap. */
|
|
44
|
-
function sitemapRouteTestID(path) {
|
|
45
|
-
return `buoy-routes-route-${pathSlug(path)}`;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** `buoy-routes-group-<slug>` for a sitemap group header. */
|
|
49
|
-
function sitemapGroupTestID(title) {
|
|
50
|
-
return `buoy-routes-group-${pathSlug(title)}`;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* `buoy-routes-stack-item-<index>` for one frame of the navigation stack.
|
|
55
|
-
*
|
|
56
|
-
* The exception to addressing by path: a stack legitimately holds the same
|
|
57
|
-
* route twice (push `/route-bench/1` from `/route-bench/1`), and its whole
|
|
58
|
-
* subject is POSITION — "index 2 of 4" is what the row means, so the position
|
|
59
|
-
* is what the handle should say.
|
|
60
|
-
*/
|
|
61
|
-
function stackItemTestID(index) {
|
|
62
|
-
return `buoy-routes-stack-item-${index}`;
|
|
63
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.eventRowTestID=eventRowTestID;exports.pathSlug=pathSlug;exports.sitemapGroupTestID=sitemapGroupTestID;exports.sitemapRouteTestID=sitemapRouteTestID;exports.stackItemTestID=stackItemTestID;function pathSlug(e){return String(e).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"root"}function eventRowTestID(e,t){return`buoy-routes-event-row-${pathSlug(e)}-${t}`}function sitemapRouteTestID(e){return`buoy-routes-route-${pathSlug(e)}`}function sitemapGroupTestID(e){return`buoy-routes-group-${pathSlug(e)}`}function stackItemTestID(e){return`buoy-routes-stack-item-${e}`}
|