@getuserfeedback/react-native 5.9.0 → 5.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ import type { EventProperties } from "./client.js";
2
+ import { type ScreenTrackingErrorHandler } from "./screen-tracking.js";
3
+ export type ExpoRouterScreen = {
4
+ name: string;
5
+ properties?: EventProperties;
6
+ };
7
+ export type ExpoRouterScreenTrackingOptions = {
8
+ /**
9
+ * Maps the current pathname to a stable screen name and safe properties.
10
+ * Return `null` to ignore a pathname.
11
+ */
12
+ toScreen?: (pathname: string) => ExpoRouterScreen | null | undefined;
13
+ /** Receives rejected `screen()` calls. */
14
+ onError?: ScreenTrackingErrorHandler;
15
+ };
16
+ /**
17
+ * Reports Expo Router pathname changes through `client.screen()`.
18
+ *
19
+ * Pass the value returned by Expo Router's `usePathname()`. Keeping that hook
20
+ * in application code lets this adapter stay optional and avoids making Expo a
21
+ * dependency of the React Native SDK. Consecutive renders of the same pathname
22
+ * are treated as one screen transition.
23
+ */
24
+ export declare function useExpoRouterScreenTracking(pathname: string, options?: ExpoRouterScreenTrackingOptions): void;
@@ -0,0 +1,24 @@
1
+ import { useEffect } from "react";
2
+ import { useScreenOccurrenceReporter, } from "./screen-tracking.js";
3
+ /**
4
+ * Reports Expo Router pathname changes through `client.screen()`.
5
+ *
6
+ * Pass the value returned by Expo Router's `usePathname()`. Keeping that hook
7
+ * in application code lets this adapter stay optional and avoids making Expo a
8
+ * dependency of the React Native SDK. Consecutive renders of the same pathname
9
+ * are treated as one screen transition.
10
+ */
11
+ export function useExpoRouterScreenTracking(pathname, options = {}) {
12
+ const reportScreen = useScreenOccurrenceReporter(options.onError);
13
+ useEffect(() => {
14
+ const screen = options.toScreen
15
+ ? options.toScreen(pathname)
16
+ : { name: pathname };
17
+ reportScreen({
18
+ key: pathname,
19
+ screen: screen
20
+ ? { name: screen.name, properties: screen.properties }
21
+ : null,
22
+ });
23
+ }, [options.toScreen, pathname, reportScreen]);
24
+ }
@@ -39,14 +39,14 @@ export function createNativeProviderClient({ dispatchCommand, flow, instanceId,
39
39
  const track = (eventName, properties, options) => {
40
40
  return dispatchCommand(buildCustomerOccurrenceCommand({
41
41
  type: "track",
42
- event: parseRequiredString("eventName", eventName),
42
+ event: eventName,
43
43
  properties,
44
44
  options,
45
45
  }));
46
46
  };
47
47
  const screen = (name, properties, options) => dispatchCommand(buildCustomerOccurrenceCommand({
48
48
  type: "screen",
49
- event: parseRequiredString("screenName", name),
49
+ event: name,
50
50
  properties,
51
51
  options,
52
52
  }));
@@ -0,0 +1,24 @@
1
+ import type { EventProperties } from "./client.js";
2
+ import type { ScreenTrackingObservation } from "./screen-tracking.js";
3
+ /** The active-route fields used by the React Navigation adapter. */
4
+ export type ReactNavigationRoute = {
5
+ key: string;
6
+ name: string;
7
+ params?: unknown;
8
+ };
9
+ /** Structural subset of a React Navigation container ref. */
10
+ export type ReactNavigationContainerRef = {
11
+ addListener: (event: "state", listener: () => void) => () => void;
12
+ getCurrentRoute: () => ReactNavigationRoute | undefined;
13
+ isReady: () => boolean;
14
+ };
15
+ export type ReactNavigationScreen = {
16
+ name: string;
17
+ properties?: EventProperties;
18
+ };
19
+ export type ReactNavigationScreenMapper = (route: ReactNavigationRoute) => ReactNavigationScreen | null | undefined;
20
+ export declare function observeReactNavigationScreens(input: {
21
+ navigationRef: ReactNavigationContainerRef;
22
+ observeScreen: (observation: ScreenTrackingObservation) => void;
23
+ toScreen?: ReactNavigationScreenMapper;
24
+ }): () => void;
@@ -0,0 +1,29 @@
1
+ export function observeReactNavigationScreens(input) {
2
+ const reportCurrentRoute = () => {
3
+ if (!input.navigationRef.isReady()) {
4
+ return;
5
+ }
6
+ const route = input.navigationRef.getCurrentRoute();
7
+ if (!route) {
8
+ return;
9
+ }
10
+ const screen = input.toScreen
11
+ ? input.toScreen(route)
12
+ : { name: route.name };
13
+ input.observeScreen({
14
+ key: route.key,
15
+ screen: screen
16
+ ? { name: screen.name, properties: screen.properties }
17
+ : null,
18
+ });
19
+ };
20
+ const unsubscribeState = input.navigationRef.addListener("state", reportCurrentRoute);
21
+ try {
22
+ reportCurrentRoute();
23
+ }
24
+ catch (error) {
25
+ unsubscribeState();
26
+ throw error;
27
+ }
28
+ return unsubscribeState;
29
+ }
@@ -0,0 +1,20 @@
1
+ import { type ReactNavigationContainerRef, type ReactNavigationScreenMapper } from "./react-navigation-screen-observer.js";
2
+ import { type ScreenTrackingErrorHandler } from "./screen-tracking.js";
3
+ export type { ReactNavigationContainerRef, ReactNavigationRoute, ReactNavigationScreen, } from "./react-navigation-screen-observer.js";
4
+ export type ReactNavigationScreenTrackingOptions = {
5
+ /**
6
+ * Maps an active route to a stable screen name and safe event properties.
7
+ * Return `null` to ignore a route.
8
+ */
9
+ toScreen?: ReactNavigationScreenMapper;
10
+ /** Receives rejected `screen()` calls. */
11
+ onError?: ScreenTrackingErrorHandler;
12
+ };
13
+ /**
14
+ * Reports the active React Navigation route through `client.screen()`.
15
+ *
16
+ * Mount once below `GetUserFeedbackProvider` and pass the same ref used by the
17
+ * root navigation container. Consecutive notifications for the same route
18
+ * occurrence are ignored.
19
+ */
20
+ export declare function useReactNavigationScreenTracking(navigationRef: ReactNavigationContainerRef, options?: ReactNavigationScreenTrackingOptions): void;
@@ -0,0 +1,18 @@
1
+ import { useEffect } from "react";
2
+ import { observeReactNavigationScreens, } from "./react-navigation-screen-observer.js";
3
+ import { useScreenOccurrenceReporter, } from "./screen-tracking.js";
4
+ /**
5
+ * Reports the active React Navigation route through `client.screen()`.
6
+ *
7
+ * Mount once below `GetUserFeedbackProvider` and pass the same ref used by the
8
+ * root navigation container. Consecutive notifications for the same route
9
+ * occurrence are ignored.
10
+ */
11
+ export function useReactNavigationScreenTracking(navigationRef, options = {}) {
12
+ const reportScreen = useScreenOccurrenceReporter(options.onError);
13
+ useEffect(() => observeReactNavigationScreens({
14
+ navigationRef,
15
+ observeScreen: reportScreen,
16
+ toScreen: options.toScreen,
17
+ }), [navigationRef, options.toScreen, reportScreen]);
18
+ }
@@ -0,0 +1,23 @@
1
+ import { type MutableRefObject } from "react";
2
+ import type { Client, EventProperties } from "./client.js";
3
+ type ScreenTrackingScreen = {
4
+ name: string;
5
+ properties?: EventProperties;
6
+ };
7
+ export type ScreenTrackingObservation = {
8
+ key: string;
9
+ screen: ScreenTrackingScreen | null;
10
+ };
11
+ export type ScreenTrackingErrorHandler = (error: Error) => void | PromiseLike<void>;
12
+ type LastReportedScreen = {
13
+ client: Client;
14
+ key: string;
15
+ };
16
+ export declare const reportScreenOccurrence: (input: {
17
+ client: Client;
18
+ observation: ScreenTrackingObservation;
19
+ lastReportedRef: MutableRefObject<LastReportedScreen | null>;
20
+ onError?: ScreenTrackingErrorHandler;
21
+ }) => void;
22
+ export declare const useScreenOccurrenceReporter: (onError?: ScreenTrackingErrorHandler) => ((observation: ScreenTrackingObservation) => void);
23
+ export {};
@@ -0,0 +1,45 @@
1
+ import { useCallback, useRef } from "react";
2
+ import { useGetUserFeedback } from "./native-provider.js";
3
+ const toError = (value) => value instanceof Error ? value : new Error(String(value));
4
+ const reportTrackingError = (onError, error) => {
5
+ try {
6
+ void Promise.resolve(onError === null || onError === void 0 ? void 0 : onError(toError(error))).catch(() => { });
7
+ }
8
+ catch (_a) {
9
+ // Error observers cannot destabilize router listeners or React effects.
10
+ }
11
+ };
12
+ export const reportScreenOccurrence = (input) => {
13
+ var _a;
14
+ if (((_a = input.lastReportedRef.current) === null || _a === void 0 ? void 0 : _a.client) === input.client &&
15
+ input.lastReportedRef.current.key === input.observation.key) {
16
+ return;
17
+ }
18
+ input.lastReportedRef.current = {
19
+ client: input.client,
20
+ key: input.observation.key,
21
+ };
22
+ if (!input.observation.screen) {
23
+ return;
24
+ }
25
+ try {
26
+ void input.client
27
+ .screen(input.observation.screen.name, input.observation.screen.properties)
28
+ .catch((error) => reportTrackingError(input.onError, error));
29
+ }
30
+ catch (error) {
31
+ reportTrackingError(input.onError, error);
32
+ }
33
+ };
34
+ export const useScreenOccurrenceReporter = (onError) => {
35
+ const client = useGetUserFeedback();
36
+ const lastReportedRef = useRef(null);
37
+ const onErrorRef = useRef(onError);
38
+ onErrorRef.current = onError;
39
+ return useCallback((observation) => reportScreenOccurrence({
40
+ client,
41
+ observation,
42
+ lastReportedRef,
43
+ onError: onErrorRef.current,
44
+ }), [client]);
45
+ };
package/dist/version.js CHANGED
@@ -3,4 +3,4 @@ const reactNativeSdkVersion = typeof __GX_REACT_NATIVE_SDK_VERSION__ === "string
3
3
  : "";
4
4
  // Build scripts patch this fallback to the package version for published artifacts.
5
5
  // Source-linked workspace usage keeps the local fallback.
6
- export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "5.9.0";
6
+ export const REACT_NATIVE_SDK_VERSION = reactNativeSdkVersion.length > 0 ? reactNativeSdkVersion : "5.11.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getuserfeedback/react-native",
3
- "version": "5.9.0",
3
+ "version": "5.11.0",
4
4
  "description": "getuserfeedback React Native SDK",
5
5
  "keywords": [
6
6
  "getuserfeedback",
@@ -26,6 +26,16 @@
26
26
  "types": "./dist/public-api.d.ts",
27
27
  "import": "./dist/public-api.js",
28
28
  "default": "./dist/public-api.js"
29
+ },
30
+ "./expo-router": {
31
+ "types": "./dist/expo-router.d.ts",
32
+ "import": "./dist/expo-router.js",
33
+ "default": "./dist/expo-router.js"
34
+ },
35
+ "./react-navigation": {
36
+ "types": "./dist/react-navigation.d.ts",
37
+ "import": "./dist/react-navigation.js",
38
+ "default": "./dist/react-navigation.js"
29
39
  }
30
40
  },
31
41
  "files": [
@@ -44,8 +54,8 @@
44
54
  "lint": "biome check ."
45
55
  },
46
56
  "dependencies": {
47
- "@getuserfeedback/protocol": "^5.4.1",
48
- "@getuserfeedback/sdk": "^0.17.1",
57
+ "@getuserfeedback/protocol": "^5.4.2",
58
+ "@getuserfeedback/sdk": "^0.18.0",
49
59
  "robot3": "^1.2.0"
50
60
  },
51
61
  "peerDependencies": {