react-event-tracking 1.0.10 → 2.0.1
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 +146 -30
- package/dist/index.cjs +65 -3
- package/dist/index.d.cts +25 -13
- package/dist/index.d.mts +25 -13
- package/dist/index.d.ts +25 -13
- package/dist/index.mjs +65 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@ A convenient React context for tracking analytics events.
|
|
|
3
3
|
|
|
4
4
|
## Features
|
|
5
5
|
|
|
6
|
+
- **Elegant Type-Safe Api**: enjoy a seamless dot-notation experience with full TypeScript autocompletion.
|
|
6
7
|
- **Nested Contexts**: Automatically merges parameters from parent providers.
|
|
7
8
|
- **Zero Re-renders**: No need to wrap props in `useCallback`/`useMemo`.
|
|
8
9
|
- **Multiple Providers**: Send events to different analytics services.
|
|
@@ -15,6 +16,10 @@ A convenient React context for tracking analytics events.
|
|
|
15
16
|
|
|
16
17
|
- [Installation](#installation)
|
|
17
18
|
- [Quickstart](#quickstart)
|
|
19
|
+
- [Usage Guide](#usage-guide)
|
|
20
|
+
* [Basic Hook](#basic-hook)
|
|
21
|
+
* [Typed Hook Factory](#typed-hook-factory)
|
|
22
|
+
* [Custom Handlers](#custom-handlers)
|
|
18
23
|
- [Advanced Usage](#advanced-usage)
|
|
19
24
|
* [Multiple Trackers & Factory](#multiple-trackers--factory)
|
|
20
25
|
* [Filtering Events](#filtering-events)
|
|
@@ -47,6 +52,7 @@ const Main = () => (
|
|
|
47
52
|
</TrackRoot>
|
|
48
53
|
);
|
|
49
54
|
```
|
|
55
|
+
|
|
50
56
|
2. Wrap any component with shared parameters
|
|
51
57
|
```tsx
|
|
52
58
|
import { TrackProvider } from 'react-event-tracking';
|
|
@@ -58,7 +64,12 @@ const Dashboard = () => (
|
|
|
58
64
|
);
|
|
59
65
|
```
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
## Usage Guide
|
|
68
|
+
|
|
69
|
+
### Basic Hook
|
|
70
|
+
|
|
71
|
+
Use `useReactEventTracking` for simple event tracking
|
|
72
|
+
|
|
62
73
|
```tsx
|
|
63
74
|
import { useReactEventTracking } from 'react-event-tracking';
|
|
64
75
|
|
|
@@ -66,21 +77,127 @@ const MyButton = () => {
|
|
|
66
77
|
const { track } = useReactEventTracking();
|
|
67
78
|
|
|
68
79
|
return (
|
|
69
|
-
|
|
70
|
-
// event sent with parameters: { screen: 'dashboard', button_id: '123' }
|
|
80
|
+
{/* Option A: String } */}
|
|
71
81
|
<button onClick={() => track('click', { button_id: '123' })}>
|
|
72
82
|
Click me
|
|
73
83
|
</button>
|
|
74
84
|
|
|
75
|
-
{/* Option B: Object call */}
|
|
76
|
-
<button onClick={() => track({ eventName: 'click', params: { button_id: '456' } })}>
|
|
77
|
-
Click me
|
|
78
|
-
</button>
|
|
79
|
-
|
|
85
|
+
{/* Option B: Object call */}
|
|
86
|
+
<button onClick={() => track({ eventName: 'click', params: { button_id: '456' } })}>
|
|
87
|
+
Click me
|
|
88
|
+
</button>
|
|
89
|
+
|
|
80
90
|
);
|
|
81
91
|
};
|
|
82
92
|
```
|
|
83
93
|
|
|
94
|
+
### Typed Hook Factory
|
|
95
|
+
|
|
96
|
+
For a more convenient dot-notation syntax and full TypeScript support, create your own hook using `createReactEventTrackingHook`.
|
|
97
|
+
|
|
98
|
+
1. Create a hook:
|
|
99
|
+
```tsx
|
|
100
|
+
import { createReactEventTrackingHook } from 'react-event-tracking';
|
|
101
|
+
|
|
102
|
+
// LoadingScreen.tsx
|
|
103
|
+
export type LoginScreenEvents = {
|
|
104
|
+
forgot_password: { from: "footer" | "button" }
|
|
105
|
+
logged_in: { timePassed: number }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
type SystemEvents = {
|
|
109
|
+
app_updated: { previous_version: string; current_version: string }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// analytics.ts
|
|
113
|
+
export type AnalyticsEvents = SystemEvents & {
|
|
114
|
+
login_screen: LoginScreenEvents
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export const useTracking = createReactEventTrackingHook<AnalyticsEvents>();
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
2. Use it in your components:
|
|
121
|
+
```tsx
|
|
122
|
+
const LoginButton = () => {
|
|
123
|
+
// You can use the full tracker
|
|
124
|
+
const { track } = useTracking();
|
|
125
|
+
|
|
126
|
+
// Or narrow it down to a specific scope
|
|
127
|
+
const { track } = useTracking("login_screen");
|
|
128
|
+
|
|
129
|
+
const handleLogin = () => {
|
|
130
|
+
// Full path: eventName is automatically derived from the call chain (result: "login_screen.logged_in")
|
|
131
|
+
track.login_screen.logged_in({ timePassed: 3000 });
|
|
132
|
+
|
|
133
|
+
// Narrowed path: the same result: "login_screen.logged_in":
|
|
134
|
+
track.logged_in({ timePassed: 3000 });
|
|
135
|
+
|
|
136
|
+
// Explicit event name: first argument overrides the event name. Result is "Logged In"
|
|
137
|
+
track.logged_in("Logged In", { timePassed: 3000 })
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<button onClick={handleLogin}>
|
|
142
|
+
Login with Google
|
|
143
|
+
</button>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Custom Handlers
|
|
149
|
+
|
|
150
|
+
Sometimes you need to expose more than just the `track` function, for example, a way to identify users. You can pass custom handlers to the factory.
|
|
151
|
+
|
|
152
|
+
1. Define your handlers type and create the hook:
|
|
153
|
+
```tsx
|
|
154
|
+
type MyCustomHandlers = {
|
|
155
|
+
setUserId: (id: string) => void;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export const useTracking = createReactEventTrackingHook<AnalyticsEvents, MyCustomHandlers>();
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
2. Create a custom Root using [TrackRoot.factory](#multiple-trackers--factory):
|
|
162
|
+
```tsx
|
|
163
|
+
import { TrackRoot } from 'react-event-tracking';
|
|
164
|
+
|
|
165
|
+
const CustomTrackRoot = TrackRoot.factory<MyCustomHandlers>({
|
|
166
|
+
onEvent: (name, params) => {
|
|
167
|
+
amplitude.logEvent(name, params);
|
|
168
|
+
},
|
|
169
|
+
customHandlers: {
|
|
170
|
+
setUserId: (id) => {
|
|
171
|
+
amplitude.setUserId(id);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const App = () => (
|
|
177
|
+
<CustomTrackRoot>
|
|
178
|
+
<Main />
|
|
179
|
+
</CustomTrackRoot>
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
3. Use it in your components:
|
|
184
|
+
```tsx
|
|
185
|
+
const Profile = () => {
|
|
186
|
+
const { track, setUserId } = useTracking();
|
|
187
|
+
|
|
188
|
+
const handleLogin = () => {
|
|
189
|
+
track.login_screen.logged_in({ timePassed: 3000 });
|
|
190
|
+
setUserId('user_123')
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<button onClick={handleLogin}>
|
|
195
|
+
Login
|
|
196
|
+
</button>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
84
201
|
## Advanced Usage
|
|
85
202
|
|
|
86
203
|
### Multiple Trackers & Factory
|
|
@@ -91,13 +208,13 @@ Use `TrackRoot.factory` to create reusable tracker components:
|
|
|
91
208
|
|
|
92
209
|
1. Create specific trackers
|
|
93
210
|
```tsx
|
|
94
|
-
const TrackRootGoogle = TrackRoot.factory(
|
|
95
|
-
(name, params) => gtag('event', name, params)
|
|
96
|
-
);
|
|
211
|
+
const TrackRootGoogle = TrackRoot.factory({
|
|
212
|
+
onEvent: (name, params) => gtag('event', name, params)
|
|
213
|
+
});
|
|
97
214
|
|
|
98
|
-
const TrackRootAmplitude = TrackRoot.factory(
|
|
99
|
-
(name, params) => amplitude.logEvent(name, params)
|
|
100
|
-
);
|
|
215
|
+
const TrackRootAmplitude = TrackRoot.factory({
|
|
216
|
+
onEvent: (name, params) => amplitude.logEvent(name, params)
|
|
217
|
+
});
|
|
101
218
|
```
|
|
102
219
|
|
|
103
220
|
2. Compose them in your app
|
|
@@ -113,19 +230,19 @@ const App = () => (
|
|
|
113
230
|
|
|
114
231
|
### Filtering Events
|
|
115
232
|
|
|
116
|
-
You can control which events are sent to which provider using the `filter` prop
|
|
233
|
+
You can control which events are sent to which provider using the `filter` prop in `factory`. If the filter returns `false`, the event is skipped for that tracker but continues to bubble up to others.
|
|
117
234
|
|
|
118
235
|
```tsx
|
|
119
236
|
// Google Analytics: only track page_* events
|
|
120
|
-
const TrackRootGoogle = TrackRoot.factory(
|
|
121
|
-
(name, params) => gtag('event', name, params),
|
|
122
|
-
(name) => name.startsWith('page_')
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
// Amplitude: track everything
|
|
126
|
-
const TrackRootAmplitude = TrackRoot.factory(
|
|
127
|
-
(name, params) =>
|
|
128
|
-
);
|
|
237
|
+
const TrackRootGoogle = TrackRoot.factory({
|
|
238
|
+
onEvent: (name, params) => gtag('event', name, params),
|
|
239
|
+
filter: (name) => name.startsWith('page_')
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Amplitude: track everything
|
|
243
|
+
const TrackRootAmplitude = TrackRoot.factory({
|
|
244
|
+
onEvent: (name, params) => amplitude.logEvent(name, params),
|
|
245
|
+
});
|
|
129
246
|
```
|
|
130
247
|
|
|
131
248
|
Compose them in your app:
|
|
@@ -142,16 +259,15 @@ const App = () => (
|
|
|
142
259
|
|
|
143
260
|
### Transforming Events
|
|
144
261
|
|
|
145
|
-
You can modify the event name or parameters before they
|
|
262
|
+
You can modify the event name or parameters before they are sent to the handler using the `transform` prop in `factory`.
|
|
146
263
|
|
|
147
264
|
Note: Transformations apply locally and do not affect the event bubbling up to parent providers.
|
|
148
265
|
|
|
149
266
|
```tsx
|
|
150
267
|
// GDPR Tracker
|
|
151
|
-
const
|
|
152
|
-
(name, params) => amplitude.logEvent(name, params),
|
|
153
|
-
|
|
154
|
-
(name, params) => {
|
|
268
|
+
const AmplitudeUS = TrackRoot.factory({
|
|
269
|
+
onEvent: (name, params) => amplitude.logEvent(name, params),
|
|
270
|
+
transform: (name, params) => {
|
|
155
271
|
if (params?.userRegion === 'EU') {
|
|
156
272
|
// Remove PII (Personally Identifiable Information)
|
|
157
273
|
const { userId, email, ...safeParams } = params;
|
|
@@ -162,7 +278,7 @@ const AmpltitudeUS = TrackRoot.factory(
|
|
|
162
278
|
}
|
|
163
279
|
return { eventName: name, params };
|
|
164
280
|
}
|
|
165
|
-
);
|
|
281
|
+
});
|
|
166
282
|
```
|
|
167
283
|
|
|
168
284
|
### TypeScript Generics Support
|
package/dist/index.cjs
CHANGED
|
@@ -28,11 +28,18 @@ const useReactEventTracking = () => {
|
|
|
28
28
|
return ctx;
|
|
29
29
|
};
|
|
30
30
|
const EmptyParams = {};
|
|
31
|
-
const TrackRootComponent = ({
|
|
31
|
+
const TrackRootComponent = ({
|
|
32
|
+
onEvent,
|
|
33
|
+
children,
|
|
34
|
+
filter,
|
|
35
|
+
transform,
|
|
36
|
+
customHandlers
|
|
37
|
+
}) => {
|
|
32
38
|
const parentCtx = React.useContext(TrackContext);
|
|
33
39
|
const onEventRef = useFreshRef(onEvent);
|
|
34
40
|
const filterRef = useFreshRef(filter);
|
|
35
41
|
const transformRef = useFreshRef(transform);
|
|
42
|
+
const customHandlersRef = useFreshRef(customHandlers);
|
|
36
43
|
function track(eventNameOrObject, eventParams) {
|
|
37
44
|
const { eventName, params: incomingParams } = parseEventArgs(
|
|
38
45
|
eventNameOrObject,
|
|
@@ -71,7 +78,31 @@ const TrackRootComponent = ({ onEvent, children, filter, transform }) => {
|
|
|
71
78
|
parentCtx.track(eventName, incomingParams);
|
|
72
79
|
}
|
|
73
80
|
}
|
|
74
|
-
const value = React.useMemo(() =>
|
|
81
|
+
const value = React.useMemo(() => {
|
|
82
|
+
return new Proxy({}, {
|
|
83
|
+
get(_, prop) {
|
|
84
|
+
if (prop === track.name) return track;
|
|
85
|
+
const handler = customHandlersRef.current?.[prop];
|
|
86
|
+
if (typeof handler === "function") {
|
|
87
|
+
return (...args) => handler(...args);
|
|
88
|
+
}
|
|
89
|
+
return void 0;
|
|
90
|
+
},
|
|
91
|
+
has(_, prop) {
|
|
92
|
+
return prop === track.name || (customHandlersRef.current ? prop in customHandlersRef.current : false);
|
|
93
|
+
},
|
|
94
|
+
ownKeys() {
|
|
95
|
+
const customKeys = customHandlersRef.current ? Object.keys(customHandlersRef.current) : [];
|
|
96
|
+
return Array.from(/* @__PURE__ */ new Set([track.name, ...customKeys]));
|
|
97
|
+
},
|
|
98
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
99
|
+
return {
|
|
100
|
+
enumerable: true,
|
|
101
|
+
configurable: true
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}, [parentCtx]);
|
|
75
106
|
return /* @__PURE__ */ React__default.createElement(TrackContext.Provider, { value }, children);
|
|
76
107
|
};
|
|
77
108
|
const factory = (args) => {
|
|
@@ -81,6 +112,7 @@ const factory = (args) => {
|
|
|
81
112
|
onEvent: args.onEvent,
|
|
82
113
|
filter: args.filter,
|
|
83
114
|
transform: args.transform,
|
|
115
|
+
customHandlers: args.customHandlers,
|
|
84
116
|
...props
|
|
85
117
|
}
|
|
86
118
|
);
|
|
@@ -103,7 +135,7 @@ const TrackProvider = ({
|
|
|
103
135
|
...incomingParams
|
|
104
136
|
});
|
|
105
137
|
}
|
|
106
|
-
const value = React.useMemo(() => ({ track }), [ctx]);
|
|
138
|
+
const value = React.useMemo(() => ({ ...ctx, track }), [ctx]);
|
|
107
139
|
return /* @__PURE__ */ React__default.createElement(TrackContext.Provider, { value }, children);
|
|
108
140
|
};
|
|
109
141
|
function useFreshRef(data) {
|
|
@@ -125,7 +157,37 @@ function useMountEvent(eventNameOrObject, eventParams) {
|
|
|
125
157
|
}, []);
|
|
126
158
|
}
|
|
127
159
|
|
|
160
|
+
function createTracker(path = [], track) {
|
|
161
|
+
return new Proxy(() => {
|
|
162
|
+
}, {
|
|
163
|
+
get(_, prop) {
|
|
164
|
+
return createTracker([...path, prop], track);
|
|
165
|
+
},
|
|
166
|
+
apply(_, __, [name, params]) {
|
|
167
|
+
let eventParams = typeof name === "object" ? name : params;
|
|
168
|
+
const eventName = typeof name === "object" ? path.join(".") : name;
|
|
169
|
+
track(eventName, eventParams);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function createReactEventTrackingHook() {
|
|
175
|
+
function useTracking(scope) {
|
|
176
|
+
const ctx = useReactEventTracking();
|
|
177
|
+
const tracker = React.useMemo(() => {
|
|
178
|
+
const prefix = scope ? [String(scope)] : [];
|
|
179
|
+
return {
|
|
180
|
+
...ctx,
|
|
181
|
+
track: createTracker(prefix, ctx.track)
|
|
182
|
+
};
|
|
183
|
+
}, [ctx, scope]);
|
|
184
|
+
return tracker;
|
|
185
|
+
}
|
|
186
|
+
return useTracking;
|
|
187
|
+
}
|
|
188
|
+
|
|
128
189
|
exports.TrackProvider = TrackProvider;
|
|
129
190
|
exports.TrackRoot = TrackRoot;
|
|
191
|
+
exports.createReactEventTrackingHook = createReactEventTrackingHook;
|
|
130
192
|
exports.useMountEvent = useMountEvent;
|
|
131
193
|
exports.useReactEventTracking = useReactEventTracking;
|
package/dist/index.d.cts
CHANGED
|
@@ -2,13 +2,19 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { PropsWithChildren } from 'react';
|
|
3
3
|
|
|
4
4
|
type EventParams<T extends Record<string, any> = Record<string, any>> = T;
|
|
5
|
-
|
|
5
|
+
type EventsMap = Record<string, any>;
|
|
6
|
+
type AnyFunction = (...args: any[]) => any;
|
|
7
|
+
type IsLeaf<T> = T extends Record<string, any> ? (keyof T extends never ? true : T[keyof T] extends Record<string, any> ? false : true) : true;
|
|
8
|
+
type FlatTracker<T> = {
|
|
9
|
+
[K in keyof T]: IsLeaf<T[K]> extends true ? ((params: T[K]) => void) & ((eventName: string, params: T[K]) => void) : FlatTracker<T[K]>;
|
|
10
|
+
};
|
|
11
|
+
interface TrackContextValueLegacy {
|
|
6
12
|
track(eventName: string, params?: EventParams): void;
|
|
7
13
|
track(event: EventObject): void;
|
|
8
14
|
}
|
|
9
|
-
type EventObject = {
|
|
10
|
-
eventName:
|
|
11
|
-
params?:
|
|
15
|
+
type EventObject<E extends string = string, P = EventParams> = {
|
|
16
|
+
eventName: E;
|
|
17
|
+
params?: P;
|
|
12
18
|
};
|
|
13
19
|
type EventFilter = (eventName: string, params: EventParams) => boolean;
|
|
14
20
|
type TransformedEvent = {
|
|
@@ -17,18 +23,15 @@ type TransformedEvent = {
|
|
|
17
23
|
};
|
|
18
24
|
type EventTransformer = (eventName: string, params: EventParams) => TransformedEvent;
|
|
19
25
|
|
|
20
|
-
declare const useReactEventTracking: () =>
|
|
21
|
-
type TrackRootProps = PropsWithChildren<{
|
|
26
|
+
declare const useReactEventTracking: () => TrackContextValueLegacy;
|
|
27
|
+
type TrackRootProps<CustomHandlers extends Record<string, AnyFunction>> = PropsWithChildren<{
|
|
22
28
|
onEvent: (eventName: string, params: EventParams) => void;
|
|
23
29
|
filter?: EventFilter;
|
|
24
30
|
transform?: EventTransformer;
|
|
31
|
+
customHandlers?: CustomHandlers;
|
|
25
32
|
}>;
|
|
26
|
-
declare const TrackRoot: (({ onEvent, children, filter, transform }: TrackRootProps) => react_jsx_runtime.JSX.Element) & {
|
|
27
|
-
factory: (args:
|
|
28
|
-
onEvent: (eventName: string, params?: EventParams) => void;
|
|
29
|
-
filter?: EventFilter;
|
|
30
|
-
transform?: EventTransformer;
|
|
31
|
-
}) => (props: Omit<TrackRootProps, "onEvent" | "filter" | "transform">) => react_jsx_runtime.JSX.Element;
|
|
33
|
+
declare const TrackRoot: (<CustomHandlers extends Record<string, AnyFunction> = {}>({ onEvent, children, filter, transform, customHandlers }: TrackRootProps<CustomHandlers>) => react_jsx_runtime.JSX.Element) & {
|
|
34
|
+
factory: <T extends Record<string, AnyFunction> = {}>(args: TrackRootProps<T>) => (props: Omit<TrackRootProps<T>, "onEvent" | "filter" | "transform" | "customHandlers">) => react_jsx_runtime.JSX.Element;
|
|
32
35
|
};
|
|
33
36
|
declare const TrackProvider: <T extends Record<string, any>>({ params, children }: PropsWithChildren<{
|
|
34
37
|
params: EventParams<T>;
|
|
@@ -37,4 +40,13 @@ declare const TrackProvider: <T extends Record<string, any>>({ params, children
|
|
|
37
40
|
declare function useMountEvent(eventName: string, params?: EventParams): void;
|
|
38
41
|
declare function useMountEvent(event: EventObject): void;
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
declare function createReactEventTrackingHook<Map extends EventsMap, CustomHandlers extends Record<string, AnyFunction> = {}>(): {
|
|
44
|
+
(): {
|
|
45
|
+
track: FlatTracker<Map>;
|
|
46
|
+
} & CustomHandlers;
|
|
47
|
+
<K extends keyof Map>(scope: K): {
|
|
48
|
+
track: FlatTracker<Map>[K];
|
|
49
|
+
} & CustomHandlers;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { TrackProvider, TrackRoot, createReactEventTrackingHook, useMountEvent, useReactEventTracking };
|
package/dist/index.d.mts
CHANGED
|
@@ -2,13 +2,19 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { PropsWithChildren } from 'react';
|
|
3
3
|
|
|
4
4
|
type EventParams<T extends Record<string, any> = Record<string, any>> = T;
|
|
5
|
-
|
|
5
|
+
type EventsMap = Record<string, any>;
|
|
6
|
+
type AnyFunction = (...args: any[]) => any;
|
|
7
|
+
type IsLeaf<T> = T extends Record<string, any> ? (keyof T extends never ? true : T[keyof T] extends Record<string, any> ? false : true) : true;
|
|
8
|
+
type FlatTracker<T> = {
|
|
9
|
+
[K in keyof T]: IsLeaf<T[K]> extends true ? ((params: T[K]) => void) & ((eventName: string, params: T[K]) => void) : FlatTracker<T[K]>;
|
|
10
|
+
};
|
|
11
|
+
interface TrackContextValueLegacy {
|
|
6
12
|
track(eventName: string, params?: EventParams): void;
|
|
7
13
|
track(event: EventObject): void;
|
|
8
14
|
}
|
|
9
|
-
type EventObject = {
|
|
10
|
-
eventName:
|
|
11
|
-
params?:
|
|
15
|
+
type EventObject<E extends string = string, P = EventParams> = {
|
|
16
|
+
eventName: E;
|
|
17
|
+
params?: P;
|
|
12
18
|
};
|
|
13
19
|
type EventFilter = (eventName: string, params: EventParams) => boolean;
|
|
14
20
|
type TransformedEvent = {
|
|
@@ -17,18 +23,15 @@ type TransformedEvent = {
|
|
|
17
23
|
};
|
|
18
24
|
type EventTransformer = (eventName: string, params: EventParams) => TransformedEvent;
|
|
19
25
|
|
|
20
|
-
declare const useReactEventTracking: () =>
|
|
21
|
-
type TrackRootProps = PropsWithChildren<{
|
|
26
|
+
declare const useReactEventTracking: () => TrackContextValueLegacy;
|
|
27
|
+
type TrackRootProps<CustomHandlers extends Record<string, AnyFunction>> = PropsWithChildren<{
|
|
22
28
|
onEvent: (eventName: string, params: EventParams) => void;
|
|
23
29
|
filter?: EventFilter;
|
|
24
30
|
transform?: EventTransformer;
|
|
31
|
+
customHandlers?: CustomHandlers;
|
|
25
32
|
}>;
|
|
26
|
-
declare const TrackRoot: (({ onEvent, children, filter, transform }: TrackRootProps) => react_jsx_runtime.JSX.Element) & {
|
|
27
|
-
factory: (args:
|
|
28
|
-
onEvent: (eventName: string, params?: EventParams) => void;
|
|
29
|
-
filter?: EventFilter;
|
|
30
|
-
transform?: EventTransformer;
|
|
31
|
-
}) => (props: Omit<TrackRootProps, "onEvent" | "filter" | "transform">) => react_jsx_runtime.JSX.Element;
|
|
33
|
+
declare const TrackRoot: (<CustomHandlers extends Record<string, AnyFunction> = {}>({ onEvent, children, filter, transform, customHandlers }: TrackRootProps<CustomHandlers>) => react_jsx_runtime.JSX.Element) & {
|
|
34
|
+
factory: <T extends Record<string, AnyFunction> = {}>(args: TrackRootProps<T>) => (props: Omit<TrackRootProps<T>, "onEvent" | "filter" | "transform" | "customHandlers">) => react_jsx_runtime.JSX.Element;
|
|
32
35
|
};
|
|
33
36
|
declare const TrackProvider: <T extends Record<string, any>>({ params, children }: PropsWithChildren<{
|
|
34
37
|
params: EventParams<T>;
|
|
@@ -37,4 +40,13 @@ declare const TrackProvider: <T extends Record<string, any>>({ params, children
|
|
|
37
40
|
declare function useMountEvent(eventName: string, params?: EventParams): void;
|
|
38
41
|
declare function useMountEvent(event: EventObject): void;
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
declare function createReactEventTrackingHook<Map extends EventsMap, CustomHandlers extends Record<string, AnyFunction> = {}>(): {
|
|
44
|
+
(): {
|
|
45
|
+
track: FlatTracker<Map>;
|
|
46
|
+
} & CustomHandlers;
|
|
47
|
+
<K extends keyof Map>(scope: K): {
|
|
48
|
+
track: FlatTracker<Map>[K];
|
|
49
|
+
} & CustomHandlers;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { TrackProvider, TrackRoot, createReactEventTrackingHook, useMountEvent, useReactEventTracking };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,13 +2,19 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { PropsWithChildren } from 'react';
|
|
3
3
|
|
|
4
4
|
type EventParams<T extends Record<string, any> = Record<string, any>> = T;
|
|
5
|
-
|
|
5
|
+
type EventsMap = Record<string, any>;
|
|
6
|
+
type AnyFunction = (...args: any[]) => any;
|
|
7
|
+
type IsLeaf<T> = T extends Record<string, any> ? (keyof T extends never ? true : T[keyof T] extends Record<string, any> ? false : true) : true;
|
|
8
|
+
type FlatTracker<T> = {
|
|
9
|
+
[K in keyof T]: IsLeaf<T[K]> extends true ? ((params: T[K]) => void) & ((eventName: string, params: T[K]) => void) : FlatTracker<T[K]>;
|
|
10
|
+
};
|
|
11
|
+
interface TrackContextValueLegacy {
|
|
6
12
|
track(eventName: string, params?: EventParams): void;
|
|
7
13
|
track(event: EventObject): void;
|
|
8
14
|
}
|
|
9
|
-
type EventObject = {
|
|
10
|
-
eventName:
|
|
11
|
-
params?:
|
|
15
|
+
type EventObject<E extends string = string, P = EventParams> = {
|
|
16
|
+
eventName: E;
|
|
17
|
+
params?: P;
|
|
12
18
|
};
|
|
13
19
|
type EventFilter = (eventName: string, params: EventParams) => boolean;
|
|
14
20
|
type TransformedEvent = {
|
|
@@ -17,18 +23,15 @@ type TransformedEvent = {
|
|
|
17
23
|
};
|
|
18
24
|
type EventTransformer = (eventName: string, params: EventParams) => TransformedEvent;
|
|
19
25
|
|
|
20
|
-
declare const useReactEventTracking: () =>
|
|
21
|
-
type TrackRootProps = PropsWithChildren<{
|
|
26
|
+
declare const useReactEventTracking: () => TrackContextValueLegacy;
|
|
27
|
+
type TrackRootProps<CustomHandlers extends Record<string, AnyFunction>> = PropsWithChildren<{
|
|
22
28
|
onEvent: (eventName: string, params: EventParams) => void;
|
|
23
29
|
filter?: EventFilter;
|
|
24
30
|
transform?: EventTransformer;
|
|
31
|
+
customHandlers?: CustomHandlers;
|
|
25
32
|
}>;
|
|
26
|
-
declare const TrackRoot: (({ onEvent, children, filter, transform }: TrackRootProps) => react_jsx_runtime.JSX.Element) & {
|
|
27
|
-
factory: (args:
|
|
28
|
-
onEvent: (eventName: string, params?: EventParams) => void;
|
|
29
|
-
filter?: EventFilter;
|
|
30
|
-
transform?: EventTransformer;
|
|
31
|
-
}) => (props: Omit<TrackRootProps, "onEvent" | "filter" | "transform">) => react_jsx_runtime.JSX.Element;
|
|
33
|
+
declare const TrackRoot: (<CustomHandlers extends Record<string, AnyFunction> = {}>({ onEvent, children, filter, transform, customHandlers }: TrackRootProps<CustomHandlers>) => react_jsx_runtime.JSX.Element) & {
|
|
34
|
+
factory: <T extends Record<string, AnyFunction> = {}>(args: TrackRootProps<T>) => (props: Omit<TrackRootProps<T>, "onEvent" | "filter" | "transform" | "customHandlers">) => react_jsx_runtime.JSX.Element;
|
|
32
35
|
};
|
|
33
36
|
declare const TrackProvider: <T extends Record<string, any>>({ params, children }: PropsWithChildren<{
|
|
34
37
|
params: EventParams<T>;
|
|
@@ -37,4 +40,13 @@ declare const TrackProvider: <T extends Record<string, any>>({ params, children
|
|
|
37
40
|
declare function useMountEvent(eventName: string, params?: EventParams): void;
|
|
38
41
|
declare function useMountEvent(event: EventObject): void;
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
declare function createReactEventTrackingHook<Map extends EventsMap, CustomHandlers extends Record<string, AnyFunction> = {}>(): {
|
|
44
|
+
(): {
|
|
45
|
+
track: FlatTracker<Map>;
|
|
46
|
+
} & CustomHandlers;
|
|
47
|
+
<K extends keyof Map>(scope: K): {
|
|
48
|
+
track: FlatTracker<Map>[K];
|
|
49
|
+
} & CustomHandlers;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { TrackProvider, TrackRoot, createReactEventTrackingHook, useMountEvent, useReactEventTracking };
|
package/dist/index.mjs
CHANGED
|
@@ -22,11 +22,18 @@ const useReactEventTracking = () => {
|
|
|
22
22
|
return ctx;
|
|
23
23
|
};
|
|
24
24
|
const EmptyParams = {};
|
|
25
|
-
const TrackRootComponent = ({
|
|
25
|
+
const TrackRootComponent = ({
|
|
26
|
+
onEvent,
|
|
27
|
+
children,
|
|
28
|
+
filter,
|
|
29
|
+
transform,
|
|
30
|
+
customHandlers
|
|
31
|
+
}) => {
|
|
26
32
|
const parentCtx = useContext(TrackContext);
|
|
27
33
|
const onEventRef = useFreshRef(onEvent);
|
|
28
34
|
const filterRef = useFreshRef(filter);
|
|
29
35
|
const transformRef = useFreshRef(transform);
|
|
36
|
+
const customHandlersRef = useFreshRef(customHandlers);
|
|
30
37
|
function track(eventNameOrObject, eventParams) {
|
|
31
38
|
const { eventName, params: incomingParams } = parseEventArgs(
|
|
32
39
|
eventNameOrObject,
|
|
@@ -65,7 +72,31 @@ const TrackRootComponent = ({ onEvent, children, filter, transform }) => {
|
|
|
65
72
|
parentCtx.track(eventName, incomingParams);
|
|
66
73
|
}
|
|
67
74
|
}
|
|
68
|
-
const value = useMemo(() =>
|
|
75
|
+
const value = useMemo(() => {
|
|
76
|
+
return new Proxy({}, {
|
|
77
|
+
get(_, prop) {
|
|
78
|
+
if (prop === track.name) return track;
|
|
79
|
+
const handler = customHandlersRef.current?.[prop];
|
|
80
|
+
if (typeof handler === "function") {
|
|
81
|
+
return (...args) => handler(...args);
|
|
82
|
+
}
|
|
83
|
+
return void 0;
|
|
84
|
+
},
|
|
85
|
+
has(_, prop) {
|
|
86
|
+
return prop === track.name || (customHandlersRef.current ? prop in customHandlersRef.current : false);
|
|
87
|
+
},
|
|
88
|
+
ownKeys() {
|
|
89
|
+
const customKeys = customHandlersRef.current ? Object.keys(customHandlersRef.current) : [];
|
|
90
|
+
return Array.from(/* @__PURE__ */ new Set([track.name, ...customKeys]));
|
|
91
|
+
},
|
|
92
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
93
|
+
return {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
configurable: true
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}, [parentCtx]);
|
|
69
100
|
return /* @__PURE__ */ React.createElement(TrackContext.Provider, { value }, children);
|
|
70
101
|
};
|
|
71
102
|
const factory = (args) => {
|
|
@@ -75,6 +106,7 @@ const factory = (args) => {
|
|
|
75
106
|
onEvent: args.onEvent,
|
|
76
107
|
filter: args.filter,
|
|
77
108
|
transform: args.transform,
|
|
109
|
+
customHandlers: args.customHandlers,
|
|
78
110
|
...props
|
|
79
111
|
}
|
|
80
112
|
);
|
|
@@ -97,7 +129,7 @@ const TrackProvider = ({
|
|
|
97
129
|
...incomingParams
|
|
98
130
|
});
|
|
99
131
|
}
|
|
100
|
-
const value = useMemo(() => ({ track }), [ctx]);
|
|
132
|
+
const value = useMemo(() => ({ ...ctx, track }), [ctx]);
|
|
101
133
|
return /* @__PURE__ */ React.createElement(TrackContext.Provider, { value }, children);
|
|
102
134
|
};
|
|
103
135
|
function useFreshRef(data) {
|
|
@@ -119,4 +151,33 @@ function useMountEvent(eventNameOrObject, eventParams) {
|
|
|
119
151
|
}, []);
|
|
120
152
|
}
|
|
121
153
|
|
|
122
|
-
|
|
154
|
+
function createTracker(path = [], track) {
|
|
155
|
+
return new Proxy(() => {
|
|
156
|
+
}, {
|
|
157
|
+
get(_, prop) {
|
|
158
|
+
return createTracker([...path, prop], track);
|
|
159
|
+
},
|
|
160
|
+
apply(_, __, [name, params]) {
|
|
161
|
+
let eventParams = typeof name === "object" ? name : params;
|
|
162
|
+
const eventName = typeof name === "object" ? path.join(".") : name;
|
|
163
|
+
track(eventName, eventParams);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function createReactEventTrackingHook() {
|
|
169
|
+
function useTracking(scope) {
|
|
170
|
+
const ctx = useReactEventTracking();
|
|
171
|
+
const tracker = useMemo(() => {
|
|
172
|
+
const prefix = scope ? [String(scope)] : [];
|
|
173
|
+
return {
|
|
174
|
+
...ctx,
|
|
175
|
+
track: createTracker(prefix, ctx.track)
|
|
176
|
+
};
|
|
177
|
+
}, [ctx, scope]);
|
|
178
|
+
return tracker;
|
|
179
|
+
}
|
|
180
|
+
return useTracking;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export { TrackProvider, TrackRoot, createReactEventTrackingHook, useMountEvent, useReactEventTracking };
|