;
+export declare function ObserveRoot({ children, ...props }: AppMetricsRootProps & {
+ children: ReactNode;
+}): import("react/jsx-runtime").JSX.Element;
+export declare namespace ObserveRoot {
+ var wrap: >(Component: React.ComponentType
) => React.ComponentType
;
+}
+export {};
+//# sourceMappingURL=ObserveRoot.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/ObserveRoot.d.ts.map b/packages/expo-observe/build/ObserveRoot.d.ts.map
new file mode 100644
index 00000000000000..2a5e9ed366f153
--- /dev/null
+++ b/packages/expo-observe/build/ObserveRoot.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"ObserveRoot.d.ts","sourceRoot":"","sources":["../src/ObserveRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvD,KAAK,mBAAmB,GAAG,cAAc,CAAC,OAAO,cAAc,CAAC,CAAC;AAEjE,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,mBAAmB,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAMhG;yBANe,WAAW;eAQM,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,aACrD,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAChC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/ObserveRoot.js b/packages/expo-observe/build/ObserveRoot.js
new file mode 100644
index 00000000000000..f29fbf80e5994e
--- /dev/null
+++ b/packages/expo-observe/build/ObserveRoot.js
@@ -0,0 +1,12 @@
+import { jsx as _jsx } from "react/jsx-runtime";
+import { AppMetricsRoot } from 'expo-app-metrics';
+import { ObserveProvider } from './ObserveProvider';
+export function ObserveRoot({ children, ...props }) {
+ return (_jsx(AppMetricsRoot, { ...props, children: _jsx(ObserveProvider, { children: children }) }));
+}
+ObserveRoot.wrap = function wrap(Component) {
+ const Wrapped = (props) => (_jsx(ObserveRoot, { children: _jsx(Component, { ...props }) }));
+ Wrapped.displayName = `ObserveRoot(${Component.displayName || Component.name || 'Component'})`;
+ return Wrapped;
+};
+//# sourceMappingURL=ObserveRoot.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/ObserveRoot.js.map b/packages/expo-observe/build/ObserveRoot.js.map
new file mode 100644
index 00000000000000..668594aca34116
--- /dev/null
+++ b/packages/expo-observe/build/ObserveRoot.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"ObserveRoot.js","sourceRoot":"","sources":["../src/ObserveRoot.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpD,MAAM,UAAU,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAiD;IAC/F,OAAO,CACL,KAAC,cAAc,OAAK,KAAK,YACvB,KAAC,eAAe,cAAE,QAAQ,GAAmB,GAC9B,CAClB,CAAC;AACJ,CAAC;AAED,WAAW,CAAC,IAAI,GAAG,SAAS,IAAI,CAC9B,SAAiC;IAEjC,MAAM,OAAO,GAAG,CAAC,KAAQ,EAAE,EAAE,CAAC,CAC5B,KAAC,WAAW,cACV,KAAC,SAAS,OAAK,KAAK,GAAI,GACZ,CACf,CAAC;IACF,OAAO,CAAC,WAAW,GAAG,eAAe,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,IAAI,IAAI,WAAW,GAAG,CAAC;IAC/F,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["import { AppMetricsRoot } from 'expo-app-metrics';\nimport type { ComponentProps, ReactNode } from 'react';\n\nimport { ObserveProvider } from './ObserveProvider';\n\ntype AppMetricsRootProps = ComponentProps;\n\nexport function ObserveRoot({ children, ...props }: AppMetricsRootProps & { children: ReactNode }) {\n return (\n \n {children}\n \n );\n}\n\nObserveRoot.wrap = function wrap>(\n Component: React.ComponentType
\n): React.ComponentType
{\n const Wrapped = (props: P) => (\n \n \n \n );\n Wrapped.displayName = `ObserveRoot(${Component.displayName || Component.name || 'Component'})`;\n return Wrapped;\n};\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/index.d.ts b/packages/expo-observe/build/index.d.ts
index 57369aaf8b9113..e2db509086f1de 100644
--- a/packages/expo-observe/build/index.d.ts
+++ b/packages/expo-observe/build/index.d.ts
@@ -1,4 +1,6 @@
-export { default as AppMetrics, AppMetricsRoot } from 'expo-app-metrics';
+export { default as AppMetrics } from 'expo-app-metrics';
+export { ObserveRoot } from './ObserveRoot';
export { default } from './module';
export * from './types';
+export { useObserve } from './useObserve';
//# sourceMappingURL=index.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/index.d.ts.map b/packages/expo-observe/build/index.d.ts.map
index a967be55aec22f..9dad5e8bba0c57 100644
--- a/packages/expo-observe/build/index.d.ts.map
+++ b/packages/expo-observe/build/index.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOzE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,cAAc,SAAS,CAAC"}
\ No newline at end of file
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAO5C,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/index.js b/packages/expo-observe/build/index.js
index 5399b6eefc8a16..ac1857cc720266 100644
--- a/packages/expo-observe/build/index.js
+++ b/packages/expo-observe/build/index.js
@@ -1,9 +1,11 @@
import ExpoObserve from './module';
-export { default as AppMetrics, AppMetricsRoot } from 'expo-app-metrics';
+export { default as AppMetrics } from 'expo-app-metrics';
+export { ObserveRoot } from './ObserveRoot';
ExpoObserve.setBundleDefaults({
environment: process.env.NODE_ENV ?? 'production',
isJsDev: !!__DEV__,
});
export { default } from './module';
export * from './types';
+export { useObserve } from './useObserve';
//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/index.js.map b/packages/expo-observe/build/index.js.map
index 617e9a79bf2368..1b3186084da2e2 100644
--- a/packages/expo-observe/build/index.js.map
+++ b/packages/expo-observe/build/index.js.map
@@ -1 +1 @@
-{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEzE,WAAW,CAAC,iBAAiB,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,YAAY;IACjD,OAAO,EAAE,CAAC,CAAC,OAAO;CACnB,CAAC,CAAC;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,cAAc,SAAS,CAAC","sourcesContent":["import ExpoObserve from './module';\n\nexport { default as AppMetrics, AppMetricsRoot } from 'expo-app-metrics';\n\nExpoObserve.setBundleDefaults({\n environment: process.env.NODE_ENV ?? 'production',\n isJsDev: !!__DEV__,\n});\n\nexport { default } from './module';\nexport * from './types';\n"]}
\ No newline at end of file
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,WAAW,CAAC,iBAAiB,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,YAAY;IACjD,OAAO,EAAE,CAAC,CAAC,OAAO;CACnB,CAAC,CAAC;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC","sourcesContent":["import ExpoObserve from './module';\n\nexport { default as AppMetrics } from 'expo-app-metrics';\nexport { ObserveRoot } from './ObserveRoot';\n\nExpoObserve.setBundleDefaults({\n environment: process.env.NODE_ENV ?? 'production',\n isJsDev: !!__DEV__,\n});\n\nexport { default } from './module';\nexport * from './types';\nexport { useObserve } from './useObserve';\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/index.d.ts b/packages/expo-observe/build/integrations/expo-router/index.d.ts
new file mode 100644
index 00000000000000..4cf39199526ce0
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/index.d.ts
@@ -0,0 +1,4 @@
+export { isRouterInstalled } from './router';
+export { useObserveForRouter } from './useObserveForRouter';
+export { initRouterIntegration } from './init';
+//# sourceMappingURL=index.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/index.d.ts.map b/packages/expo-observe/build/integrations/expo-router/index.d.ts.map
new file mode 100644
index 00000000000000..772d45ae9ee301
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/index.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/integrations/expo-router/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/index.js b/packages/expo-observe/build/integrations/expo-router/index.js
new file mode 100644
index 00000000000000..f08d54773c01ea
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/index.js
@@ -0,0 +1,4 @@
+export { isRouterInstalled } from './router';
+export { useObserveForRouter } from './useObserveForRouter';
+export { initRouterIntegration } from './init';
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/index.js.map b/packages/expo-observe/build/integrations/expo-router/index.js.map
new file mode 100644
index 00000000000000..612a8fb4675e74
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/integrations/expo-router/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAC","sourcesContent":["export { isRouterInstalled } from './router';\nexport { useObserveForRouter } from './useObserveForRouter';\nexport { initRouterIntegration } from './init';\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/init.d.ts b/packages/expo-observe/build/integrations/expo-router/init.d.ts
new file mode 100644
index 00000000000000..a155cac7c92683
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/init.d.ts
@@ -0,0 +1,3 @@
+export declare const isInitialized: () => boolean;
+export declare function initRouterIntegration(): void;
+//# sourceMappingURL=init.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/init.d.ts.map b/packages/expo-observe/build/integrations/expo-router/init.d.ts.map
new file mode 100644
index 00000000000000..c739b1bfa334e7
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/init.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/integrations/expo-router/init.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,eAAoB,CAAC;AAE/C,wBAAgB,qBAAqB,SAEpC"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/init.js b/packages/expo-observe/build/integrations/expo-router/init.js
new file mode 100644
index 00000000000000..d32e90536a2f0f
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/init.js
@@ -0,0 +1,6 @@
+let initialized = false;
+export const isInitialized = () => initialized;
+export function initRouterIntegration() {
+ initialized = true;
+}
+//# sourceMappingURL=init.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/init.js.map b/packages/expo-observe/build/integrations/expo-router/init.js.map
new file mode 100644
index 00000000000000..bd35f87018a822
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/init.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/integrations/expo-router/init.ts"],"names":[],"mappings":"AAAA,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC;AAE/C,MAAM,UAAU,qBAAqB;IACnC,WAAW,GAAG,IAAI,CAAC;AACrB,CAAC","sourcesContent":["let initialized = false;\n\nexport const isInitialized = () => initialized;\n\nexport function initRouterIntegration() {\n initialized = true;\n}\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/router.d.ts b/packages/expo-observe/build/integrations/expo-router/router.d.ts
new file mode 100644
index 00000000000000..18ebe98531dbce
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/router.d.ts
@@ -0,0 +1,4 @@
+declare let optionalRouter: typeof import('expo-router') | undefined;
+declare const isRouterInstalled: boolean;
+export { optionalRouter, isRouterInstalled };
+//# sourceMappingURL=router.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/router.d.ts.map b/packages/expo-observe/build/integrations/expo-router/router.d.ts.map
new file mode 100644
index 00000000000000..1ce4ef8748cd25
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/router.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/integrations/expo-router/router.ts"],"names":[],"mappings":"AAEA,QAAA,IAAI,cAAc,EAAE,cAAc,aAAa,CAAC,GAAG,SAAS,CAAC;AAM7D,QAAA,MAAM,iBAAiB,SAAmB,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/router.js b/packages/expo-observe/build/integrations/expo-router/router.js
new file mode 100644
index 00000000000000..a885c33624373a
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/router.js
@@ -0,0 +1,12 @@
+// expo-router is an optional peerDependency of expo-observe. When the host app
+// hasn't installed it, `require` throws and the integration becomes a no-op.
+let optionalRouter;
+try {
+ optionalRouter = require('expo-router');
+}
+catch {
+ // expo-router not installed — integration disabled.
+}
+const isRouterInstalled = !!optionalRouter;
+export { optionalRouter, isRouterInstalled };
+//# sourceMappingURL=router.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/router.js.map b/packages/expo-observe/build/integrations/expo-router/router.js.map
new file mode 100644
index 00000000000000..3155cdab6f338c
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/router.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/integrations/expo-router/router.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6EAA6E;AAC7E,IAAI,cAAwD,CAAC;AAC7D,IAAI,CAAC;IACH,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;AAC1C,CAAC;AAAC,MAAM,CAAC;IACP,oDAAoD;AACtD,CAAC;AACD,MAAM,iBAAiB,GAAG,CAAC,CAAC,cAAc,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["// expo-router is an optional peerDependency of expo-observe. When the host app\n// hasn't installed it, `require` throws and the integration becomes a no-op.\nlet optionalRouter: typeof import('expo-router') | undefined;\ntry {\n optionalRouter = require('expo-router');\n} catch {\n // expo-router not installed — integration disabled.\n}\nconst isRouterInstalled = !!optionalRouter;\n\nexport { optionalRouter, isRouterInstalled };\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.d.ts b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.d.ts
new file mode 100644
index 00000000000000..778af965058d0c
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.d.ts
@@ -0,0 +1,5 @@
+import AppMetrics from 'expo-app-metrics';
+type MarkInteractive = (typeof AppMetrics)['markInteractive'];
+export declare function useObserveForRouter(): MarkInteractive | null;
+export {};
+//# sourceMappingURL=useObserveForRouter.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.d.ts.map b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.d.ts.map
new file mode 100644
index 00000000000000..d1263be6820ee2
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"useObserveForRouter.d.ts","sourceRoot":"","sources":["../../../src/integrations/expo-router/useObserveForRouter.ts"],"names":[],"mappings":"AAAA,OAAO,UAAqC,MAAM,kBAAkB,CAAC;AAMrE,KAAK,eAAe,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,iBAAiB,CAAC,CAAC;AAE9D,wBAAgB,mBAAmB,IAAI,eAAe,GAAG,IAAI,CAwD5D"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.js b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.js
new file mode 100644
index 00000000000000..c5a6d2a99614f5
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.js
@@ -0,0 +1,48 @@
+import AppMetrics, {} from 'expo-app-metrics';
+import { useCallback, useEffect, useRef } from 'react';
+import { isInitialized } from './init';
+import { optionalRouter } from './router';
+export function useObserveForRouter() {
+ const isMounted = useRef(true);
+ const route = optionalRouter?.useRoute();
+ const navigation = optionalRouter?.useNavigation();
+ const pathname = optionalRouter?.useCurrentRouteInfo()?.pathname;
+ const initializedAtMount = useRef(isInitialized());
+ if (initializedAtMount.current !== isInitialized()) {
+ throw new Error("[expo-observe] Router integration was toggled during a screen's lifecycle. " +
+ 'Call `ExpoObserve.configure({ disableRouterIntegration })` once at startup before any screen mounts.');
+ }
+ const screenId = route?.key;
+ const prevScreenId = useRef(screenId);
+ if (prevScreenId.current !== screenId) {
+ console.warn('[expo-observe] Screen ID changed between renders. This is most likely an expo-router bug.');
+ prevScreenId.current = screenId;
+ }
+ useEffect(() => {
+ // Strict-mode mounts the effect twice (mount → cleanup → re-mount). Without
+ // restoring isMounted here, the second mount would leave it permanently false
+ // and every markInteractive call would warn "unmounted screen".
+ isMounted.current = true;
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
+ const markInteractive = useCallback(async (attributes) => {
+ if (!isMounted.current) {
+ console.warn('[expo-observe] Calling markInteractive on unmounted screen');
+ return;
+ }
+ if (!screenId) {
+ console.warn('[expo-observe] No metadata available for the current screen. Make sure to call useObserve inside a screen component.');
+ return;
+ }
+ if (navigation?.isFocused()) {
+ AppMetrics.markInteractive({
+ ...(attributes ?? {}),
+ routeName: pathname,
+ });
+ }
+ }, [screenId, navigation, pathname]);
+ return initializedAtMount.current ? markInteractive : null;
+}
+//# sourceMappingURL=useObserveForRouter.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.js.map b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.js.map
new file mode 100644
index 00000000000000..986fb74c74bd02
--- /dev/null
+++ b/packages/expo-observe/build/integrations/expo-router/useObserveForRouter.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"useObserveForRouter.js","sourceRoot":"","sources":["../../../src/integrations/expo-router/useObserveForRouter.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,EAAE,EAAyB,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAI1C,MAAM,UAAU,mBAAmB;IACjC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,cAAc,EAAE,QAAQ,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,cAAc,EAAE,aAAa,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,cAAc,EAAE,mBAAmB,EAAE,EAAE,QAAQ,CAAC;IAEjE,MAAM,kBAAkB,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IACnD,IAAI,kBAAkB,CAAC,OAAO,KAAK,aAAa,EAAE,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CACb,6EAA6E;YAC3E,sGAAsG,CACzG,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAG,CAAC;IAC5B,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,IAAI,YAAY,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,CACV,2FAA2F,CAC5F,CAAC;QACF,YAAY,CAAC,OAAO,GAAG,QAAQ,CAAC;IAClC,CAAC;IAED,SAAS,CAAC,GAAG,EAAE;QACb,4EAA4E;QAC5E,8EAA8E;QAC9E,gEAAgE;QAChE,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;QACzB,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,OAAO,GAAG,KAAK,CAAC;QAC5B,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,eAAe,GAAG,WAAW,CACjC,KAAK,EAAE,UAA6B,EAAE,EAAE;QACtC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CACV,sHAAsH,CACvH,CAAC;YACF,OAAO;QACT,CAAC;QACD,IAAI,UAAU,EAAE,SAAS,EAAE,EAAE,CAAC;YAC5B,UAAU,CAAC,eAAe,CAAC;gBACzB,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;gBACrB,SAAS,EAAE,QAAQ;aACpB,CAAC,CAAC;QACL,CAAC;IACH,CAAC,EACD,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CACjC,CAAC;IAEF,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7D,CAAC","sourcesContent":["import AppMetrics, { type MetricAttributes } from 'expo-app-metrics';\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport { isInitialized } from './init';\nimport { optionalRouter } from './router';\n\ntype MarkInteractive = (typeof AppMetrics)['markInteractive'];\n\nexport function useObserveForRouter(): MarkInteractive | null {\n const isMounted = useRef(true);\n const route = optionalRouter?.useRoute();\n const navigation = optionalRouter?.useNavigation();\n const pathname = optionalRouter?.useCurrentRouteInfo()?.pathname;\n\n const initializedAtMount = useRef(isInitialized());\n if (initializedAtMount.current !== isInitialized()) {\n throw new Error(\n \"[expo-observe] Router integration was toggled during a screen's lifecycle. \" +\n 'Call `ExpoObserve.configure({ disableRouterIntegration })` once at startup before any screen mounts.'\n );\n }\n\n const screenId = route?.key;\n const prevScreenId = useRef(screenId);\n if (prevScreenId.current !== screenId) {\n console.warn(\n '[expo-observe] Screen ID changed between renders. This is most likely an expo-router bug.'\n );\n prevScreenId.current = screenId;\n }\n\n useEffect(() => {\n // Strict-mode mounts the effect twice (mount → cleanup → re-mount). Without\n // restoring isMounted here, the second mount would leave it permanently false\n // and every markInteractive call would warn \"unmounted screen\".\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const markInteractive = useCallback(\n async (attributes?: MetricAttributes) => {\n if (!isMounted.current) {\n console.warn('[expo-observe] Calling markInteractive on unmounted screen');\n return;\n }\n if (!screenId) {\n console.warn(\n '[expo-observe] No metadata available for the current screen. Make sure to call useObserve inside a screen component.'\n );\n return;\n }\n if (navigation?.isFocused()) {\n AppMetrics.markInteractive({\n ...(attributes ?? {}),\n routeName: pathname,\n });\n }\n },\n [screenId, navigation, pathname]\n );\n\n return initializedAtMount.current ? markInteractive : null;\n}\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/module.d.ts b/packages/expo-observe/build/module.d.ts
index f993fe50a040e5..7088006f2a067a 100644
--- a/packages/expo-observe/build/module.d.ts
+++ b/packages/expo-observe/build/module.d.ts
@@ -1,4 +1,4 @@
import type { ExpoObserveModuleType } from './types';
-declare const _default: ExpoObserveModuleType;
-export default _default;
+declare const ExpoObserve: ExpoObserveModuleType;
+export default ExpoObserve;
//# sourceMappingURL=module.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/module.d.ts.map b/packages/expo-observe/build/module.d.ts.map
index f5beee35cd0add..65fc4784860883 100644
--- a/packages/expo-observe/build/module.d.ts.map
+++ b/packages/expo-observe/build/module.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;;AAErD,wBAAyE"}
\ No newline at end of file
+{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAU,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAI7D,QAAA,MAAM,WAAW,EAAE,qBAajB,CAAC;AAEH,eAAe,WAAW,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/module.js b/packages/expo-observe/build/module.js
index 46f52e35524046..80ebc32a871d96 100644
--- a/packages/expo-observe/build/module.js
+++ b/packages/expo-observe/build/module.js
@@ -1,3 +1,20 @@
import { requireNativeModule } from 'expo';
-export default requireNativeModule('ExpoObserve');
+import { initRouterIntegration } from './integrations/expo-router/init';
+import { isRouterInstalled } from './integrations/expo-router/router';
+const native = requireNativeModule('ExpoObserve');
+const ExpoObserve = new Proxy(native, {
+ get(target, prop, receiver) {
+ if (prop === 'configure') {
+ return (config) => {
+ const { disableRouterIntegration, ...nativeConfig } = config;
+ if (!disableRouterIntegration && isRouterInstalled) {
+ initRouterIntegration();
+ }
+ return target.configure(nativeConfig);
+ };
+ }
+ return Reflect.get(target, prop, receiver);
+ },
+});
+export default ExpoObserve;
//# sourceMappingURL=module.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/module.js.map b/packages/expo-observe/build/module.js.map
index bd74054410b6eb..d480815813a9b9 100644
--- a/packages/expo-observe/build/module.js.map
+++ b/packages/expo-observe/build/module.js.map
@@ -1 +1 @@
-{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAI3C,eAAe,mBAAmB,CAAwB,aAAa,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo';\n\nimport type { ExpoObserveModuleType } from './types';\n\nexport default requireNativeModule('ExpoObserve');\n"]}
\ No newline at end of file
+{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAE3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAGtE,MAAM,MAAM,GAAG,mBAAmB,CAAwB,aAAa,CAAC,CAAC;AAEzE,MAAM,WAAW,GAA0B,IAAI,KAAK,CAAC,MAAM,EAAE;IAC3D,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ;QACxB,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YACzB,OAAO,CAAC,MAAc,EAAE,EAAE;gBACxB,MAAM,EAAE,wBAAwB,EAAE,GAAG,YAAY,EAAE,GAAG,MAAM,CAAC;gBAC7D,IAAI,CAAC,wBAAwB,IAAI,iBAAiB,EAAE,CAAC;oBACnD,qBAAqB,EAAE,CAAC;gBAC1B,CAAC;gBACD,OAAO,MAAM,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YACxC,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;CACF,CAAC,CAAC;AAEH,eAAe,WAAW,CAAC","sourcesContent":["import { requireNativeModule } from 'expo';\n\nimport { initRouterIntegration } from './integrations/expo-router/init';\nimport { isRouterInstalled } from './integrations/expo-router/router';\nimport type { Config, ExpoObserveModuleType } from './types';\n\nconst native = requireNativeModule('ExpoObserve');\n\nconst ExpoObserve: ExpoObserveModuleType = new Proxy(native, {\n get(target, prop, receiver) {\n if (prop === 'configure') {\n return (config: Config) => {\n const { disableRouterIntegration, ...nativeConfig } = config;\n if (!disableRouterIntegration && isRouterInstalled) {\n initRouterIntegration();\n }\n return target.configure(nativeConfig);\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n});\n\nexport default ExpoObserve;\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/types.d.ts b/packages/expo-observe/build/types.d.ts
index beb13bc9711a5c..062549d5c6a9df 100644
--- a/packages/expo-observe/build/types.d.ts
+++ b/packages/expo-observe/build/types.d.ts
@@ -45,6 +45,14 @@ export type Config = {
* @default undefined - metrics from all devices are sent
*/
sampleRate?: number;
+ /**
+ * Disables the automatic `expo-router` integration that records TTR/TTI per screen.
+ *
+ * When `true` or `expo-router` is not installed, the router integration will not be used.
+ *
+ * @default false
+ */
+ disableRouterIntegration?: boolean;
};
export interface ExpoObserveModuleType {
dispatchEvents(): Promise;
diff --git a/packages/expo-observe/build/types.d.ts.map b/packages/expo-observe/build/types.d.ts.map
index ed8a24f91d8015..53abce322dc08e 100644
--- a/packages/expo-observe/build/types.d.ts.map
+++ b/packages/expo-observe/build/types.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;;OAMG;IACH,iBAAiB,CAAC,QAAQ,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9E"}
\ No newline at end of file
+{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,MAAM,GAAG;IACnB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;;;;;;;OAYG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;;OAMG;IACH,iBAAiB,CAAC,QAAQ,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9E"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/types.js.map b/packages/expo-observe/build/types.js.map
index f5f2ca35b9f558..77e4c6045bc328 100644
--- a/packages/expo-observe/build/types.js.map
+++ b/packages/expo-observe/build/types.js.map
@@ -1 +1 @@
-{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type Config = {\n /**\n * The environment for observability events\n *\n * @default process.env.NODE_ENV\n */\n environment?: string;\n /**\n * Whether to dispatch observability events to the server.\n *\n * When `false`, any pending metrics are marked as sent without being dispatched\n * and no further metrics are dispatched until this is set back to `true`.\n *\n * @default true\n */\n dispatchingEnabled?: boolean;\n /**\n * Whether to dispatch metrics that were collected in a debug build of the host app.\n *\n * When `false`, metrics produced by debug builds are marked as sent without being dispatched.\n * When `true`, debug-build metrics are dispatched alongside release-build metrics.\n *\n * Has no effect on release builds.\n *\n * If `dispatchingEnabled` is `false` or this device is out-of-sample for `sampleRate`, nothing\n * is dispatched regardless of `dispatchInDebug`.\n *\n * @default false\n */\n dispatchInDebug?: boolean;\n /**\n * Fraction of installations that should dispatch metrics, in `[0, 1]`. Values outside that range\n * are clamped.\n *\n * The decision is **deterministic per installation** — a device is either permanently in-sample\n * or out-of-sample for a given rate, so the choice is stable across app launches.\n *\n * Interaction with `dispatchingEnabled`:\n * - If `dispatchingEnabled` is `false`, metrics are never dispatched\n * - If `dispatchingEnabled` is `true` (or unset), metrics are dispatched only when this device\n * is in-sample.\n *\n * > Note: Devices that end up out-of-sample drop pending metrics rather than accumulating them.\n *\n * @default undefined - metrics from all devices are sent\n */\n sampleRate?: number;\n};\n\nexport interface ExpoObserveModuleType {\n dispatchEvents(): Promise;\n /**\n * Configures observability settings.\n */\n configure(config: Config): void;\n /**\n * Pushes JS-bundle-derived facts (`process.env.NODE_ENV`, `__DEV__`) into native\n * storage. Called automatically once when the package is first imported; should\n * not be called by host apps directly.\n *\n * @internal\n */\n setBundleDefaults(defaults: { environment: string; isJsDev: boolean }): void;\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type Config = {\n /**\n * The environment for observability events\n *\n * @default process.env.NODE_ENV\n */\n environment?: string;\n /**\n * Whether to dispatch observability events to the server.\n *\n * When `false`, any pending metrics are marked as sent without being dispatched\n * and no further metrics are dispatched until this is set back to `true`.\n *\n * @default true\n */\n dispatchingEnabled?: boolean;\n /**\n * Whether to dispatch metrics that were collected in a debug build of the host app.\n *\n * When `false`, metrics produced by debug builds are marked as sent without being dispatched.\n * When `true`, debug-build metrics are dispatched alongside release-build metrics.\n *\n * Has no effect on release builds.\n *\n * If `dispatchingEnabled` is `false` or this device is out-of-sample for `sampleRate`, nothing\n * is dispatched regardless of `dispatchInDebug`.\n *\n * @default false\n */\n dispatchInDebug?: boolean;\n /**\n * Fraction of installations that should dispatch metrics, in `[0, 1]`. Values outside that range\n * are clamped.\n *\n * The decision is **deterministic per installation** — a device is either permanently in-sample\n * or out-of-sample for a given rate, so the choice is stable across app launches.\n *\n * Interaction with `dispatchingEnabled`:\n * - If `dispatchingEnabled` is `false`, metrics are never dispatched\n * - If `dispatchingEnabled` is `true` (or unset), metrics are dispatched only when this device\n * is in-sample.\n *\n * > Note: Devices that end up out-of-sample drop pending metrics rather than accumulating them.\n *\n * @default undefined - metrics from all devices are sent\n */\n sampleRate?: number;\n /**\n * Disables the automatic `expo-router` integration that records TTR/TTI per screen.\n *\n * When `true` or `expo-router` is not installed, the router integration will not be used.\n *\n * @default false\n */\n disableRouterIntegration?: boolean;\n};\n\nexport interface ExpoObserveModuleType {\n dispatchEvents(): Promise;\n /**\n * Configures observability settings.\n */\n configure(config: Config): void;\n /**\n * Pushes JS-bundle-derived facts (`process.env.NODE_ENV`, `__DEV__`) into native\n * storage. Called automatically once when the package is first imported; should\n * not be called by host apps directly.\n *\n * @internal\n */\n setBundleDefaults(defaults: { environment: string; isJsDev: boolean }): void;\n}\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/build/useObserve.d.ts b/packages/expo-observe/build/useObserve.d.ts
new file mode 100644
index 00000000000000..8f87e572f92e48
--- /dev/null
+++ b/packages/expo-observe/build/useObserve.d.ts
@@ -0,0 +1,4 @@
+export declare function useObserve(): {
+ markInteractive: (attributes?: import("expo-app-metrics").MetricAttributes) => void;
+};
+//# sourceMappingURL=useObserve.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/useObserve.d.ts.map b/packages/expo-observe/build/useObserve.d.ts.map
new file mode 100644
index 00000000000000..c233593511cc28
--- /dev/null
+++ b/packages/expo-observe/build/useObserve.d.ts.map
@@ -0,0 +1 @@
+{"version":3,"file":"useObserve.d.ts","sourceRoot":"","sources":["../src/useObserve.ts"],"names":[],"mappings":"AAIA,wBAAgB,UAAU;;EAKzB"}
\ No newline at end of file
diff --git a/packages/expo-observe/build/useObserve.js b/packages/expo-observe/build/useObserve.js
new file mode 100644
index 00000000000000..b1d5e7c0865abe
--- /dev/null
+++ b/packages/expo-observe/build/useObserve.js
@@ -0,0 +1,9 @@
+import AppMetrics from 'expo-app-metrics';
+import { useObserveForRouter } from './integrations/expo-router';
+export function useObserve() {
+ const routerMarkInteractive = useObserveForRouter();
+ return {
+ markInteractive: routerMarkInteractive ?? AppMetrics.markInteractive,
+ };
+}
+//# sourceMappingURL=useObserve.js.map
\ No newline at end of file
diff --git a/packages/expo-observe/build/useObserve.js.map b/packages/expo-observe/build/useObserve.js.map
new file mode 100644
index 00000000000000..bba0efe1041872
--- /dev/null
+++ b/packages/expo-observe/build/useObserve.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"useObserve.js","sourceRoot":"","sources":["../src/useObserve.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAE1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,UAAU,UAAU;IACxB,MAAM,qBAAqB,GAAG,mBAAmB,EAAE,CAAC;IACpD,OAAO;QACL,eAAe,EAAE,qBAAqB,IAAI,UAAU,CAAC,eAAe;KACrE,CAAC;AACJ,CAAC","sourcesContent":["import AppMetrics from 'expo-app-metrics';\n\nimport { useObserveForRouter } from './integrations/expo-router';\n\nexport function useObserve() {\n const routerMarkInteractive = useObserveForRouter();\n return {\n markInteractive: routerMarkInteractive ?? AppMetrics.markInteractive,\n };\n}\n"]}
\ No newline at end of file
diff --git a/packages/expo-observe/jest.config.js b/packages/expo-observe/jest.config.js
new file mode 100644
index 00000000000000..26e5d3eb92932e
--- /dev/null
+++ b/packages/expo-observe/jest.config.js
@@ -0,0 +1,2 @@
+/** @type {import('jest').Config} */
+module.exports = require('expo-module-scripts/jest-preset');
diff --git a/packages/expo-observe/package.json b/packages/expo-observe/package.json
index f56c11e8d429ce..bd81d5ef6a5ff6 100644
--- a/packages/expo-observe/package.json
+++ b/packages/expo-observe/package.json
@@ -36,11 +36,20 @@
"expo-eas-client": "workspace:~56.0.0"
},
"devDependencies": {
+ "@testing-library/react-native": "^13.3.0",
+ "@types/react": "~19.2.0",
"expo": "workspace:*",
"expo-module-scripts": "workspace:*"
},
"peerDependencies": {
"expo": "*",
- "react-native": "*"
+ "react": "*",
+ "react-native": "*",
+ "expo-router": "*"
+ },
+ "peerDependenciesMeta": {
+ "expo-router": {
+ "optional": true
+ }
}
}
diff --git a/packages/expo-observe/src/ObserveProvider.tsx b/packages/expo-observe/src/ObserveProvider.tsx
new file mode 100644
index 00000000000000..3a267894c72350
--- /dev/null
+++ b/packages/expo-observe/src/ObserveProvider.tsx
@@ -0,0 +1,5 @@
+import { type PropsWithChildren } from 'react';
+
+export function ObserveProvider({ children }: PropsWithChildren) {
+ return <>{children}>;
+}
diff --git a/packages/expo-observe/src/ObserveRoot.tsx b/packages/expo-observe/src/ObserveRoot.tsx
new file mode 100644
index 00000000000000..07b0de441842eb
--- /dev/null
+++ b/packages/expo-observe/src/ObserveRoot.tsx
@@ -0,0 +1,26 @@
+import { AppMetricsRoot } from 'expo-app-metrics';
+import type { ComponentProps, ReactNode } from 'react';
+
+import { ObserveProvider } from './ObserveProvider';
+
+type AppMetricsRootProps = ComponentProps;
+
+export function ObserveRoot({ children, ...props }: AppMetricsRootProps & { children: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
+
+ObserveRoot.wrap = function wrap>(
+ Component: React.ComponentType
+): React.ComponentType
{
+ const Wrapped = (props: P) => (
+
+
+
+ );
+ Wrapped.displayName = `ObserveRoot(${Component.displayName || Component.name || 'Component'})`;
+ return Wrapped;
+};
diff --git a/packages/expo-observe/src/__tests__/module.test.native.ts b/packages/expo-observe/src/__tests__/module.test.native.ts
new file mode 100644
index 00000000000000..13c9a3e6345861
--- /dev/null
+++ b/packages/expo-observe/src/__tests__/module.test.native.ts
@@ -0,0 +1,95 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
+const mockNative = {
+ configure: jest.fn(),
+ setBundleDefaults: jest.fn(),
+ dispatchEvents: jest.fn(() => Promise.resolve()),
+};
+
+jest.mock('expo', () => ({
+ requireNativeModule: jest.fn(() => mockNative),
+}));
+
+jest.mock('../integrations/expo-router/router', () => ({
+ isRouterInstalled: true,
+ optionalRouter: undefined,
+}));
+
+jest.mock('../integrations/expo-router/init', () => ({
+ initRouterIntegration: jest.fn(),
+ isInitialized: jest.fn(() => false),
+ initListeners: jest.fn(() => () => {}),
+}));
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ jest.resetModules();
+ jest.doMock('expo', () => ({ requireNativeModule: jest.fn(() => mockNative) }));
+ jest.doMock('../integrations/expo-router/router', () => ({
+ isRouterInstalled: true,
+ optionalRouter: undefined,
+ }));
+ jest.doMock('../integrations/expo-router/init', () => ({
+ initRouterIntegration: jest.fn(),
+ isInitialized: jest.fn(() => false),
+ initListeners: jest.fn(() => () => {}),
+ }));
+});
+
+function loadModule() {
+ return require('../module').default as typeof import('../module').default;
+}
+
+function loadInit() {
+ return require('../integrations/expo-router/init') as typeof import('../integrations/expo-router/init');
+}
+
+describe('module Proxy', () => {
+ it('strips disableRouterIntegration from the config forwarded to native', () => {
+ const ExpoObserve = loadModule();
+ ExpoObserve.configure({ environment: 'test', disableRouterIntegration: true });
+ expect(mockNative.configure).toHaveBeenCalledWith({ environment: 'test' });
+ });
+
+ it('calls initRouterIntegration when router is installed and integration is enabled', () => {
+ const ExpoObserve = loadModule();
+ const { initRouterIntegration } = loadInit();
+ ExpoObserve.configure({ environment: 'test' });
+ expect(initRouterIntegration).toHaveBeenCalledTimes(1);
+ });
+
+ it('skips initRouterIntegration when disableRouterIntegration is true', () => {
+ const ExpoObserve = loadModule();
+ const { initRouterIntegration } = loadInit();
+ ExpoObserve.configure({ disableRouterIntegration: true });
+ expect(initRouterIntegration).not.toHaveBeenCalled();
+ });
+
+ it('skips initRouterIntegration when router is not installed', () => {
+ jest.doMock('../integrations/expo-router/router', () => ({
+ isRouterInstalled: false,
+ optionalRouter: undefined,
+ }));
+ const ExpoObserve = loadModule();
+ const { initRouterIntegration } = loadInit();
+ ExpoObserve.configure({});
+ expect(initRouterIntegration).not.toHaveBeenCalled();
+ });
+
+ it('passes through dispatchEvents and setBundleDefaults to native', () => {
+ const ExpoObserve = loadModule();
+ ExpoObserve.dispatchEvents();
+ ExpoObserve.setBundleDefaults({ environment: 'production', isJsDev: false });
+ expect(mockNative.dispatchEvents).toHaveBeenCalledTimes(1);
+ expect(mockNative.setBundleDefaults).toHaveBeenCalledWith({
+ environment: 'production',
+ isJsDev: false,
+ });
+ });
+
+ it('returns the native function via Reflect.get for unknown props', () => {
+ const ExpoObserve = loadModule();
+ expect((ExpoObserve as { dispatchEvents: unknown }).dispatchEvents).toBe(
+ mockNative.dispatchEvents
+ );
+ });
+});
diff --git a/packages/expo-observe/src/__tests__/useObserve.test.native.tsx b/packages/expo-observe/src/__tests__/useObserve.test.native.tsx
new file mode 100644
index 00000000000000..b4f2f62a6860d0
--- /dev/null
+++ b/packages/expo-observe/src/__tests__/useObserve.test.native.tsx
@@ -0,0 +1,61 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
+import { renderHook } from '@testing-library/react-native';
+import AppMetrics from 'expo-app-metrics';
+
+import * as routerIntegration from '../integrations/expo-router';
+import { useObserve } from '../useObserve';
+
+jest.mock('expo-app-metrics', () => ({
+ __esModule: true,
+ default: {
+ markInteractive: jest.fn(),
+ getMainSessionId: jest.fn(() => 'session-1'),
+ addCustomMetricToSession: jest.fn(),
+ },
+}));
+
+jest.mock('../integrations/expo-router', () => ({
+ __esModule: true,
+ useObserveForRouter: jest.fn(),
+}));
+
+const mockUseObserveForRouter = routerIntegration.useObserveForRouter as jest.Mock;
+
+beforeEach(() => {
+ jest.clearAllMocks();
+});
+
+describe('useObserve', () => {
+ it('returns the router-scoped markInteractive when useObserveForRouter resolves to a function', () => {
+ const routerScoped = jest.fn();
+ mockUseObserveForRouter.mockReturnValue(routerScoped);
+
+ const { result } = renderHook(() => useObserve());
+
+ expect(result.current.markInteractive).toBe(routerScoped);
+ });
+
+ it('falls back to AppMetrics.markInteractive when useObserveForRouter returns null', () => {
+ mockUseObserveForRouter.mockReturnValue(null);
+
+ const { result } = renderHook(() => useObserve());
+
+ expect(result.current.markInteractive).toBe(AppMetrics.markInteractive);
+ });
+
+ it('calls useObserveForRouter unconditionally on every render', () => {
+ mockUseObserveForRouter.mockReturnValue(null);
+
+ const { rerender } = renderHook(() => useObserve());
+ expect(mockUseObserveForRouter).toHaveBeenCalledTimes(1);
+
+ rerender(undefined);
+ expect(mockUseObserveForRouter).toHaveBeenCalledTimes(2);
+ });
+
+ it('returns an object with exactly one own key (markInteractive)', () => {
+ mockUseObserveForRouter.mockReturnValue(null);
+ const { result } = renderHook(() => useObserve());
+ expect(Object.keys(result.current)).toEqual(['markInteractive']);
+ });
+});
diff --git a/packages/expo-observe/src/index.ts b/packages/expo-observe/src/index.ts
index d1ff1b80292a7c..8227d6a495b3c0 100644
--- a/packages/expo-observe/src/index.ts
+++ b/packages/expo-observe/src/index.ts
@@ -1,6 +1,7 @@
import ExpoObserve from './module';
-export { default as AppMetrics, AppMetricsRoot } from 'expo-app-metrics';
+export { default as AppMetrics } from 'expo-app-metrics';
+export { ObserveRoot } from './ObserveRoot';
ExpoObserve.setBundleDefaults({
environment: process.env.NODE_ENV ?? 'production',
@@ -9,3 +10,4 @@ ExpoObserve.setBundleDefaults({
export { default } from './module';
export * from './types';
+export { useObserve } from './useObserve';
diff --git a/packages/expo-observe/src/integrations/expo-router/__tests__/useObserveForRouter.test.android.tsx b/packages/expo-observe/src/integrations/expo-router/__tests__/useObserveForRouter.test.android.tsx
new file mode 100644
index 00000000000000..56352558327ecc
--- /dev/null
+++ b/packages/expo-observe/src/integrations/expo-router/__tests__/useObserveForRouter.test.android.tsx
@@ -0,0 +1,74 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
+import { renderHook, act } from '@testing-library/react-native';
+import AppMetrics from 'expo-app-metrics';
+
+import * as routerModule from '../router';
+import { useObserveForRouter } from '../useObserveForRouter';
+
+jest.mock('expo-app-metrics', () => ({
+ __esModule: true,
+ default: {
+ markInteractive: jest.fn(),
+ getMainSession: jest.fn(() => ({ id: 'session-1' })),
+ addCustomMetricToSession: jest.fn(),
+ },
+}));
+
+jest.mock('../init', () => ({
+ __esModule: true,
+ isInitialized: jest.fn(() => true),
+ initRouterIntegration: jest.fn(),
+}));
+
+jest.mock('../router', () => {
+ const useRoute = jest.fn(() => ({ key: 'screen-a' }));
+ const useNavigation = jest.fn(() => ({ isFocused: () => true }));
+ const useCurrentRouteInfo = jest.fn(() => ({
+ pathname: '/test',
+ params: { x: '1' },
+ segments: ['test'],
+ }));
+ return {
+ optionalRouter: {
+ useRoute,
+ useNavigation,
+ useCurrentRouteInfo,
+ },
+ isRouterInstalled: true,
+ __useRoute: useRoute,
+ __useNavigation: useNavigation,
+ };
+});
+
+const mockUseRoute = (routerModule as unknown as { __useRoute: jest.Mock }).__useRoute;
+const mockUseNavigation = (routerModule as unknown as { __useNavigation: jest.Mock })
+ .__useNavigation;
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ mockUseRoute.mockReturnValue({ key: 'screen-a' });
+ mockUseNavigation.mockReturnValue({ isFocused: () => true });
+});
+
+describe('useObserveForRouter (android)', () => {
+ it('calls AppMetrics.markInteractive when the screen is focused', async () => {
+ const { result } = renderHook(() => useObserveForRouter());
+ const arg = { params: { x: 'payload' } };
+ await act(async () => {
+ await result.current!({ ...arg });
+ });
+ expect(AppMetrics.markInteractive).toHaveBeenCalledWith({ ...arg, routeName: '/test' });
+ });
+
+ it('does not call AppMetrics.markInteractive when the screen is not focused', async () => {
+ mockUseNavigation.mockReturnValue({ isFocused: () => false });
+ jest.spyOn(Date, 'now').mockReturnValue(1300);
+
+ const { result } = renderHook(() => useObserveForRouter());
+ await act(async () => {
+ await result.current!();
+ });
+
+ expect(AppMetrics.markInteractive).not.toHaveBeenCalled();
+ });
+});
diff --git a/packages/expo-observe/src/integrations/expo-router/__tests__/useObserveForRouter.test.ios.tsx b/packages/expo-observe/src/integrations/expo-router/__tests__/useObserveForRouter.test.ios.tsx
new file mode 100644
index 00000000000000..961735dce6dd0a
--- /dev/null
+++ b/packages/expo-observe/src/integrations/expo-router/__tests__/useObserveForRouter.test.ios.tsx
@@ -0,0 +1,74 @@
+/* eslint-disable @typescript-eslint/no-require-imports */
+import { renderHook, act } from '@testing-library/react-native';
+import AppMetrics from 'expo-app-metrics';
+
+import * as routerModule from '../router';
+import { useObserveForRouter } from '../useObserveForRouter';
+
+jest.mock('expo-app-metrics', () => ({
+ __esModule: true,
+ default: {
+ markInteractive: jest.fn(),
+ getMainSession: jest.fn(() => ({ id: 'session-1' })),
+ addCustomMetricToSession: jest.fn(),
+ },
+}));
+
+jest.mock('../init', () => ({
+ __esModule: true,
+ isInitialized: jest.fn(() => true),
+ initRouterIntegration: jest.fn(),
+}));
+
+jest.mock('../router', () => {
+ const useRoute = jest.fn(() => ({ key: 'screen-a' }));
+ const useNavigation = jest.fn(() => ({ isFocused: () => true }));
+ const useCurrentRouteInfo = jest.fn(() => ({
+ pathname: '/test',
+ params: { x: '1' },
+ segments: ['test'],
+ }));
+ return {
+ optionalRouter: {
+ useRoute,
+ useNavigation,
+ useCurrentRouteInfo,
+ },
+ isRouterInstalled: true,
+ __useRoute: useRoute,
+ __useNavigation: useNavigation,
+ };
+});
+
+const mockUseRoute = (routerModule as unknown as { __useRoute: jest.Mock }).__useRoute;
+const mockUseNavigation = (routerModule as unknown as { __useNavigation: jest.Mock })
+ .__useNavigation;
+
+beforeEach(() => {
+ jest.clearAllMocks();
+ mockUseRoute.mockReturnValue({ key: 'screen-a' });
+ mockUseNavigation.mockReturnValue({ isFocused: () => true });
+});
+
+describe('useObserveForRouter (ios)', () => {
+ it('calls AppMetrics.markInteractive when the screen is focused', async () => {
+ const { result } = renderHook(() => useObserveForRouter());
+ const arg = { params: { x: 'payload' } };
+ await act(async () => {
+ await result.current!({ ...arg });
+ });
+ expect(AppMetrics.markInteractive).toHaveBeenCalledWith({ ...arg, routeName: '/test' });
+ });
+
+ it('does not call AppMetrics.markInteractive when the screen is not focused', async () => {
+ mockUseNavigation.mockReturnValue({ isFocused: () => false });
+ jest.spyOn(Date, 'now').mockReturnValue(1300);
+
+ const { result } = renderHook(() => useObserveForRouter());
+ await act(async () => {
+ await result.current!();
+ });
+
+ expect(AppMetrics.markInteractive).not.toHaveBeenCalled();
+ });
+});
diff --git a/packages/expo-observe/src/integrations/expo-router/index.ts b/packages/expo-observe/src/integrations/expo-router/index.ts
new file mode 100644
index 00000000000000..92a8602e977ecf
--- /dev/null
+++ b/packages/expo-observe/src/integrations/expo-router/index.ts
@@ -0,0 +1,3 @@
+export { isRouterInstalled } from './router';
+export { useObserveForRouter } from './useObserveForRouter';
+export { initRouterIntegration } from './init';
diff --git a/packages/expo-observe/src/integrations/expo-router/init.ts b/packages/expo-observe/src/integrations/expo-router/init.ts
new file mode 100644
index 00000000000000..37d510c7d8ed59
--- /dev/null
+++ b/packages/expo-observe/src/integrations/expo-router/init.ts
@@ -0,0 +1,7 @@
+let initialized = false;
+
+export const isInitialized = () => initialized;
+
+export function initRouterIntegration() {
+ initialized = true;
+}
diff --git a/packages/expo-observe/src/integrations/expo-router/router.ts b/packages/expo-observe/src/integrations/expo-router/router.ts
new file mode 100644
index 00000000000000..0bc8bf6c39bc8c
--- /dev/null
+++ b/packages/expo-observe/src/integrations/expo-router/router.ts
@@ -0,0 +1,11 @@
+// expo-router is an optional peerDependency of expo-observe. When the host app
+// hasn't installed it, `require` throws and the integration becomes a no-op.
+let optionalRouter: typeof import('expo-router') | undefined;
+try {
+ optionalRouter = require('expo-router');
+} catch {
+ // expo-router not installed — integration disabled.
+}
+const isRouterInstalled = !!optionalRouter;
+
+export { optionalRouter, isRouterInstalled };
diff --git a/packages/expo-observe/src/integrations/expo-router/useObserveForRouter.ts b/packages/expo-observe/src/integrations/expo-router/useObserveForRouter.ts
new file mode 100644
index 00000000000000..7f18f9c3ce9ee4
--- /dev/null
+++ b/packages/expo-observe/src/integrations/expo-router/useObserveForRouter.ts
@@ -0,0 +1,65 @@
+import AppMetrics, { type MetricAttributes } from 'expo-app-metrics';
+import { useCallback, useEffect, useRef } from 'react';
+
+import { isInitialized } from './init';
+import { optionalRouter } from './router';
+
+type MarkInteractive = (typeof AppMetrics)['markInteractive'];
+
+export function useObserveForRouter(): MarkInteractive | null {
+ const isMounted = useRef(true);
+ const route = optionalRouter?.useRoute();
+ const navigation = optionalRouter?.useNavigation();
+ const pathname = optionalRouter?.useCurrentRouteInfo()?.pathname;
+
+ const initializedAtMount = useRef(isInitialized());
+ if (initializedAtMount.current !== isInitialized()) {
+ throw new Error(
+ "[expo-observe] Router integration was toggled during a screen's lifecycle. " +
+ 'Call `ExpoObserve.configure({ disableRouterIntegration })` once at startup before any screen mounts.'
+ );
+ }
+
+ const screenId = route?.key;
+ const prevScreenId = useRef(screenId);
+ if (prevScreenId.current !== screenId) {
+ console.warn(
+ '[expo-observe] Screen ID changed between renders. This is most likely an expo-router bug.'
+ );
+ prevScreenId.current = screenId;
+ }
+
+ useEffect(() => {
+ // Strict-mode mounts the effect twice (mount → cleanup → re-mount). Without
+ // restoring isMounted here, the second mount would leave it permanently false
+ // and every markInteractive call would warn "unmounted screen".
+ isMounted.current = true;
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
+
+ const markInteractive = useCallback(
+ async (attributes?: MetricAttributes) => {
+ if (!isMounted.current) {
+ console.warn('[expo-observe] Calling markInteractive on unmounted screen');
+ return;
+ }
+ if (!screenId) {
+ console.warn(
+ '[expo-observe] No metadata available for the current screen. Make sure to call useObserve inside a screen component.'
+ );
+ return;
+ }
+ if (navigation?.isFocused()) {
+ AppMetrics.markInteractive({
+ ...(attributes ?? {}),
+ routeName: pathname,
+ });
+ }
+ },
+ [screenId, navigation, pathname]
+ );
+
+ return initializedAtMount.current ? markInteractive : null;
+}
diff --git a/packages/expo-observe/src/module.ts b/packages/expo-observe/src/module.ts
index c71c68f0f969a6..88de7c6a549aae 100644
--- a/packages/expo-observe/src/module.ts
+++ b/packages/expo-observe/src/module.ts
@@ -1,5 +1,24 @@
import { requireNativeModule } from 'expo';
-import type { ExpoObserveModuleType } from './types';
+import { initRouterIntegration } from './integrations/expo-router/init';
+import { isRouterInstalled } from './integrations/expo-router/router';
+import type { Config, ExpoObserveModuleType } from './types';
-export default requireNativeModule('ExpoObserve');
+const native = requireNativeModule('ExpoObserve');
+
+const ExpoObserve: ExpoObserveModuleType = new Proxy(native, {
+ get(target, prop, receiver) {
+ if (prop === 'configure') {
+ return (config: Config) => {
+ const { disableRouterIntegration, ...nativeConfig } = config;
+ if (!disableRouterIntegration && isRouterInstalled) {
+ initRouterIntegration();
+ }
+ return target.configure(nativeConfig);
+ };
+ }
+ return Reflect.get(target, prop, receiver);
+ },
+});
+
+export default ExpoObserve;
diff --git a/packages/expo-observe/src/types.ts b/packages/expo-observe/src/types.ts
index 94827ca58fae82..eec6c6c2322a29 100644
--- a/packages/expo-observe/src/types.ts
+++ b/packages/expo-observe/src/types.ts
@@ -45,6 +45,14 @@ export type Config = {
* @default undefined - metrics from all devices are sent
*/
sampleRate?: number;
+ /**
+ * Disables the automatic `expo-router` integration that records TTR/TTI per screen.
+ *
+ * When `true` or `expo-router` is not installed, the router integration will not be used.
+ *
+ * @default false
+ */
+ disableRouterIntegration?: boolean;
};
export interface ExpoObserveModuleType {
diff --git a/packages/expo-observe/src/useObserve.ts b/packages/expo-observe/src/useObserve.ts
new file mode 100644
index 00000000000000..f8187d2df60609
--- /dev/null
+++ b/packages/expo-observe/src/useObserve.ts
@@ -0,0 +1,10 @@
+import AppMetrics from 'expo-app-metrics';
+
+import { useObserveForRouter } from './integrations/expo-router';
+
+export function useObserve() {
+ const routerMarkInteractive = useObserveForRouter();
+ return {
+ markInteractive: routerMarkInteractive ?? AppMetrics.markInteractive,
+ };
+}
diff --git a/packages/expo-router/CHANGELOG.md b/packages/expo-router/CHANGELOG.md
index ccabd650eb127e..757b6c24ef953a 100644
--- a/packages/expo-router/CHANGELOG.md
+++ b/packages/expo-router/CHANGELOG.md
@@ -6,8 +6,12 @@
### 🎉 New features
+- export new useCurrentRouteInfo hook ([#45566](https://github.com/expo/expo/pull/45566) by [@Ubax](https://github.com/Ubax))
+
### 🐛 Bug fixes
+- Fix drawer toggle asset path. ([#45170](https://github.com/expo/expo/pull/45170) by [@sleda](https://github.com/sleda))
+
### 💡 Others
## 56.1.1 — 2026-05-08
diff --git a/packages/expo-router/__mocks__/imageMock.js b/packages/expo-router/__mocks__/imageMock.js
deleted file mode 100644
index 009c00d736290c..00000000000000
--- a/packages/expo-router/__mocks__/imageMock.js
+++ /dev/null
@@ -1,2 +0,0 @@
-// Jest mock for image/file imports (png, jpg, etc.)
-module.exports = 1;
diff --git a/packages/expo-router/__mocks__/imageTransformer.js b/packages/expo-router/__mocks__/imageTransformer.js
new file mode 100644
index 00000000000000..a584e8936f3f35
--- /dev/null
+++ b/packages/expo-router/__mocks__/imageTransformer.js
@@ -0,0 +1,9 @@
+// Jest transformer for image assets. Jest's resolver runs first, so a broken
+// relative path fails with "Cannot find module ..." before this transformer is
+// invoked — that's the regression guard against bugs like #45170. When the
+// file exists, return a numeric stub like Metro does.
+module.exports = {
+ process() {
+ return { code: 'module.exports = 1;' };
+ },
+};
diff --git a/packages/expo-router/build/exports.d.ts b/packages/expo-router/build/exports.d.ts
index 0edc24668320fc..7b8f9ae993be89 100644
--- a/packages/expo-router/build/exports.d.ts
+++ b/packages/expo-router/build/exports.d.ts
@@ -1,5 +1,5 @@
import { Navigator, Slot } from './views/Navigator';
-export { useRouter, useUnstableGlobalHref, usePathname, useNavigationContainerRef, useGlobalSearchParams, useLocalSearchParams, useSegments, useRootNavigation, useRootNavigationState, useLoaderData, } from './hooks';
+export { useRouter, useUnstableGlobalHref, usePathname, useNavigationContainerRef, useGlobalSearchParams, useLocalSearchParams, useSegments, useRootNavigation, useRootNavigationState, useLoaderData, useCurrentRouteInfo, } from './hooks';
export { router, type ImperativeRouter } from './imperative-api';
export { withLayoutContext } from './layouts/withLayoutContext';
export { Navigator, Slot };
diff --git a/packages/expo-router/build/exports.d.ts.map b/packages/expo-router/build/exports.d.ts.map
index 0257ffcd68113c..969fcafd57299f 100644
--- a/packages/expo-router/build/exports.d.ts.map
+++ b/packages/expo-router/build/exports.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,WAAW,EACX,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GACd,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,MAAM,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;GAEG;AACH,OAAO,KAAK,YAAY,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAE5D,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,mBAAmB,SAAS,CAAC;AAE7B,OAAO,EACL,KAAK,EACL,KAAK,UAAU,EACf,IAAI,EACJ,KAAK,SAAS,EACd,KAAK,EACL,KAAK,UAAU,EACf,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;GAEG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EACV,kCAAkC,EAClC,mCAAmC,EACnC,+BAA+B,EAC/B,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC"}
\ No newline at end of file
+{"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,WAAW,EACX,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,mBAAmB,GACpB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,MAAM,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAG3B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAClE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD;;GAEG;AACH,OAAO,KAAK,YAAY,MAAM,gBAAgB,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,EAAE,SAAS,EAAE,MAAM,6CAA6C,CAAC;AACxE,OAAO,EAAE,YAAY,EAAE,MAAM,gDAAgD,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,0CAA0C,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAE5D,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,mBAAmB,SAAS,CAAC;AAE7B,OAAO,EACL,KAAK,EACL,KAAK,UAAU,EACf,IAAI,EACJ,KAAK,SAAS,EACd,KAAK,EACL,KAAK,UAAU,EACf,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAE/D;;GAEG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EACV,kCAAkC,EAClC,mCAAmC,EACnC,+BAA+B,EAC/B,4BAA4B,GAC7B,MAAM,8BAA8B,CAAC"}
\ No newline at end of file
diff --git a/packages/expo-router/build/exports.js b/packages/expo-router/build/exports.js
index b54b5c585e167d..edeb7b90a06746 100644
--- a/packages/expo-router/build/exports.js
+++ b/packages/expo-router/build/exports.js
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
-exports.ExperimentalStack = exports.Tabs = exports.unstable_navigationEvents = exports.VectorIcon = exports.Label = exports.Icon = exports.Badge = exports.useRoute = exports.useScrollToTop = exports.useRoutePath = exports.useTheme = exports.ThemeProvider = exports.DefaultTheme = exports.DarkTheme = exports.useIsFocused = exports.useFocusEffect = exports.useNavigation = exports.SplashScreen = exports.SuspenseFallback = exports.ErrorBoundary = exports.useSitemap = exports.Sitemap = exports.Unmatched = exports.ExpoRoot = exports.Slot = exports.Navigator = exports.withLayoutContext = exports.router = exports.useLoaderData = exports.useRootNavigationState = exports.useRootNavigation = exports.useSegments = exports.useLocalSearchParams = exports.useGlobalSearchParams = exports.useNavigationContainerRef = exports.usePathname = exports.useUnstableGlobalHref = exports.useRouter = void 0;
+exports.ExperimentalStack = exports.Tabs = exports.unstable_navigationEvents = exports.VectorIcon = exports.Label = exports.Icon = exports.Badge = exports.useRoute = exports.useScrollToTop = exports.useRoutePath = exports.useTheme = exports.ThemeProvider = exports.DefaultTheme = exports.DarkTheme = exports.useIsFocused = exports.useFocusEffect = exports.useNavigation = exports.SplashScreen = exports.SuspenseFallback = exports.ErrorBoundary = exports.useSitemap = exports.Sitemap = exports.Unmatched = exports.ExpoRoot = exports.Slot = exports.Navigator = exports.withLayoutContext = exports.router = exports.useCurrentRouteInfo = exports.useLoaderData = exports.useRootNavigationState = exports.useRootNavigation = exports.useSegments = exports.useLocalSearchParams = exports.useGlobalSearchParams = exports.useNavigationContainerRef = exports.usePathname = exports.useUnstableGlobalHref = exports.useRouter = void 0;
// Expo Router API
const Navigator_1 = require("./views/Navigator");
Object.defineProperty(exports, "Navigator", { enumerable: true, get: function () { return Navigator_1.Navigator; } });
@@ -49,6 +49,7 @@ Object.defineProperty(exports, "useSegments", { enumerable: true, get: function
Object.defineProperty(exports, "useRootNavigation", { enumerable: true, get: function () { return hooks_1.useRootNavigation; } });
Object.defineProperty(exports, "useRootNavigationState", { enumerable: true, get: function () { return hooks_1.useRootNavigationState; } });
Object.defineProperty(exports, "useLoaderData", { enumerable: true, get: function () { return hooks_1.useLoaderData; } });
+Object.defineProperty(exports, "useCurrentRouteInfo", { enumerable: true, get: function () { return hooks_1.useCurrentRouteInfo; } });
var imperative_api_1 = require("./imperative-api");
Object.defineProperty(exports, "router", { enumerable: true, get: function () { return imperative_api_1.router; } });
var withLayoutContext_1 = require("./layouts/withLayoutContext");
diff --git a/packages/expo-router/build/exports.js.map b/packages/expo-router/build/exports.js.map
index 5a64b45ef52fd7..0ccc24115efe4f 100644
--- a/packages/expo-router/build/exports.js.map
+++ b/packages/expo-router/build/exports.js.map
@@ -1 +1 @@
-{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kBAAkB;AAClB,iDAAoD;AAkB3C,0FAlBA,qBAAS,OAkBA;AAAE,qFAlBA,gBAAI,OAkBA;AAhBxB,iCAWiB;AAVf,kGAAA,SAAS,OAAA;AACT,8GAAA,qBAAqB,OAAA;AACrB,oGAAA,WAAW,OAAA;AACX,kHAAA,yBAAyB,OAAA;AACzB,8GAAA,qBAAqB,OAAA;AACrB,6GAAA,oBAAoB,OAAA;AACpB,oGAAA,WAAW,OAAA;AACX,0GAAA,iBAAiB,OAAA;AACjB,+GAAA,sBAAsB,OAAA;AACtB,sGAAA,aAAa,OAAA;AAGf,mDAAiE;AAAxD,wGAAA,MAAM,OAAA;AAEf,iEAAgE;AAAvD,sHAAA,iBAAiB,OAAA;AAG1B,oBAAoB;AACpB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AACjB,+CAA8C;AAArC,sGAAA,SAAS,OAAA;AAClB,2CAA0C;AAAjC,kGAAA,OAAO,OAAA;AAChB,iDAAkE;AAAzD,wGAAA,UAAU,OAAA;AAEnB,uDAAsD;AAA7C,8GAAA,aAAa,OAAA;AACtB,6DAAwF;AAA/E,oHAAA,gBAAgB,OAAA;AAGzB,WAAW;AACX;;GAEG;AACH,+DAA+C;AAE/C,mBAAmB;AACnB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,mDAAuE;AAA9D,gHAAA,cAAc,OAAA;AACvB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAGrB,yEAAwE;AAA/D,sGAAA,SAAS,OAAA;AAClB,+EAA8E;AAArE,4GAAA,YAAY,OAAA;AACrB,+EAA8E;AAArE,8GAAA,aAAa,OAAA;AACtB,qEAAoE;AAA3D,oGAAA,QAAQ,OAAA;AACjB,uEAAsE;AAA7D,4GAAA,YAAY,OAAA;AACrB,2EAA0E;AAAjE,gHAAA,cAAc,OAAA;AACvB,6DAA4D;AAAnD,oGAAA,QAAQ,OAAA;AAOjB,2CASsB;AARpB,mGAAA,KAAK,OAAA;AAEL,kGAAA,IAAI,OAAA;AAEJ,mGAAA,KAAK,OAAA;AAEL,wGAAA,UAAU,OAAA;AAIZ,uDAA+D;AAAtD,6HAAA,yBAAyB,OAAA;AAElC;;GAEG;AACH,uCAAsC;AAA7B,4FAAA,IAAI,OAAA;AAEb,mEAAiE;AAAxD,uHAAA,iBAAiB,OAAA","sourcesContent":["// Expo Router API\nimport { Navigator, Slot } from './views/Navigator';\n\nexport {\n useRouter,\n useUnstableGlobalHref,\n usePathname,\n useNavigationContainerRef,\n useGlobalSearchParams,\n useLocalSearchParams,\n useSegments,\n useRootNavigation,\n useRootNavigationState,\n useLoaderData,\n} from './hooks';\n\nexport { router, type ImperativeRouter } from './imperative-api';\n\nexport { withLayoutContext } from './layouts/withLayoutContext';\nexport { Navigator, Slot };\n\n// Expo Router Views\nexport { ExpoRoot } from './ExpoRoot';\nexport { Unmatched } from './views/Unmatched';\nexport { Sitemap } from './views/Sitemap';\nexport { useSitemap, type SitemapType } from './views/useSitemap';\nexport type { ErrorBoundaryProps } from './views/Try';\nexport { ErrorBoundary } from './views/ErrorBoundary';\nexport { SuspenseFallback, type SuspenseFallbackProps } from './views/SuspenseFallback';\nexport type { ScreenProps } from './useScreens';\n\n// Platform\n/**\n * @hidden\n */\nexport * as SplashScreen from './views/Splash';\n\n// React Navigation\nexport { useNavigation } from './useNavigation';\nexport { useFocusEffect, type EffectCallback } from './useFocusEffect';\nexport { useIsFocused } from './useIsFocused';\nexport type { ResultState } from './fork/getStateFromPath';\n\nexport { DarkTheme } from './react-navigation/native/theming/DarkTheme';\nexport { DefaultTheme } from './react-navigation/native/theming/DefaultTheme';\nexport { ThemeProvider } from './react-navigation/core/theming/ThemeProvider';\nexport { useTheme } from './react-navigation/core/theming/useTheme';\nexport { useRoutePath } from './react-navigation/native/useRoutePath';\nexport { useScrollToTop } from './react-navigation/native/useScrollToTop';\nexport { useRoute } from './react-navigation/core/useRoute';\n\nexport type { RedirectConfig } from './getRoutesCore';\nexport type { SingularOptions } from './useScreens';\n\nexport type * from './types';\n\nexport {\n Badge,\n type BadgeProps,\n Icon,\n type IconProps,\n Label,\n type LabelProps,\n VectorIcon,\n type VectorIconProps,\n} from './primitives';\n\nexport { unstable_navigationEvents } from './navigationEvents';\n\n/**\n * @deprecated Use `import { Tabs } from 'expo-router/js-tabs'` instead.\n */\nexport { Tabs } from './layouts/Tabs';\n\nexport { ExperimentalStack } from './layouts/experimental-stack';\nexport type {\n ExperimentalStackNavigationOptions,\n ExperimentalStackNavigationEventMap,\n ExperimentalStackNavigationProp,\n ExperimentalStackScreenProps,\n} from './layouts/experimental-stack';\n"]}
\ No newline at end of file
+{"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kBAAkB;AAClB,iDAAoD;AAmB3C,0FAnBA,qBAAS,OAmBA;AAAE,qFAnBA,gBAAI,OAmBA;AAjBxB,iCAYiB;AAXf,kGAAA,SAAS,OAAA;AACT,8GAAA,qBAAqB,OAAA;AACrB,oGAAA,WAAW,OAAA;AACX,kHAAA,yBAAyB,OAAA;AACzB,8GAAA,qBAAqB,OAAA;AACrB,6GAAA,oBAAoB,OAAA;AACpB,oGAAA,WAAW,OAAA;AACX,0GAAA,iBAAiB,OAAA;AACjB,+GAAA,sBAAsB,OAAA;AACtB,sGAAA,aAAa,OAAA;AACb,4GAAA,mBAAmB,OAAA;AAGrB,mDAAiE;AAAxD,wGAAA,MAAM,OAAA;AAEf,iEAAgE;AAAvD,sHAAA,iBAAiB,OAAA;AAG1B,oBAAoB;AACpB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA;AACjB,+CAA8C;AAArC,sGAAA,SAAS,OAAA;AAClB,2CAA0C;AAAjC,kGAAA,OAAO,OAAA;AAChB,iDAAkE;AAAzD,wGAAA,UAAU,OAAA;AAEnB,uDAAsD;AAA7C,8GAAA,aAAa,OAAA;AACtB,6DAAwF;AAA/E,oHAAA,gBAAgB,OAAA;AAGzB,WAAW;AACX;;GAEG;AACH,+DAA+C;AAE/C,mBAAmB;AACnB,iDAAgD;AAAvC,8GAAA,aAAa,OAAA;AACtB,mDAAuE;AAA9D,gHAAA,cAAc,OAAA;AACvB,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AAGrB,yEAAwE;AAA/D,sGAAA,SAAS,OAAA;AAClB,+EAA8E;AAArE,4GAAA,YAAY,OAAA;AACrB,+EAA8E;AAArE,8GAAA,aAAa,OAAA;AACtB,qEAAoE;AAA3D,oGAAA,QAAQ,OAAA;AACjB,uEAAsE;AAA7D,4GAAA,YAAY,OAAA;AACrB,2EAA0E;AAAjE,gHAAA,cAAc,OAAA;AACvB,6DAA4D;AAAnD,oGAAA,QAAQ,OAAA;AAOjB,2CASsB;AARpB,mGAAA,KAAK,OAAA;AAEL,kGAAA,IAAI,OAAA;AAEJ,mGAAA,KAAK,OAAA;AAEL,wGAAA,UAAU,OAAA;AAIZ,uDAA+D;AAAtD,6HAAA,yBAAyB,OAAA;AAElC;;GAEG;AACH,uCAAsC;AAA7B,4FAAA,IAAI,OAAA;AAEb,mEAAiE;AAAxD,uHAAA,iBAAiB,OAAA","sourcesContent":["// Expo Router API\nimport { Navigator, Slot } from './views/Navigator';\n\nexport {\n useRouter,\n useUnstableGlobalHref,\n usePathname,\n useNavigationContainerRef,\n useGlobalSearchParams,\n useLocalSearchParams,\n useSegments,\n useRootNavigation,\n useRootNavigationState,\n useLoaderData,\n useCurrentRouteInfo,\n} from './hooks';\n\nexport { router, type ImperativeRouter } from './imperative-api';\n\nexport { withLayoutContext } from './layouts/withLayoutContext';\nexport { Navigator, Slot };\n\n// Expo Router Views\nexport { ExpoRoot } from './ExpoRoot';\nexport { Unmatched } from './views/Unmatched';\nexport { Sitemap } from './views/Sitemap';\nexport { useSitemap, type SitemapType } from './views/useSitemap';\nexport type { ErrorBoundaryProps } from './views/Try';\nexport { ErrorBoundary } from './views/ErrorBoundary';\nexport { SuspenseFallback, type SuspenseFallbackProps } from './views/SuspenseFallback';\nexport type { ScreenProps } from './useScreens';\n\n// Platform\n/**\n * @hidden\n */\nexport * as SplashScreen from './views/Splash';\n\n// React Navigation\nexport { useNavigation } from './useNavigation';\nexport { useFocusEffect, type EffectCallback } from './useFocusEffect';\nexport { useIsFocused } from './useIsFocused';\nexport type { ResultState } from './fork/getStateFromPath';\n\nexport { DarkTheme } from './react-navigation/native/theming/DarkTheme';\nexport { DefaultTheme } from './react-navigation/native/theming/DefaultTheme';\nexport { ThemeProvider } from './react-navigation/core/theming/ThemeProvider';\nexport { useTheme } from './react-navigation/core/theming/useTheme';\nexport { useRoutePath } from './react-navigation/native/useRoutePath';\nexport { useScrollToTop } from './react-navigation/native/useScrollToTop';\nexport { useRoute } from './react-navigation/core/useRoute';\n\nexport type { RedirectConfig } from './getRoutesCore';\nexport type { SingularOptions } from './useScreens';\n\nexport type * from './types';\n\nexport {\n Badge,\n type BadgeProps,\n Icon,\n type IconProps,\n Label,\n type LabelProps,\n VectorIcon,\n type VectorIconProps,\n} from './primitives';\n\nexport { unstable_navigationEvents } from './navigationEvents';\n\n/**\n * @deprecated Use `import { Tabs } from 'expo-router/js-tabs'` instead.\n */\nexport { Tabs } from './layouts/Tabs';\n\nexport { ExperimentalStack } from './layouts/experimental-stack';\nexport type {\n ExperimentalStackNavigationOptions,\n ExperimentalStackNavigationEventMap,\n ExperimentalStackNavigationProp,\n ExperimentalStackScreenProps,\n} from './layouts/experimental-stack';\n"]}
\ No newline at end of file
diff --git a/packages/expo-router/build/hooks.d.ts b/packages/expo-router/build/hooks.d.ts
index b4f7cdf67988ee..58956421e9c7c9 100644
--- a/packages/expo-router/build/hooks.d.ts
+++ b/packages/expo-router/build/hooks.d.ts
@@ -203,4 +203,10 @@ type LoaderFunctionResult> = T extends LoaderFunct
* }
*/
export declare function useLoaderData = any>(): LoaderFunctionResult;
+/**
+ * Returns route info for a screen it is called from.
+ *
+ * @experimental
+ */
+export declare function useCurrentRouteInfo(): import("./global-state/getRouteInfoFromState").UrlObject | undefined;
//# sourceMappingURL=hooks.d.ts.map
\ No newline at end of file
diff --git a/packages/expo-router/build/hooks.d.ts.map b/packages/expo-router/build/hooks.d.ts.map
index 568cfaf3e6bdb9..dadf710c0b9901 100644
--- a/packages/expo-router/build/hooks.d.ts.map
+++ b/packages/expo-router/build/hooks.d.ts.map
@@ -1 +1 @@
-{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAMlD,OAAO,EAAS,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOzD,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAWxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,8FAEhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,kGAExC;AAiCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,IAAI,gBAAgB,CAM5C;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,WAAW,CAAC,SAAS,SAAS,SAAS,GAAG,SAAS,KAAK,aAAa,CAAC,SAAS,CAAC,CAAC;AAEjG;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,SAAS,aAAa,CAAC,SAAS,CAAC,KAAK,SAAS,CAAC;AAKrF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,OAAO,CAAC;AAEb;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,SAAS,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,SAAS,SAAS,EACxB,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;AAKnC;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,OAAO,CAAC;AAEb;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,SAAS,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,SAAS,SAAS,EACxB,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;AAkCnC,wBAAgB,eAAe,CAAC,EAAE,MAAc,EAAE;;CAAK,GAAG,eAAe,CAsBxE;AAcD,KAAK,oBAAoB,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,IACrD,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;AAElD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,oBAAoB,CAAC,CAAC,CAAC,CAwC5F"}
\ No newline at end of file
+{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAOlD,OAAO,EAAS,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAOzD,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAG1F,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAWxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,8FAEhC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,kGAExC;AAiCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,IAAI,gBAAgB,CAM5C;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,WAAW,CAAC,SAAS,SAAS,SAAS,GAAG,SAAS,KAAK,aAAa,CAAC,SAAS,CAAC,CAAC;AAEjG;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,SAAS,aAAa,CAAC,SAAS,CAAC,KAAK,SAAS,CAAC;AAKrF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,OAAO,CAAC;AAEb;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,SAAS,SAAS,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,SAAS,SAAS,EACxB,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;AAKnC;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,OAAO,CAAC;AAEb;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,SAAS,KAAK,WAAW,CAAC,MAAM,CAAC,CAAC;AAEtF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,SAAS,SAAS,EACxB,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,KACtD,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;AAkCnC,wBAAgB,eAAe,CAAC,EAAE,MAAc,EAAE;;CAAK,GAAG,eAAe,CAsBxE;AAcD,KAAK,oBAAoB,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,IACrD,CAAC,SAAS,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;AAElD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,oBAAoB,CAAC,CAAC,CAAC,CAwC5F;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,yEAIlC"}
\ No newline at end of file
diff --git a/packages/expo-router/build/hooks.js b/packages/expo-router/build/hooks.js
index c28b1f6330b775..c85be36356a210 100644
--- a/packages/expo-router/build/hooks.js
+++ b/packages/expo-router/build/hooks.js
@@ -46,10 +46,12 @@ exports.useGlobalSearchParams = useGlobalSearchParams;
exports.useLocalSearchParams = useLocalSearchParams;
exports.useSearchParams = useSearchParams;
exports.useLoaderData = useLoaderData;
+exports.useCurrentRouteInfo = useCurrentRouteInfo;
const react_1 = __importStar(require("react"));
const Route_1 = require("./Route");
const constants_1 = require("./constants");
const getRouteInfoFromState_1 = require("./global-state/getRouteInfoFromState");
+const routeInfoCache_1 = require("./global-state/routeInfoCache");
const router_store_1 = require("./global-state/router-store");
Object.defineProperty(exports, "useRouteInfo", { enumerable: true, get: function () { return router_store_1.useRouteInfo; } });
const imperative_api_1 = require("./imperative-api");
@@ -298,4 +300,14 @@ function useLoaderData() {
}
return result;
}
+/**
+ * Returns route info for a screen it is called from.
+ *
+ * @experimental
+ */
+function useCurrentRouteInfo() {
+ const state = (0, native_1.useStateForPath)();
+ const routeInfo = (0, react_1.useMemo)(() => (state ? (0, routeInfoCache_1.getCachedRouteInfo)(state) : undefined), [state]);
+ return routeInfo;
+}
//# sourceMappingURL=hooks.js.map
\ No newline at end of file
diff --git a/packages/expo-router/build/hooks.js.map b/packages/expo-router/build/hooks.js.map
index e128555e94e8f1..9c48cfc9a4f6a4 100644
--- a/packages/expo-router/build/hooks.js.map
+++ b/packages/expo-router/build/hooks.js.map
@@ -1 +1 @@
-{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"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","sourcesContent":["'use client';\n\nimport type { LoaderFunction } from 'expo-server';\nimport React, { use, useMemo } from 'react';\n\nimport { LocalRouteParamsContext, useContextKey } from './Route';\nimport { INTERNAL_SLOT_NAME } from './constants';\nimport { getRouteInfoFromState } from './global-state/getRouteInfoFromState';\nimport { store, useRouteInfo } from './global-state/router-store';\nimport type { ImperativeRouter } from './imperative-api';\nimport { router } from './imperative-api';\nimport { usePreviewInfo } from './link/preview/PreviewRouteContext';\nimport { LoaderCacheContext } from './loaders/LoaderCache';\nimport { ServerDataLoaderContext } from './loaders/ServerDataLoaderContext';\nimport { getLoaderData } from './loaders/getLoaderData';\nimport { fetchLoader } from './loaders/utils';\nimport type { NavigationProp, NavigationState } from './react-navigation/native';\nimport { useNavigation, useStateForPath } from './react-navigation/native';\nimport type { RouteParams, RouteSegments, UnknownOutputParams, RoutePath } from './types';\nimport { getSingularId } from './useScreens';\n\nexport { useRouteInfo };\n\n/**\n * Returns the [navigation state](https://reactnavigation.org/docs/navigation-state/)\n * of the navigator which contains the current screen.\n *\n * @example\n * ```tsx\n * import { useRootNavigationState } from 'expo-router';\n *\n * export default function Route() {\n * const { routes } = useRootNavigationState();\n *\n * return {routes[0].name};\n * }\n * ```\n */\nexport function useRootNavigationState(): NavigationState {\n const parent =\n // We assume that this is called from routes in __root\n // Users cannot customize the generated Sitemap or NotFound routes, so we should be safe\n useNavigation>().getParent(INTERNAL_SLOT_NAME);\n if (!parent) {\n throw new Error(\n 'useRootNavigationState was called from a generated route. This is likely a bug in Expo Router.'\n );\n }\n return parent.getState();\n}\n\n/**\n * @deprecated Use [`useNavigationContainerRef`](#usenavigationcontainerref) instead,\n * which returns a React `ref`.\n */\nexport function useRootNavigation() {\n return store.navigationRef.current;\n}\n\n/**\n * @return The root `` ref for the app. The `ref.current` may be `null`\n * if the `` hasn't mounted yet.\n */\nexport function useNavigationContainerRef() {\n return store.navigationRef;\n}\n\nconst displayWarningForProp = (prop: string) => {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `router.${prop} should not be used in a previewed screen. To fix this issue, wrap navigation calls with 'if (!isPreview) { ... }'.`\n );\n }\n};\n\nconst createNOOPWithWarning = (prop: string) => () => displayWarningForProp(prop);\n\nconst routerWithWarnings: ImperativeRouter = {\n back: createNOOPWithWarning('back'),\n canGoBack: () => {\n displayWarningForProp('canGoBack');\n return false;\n },\n push: createNOOPWithWarning('push'),\n navigate: createNOOPWithWarning('navigate'),\n replace: createNOOPWithWarning('replace'),\n dismiss: createNOOPWithWarning('dismiss'),\n dismissTo: createNOOPWithWarning('dismissTo'),\n dismissAll: createNOOPWithWarning('dismissAll'),\n canDismiss: () => {\n displayWarningForProp('canDismiss');\n return false;\n },\n setParams: createNOOPWithWarning('setParams'),\n reload: createNOOPWithWarning('reload'),\n prefetch: createNOOPWithWarning('prefetch'),\n};\n\n/**\n *\n * Returns the [Router](#router) object for imperative navigation.\n *\n * @example\n *```tsx\n * import { useRouter } from 'expo-router';\n * import { Text } from 'react-native';\n *\n * export default function Route() {\n * const router = useRouter();\n *\n * return (\n * router.push('/home')}>Go Home\n * );\n *}\n * ```\n */\nexport function useRouter(): ImperativeRouter {\n const { isPreview } = usePreviewInfo();\n if (isPreview) {\n return routerWithWarnings;\n }\n return router;\n}\n\n/**\n * @private\n * @returns The current global pathname with query params attached. This may change in the future to include the hostname\n * from a predefined universal link. For example, `/foobar?hey=world` becomes `https://acme.dev/foobar?hey=world`.\n */\nexport function useUnstableGlobalHref(): string {\n return useRouteInfo().unstable_globalHref;\n}\n\n/**\n * Returns a list of selected file segments for the currently selected route. Segments are not normalized,\n * so they will be the same as the file path. For example, `/[id]?id=normal` becomes `[\"[id]\"]`.\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useSegments } from 'expo-router';\n *\n * export default function Route() {\n * // segments = [\"profile\", \"[user]\"]\n * const segments = useSegments();\n *\n * return Hello;\n * }\n * ```\n *\n *\n * `useSegments` can be typed using an abstract. Consider the following file structure:\n *\n * ```md\n * - app\n * - [user]\n * - index.tsx\n * - followers.tsx\n * - settings.tsx\n * ```\n *\n *\n * This can be strictly typed using the following abstract with `useSegments` hook:\n *\n * ```tsx\n * const [first, second] = useSegments<['settings'] | ['[user]'] | ['[user]', 'followers']>()\n * ```\n */\nexport function useSegments(): RouteSegments;\n\n/**\n * @hidden\n */\nexport function useSegments>(): TSegments;\nexport function useSegments() {\n return useRouteInfo().segments;\n}\n\n/**\n * Returns the currently selected route location without search parameters. For example, `/acme?foo=bar` returns `/acme`.\n * Segments will be normalized. For example, `/[id]?id=normal` becomes `/normal`.\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { usePathname } from 'expo-router';\n *\n * export default function Route() {\n * // pathname = \"/profile/baconbrix\"\n * const pathname = usePathname();\n *\n * return Pathname: {pathname};\n * }\n * ```\n */\nexport function usePathname(): string {\n return useRouteInfo().pathname;\n}\n\n/**\n * @hidden\n */\nexport function useGlobalSearchParams<\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): TParams;\n\n/**\n * @hidden\n */\nexport function useGlobalSearchParams(): RouteParams;\n\n/**\n * Returns URL parameters for globally selected route, including dynamic path segments.\n * This function updates even when the route is not focused. Useful for analytics or\n * other background operations that don't draw to the screen.\n *\n * Route URL example: `acme://profile/baconbrix?extra=info`.\n *\n * When querying search params in a stack, opt-towards using\n * [`useLocalSearchParams`](#uselocalsearchparams) because it will only update when the route is focused.\n *\n * > **Note:** For usage information, see\n * [Local versus global search parameters](/router/reference/url-parameters/#local-versus-global-url-parameters).\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useGlobalSearchParams } from 'expo-router';\n *\n * export default function Route() {\n * // user=baconbrix & extra=info\n * const { user, extra } = useGlobalSearchParams();\n *\n * return User: {user};\n * }\n * ```\n */\nexport function useGlobalSearchParams<\n TRoute extends RoutePath,\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): RouteParams & TParams;\nexport function useGlobalSearchParams() {\n return useRouteInfo().params;\n}\n\n/**\n * @hidden\n */\nexport function useLocalSearchParams<\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): TParams;\n\n/**\n * @hidden\n */\nexport function useLocalSearchParams(): RouteParams;\n\n/**\n * Returns the URL parameters for the contextually focused route. Useful for stacks where you may push a new screen\n * that changes the query parameters. For dynamic routes, both the route parameters and the search parameters are returned.\n *\n * Route URL example: `acme://profile/baconbrix?extra=info`.\n *\n * To observe updates even when the invoking route is not focused, use [`useGlobalSearchParams`](#useglobalsearchparams).\n *\n * > **Note:** For usage information, see\n * [Local versus global search parameters](/router/reference/url-parameters/#local-versus-global-url-parameters).\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useLocalSearchParams } from 'expo-router';\n *\n * export default function Route() {\n * // user=baconbrix & extra=info\n * const { user, extra } = useLocalSearchParams();\n *\n * return User: {user};\n * }\n */\nexport function useLocalSearchParams<\n TRoute extends RoutePath,\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): RouteParams & TParams;\nexport function useLocalSearchParams() {\n const params = React.use(LocalRouteParamsContext) ?? {};\n const { params: previewParams } = usePreviewInfo();\n return Object.fromEntries(\n Object.entries(previewParams ?? params).map(([key, value]) => {\n // React Navigation doesn't remove \"undefined\" values from the params object, and you cannot remove them via\n // navigation.setParams as it shallow merges. Hence, we hide them here\n if (value === undefined) {\n return [key, undefined];\n }\n\n if (Array.isArray(value)) {\n return [\n key,\n value.map((v) => {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n }),\n ];\n } else {\n try {\n return [key, decodeURIComponent(value as string)];\n } catch {\n return [key, value];\n }\n }\n })\n ) as any;\n}\n\nexport function useSearchParams({ global = false } = {}): URLSearchParams {\n const globalRef = React.useRef(global);\n if (process.env.NODE_ENV !== 'production') {\n if (global !== globalRef.current) {\n console.warn(\n `Detected change in 'global' option of useSearchParams. This value cannot change between renders`\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const params = global ? useGlobalSearchParams() : useLocalSearchParams();\n const entries = Object.entries(params).flatMap(([key, value]) => {\n if (global) {\n if (key === 'params') return [];\n if (key === 'screen') return [];\n }\n\n return Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]];\n });\n\n return new ReadOnlyURLSearchParams(entries);\n}\n\nclass ReadOnlyURLSearchParams extends URLSearchParams {\n set() {\n throw new Error('The URLSearchParams object return from useSearchParams is read-only');\n }\n append() {\n throw new Error('The URLSearchParams object return from useSearchParams is read-only');\n }\n delete() {\n throw new Error('The URLSearchParams object return from useSearchParams is read-only');\n }\n}\n\ntype LoaderFunctionResult> =\n T extends LoaderFunction ? R : unknown;\n\n/**\n * Returns the result of the `loader` function for the calling route.\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useLoaderData } from 'expo-router';\n *\n * export function loader() {\n * return Promise.resolve({ foo: 'bar' }};\n * }\n *\n * export default function Route() {\n * const data = useLoaderData(); // { foo: 'bar' }\n *\n * return Data: {JSON.stringify(data)};\n * }\n */\nexport function useLoaderData = any>(): LoaderFunctionResult {\n const serverDataLoaderContext = use(ServerDataLoaderContext);\n const loaderCache = use(LoaderCacheContext);\n\n const stateForPath = useStateForPath();\n const contextKey = useContextKey();\n\n const resolvedPath = useMemo(() => {\n const routeInfo = getRouteInfoFromState(stateForPath);\n const contextPath = contextKey.startsWith('/') ? contextKey.slice(1) : contextKey;\n const resolvedPathname = `/${getSingularId(contextPath, { params: routeInfo.params })}`;\n const searchString = routeInfo.searchParams?.toString() || '';\n\n return searchString ? `${resolvedPathname}?${searchString}` : resolvedPathname;\n }, [contextKey, stateForPath]);\n\n // First invocation of this hook will happen server-side, so we look up the loaded data from context\n if (serverDataLoaderContext) {\n return serverDataLoaderContext[resolvedPath];\n }\n\n // The second invocation happens after the client has hydrated on initial load, so we look up the data injected\n // by `` using `globalThis.__EXPO_ROUTER_LOADER_DATA__`\n if (typeof window !== 'undefined' && globalThis.__EXPO_ROUTER_LOADER_DATA__) {\n if (globalThis.__EXPO_ROUTER_LOADER_DATA__[resolvedPath]) {\n return globalThis.__EXPO_ROUTER_LOADER_DATA__[resolvedPath];\n }\n }\n\n const result = getLoaderData>({\n resolvedPath,\n cache: loaderCache,\n fetcher: fetchLoader,\n });\n\n if (result instanceof Promise) {\n return use(result);\n }\n\n return result;\n}\n"]}
\ No newline at end of file
+{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCb,wDAWC;AAMD,8CAEC;AAMD,8DAEC;AAmDD,8BAMC;AAOD,sDAEC;AA2CD,kCAEC;AAmBD,kCAEC;AA4CD,sDAEC;AAyCD,oDA+BC;AAED,0CAsBC;AAmCD,sCAwCC;AAOD,kDAIC;AAvaD,+CAA4C;AAE5C,mCAAiE;AACjE,2CAAiD;AACjD,gFAA6E;AAC7E,kEAAmE;AACnE,8DAAkE;AAazD,6FAbO,2BAAY,OAaP;AAXrB,qDAA0C;AAC1C,4EAAoE;AACpE,uDAA2D;AAC3D,+EAA4E;AAC5E,2DAAwD;AACxD,2CAA8C;AAE9C,sDAA2E;AAE3E,6CAA6C;AAI7C;;;;;;;;;;;;;;GAcG;AACH,SAAgB,sBAAsB;IACpC,MAAM,MAAM;IACV,sDAAsD;IACtD,wFAAwF;IACxF,IAAA,sBAAa,GAAyC,CAAC,SAAS,CAAC,8BAAkB,CAAC,CAAC;IACvF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,gGAAgG,CACjG,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,OAAO,oBAAK,CAAC,aAAa,CAAC,OAAO,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,SAAgB,yBAAyB;IACvC,OAAO,oBAAK,CAAC,aAAa,CAAC;AAC7B,CAAC;AAED,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,EAAE;IAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CACV,UAAU,IAAI,qHAAqH,CACpI,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;AAElF,MAAM,kBAAkB,GAAqB;IAC3C,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC;IACnC,SAAS,EAAE,GAAG,EAAE;QACd,qBAAqB,CAAC,WAAW,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC;IACnC,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC;IAC3C,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC;IACzC,OAAO,EAAE,qBAAqB,CAAC,SAAS,CAAC;IACzC,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC;IAC7C,UAAU,EAAE,qBAAqB,CAAC,YAAY,CAAC;IAC/C,UAAU,EAAE,GAAG,EAAE;QACf,qBAAqB,CAAC,YAAY,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,SAAS,EAAE,qBAAqB,CAAC,WAAW,CAAC;IAC7C,MAAM,EAAE,qBAAqB,CAAC,QAAQ,CAAC;IACvC,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC;CAC5C,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,SAAS;IACvB,MAAM,EAAE,SAAS,EAAE,GAAG,IAAA,oCAAc,GAAE,CAAC;IACvC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,uBAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB;IACnC,OAAO,IAAA,2BAAY,GAAE,CAAC,mBAAmB,CAAC;AAC5C,CAAC;AA2CD,SAAgB,WAAW;IACzB,OAAO,IAAA,2BAAY,GAAE,CAAC,QAAQ,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,WAAW;IACzB,OAAO,IAAA,2BAAY,GAAE,CAAC,QAAQ,CAAC;AACjC,CAAC;AA4CD,SAAgB,qBAAqB;IACnC,OAAO,IAAA,2BAAY,GAAE,CAAC,MAAM,CAAC;AAC/B,CAAC;AAyCD,SAAgB,oBAAoB;IAClC,MAAM,MAAM,GAAG,eAAK,CAAC,GAAG,CAAC,+BAAuB,CAAC,IAAI,EAAE,CAAC;IACxD,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,IAAA,oCAAc,GAAE,CAAC;IACnD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QAC3D,4GAA4G;QAC5G,sEAAsE;QACtE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1B,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;gBACL,GAAG;gBACH,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;oBACd,IAAI,CAAC;wBACH,OAAO,kBAAkB,CAAC,CAAC,CAAC,CAAC;oBAC/B,CAAC;oBAAC,MAAM,CAAC;wBACP,OAAO,CAAC,CAAC;oBACX,CAAC;gBACH,CAAC,CAAC;aACH,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBACH,OAAO,CAAC,GAAG,EAAE,kBAAkB,CAAC,KAAe,CAAC,CAAC,CAAC;YACpD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CACI,CAAC;AACX,CAAC;AAED,SAAgB,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,EAAE;IACrD,MAAM,SAAS,GAAG,eAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE,CAAC;QAC1C,IAAI,MAAM,KAAK,SAAS,CAAC,OAAO,EAAE,CAAC;YACjC,OAAO,CAAC,IAAI,CACV,iGAAiG,CAClG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,oBAAoB,EAAE,CAAC;IACzE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;QAC9D,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,GAAG,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAC;YAChC,IAAI,GAAG,KAAK,QAAQ;gBAAE,OAAO,EAAE,CAAC;QAClC,CAAC;QAED,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,uBAAuB,CAAC,OAAO,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,uBAAwB,SAAQ,eAAe;IACnD,GAAG;QACD,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM;QACJ,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM;QACJ,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;CACF;AAKD;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,aAAa;IAC3B,MAAM,uBAAuB,GAAG,IAAA,WAAG,EAAC,iDAAuB,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,IAAA,WAAG,EAAC,gCAAkB,CAAC,CAAC;IAE5C,MAAM,YAAY,GAAG,IAAA,wBAAe,GAAE,CAAC;IACvC,MAAM,UAAU,GAAG,IAAA,qBAAa,GAAE,CAAC;IAEnC,MAAM,YAAY,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE;QAChC,MAAM,SAAS,GAAG,IAAA,6CAAqB,EAAC,YAAY,CAAC,CAAC;QACtD,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QAClF,MAAM,gBAAgB,GAAG,IAAI,IAAA,0BAAa,EAAC,WAAW,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;QACxF,MAAM,YAAY,GAAG,SAAS,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAE9D,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,gBAAgB,IAAI,YAAY,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACjF,CAAC,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;IAE/B,oGAAoG;IACpG,IAAI,uBAAuB,EAAE,CAAC;QAC5B,OAAO,uBAAuB,CAAC,YAAY,CAAC,CAAC;IAC/C,CAAC;IAED,+GAA+G;IAC/G,8EAA8E;IAC9E,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,UAAU,CAAC,2BAA2B,EAAE,CAAC;QAC5E,IAAI,UAAU,CAAC,2BAA2B,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,OAAO,UAAU,CAAC,2BAA2B,CAAC,YAAY,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAA,6BAAa,EAA0B;QACpD,YAAY;QACZ,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,mBAAW;KACrB,CAAC,CAAC;IAEH,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;QAC9B,OAAO,IAAA,WAAG,EAAC,MAAM,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAgB,mBAAmB;IACjC,MAAM,KAAK,GAAG,IAAA,wBAAe,GAAE,CAAC;IAChC,MAAM,SAAS,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,mCAAkB,EAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1F,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["'use client';\n\nimport type { LoaderFunction } from 'expo-server';\nimport React, { use, useMemo } from 'react';\n\nimport { LocalRouteParamsContext, useContextKey } from './Route';\nimport { INTERNAL_SLOT_NAME } from './constants';\nimport { getRouteInfoFromState } from './global-state/getRouteInfoFromState';\nimport { getCachedRouteInfo } from './global-state/routeInfoCache';\nimport { store, useRouteInfo } from './global-state/router-store';\nimport type { ImperativeRouter } from './imperative-api';\nimport { router } from './imperative-api';\nimport { usePreviewInfo } from './link/preview/PreviewRouteContext';\nimport { LoaderCacheContext } from './loaders/LoaderCache';\nimport { ServerDataLoaderContext } from './loaders/ServerDataLoaderContext';\nimport { getLoaderData } from './loaders/getLoaderData';\nimport { fetchLoader } from './loaders/utils';\nimport type { NavigationProp, NavigationState } from './react-navigation/native';\nimport { useNavigation, useStateForPath } from './react-navigation/native';\nimport type { RouteParams, RouteSegments, UnknownOutputParams, RoutePath } from './types';\nimport { getSingularId } from './useScreens';\n\nexport { useRouteInfo };\n\n/**\n * Returns the [navigation state](https://reactnavigation.org/docs/navigation-state/)\n * of the navigator which contains the current screen.\n *\n * @example\n * ```tsx\n * import { useRootNavigationState } from 'expo-router';\n *\n * export default function Route() {\n * const { routes } = useRootNavigationState();\n *\n * return {routes[0].name};\n * }\n * ```\n */\nexport function useRootNavigationState(): NavigationState {\n const parent =\n // We assume that this is called from routes in __root\n // Users cannot customize the generated Sitemap or NotFound routes, so we should be safe\n useNavigation>().getParent(INTERNAL_SLOT_NAME);\n if (!parent) {\n throw new Error(\n 'useRootNavigationState was called from a generated route. This is likely a bug in Expo Router.'\n );\n }\n return parent.getState();\n}\n\n/**\n * @deprecated Use [`useNavigationContainerRef`](#usenavigationcontainerref) instead,\n * which returns a React `ref`.\n */\nexport function useRootNavigation() {\n return store.navigationRef.current;\n}\n\n/**\n * @return The root `` ref for the app. The `ref.current` may be `null`\n * if the `` hasn't mounted yet.\n */\nexport function useNavigationContainerRef() {\n return store.navigationRef;\n}\n\nconst displayWarningForProp = (prop: string) => {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(\n `router.${prop} should not be used in a previewed screen. To fix this issue, wrap navigation calls with 'if (!isPreview) { ... }'.`\n );\n }\n};\n\nconst createNOOPWithWarning = (prop: string) => () => displayWarningForProp(prop);\n\nconst routerWithWarnings: ImperativeRouter = {\n back: createNOOPWithWarning('back'),\n canGoBack: () => {\n displayWarningForProp('canGoBack');\n return false;\n },\n push: createNOOPWithWarning('push'),\n navigate: createNOOPWithWarning('navigate'),\n replace: createNOOPWithWarning('replace'),\n dismiss: createNOOPWithWarning('dismiss'),\n dismissTo: createNOOPWithWarning('dismissTo'),\n dismissAll: createNOOPWithWarning('dismissAll'),\n canDismiss: () => {\n displayWarningForProp('canDismiss');\n return false;\n },\n setParams: createNOOPWithWarning('setParams'),\n reload: createNOOPWithWarning('reload'),\n prefetch: createNOOPWithWarning('prefetch'),\n};\n\n/**\n *\n * Returns the [Router](#router) object for imperative navigation.\n *\n * @example\n *```tsx\n * import { useRouter } from 'expo-router';\n * import { Text } from 'react-native';\n *\n * export default function Route() {\n * const router = useRouter();\n *\n * return (\n * router.push('/home')}>Go Home\n * );\n *}\n * ```\n */\nexport function useRouter(): ImperativeRouter {\n const { isPreview } = usePreviewInfo();\n if (isPreview) {\n return routerWithWarnings;\n }\n return router;\n}\n\n/**\n * @private\n * @returns The current global pathname with query params attached. This may change in the future to include the hostname\n * from a predefined universal link. For example, `/foobar?hey=world` becomes `https://acme.dev/foobar?hey=world`.\n */\nexport function useUnstableGlobalHref(): string {\n return useRouteInfo().unstable_globalHref;\n}\n\n/**\n * Returns a list of selected file segments for the currently selected route. Segments are not normalized,\n * so they will be the same as the file path. For example, `/[id]?id=normal` becomes `[\"[id]\"]`.\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useSegments } from 'expo-router';\n *\n * export default function Route() {\n * // segments = [\"profile\", \"[user]\"]\n * const segments = useSegments();\n *\n * return Hello;\n * }\n * ```\n *\n *\n * `useSegments` can be typed using an abstract. Consider the following file structure:\n *\n * ```md\n * - app\n * - [user]\n * - index.tsx\n * - followers.tsx\n * - settings.tsx\n * ```\n *\n *\n * This can be strictly typed using the following abstract with `useSegments` hook:\n *\n * ```tsx\n * const [first, second] = useSegments<['settings'] | ['[user]'] | ['[user]', 'followers']>()\n * ```\n */\nexport function useSegments(): RouteSegments;\n\n/**\n * @hidden\n */\nexport function useSegments>(): TSegments;\nexport function useSegments() {\n return useRouteInfo().segments;\n}\n\n/**\n * Returns the currently selected route location without search parameters. For example, `/acme?foo=bar` returns `/acme`.\n * Segments will be normalized. For example, `/[id]?id=normal` becomes `/normal`.\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { usePathname } from 'expo-router';\n *\n * export default function Route() {\n * // pathname = \"/profile/baconbrix\"\n * const pathname = usePathname();\n *\n * return Pathname: {pathname};\n * }\n * ```\n */\nexport function usePathname(): string {\n return useRouteInfo().pathname;\n}\n\n/**\n * @hidden\n */\nexport function useGlobalSearchParams<\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): TParams;\n\n/**\n * @hidden\n */\nexport function useGlobalSearchParams(): RouteParams;\n\n/**\n * Returns URL parameters for globally selected route, including dynamic path segments.\n * This function updates even when the route is not focused. Useful for analytics or\n * other background operations that don't draw to the screen.\n *\n * Route URL example: `acme://profile/baconbrix?extra=info`.\n *\n * When querying search params in a stack, opt-towards using\n * [`useLocalSearchParams`](#uselocalsearchparams) because it will only update when the route is focused.\n *\n * > **Note:** For usage information, see\n * [Local versus global search parameters](/router/reference/url-parameters/#local-versus-global-url-parameters).\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useGlobalSearchParams } from 'expo-router';\n *\n * export default function Route() {\n * // user=baconbrix & extra=info\n * const { user, extra } = useGlobalSearchParams();\n *\n * return User: {user};\n * }\n * ```\n */\nexport function useGlobalSearchParams<\n TRoute extends RoutePath,\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): RouteParams & TParams;\nexport function useGlobalSearchParams() {\n return useRouteInfo().params;\n}\n\n/**\n * @hidden\n */\nexport function useLocalSearchParams<\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): TParams;\n\n/**\n * @hidden\n */\nexport function useLocalSearchParams(): RouteParams;\n\n/**\n * Returns the URL parameters for the contextually focused route. Useful for stacks where you may push a new screen\n * that changes the query parameters. For dynamic routes, both the route parameters and the search parameters are returned.\n *\n * Route URL example: `acme://profile/baconbrix?extra=info`.\n *\n * To observe updates even when the invoking route is not focused, use [`useGlobalSearchParams`](#useglobalsearchparams).\n *\n * > **Note:** For usage information, see\n * [Local versus global search parameters](/router/reference/url-parameters/#local-versus-global-url-parameters).\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useLocalSearchParams } from 'expo-router';\n *\n * export default function Route() {\n * // user=baconbrix & extra=info\n * const { user, extra } = useLocalSearchParams();\n *\n * return User: {user};\n * }\n */\nexport function useLocalSearchParams<\n TRoute extends RoutePath,\n TParams extends UnknownOutputParams = UnknownOutputParams,\n>(): RouteParams & TParams;\nexport function useLocalSearchParams() {\n const params = React.use(LocalRouteParamsContext) ?? {};\n const { params: previewParams } = usePreviewInfo();\n return Object.fromEntries(\n Object.entries(previewParams ?? params).map(([key, value]) => {\n // React Navigation doesn't remove \"undefined\" values from the params object, and you cannot remove them via\n // navigation.setParams as it shallow merges. Hence, we hide them here\n if (value === undefined) {\n return [key, undefined];\n }\n\n if (Array.isArray(value)) {\n return [\n key,\n value.map((v) => {\n try {\n return decodeURIComponent(v);\n } catch {\n return v;\n }\n }),\n ];\n } else {\n try {\n return [key, decodeURIComponent(value as string)];\n } catch {\n return [key, value];\n }\n }\n })\n ) as any;\n}\n\nexport function useSearchParams({ global = false } = {}): URLSearchParams {\n const globalRef = React.useRef(global);\n if (process.env.NODE_ENV !== 'production') {\n if (global !== globalRef.current) {\n console.warn(\n `Detected change in 'global' option of useSearchParams. This value cannot change between renders`\n );\n }\n }\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const params = global ? useGlobalSearchParams() : useLocalSearchParams();\n const entries = Object.entries(params).flatMap(([key, value]) => {\n if (global) {\n if (key === 'params') return [];\n if (key === 'screen') return [];\n }\n\n return Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]];\n });\n\n return new ReadOnlyURLSearchParams(entries);\n}\n\nclass ReadOnlyURLSearchParams extends URLSearchParams {\n set() {\n throw new Error('The URLSearchParams object return from useSearchParams is read-only');\n }\n append() {\n throw new Error('The URLSearchParams object return from useSearchParams is read-only');\n }\n delete() {\n throw new Error('The URLSearchParams object return from useSearchParams is read-only');\n }\n}\n\ntype LoaderFunctionResult> =\n T extends LoaderFunction ? R : unknown;\n\n/**\n * Returns the result of the `loader` function for the calling route.\n *\n * @example\n * ```tsx app/profile/[user].tsx\n * import { Text } from 'react-native';\n * import { useLoaderData } from 'expo-router';\n *\n * export function loader() {\n * return Promise.resolve({ foo: 'bar' }};\n * }\n *\n * export default function Route() {\n * const data = useLoaderData(); // { foo: 'bar' }\n *\n * return Data: {JSON.stringify(data)};\n * }\n */\nexport function useLoaderData = any>(): LoaderFunctionResult {\n const serverDataLoaderContext = use(ServerDataLoaderContext);\n const loaderCache = use(LoaderCacheContext);\n\n const stateForPath = useStateForPath();\n const contextKey = useContextKey();\n\n const resolvedPath = useMemo(() => {\n const routeInfo = getRouteInfoFromState(stateForPath);\n const contextPath = contextKey.startsWith('/') ? contextKey.slice(1) : contextKey;\n const resolvedPathname = `/${getSingularId(contextPath, { params: routeInfo.params })}`;\n const searchString = routeInfo.searchParams?.toString() || '';\n\n return searchString ? `${resolvedPathname}?${searchString}` : resolvedPathname;\n }, [contextKey, stateForPath]);\n\n // First invocation of this hook will happen server-side, so we look up the loaded data from context\n if (serverDataLoaderContext) {\n return serverDataLoaderContext[resolvedPath];\n }\n\n // The second invocation happens after the client has hydrated on initial load, so we look up the data injected\n // by `` using `globalThis.__EXPO_ROUTER_LOADER_DATA__`\n if (typeof window !== 'undefined' && globalThis.__EXPO_ROUTER_LOADER_DATA__) {\n if (globalThis.__EXPO_ROUTER_LOADER_DATA__[resolvedPath]) {\n return globalThis.__EXPO_ROUTER_LOADER_DATA__[resolvedPath];\n }\n }\n\n const result = getLoaderData>({\n resolvedPath,\n cache: loaderCache,\n fetcher: fetchLoader,\n });\n\n if (result instanceof Promise) {\n return use(result);\n }\n\n return result;\n}\n\n/**\n * Returns route info for a screen it is called from.\n *\n * @experimental\n */\nexport function useCurrentRouteInfo() {\n const state = useStateForPath();\n const routeInfo = useMemo(() => (state ? getCachedRouteInfo(state) : undefined), [state]);\n return routeInfo;\n}\n"]}
\ No newline at end of file
diff --git a/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js b/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js
index ccb3507ef1f33a..30dd82267bd9b3 100644
--- a/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js
+++ b/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.DrawerToggleButton = DrawerToggleButton;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_native_1 = require("react-native");
-const toggle_drawer_icon_png_1 = __importDefault(require("../../../../../assets/react-navigation/drawer/toggle-drawer-icon.png"));
+const toggle_drawer_icon_png_1 = __importDefault(require("../../../../assets/react-navigation/drawer/toggle-drawer-icon.png"));
const elements_1 = require("../../elements");
const native_1 = require("../../native");
function DrawerToggleButton({ tintColor, accessibilityLabel = 'Show navigation menu', imageSource = toggle_drawer_icon_png_1.default, ...rest }) {
diff --git a/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js.map b/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js.map
index 06c865b74bc823..5254645264b596 100644
--- a/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js.map
+++ b/packages/expo-router/build/react-navigation/drawer/views/DrawerToggleButton.js.map
@@ -1 +1 @@
-{"version":3,"file":"DrawerToggleButton.js","sourceRoot":"","sources":["../../../../src/react-navigation/drawer/views/DrawerToggleButton.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;;AAgBb,gDAsBC;;AArCD,+CAA4F;AAE5F,kIAAoG;AACpG,6CAA8C;AAC9C,yCAAgF;AAWhF,SAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,kBAAkB,GAAG,sBAAsB,EAC3C,WAAW,GAAG,gCAAgB,EAC9B,GAAG,IAAI,EACD;IACN,MAAM,UAAU,GAAG,IAAA,sBAAa,GAAuC,CAAC;IAExE,OAAO,CACL,uBAAC,uBAAY,OACP,IAAI,EACR,kBAAkB,EAAE,kBAAkB,EACtC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,sBAAa,CAAC,YAAY,EAAE,CAAC,YAChE,uBAAC,oBAAK,IACJ,UAAU,EAAC,SAAS,EACpB,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,CAAC,EACf,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,MAAM,CAAC,IAAI,GAClB,GACW,CAChB,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,yBAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;QACT,cAAc,EAAE,CAAC;QACjB,gBAAgB,EAAE,CAAC;KACpB;CACF,CAAC,CAAC","sourcesContent":["'use client';\nimport { type ColorValue, Image, type ImageSourcePropType, StyleSheet } from 'react-native';\n\nimport toggleDrawerIcon from '../../../../../assets/react-navigation/drawer/toggle-drawer-icon.png';\nimport { HeaderButton } from '../../elements';\nimport { DrawerActions, type ParamListBase, useNavigation } from '../../native';\nimport type { DrawerNavigationProp } from '../types';\n\ntype Props = {\n accessibilityLabel?: string;\n pressColor?: ColorValue;\n pressOpacity?: number;\n tintColor?: ColorValue;\n imageSource?: ImageSourcePropType;\n};\n\nexport function DrawerToggleButton({\n tintColor,\n accessibilityLabel = 'Show navigation menu',\n imageSource = toggleDrawerIcon,\n ...rest\n}: Props) {\n const navigation = useNavigation>();\n\n return (\n navigation.dispatch(DrawerActions.toggleDrawer())}>\n \n \n );\n}\n\nconst styles = StyleSheet.create({\n icon: {\n height: 24,\n width: 24,\n marginVertical: 8,\n marginHorizontal: 5,\n },\n});\n"]}
\ No newline at end of file
+{"version":3,"file":"DrawerToggleButton.js","sourceRoot":"","sources":["../../../../src/react-navigation/drawer/views/DrawerToggleButton.tsx"],"names":[],"mappings":";AAAA,YAAY,CAAC;;;;;AAgBb,gDAsBC;;AArCD,+CAA4F;AAE5F,+HAAiG;AACjG,6CAA8C;AAC9C,yCAAgF;AAWhF,SAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,kBAAkB,GAAG,sBAAsB,EAC3C,WAAW,GAAG,gCAAgB,EAC9B,GAAG,IAAI,EACD;IACN,MAAM,UAAU,GAAG,IAAA,sBAAa,GAAuC,CAAC;IAExE,OAAO,CACL,uBAAC,uBAAY,OACP,IAAI,EACR,kBAAkB,EAAE,kBAAkB,EACtC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,sBAAa,CAAC,YAAY,EAAE,CAAC,YAChE,uBAAC,oBAAK,IACJ,UAAU,EAAC,SAAS,EACpB,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,CAAC,EACf,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,MAAM,CAAC,IAAI,GAClB,GACW,CAChB,CAAC;AACJ,CAAC;AAED,MAAM,MAAM,GAAG,yBAAU,CAAC,MAAM,CAAC;IAC/B,IAAI,EAAE;QACJ,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;QACT,cAAc,EAAE,CAAC;QACjB,gBAAgB,EAAE,CAAC;KACpB;CACF,CAAC,CAAC","sourcesContent":["'use client';\nimport { type ColorValue, Image, type ImageSourcePropType, StyleSheet } from 'react-native';\n\nimport toggleDrawerIcon from '../../../../assets/react-navigation/drawer/toggle-drawer-icon.png';\nimport { HeaderButton } from '../../elements';\nimport { DrawerActions, type ParamListBase, useNavigation } from '../../native';\nimport type { DrawerNavigationProp } from '../types';\n\ntype Props = {\n accessibilityLabel?: string;\n pressColor?: ColorValue;\n pressOpacity?: number;\n tintColor?: ColorValue;\n imageSource?: ImageSourcePropType;\n};\n\nexport function DrawerToggleButton({\n tintColor,\n accessibilityLabel = 'Show navigation menu',\n imageSource = toggleDrawerIcon,\n ...rest\n}: Props) {\n const navigation = useNavigation>();\n\n return (\n navigation.dispatch(DrawerActions.toggleDrawer())}>\n \n \n );\n}\n\nconst styles = StyleSheet.create({\n icon: {\n height: 24,\n width: 24,\n marginVertical: 8,\n marginHorizontal: 5,\n },\n});\n"]}
\ No newline at end of file
diff --git a/packages/expo-router/jest.config.js b/packages/expo-router/jest.config.js
index afb94d28df0be1..75399308b02688 100644
--- a/packages/expo-router/jest.config.js
+++ b/packages/expo-router/jest.config.js
@@ -20,8 +20,10 @@ function withDefaults({ watchPlugins, ...config }) {
'^.+\\.module\\.css$': '/__mocks__/styleMock.js',
// Plain CSS (and other style files) can be stubbed with an empty object.
'^.+\\.(css|less|sass|scss)$': '/__mocks__/styleMock.js',
- // Image assets: stub with a simple numeric value (like Metro does).
- '^.+\\.(png|jpg|jpeg|gif|svg)$': '/__mocks__/imageMock.js',
+ },
+ transform: {
+ ...(config.transform || {}),
+ '^.+\\.(png|jpg|jpeg|gif|svg)$': '/__mocks__/imageTransformer.js',
},
};
}
diff --git a/packages/expo-router/src/exports.ts b/packages/expo-router/src/exports.ts
index 90d06959a661d2..a2be7815493b8c 100644
--- a/packages/expo-router/src/exports.ts
+++ b/packages/expo-router/src/exports.ts
@@ -12,6 +12,7 @@ export {
useRootNavigation,
useRootNavigationState,
useLoaderData,
+ useCurrentRouteInfo,
} from './hooks';
export { router, type ImperativeRouter } from './imperative-api';
diff --git a/packages/expo-router/src/hooks.ts b/packages/expo-router/src/hooks.ts
index b2bdede940a938..5cad03592ae230 100644
--- a/packages/expo-router/src/hooks.ts
+++ b/packages/expo-router/src/hooks.ts
@@ -6,6 +6,7 @@ import React, { use, useMemo } from 'react';
import { LocalRouteParamsContext, useContextKey } from './Route';
import { INTERNAL_SLOT_NAME } from './constants';
import { getRouteInfoFromState } from './global-state/getRouteInfoFromState';
+import { getCachedRouteInfo } from './global-state/routeInfoCache';
import { store, useRouteInfo } from './global-state/router-store';
import type { ImperativeRouter } from './imperative-api';
import { router } from './imperative-api';
@@ -413,3 +414,14 @@ export function useLoaderData = any>(): LoaderFunc
return result;
}
+
+/**
+ * Returns route info for a screen it is called from.
+ *
+ * @experimental
+ */
+export function useCurrentRouteInfo() {
+ const state = useStateForPath();
+ const routeInfo = useMemo(() => (state ? getCachedRouteInfo(state) : undefined), [state]);
+ return routeInfo;
+}
diff --git a/packages/expo-router/src/react-navigation/drawer/views/DrawerToggleButton.tsx b/packages/expo-router/src/react-navigation/drawer/views/DrawerToggleButton.tsx
index 11b9ed77943298..718a56954d1d88 100644
--- a/packages/expo-router/src/react-navigation/drawer/views/DrawerToggleButton.tsx
+++ b/packages/expo-router/src/react-navigation/drawer/views/DrawerToggleButton.tsx
@@ -1,7 +1,7 @@
'use client';
import { type ColorValue, Image, type ImageSourcePropType, StyleSheet } from 'react-native';
-import toggleDrawerIcon from '../../../../../assets/react-navigation/drawer/toggle-drawer-icon.png';
+import toggleDrawerIcon from '../../../../assets/react-navigation/drawer/toggle-drawer-icon.png';
import { HeaderButton } from '../../elements';
import { DrawerActions, type ParamListBase, useNavigation } from '../../native';
import type { DrawerNavigationProp } from '../types';
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5326a5ab8c8d83..8a68832fe392cf 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -5017,10 +5017,22 @@ importers:
expo-eas-client:
specifier: workspace:~56.0.0
version: link:../expo-eas-client
+ expo-router:
+ specifier: '*'
+ version: link:../expo-router
+ react:
+ specifier: 19.2.3
+ version: 19.2.3
react-native:
specifier: 0.85.3
version: 0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3)
devDependencies:
+ '@testing-library/react-native':
+ specifier: ^13.3.0
+ version: 13.3.3(jest@29.7.0(@types/node@22.19.15)(ts-node@10.9.2(@swc/core@1.15.18)(@types/node@22.19.15)(typescript@6.0.3)))(react-native@0.85.3(@babel/core@7.29.0)(@react-native/jest-preset@0.85.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.85.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react-test-renderer@19.2.3(react@19.2.3))(react@19.2.3)
+ '@types/react':
+ specifier: ~19.2.0
+ version: 19.2.14
expo:
specifier: workspace:*
version: link:../expo
diff --git a/tools/src/commands/GenerateDocsAPIData.ts b/tools/src/commands/GenerateDocsAPIData.ts
index d32eca15d2d099..8a98e7733dd592 100644
--- a/tools/src/commands/GenerateDocsAPIData.ts
+++ b/tools/src/commands/GenerateDocsAPIData.ts
@@ -30,6 +30,10 @@ const uiPackagesMapping: Record = {
'expo-ui/community/segmented-control': ['community/segmented-control/index.tsx', 'expo-ui'],
// Swift UI
+ 'expo-ui/swift-ui/accessorywidgetbackground': [
+ 'swift-ui/AccessoryWidgetBackground/index.tsx',
+ 'expo-ui',
+ ],
'expo-ui/swift-ui/bottomsheet': ['swift-ui/BottomSheet/index.tsx', 'expo-ui'],
'expo-ui/swift-ui/button': ['swift-ui/Button/index.tsx', 'expo-ui'],
'expo-ui/swift-ui/circularprogress': ['swift-ui/ProgressView/index.tsx', 'expo-ui'],
@@ -239,6 +243,7 @@ const PACKAGES_MAPPING: Record = {
'expo-router/color': ['color/index.ts', 'expo-router'],
'expo-router/native-tabs': ['native-tabs/index.ts', 'expo-router'],
'expo-router/split-view': ['split-view/index.ts', 'expo-router'],
+ 'expo-router/experimental-stack': ['layouts/experimental-stack/index.tsx', 'expo-router'],
'expo-router/ui': ['ui/index.ts', 'expo-router'],
'expo-screen-capture': ['ScreenCapture.ts'],
'expo-screen-orientation': ['ScreenOrientation.ts'],