react-event-tracking 1.0.10 → 2.0.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.
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,116 @@ 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
+ const { track } = useTracking();
124
+
125
+ const handleLogin = () => {
126
+ // This call transforms into "login_screen.logged_in" event with parameters
127
+ track.login_screen.logged_in({ timePassed: 3000 });
128
+ };
129
+ return (
130
+ <button onClick={handleLogin}>
131
+ Login with Google
132
+ </button>
133
+ );
134
+ };
135
+ ```
136
+
137
+ ### Custom Handlers
138
+
139
+ 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.
140
+
141
+ 1. Define your handlers type and create the hook:
142
+ ```tsx
143
+ type MyCustomHandlers = {
144
+ setUserId: (id: string) => void;
145
+ }
146
+
147
+ export const useTracking = createReactEventTrackingHook<AnalyticsEvents, MyCustomHandlers>();
148
+ ```
149
+
150
+ 2. Create a custom Root using [TrackRoot.factory](#multiple-trackers--factory):
151
+ ```tsx
152
+ import { TrackRoot } from 'react-event-tracking';
153
+
154
+ const CustomTrackRoot = TrackRoot.factory<MyCustomHandlers>({
155
+ onEvent: (name, params) => {
156
+ amplitude.logEvent(name, params);
157
+ },
158
+ customHandlers: {
159
+ setUserId: (id) => {
160
+ amplitude.setUserId(id);
161
+ }
162
+ }
163
+ });
164
+
165
+ const App = () => (
166
+ <CustomTrackRoot>
167
+ <Main />
168
+ </CustomTrackRoot>
169
+ );
170
+ ```
171
+
172
+ 3. Use it in your components:
173
+ ```tsx
174
+ const Profile = () => {
175
+ const { track, setUserId } = useTracking();
176
+
177
+ const handleLogin = () => {
178
+ track.login_screen.logged_in({ timePassed: 3000 });
179
+ setUserId('user_123')
180
+ };
181
+
182
+ return (
183
+ <button onClick={handleLogin}>
184
+ Login
185
+ </button>
186
+ );
187
+ }
188
+ ```
189
+
84
190
  ## Advanced Usage
85
191
 
86
192
  ### Multiple Trackers & Factory
@@ -91,13 +197,13 @@ Use `TrackRoot.factory` to create reusable tracker components:
91
197
 
92
198
  1. Create specific trackers
93
199
  ```tsx
94
- const TrackRootGoogle = TrackRoot.factory(
95
- (name, params) => gtag('event', name, params)
96
- );
200
+ const TrackRootGoogle = TrackRoot.factory({
201
+ onEvent: (name, params) => gtag('event', name, params)
202
+ });
97
203
 
98
- const TrackRootAmplitude = TrackRoot.factory(
99
- (name, params) => amplitude.logEvent(name, params)
100
- );
204
+ const TrackRootAmplitude = TrackRoot.factory({
205
+ onEvent: (name, params) => amplitude.logEvent(name, params)
206
+ });
101
207
  ```
102
208
 
103
209
  2. Compose them in your app
@@ -113,19 +219,19 @@ const App = () => (
113
219
 
114
220
  ### Filtering Events
115
221
 
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.
222
+ 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
223
 
118
224
  ```tsx
119
225
  // 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
- );
226
+ const TrackRootGoogle = TrackRoot.factory({
227
+ onEvent: (name, params) => gtag('event', name, params),
228
+ filter: (name) => name.startsWith('page_')
229
+ });
230
+
231
+ // Amplitude: track everything
232
+ const TrackRootAmplitude = TrackRoot.factory({
233
+ onEvent: (name, params) => amplitude.logEvent(name, params),
234
+ });
129
235
  ```
130
236
 
131
237
  Compose them in your app:
@@ -142,16 +248,15 @@ const App = () => (
142
248
 
143
249
  ### Transforming Events
144
250
 
145
- You can modify the event name or parameters before they reach the handler using the `transform` prop (or the third argument in `factory`).
251
+ You can modify the event name or parameters before they are sent to the handler using the `transform` prop in `factory`.
146
252
 
147
253
  Note: Transformations apply locally and do not affect the event bubbling up to parent providers.
148
254
 
149
255
  ```tsx
150
256
  // GDPR Tracker
151
- const AmpltitudeUS = TrackRoot.factory(
152
- (name, params) => amplitude.logEvent(name, params),
153
- undefined, // no filter
154
- (name, params) => {
257
+ const AmplitudeUS = TrackRoot.factory({
258
+ onEvent: (name, params) => amplitude.logEvent(name, params),
259
+ transform: (name, params) => {
155
260
  if (params?.userRegion === 'EU') {
156
261
  // Remove PII (Personally Identifiable Information)
157
262
  const { userId, email, ...safeParams } = params;
@@ -162,7 +267,7 @@ const AmpltitudeUS = TrackRoot.factory(
162
267
  }
163
268
  return { eventName: name, params };
164
269
  }
165
- );
270
+ });
166
271
  ```
167
272
 
168
273
  ### 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,36 @@ 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(_, __, [params]) {
167
+ const eventName = path.join(".");
168
+ track(eventName, params);
169
+ }
170
+ });
171
+ }
172
+
173
+ function createReactEventTrackingHook() {
174
+ function useTracking(scope) {
175
+ const ctx = useReactEventTracking();
176
+ const tracker = React.useMemo(() => {
177
+ const prefix = scope ? [String(scope)] : [];
178
+ return {
179
+ ...ctx,
180
+ track: createTracker(prefix, ctx.track)
181
+ };
182
+ }, [ctx, scope]);
183
+ return tracker;
184
+ }
185
+ return useTracking;
186
+ }
187
+
128
188
  exports.TrackProvider = TrackProvider;
129
189
  exports.TrackRoot = TrackRoot;
190
+ exports.createReactEventTrackingHook = createReactEventTrackingHook;
130
191
  exports.useMountEvent = useMountEvent;
131
192
  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 : 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 : 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 : 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,32 @@ 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(_, __, [params]) {
161
+ const eventName = path.join(".");
162
+ track(eventName, params);
163
+ }
164
+ });
165
+ }
166
+
167
+ function createReactEventTrackingHook() {
168
+ function useTracking(scope) {
169
+ const ctx = useReactEventTracking();
170
+ const tracker = useMemo(() => {
171
+ const prefix = scope ? [String(scope)] : [];
172
+ return {
173
+ ...ctx,
174
+ track: createTracker(prefix, ctx.track)
175
+ };
176
+ }, [ctx, scope]);
177
+ return tracker;
178
+ }
179
+ return useTracking;
180
+ }
181
+
182
+ 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.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],