@truewatchtech/mobile-react-native-navigation 0.0.0-stage → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,77 @@
1
- # Temporary Holding Version
1
+ # TrueWatch React Native Navigation plugin
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ This plugin tracks Wix `react-native-navigation` screen appearances as TrueWatch
4
+ RUM Views and measures appearance loading.
5
+
6
+ ## Installation
7
+
8
+ ```sh
9
+ yarn add @truewatchtech/react-native-mobile @truewatchtech/mobile-react-native-navigation
10
+ ```
11
+
12
+ Keep your existing `react-native-navigation` dependency and its native setup.
13
+ This plugin contains only JavaScript and types; it adds no native linking or
14
+ build configuration.
15
+
16
+ ## View tracking
17
+
18
+ Initialize the mobile SDK and RUM, then start tracking before displaying the
19
+ navigation root:
20
+
21
+ ```ts
22
+ import { Navigation } from 'react-native-navigation';
23
+ import { FTRumReactNativeNavigationTracking } from '@truewatchtech/mobile-react-native-navigation';
24
+
25
+ FTRumReactNativeNavigationTracking.startTracking();
26
+
27
+ Navigation.events().registerAppLaunchedListener(() => {
28
+ // Register your screens, then display the root as usual.
29
+ void Navigation.setRoot({
30
+ root: { stack: { children: [{ component: { name: 'Home' } }] } },
31
+ });
32
+ });
33
+
34
+ // Before shutting down the SDK or disposing the navigation integration:
35
+ FTRumReactNativeNavigationTracking.stopTracking();
36
+ ```
37
+
38
+ `startTracking()` is idempotent. `stopTracking()` removes all registered global screen
39
+ listeners and the AppState subscription. You can start tracking again; callbacks
40
+ queued by an old registration cannot restart or stop the new registration's View.
41
+ Starting after a screen is already visible only tracks subsequent appearance
42
+ events, so start before `setRoot`.
43
+
44
+ The plugin listens directly to `componentDidAppear` and `componentDidDisappear`,
45
+ and to `componentWillAppear` when the navigation library exposes it. It works
46
+ without patching `React.createElement` and also
47
+ covers screens using the automatic JSX runtime. Only events with
48
+ `componentType: 'Component'` are treated as screens. Top bar titles, backgrounds,
49
+ and buttons are excluded. `componentName` becomes the View name and `componentId`
50
+ identifies the screen instance.
51
+
52
+ ## Loading and lifecycle
53
+
54
+ Loading is the monotonic elapsed time from `componentWillAppear` to
55
+ `componentDidAppear`, reported in nanoseconds: 25.5 ms is 25,500,000 ns. This is the
56
+ observed appearance interval, not the completion of asynchronous content loading.
57
+ If the navigation library has no will-appear API, Views are collected without
58
+ loading data. Missing starts and non-positive durations also omit loading data.
59
+ Duplicate callbacks do not submit loading twice. Native closes automatic Views in
60
+ the background; foreground recovery starts the current screen without replaying
61
+ old loading data. A late disappearance from the previous screen cannot close a
62
+ different active screen.
63
+
64
+ Use one automatic navigation integration at a time. The SDK has one active View;
65
+ when multiple screens are simultaneously visible, the latest accepted appearance
66
+ owns it. This package does not need React Navigation or
67
+ `@truewatchtech/mobile-react-navigation`.
68
+
69
+ ## Migration
70
+
71
+ Replace the copied `example/src/FTRumReactNativeNavigationTracking.tsx` import
72
+ with `@truewatchtech/mobile-react-native-navigation`, retaining the class name and
73
+ methods. Remove the copied implementation so it cannot collect Views twice.
74
+
75
+ ## License
76
+
77
+ Apache 2.0
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.FTRumReactNativeNavigationTracking = void 0;
7
+ var _reactNativeNavigation = require("react-native-navigation");
8
+ var _reactNativeMobile = require("@truewatchtech/react-native-mobile");
9
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
10
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
11
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
12
+ /** Tracks screen events directly, including screens rendered with the JSX runtime. */
13
+ class FTRumReactNativeNavigationTracking {
14
+ /** Call after RUM initialization and before displaying the navigation root. */
15
+ static startTracking() {
16
+ if (this.subscriptions.length) return;
17
+ const lifecycle = ++this.lifecycle;
18
+ const current = () => lifecycle === this.lifecycle;
19
+ this.tracker.start();
20
+ const events = _reactNativeNavigation.Navigation.events();
21
+ try {
22
+ // Older releases expose only did-appear/disappear. Without a start
23
+ // boundary, collect Views without reporting an appearance duration.
24
+ if (typeof events.registerComponentWillAppearListener === 'function') {
25
+ this.subscriptions.push(events.registerComponentWillAppearListener(event => {
26
+ if (!current() || event.componentType !== 'Component') return;
27
+ const key = event.componentId;
28
+ const existing = this.appearances.get(key);
29
+ // A duplicate will-appear must not replace the original loading start.
30
+ if (!existing || existing.order !== this.appearance) {
31
+ this.appearances.set(key, {
32
+ order: ++this.appearance
33
+ });
34
+ }
35
+ this.tracker.setCurrent({
36
+ key,
37
+ name: event.componentName
38
+ });
39
+ this.tracker.beginLoad(key);
40
+ }));
41
+ }
42
+ this.subscriptions.push(events.registerComponentDidAppearListener(event => {
43
+ var _appearance$order;
44
+ if (!current() || event.componentType !== 'Component') return;
45
+ const key = event.componentId;
46
+ const appearance = this.appearances.get(key);
47
+ if (appearance && appearance.order !== this.appearance) return;
48
+ const generation = this.tracker.show({
49
+ key,
50
+ name: event.componentName
51
+ });
52
+ this.appearances.set(key, {
53
+ order: (_appearance$order = appearance === null || appearance === void 0 ? void 0 : appearance.order) !== null && _appearance$order !== void 0 ? _appearance$order : ++this.appearance,
54
+ generation
55
+ });
56
+ }));
57
+ this.subscriptions.push(events.registerComponentDidDisappearListener(event => {
58
+ if (!current() || event.componentType !== 'Component') return;
59
+ const key = event.componentId;
60
+ const appearance = this.appearances.get(key);
61
+ if (!appearance) return;
62
+ // Retain the appearance's generation: foreground recovery owns a new one.
63
+ this.tracker.hide(key, appearance.generation);
64
+ this.appearances.delete(key);
65
+ }));
66
+ } catch (error) {
67
+ this.stopTracking();
68
+ throw error;
69
+ }
70
+ }
71
+ static stopTracking() {
72
+ ++this.lifecycle;
73
+ this.subscriptions.forEach(subscription => subscription.remove());
74
+ this.subscriptions = [];
75
+ this.appearances.clear();
76
+ this.tracker.stop();
77
+ }
78
+ }
79
+ exports.FTRumReactNativeNavigationTracking = FTRumReactNativeNavigationTracking;
80
+ _defineProperty(FTRumReactNativeNavigationTracking, "tracker", new _reactNativeMobile.FTRumViewTracking());
81
+ _defineProperty(FTRumReactNativeNavigationTracking, "subscriptions", []);
82
+ _defineProperty(FTRumReactNativeNavigationTracking, "appearances", new Map());
83
+ _defineProperty(FTRumReactNativeNavigationTracking, "appearance", 0);
84
+ _defineProperty(FTRumReactNativeNavigationTracking, "lifecycle", 0);
85
+ //# sourceMappingURL=FTRumReactNativeNavigationTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNativeNavigation","require","_reactNativeMobile","_defineProperty","e","r","t","_toPropertyKey","Object","defineProperty","value","enumerable","configurable","writable","i","_toPrimitive","Symbol","toPrimitive","call","TypeError","String","Number","FTRumReactNativeNavigationTracking","startTracking","subscriptions","length","lifecycle","current","tracker","start","events","Navigation","registerComponentWillAppearListener","push","event","componentType","key","componentId","existing","appearances","get","order","appearance","set","setCurrent","name","componentName","beginLoad","registerComponentDidAppearListener","_appearance$order","generation","show","registerComponentDidDisappearListener","hide","delete","error","stopTracking","forEach","subscription","remove","clear","stop","exports","FTRumViewTracking","Map"],"sources":["FTRumReactNativeNavigationTracking.ts"],"sourcesContent":["import { Navigation } from 'react-native-navigation';\nimport { FTRumViewTracking } from '@truewatchtech/react-native-mobile';\n\ntype Appearance = { order: number; generation?: number };\n\n/** Tracks screen events directly, including screens rendered with the JSX runtime. */\nexport class FTRumReactNativeNavigationTracking {\n private static tracker = new FTRumViewTracking();\n private static subscriptions: { remove(): void }[] = [];\n private static appearances = new Map<string, Appearance>();\n private static appearance = 0;\n private static lifecycle = 0;\n\n /** Call after RUM initialization and before displaying the navigation root. */\n static startTracking(): void {\n if (this.subscriptions.length) return;\n const lifecycle = ++this.lifecycle;\n const current = (): boolean => lifecycle === this.lifecycle;\n this.tracker.start();\n const events = Navigation.events();\n try {\n // Older releases expose only did-appear/disappear. Without a start\n // boundary, collect Views without reporting an appearance duration.\n if (typeof events.registerComponentWillAppearListener === 'function') {\n this.subscriptions.push(\n events.registerComponentWillAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const existing = this.appearances.get(key);\n // A duplicate will-appear must not replace the original loading start.\n if (!existing || existing.order !== this.appearance) {\n this.appearances.set(key, { order: ++this.appearance });\n }\n this.tracker.setCurrent({ key, name: event.componentName });\n this.tracker.beginLoad(key);\n })\n );\n }\n this.subscriptions.push(\n events.registerComponentDidAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (appearance && appearance.order !== this.appearance) return;\n const generation = this.tracker.show({\n key,\n name: event.componentName,\n });\n this.appearances.set(key, {\n order: appearance?.order ?? ++this.appearance,\n generation,\n });\n })\n );\n this.subscriptions.push(\n events.registerComponentDidDisappearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (!appearance) return;\n // Retain the appearance's generation: foreground recovery owns a new one.\n this.tracker.hide(key, appearance.generation);\n this.appearances.delete(key);\n })\n );\n } catch (error) {\n this.stopTracking();\n throw error;\n }\n }\n\n static stopTracking(): void {\n ++this.lifecycle;\n this.subscriptions.forEach((subscription) => subscription.remove());\n this.subscriptions = [];\n this.appearances.clear();\n this.tracker.stop();\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "FTRumReactNativeNavigationTracking", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _FTRumReactNativeNavigationTracking.FTRumReactNativeNavigationTracking;
10
+ }
11
+ });
12
+ var _FTRumReactNativeNavigationTracking = require("./FTRumReactNativeNavigationTracking");
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_FTRumReactNativeNavigationTracking","require"],"sources":["index.ts"],"sourcesContent":["export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,mCAAA,GAAAC,OAAA","ignoreList":[]}
@@ -0,0 +1,78 @@
1
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
2
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
3
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
+ import { Navigation } from 'react-native-navigation';
5
+ import { FTRumViewTracking } from '@truewatchtech/react-native-mobile';
6
+ /** Tracks screen events directly, including screens rendered with the JSX runtime. */
7
+ export class FTRumReactNativeNavigationTracking {
8
+ /** Call after RUM initialization and before displaying the navigation root. */
9
+ static startTracking() {
10
+ if (this.subscriptions.length) return;
11
+ const lifecycle = ++this.lifecycle;
12
+ const current = () => lifecycle === this.lifecycle;
13
+ this.tracker.start();
14
+ const events = Navigation.events();
15
+ try {
16
+ // Older releases expose only did-appear/disappear. Without a start
17
+ // boundary, collect Views without reporting an appearance duration.
18
+ if (typeof events.registerComponentWillAppearListener === 'function') {
19
+ this.subscriptions.push(events.registerComponentWillAppearListener(event => {
20
+ if (!current() || event.componentType !== 'Component') return;
21
+ const key = event.componentId;
22
+ const existing = this.appearances.get(key);
23
+ // A duplicate will-appear must not replace the original loading start.
24
+ if (!existing || existing.order !== this.appearance) {
25
+ this.appearances.set(key, {
26
+ order: ++this.appearance
27
+ });
28
+ }
29
+ this.tracker.setCurrent({
30
+ key,
31
+ name: event.componentName
32
+ });
33
+ this.tracker.beginLoad(key);
34
+ }));
35
+ }
36
+ this.subscriptions.push(events.registerComponentDidAppearListener(event => {
37
+ var _appearance$order;
38
+ if (!current() || event.componentType !== 'Component') return;
39
+ const key = event.componentId;
40
+ const appearance = this.appearances.get(key);
41
+ if (appearance && appearance.order !== this.appearance) return;
42
+ const generation = this.tracker.show({
43
+ key,
44
+ name: event.componentName
45
+ });
46
+ this.appearances.set(key, {
47
+ order: (_appearance$order = appearance === null || appearance === void 0 ? void 0 : appearance.order) !== null && _appearance$order !== void 0 ? _appearance$order : ++this.appearance,
48
+ generation
49
+ });
50
+ }));
51
+ this.subscriptions.push(events.registerComponentDidDisappearListener(event => {
52
+ if (!current() || event.componentType !== 'Component') return;
53
+ const key = event.componentId;
54
+ const appearance = this.appearances.get(key);
55
+ if (!appearance) return;
56
+ // Retain the appearance's generation: foreground recovery owns a new one.
57
+ this.tracker.hide(key, appearance.generation);
58
+ this.appearances.delete(key);
59
+ }));
60
+ } catch (error) {
61
+ this.stopTracking();
62
+ throw error;
63
+ }
64
+ }
65
+ static stopTracking() {
66
+ ++this.lifecycle;
67
+ this.subscriptions.forEach(subscription => subscription.remove());
68
+ this.subscriptions = [];
69
+ this.appearances.clear();
70
+ this.tracker.stop();
71
+ }
72
+ }
73
+ _defineProperty(FTRumReactNativeNavigationTracking, "tracker", new FTRumViewTracking());
74
+ _defineProperty(FTRumReactNativeNavigationTracking, "subscriptions", []);
75
+ _defineProperty(FTRumReactNativeNavigationTracking, "appearances", new Map());
76
+ _defineProperty(FTRumReactNativeNavigationTracking, "appearance", 0);
77
+ _defineProperty(FTRumReactNativeNavigationTracking, "lifecycle", 0);
78
+ //# sourceMappingURL=FTRumReactNativeNavigationTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Navigation","FTRumViewTracking","FTRumReactNativeNavigationTracking","startTracking","subscriptions","length","lifecycle","current","tracker","start","events","registerComponentWillAppearListener","push","event","componentType","key","componentId","existing","appearances","get","order","appearance","set","setCurrent","name","componentName","beginLoad","registerComponentDidAppearListener","_appearance$order","generation","show","registerComponentDidDisappearListener","hide","delete","error","stopTracking","forEach","subscription","remove","clear","stop","_defineProperty","Map"],"sources":["FTRumReactNativeNavigationTracking.ts"],"sourcesContent":["import { Navigation } from 'react-native-navigation';\nimport { FTRumViewTracking } from '@truewatchtech/react-native-mobile';\n\ntype Appearance = { order: number; generation?: number };\n\n/** Tracks screen events directly, including screens rendered with the JSX runtime. */\nexport class FTRumReactNativeNavigationTracking {\n private static tracker = new FTRumViewTracking();\n private static subscriptions: { remove(): void }[] = [];\n private static appearances = new Map<string, Appearance>();\n private static appearance = 0;\n private static lifecycle = 0;\n\n /** Call after RUM initialization and before displaying the navigation root. */\n static startTracking(): void {\n if (this.subscriptions.length) return;\n const lifecycle = ++this.lifecycle;\n const current = (): boolean => lifecycle === this.lifecycle;\n this.tracker.start();\n const events = Navigation.events();\n try {\n // Older releases expose only did-appear/disappear. Without a start\n // boundary, collect Views without reporting an appearance duration.\n if (typeof events.registerComponentWillAppearListener === 'function') {\n this.subscriptions.push(\n events.registerComponentWillAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const existing = this.appearances.get(key);\n // A duplicate will-appear must not replace the original loading start.\n if (!existing || existing.order !== this.appearance) {\n this.appearances.set(key, { order: ++this.appearance });\n }\n this.tracker.setCurrent({ key, name: event.componentName });\n this.tracker.beginLoad(key);\n })\n );\n }\n this.subscriptions.push(\n events.registerComponentDidAppearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (appearance && appearance.order !== this.appearance) return;\n const generation = this.tracker.show({\n key,\n name: event.componentName,\n });\n this.appearances.set(key, {\n order: appearance?.order ?? ++this.appearance,\n generation,\n });\n })\n );\n this.subscriptions.push(\n events.registerComponentDidDisappearListener((event) => {\n if (!current() || event.componentType !== 'Component') return;\n const key = event.componentId;\n const appearance = this.appearances.get(key);\n if (!appearance) return;\n // Retain the appearance's generation: foreground recovery owns a new one.\n this.tracker.hide(key, appearance.generation);\n this.appearances.delete(key);\n })\n );\n } catch (error) {\n this.stopTracking();\n throw error;\n }\n }\n\n static stopTracking(): void {\n ++this.lifecycle;\n this.subscriptions.forEach((subscription) => subscription.remove());\n this.subscriptions = [];\n this.appearances.clear();\n this.tracker.stop();\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["FTRumReactNativeNavigationTracking"],"sources":["index.ts"],"sourcesContent":["export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';\n"],"mappings":"AAAA,SAASA,kCAAkC,QAAQ,sCAAsC","ignoreList":[]}
@@ -0,0 +1,11 @@
1
+ /** Tracks screen events directly, including screens rendered with the JSX runtime. */
2
+ export declare class FTRumReactNativeNavigationTracking {
3
+ private static tracker;
4
+ private static subscriptions;
5
+ private static appearances;
6
+ private static appearance;
7
+ private static lifecycle;
8
+ /** Call after RUM initialization and before displaying the navigation root. */
9
+ static startTracking(): void;
10
+ static stopTracking(): void;
11
+ }
@@ -0,0 +1 @@
1
+ export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';
package/package.json CHANGED
@@ -1,6 +1,64 @@
1
1
  {
2
2
  "name": "@truewatchtech/mobile-react-native-navigation",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.4.3",
4
+ "description": "Automatic TrueWatch RUM View tracking for react-native-navigation.",
5
+ "main": "lib/commonjs/index",
6
+ "module": "lib/module/index",
7
+ "types": "lib/typescript/index.d.ts",
8
+ "react-native": "src/index",
9
+ "source": "src/index",
10
+ "files": [
11
+ "src",
12
+ "lib",
13
+ "README.md",
14
+ "!**/__tests__",
15
+ "!**/__mocks__"
16
+ ],
17
+ "scripts": {
18
+ "lint": "yarn run -T eslint \"src/**/*.{ts,tsx}\" \"tests/**/*.ts\"",
19
+ "prepare": "yarn run -T bob build",
20
+ "prepack": "yarn run -T check-version && yarn prepare",
21
+ "test": "yarn run -T jest",
22
+ "typescript": "yarn run -T tsc --noEmit"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/TrueWatchTech/datakit-react-native.git"
27
+ },
28
+ "license": "Apache-2.0",
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "registry": "https://registry.npmjs.org/"
32
+ },
33
+ "peerDependencies": {
34
+ "@truewatchtech/react-native-mobile": "^0.4.3",
35
+ "react": ">=16.13.1",
36
+ "react-native": ">=0.63.4 <1.0",
37
+ "react-native-navigation": "^7.5.0"
38
+ },
39
+ "devDependencies": {
40
+ "react-native-navigation": "7.40.1"
41
+ },
42
+ "react-native-builder-bob": {
43
+ "source": "src",
44
+ "output": "lib",
45
+ "targets": [
46
+ "commonjs",
47
+ "module",
48
+ [
49
+ "typescript",
50
+ {
51
+ "tsc": "../../node_modules/.bin/tsc",
52
+ "project": "tsconfig.build.json"
53
+ }
54
+ ]
55
+ ]
56
+ },
57
+ "jest": {
58
+ "preset": "react-native",
59
+ "modulePathIgnorePatterns": [
60
+ "<rootDir>/lib/"
61
+ ]
62
+ },
63
+ "gitHead": "61ed39427761a210cbfe6b339e71296f952f9697"
6
64
  }
@@ -0,0 +1,79 @@
1
+ import { Navigation } from 'react-native-navigation';
2
+ import { FTRumViewTracking } from '@truewatchtech/react-native-mobile';
3
+
4
+ type Appearance = { order: number; generation?: number };
5
+
6
+ /** Tracks screen events directly, including screens rendered with the JSX runtime. */
7
+ export class FTRumReactNativeNavigationTracking {
8
+ private static tracker = new FTRumViewTracking();
9
+ private static subscriptions: { remove(): void }[] = [];
10
+ private static appearances = new Map<string, Appearance>();
11
+ private static appearance = 0;
12
+ private static lifecycle = 0;
13
+
14
+ /** Call after RUM initialization and before displaying the navigation root. */
15
+ static startTracking(): void {
16
+ if (this.subscriptions.length) return;
17
+ const lifecycle = ++this.lifecycle;
18
+ const current = (): boolean => lifecycle === this.lifecycle;
19
+ this.tracker.start();
20
+ const events = Navigation.events();
21
+ try {
22
+ // Older releases expose only did-appear/disappear. Without a start
23
+ // boundary, collect Views without reporting an appearance duration.
24
+ if (typeof events.registerComponentWillAppearListener === 'function') {
25
+ this.subscriptions.push(
26
+ events.registerComponentWillAppearListener((event) => {
27
+ if (!current() || event.componentType !== 'Component') return;
28
+ const key = event.componentId;
29
+ const existing = this.appearances.get(key);
30
+ // A duplicate will-appear must not replace the original loading start.
31
+ if (!existing || existing.order !== this.appearance) {
32
+ this.appearances.set(key, { order: ++this.appearance });
33
+ }
34
+ this.tracker.setCurrent({ key, name: event.componentName });
35
+ this.tracker.beginLoad(key);
36
+ })
37
+ );
38
+ }
39
+ this.subscriptions.push(
40
+ events.registerComponentDidAppearListener((event) => {
41
+ if (!current() || event.componentType !== 'Component') return;
42
+ const key = event.componentId;
43
+ const appearance = this.appearances.get(key);
44
+ if (appearance && appearance.order !== this.appearance) return;
45
+ const generation = this.tracker.show({
46
+ key,
47
+ name: event.componentName,
48
+ });
49
+ this.appearances.set(key, {
50
+ order: appearance?.order ?? ++this.appearance,
51
+ generation,
52
+ });
53
+ })
54
+ );
55
+ this.subscriptions.push(
56
+ events.registerComponentDidDisappearListener((event) => {
57
+ if (!current() || event.componentType !== 'Component') return;
58
+ const key = event.componentId;
59
+ const appearance = this.appearances.get(key);
60
+ if (!appearance) return;
61
+ // Retain the appearance's generation: foreground recovery owns a new one.
62
+ this.tracker.hide(key, appearance.generation);
63
+ this.appearances.delete(key);
64
+ })
65
+ );
66
+ } catch (error) {
67
+ this.stopTracking();
68
+ throw error;
69
+ }
70
+ }
71
+
72
+ static stopTracking(): void {
73
+ ++this.lifecycle;
74
+ this.subscriptions.forEach((subscription) => subscription.remove());
75
+ this.subscriptions = [];
76
+ this.appearances.clear();
77
+ this.tracker.stop();
78
+ }
79
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { FTRumReactNativeNavigationTracking } from './FTRumReactNativeNavigationTracking';