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 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
- 3. Send events conveniently. On button click, parameters will be merged.
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 too
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 (or the second argument in `factory`). If the filter returns `false`, the event is skipped for that tracker but continues to bubble up to others.
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 (filter is optional, defaults to allowing all events)
126
- const TrackRootAmplitude = TrackRoot.factory(
127
- (name, params) => ampltitude.logEvent(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 reach the handler using the `transform` prop (or the third argument in `factory`).
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 AmpltitudeUS = TrackRoot.factory(
152
- (name, params) => amplitude.logEvent(name, params),
153
- undefined, // no filter
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 = ({ onEvent, children, filter, transform }) => {
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(() => ({ track }), [parentCtx]);
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
- interface TrackContextValue {
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: string;
11
- params?: EventParams;
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: () => TrackContextValue;
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
- export { TrackProvider, TrackRoot, useMountEvent, useReactEventTracking };
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
- interface TrackContextValue {
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: string;
11
- params?: EventParams;
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: () => TrackContextValue;
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
- export { TrackProvider, TrackRoot, useMountEvent, useReactEventTracking };
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
- interface TrackContextValue {
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: string;
11
- params?: EventParams;
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: () => TrackContextValue;
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
- export { TrackProvider, TrackRoot, useMountEvent, useReactEventTracking };
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 = ({ onEvent, children, filter, transform }) => {
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(() => ({ track }), [parentCtx]);
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
- export { TrackProvider, TrackRoot, useMountEvent, useReactEventTracking };
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-event-tracking",
3
- "version": "1.0.10",
3
+ "version": "2.0.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],