react-fathom 0.1.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.
Files changed (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +199 -0
  3. package/dist/cjs/index.cjs +410 -0
  4. package/dist/cjs/index.cjs.map +1 -0
  5. package/dist/cjs/next/index.cjs +910 -0
  6. package/dist/cjs/next/index.cjs.map +1 -0
  7. package/dist/es/index.js +381 -0
  8. package/dist/es/index.js.map +1 -0
  9. package/dist/es/next/index.js +885 -0
  10. package/dist/es/next/index.js.map +1 -0
  11. package/dist/react-fathom.js +413 -0
  12. package/dist/react-fathom.js.map +1 -0
  13. package/dist/react-fathom.min.js +3 -0
  14. package/dist/react-fathom.min.js.map +1 -0
  15. package/package.json +127 -0
  16. package/src/FathomContext.tsx +5 -0
  17. package/src/FathomProvider.test.tsx +532 -0
  18. package/src/FathomProvider.tsx +122 -0
  19. package/src/components/TrackClick.test.tsx +191 -0
  20. package/src/components/TrackClick.tsx +62 -0
  21. package/src/components/TrackPageview.test.tsx +111 -0
  22. package/src/components/TrackPageview.tsx +36 -0
  23. package/src/components/TrackVisible.test.tsx +311 -0
  24. package/src/components/TrackVisible.tsx +105 -0
  25. package/src/components/index.ts +3 -0
  26. package/src/hooks/index.ts +4 -0
  27. package/src/hooks/useFathom.test.tsx +51 -0
  28. package/src/hooks/useFathom.ts +11 -0
  29. package/src/hooks/useTrackOnClick.test.tsx +197 -0
  30. package/src/hooks/useTrackOnClick.ts +65 -0
  31. package/src/hooks/useTrackOnMount.test.tsx +79 -0
  32. package/src/hooks/useTrackOnMount.ts +24 -0
  33. package/src/hooks/useTrackOnVisible.test.tsx +313 -0
  34. package/src/hooks/useTrackOnVisible.ts +99 -0
  35. package/src/index.ts +4 -0
  36. package/src/next/NextFathomProvider.test.tsx +131 -0
  37. package/src/next/NextFathomProvider.tsx +62 -0
  38. package/src/next/NextFathomProviderApp.test.tsx +308 -0
  39. package/src/next/NextFathomProviderApp.tsx +106 -0
  40. package/src/next/NextFathomProviderPages.test.tsx +330 -0
  41. package/src/next/NextFathomProviderPages.tsx +112 -0
  42. package/src/next/compositions/withAppRouter.test.tsx +113 -0
  43. package/src/next/compositions/withAppRouter.tsx +48 -0
  44. package/src/next/compositions/withPagesRouter.test.tsx +113 -0
  45. package/src/next/compositions/withPagesRouter.tsx +44 -0
  46. package/src/next/index.ts +7 -0
  47. package/src/next/types.ts +19 -0
  48. package/src/types.ts +37 -0
  49. package/types/FathomContext.d.ts +3 -0
  50. package/types/FathomContext.d.ts.map +1 -0
  51. package/types/FathomProvider.d.ts +5 -0
  52. package/types/FathomProvider.d.ts.map +1 -0
  53. package/types/components/TrackClick.d.ts +39 -0
  54. package/types/components/TrackClick.d.ts.map +1 -0
  55. package/types/components/TrackPageview.d.ts +21 -0
  56. package/types/components/TrackPageview.d.ts.map +1 -0
  57. package/types/components/TrackVisible.d.ts +39 -0
  58. package/types/components/TrackVisible.d.ts.map +1 -0
  59. package/types/components/index.d.ts +4 -0
  60. package/types/components/index.d.ts.map +1 -0
  61. package/types/hooks/index.d.ts +5 -0
  62. package/types/hooks/index.d.ts.map +1 -0
  63. package/types/hooks/useFathom.d.ts +6 -0
  64. package/types/hooks/useFathom.d.ts.map +1 -0
  65. package/types/hooks/useTrackOnClick.d.ts +39 -0
  66. package/types/hooks/useTrackOnClick.d.ts.map +1 -0
  67. package/types/hooks/useTrackOnMount.d.ts +14 -0
  68. package/types/hooks/useTrackOnMount.d.ts.map +1 -0
  69. package/types/hooks/useTrackOnVisible.d.ts +43 -0
  70. package/types/hooks/useTrackOnVisible.d.ts.map +1 -0
  71. package/types/index.d.ts +5 -0
  72. package/types/index.d.ts.map +1 -0
  73. package/types/next/AppRouterProvider.d.ts +7 -0
  74. package/types/next/AppRouterProvider.d.ts.map +1 -0
  75. package/types/next/NextFathomProvider.d.ts +34 -0
  76. package/types/next/NextFathomProvider.d.ts.map +1 -0
  77. package/types/next/NextFathomProviderApp.d.ts +6 -0
  78. package/types/next/NextFathomProviderApp.d.ts.map +1 -0
  79. package/types/next/NextFathomProviderPages.d.ts +6 -0
  80. package/types/next/NextFathomProviderPages.d.ts.map +1 -0
  81. package/types/next/PagesRouterProvider.d.ts +7 -0
  82. package/types/next/PagesRouterProvider.d.ts.map +1 -0
  83. package/types/next/compositions/withAppRouter.d.ts +29 -0
  84. package/types/next/compositions/withAppRouter.d.ts.map +1 -0
  85. package/types/next/compositions/withPagesRouter.d.ts +25 -0
  86. package/types/next/compositions/withPagesRouter.d.ts.map +1 -0
  87. package/types/next/index.d.ts +6 -0
  88. package/types/next/index.d.ts.map +1 -0
  89. package/types/next/types.d.ts +16 -0
  90. package/types/next/types.d.ts.map +1 -0
  91. package/types/test-setup.d.ts +2 -0
  92. package/types/test-setup.d.ts.map +1 -0
  93. package/types/types.d.ts +34 -0
  94. package/types/types.d.ts.map +1 -0
  95. package/types/useFathom.d.ts +7 -0
  96. package/types/useFathom.d.ts.map +1 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ryan Hefner, Commune Software
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,199 @@
1
+ # 😻 react-fathom
2
+
3
+ Easily compose Fathom Analytics into your React/Next.js apps with automatic pageview tracking and full TypeScript support.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Zero-config** Fathom Analytics integration for React
8
+ - 📦 **Tree-shakeable** - Only bundle what you use
9
+ - 🔄 **Automatic pageview tracking** for Next.js (Pages Router & App Router)
10
+ - 💪 **Full TypeScript** support with type definitions
11
+ - 🎯 **Flexible** - Works with any React app or Next.js
12
+ - ⚡ **Lightweight** - Minimal bundle size impact
13
+
14
+ ## Install
15
+
16
+ Via [npm](https://npmjs.com/package/react-fathom)
17
+
18
+ ```sh
19
+ npm install react-fathom fathom-client
20
+ ```
21
+
22
+ Via [Yarn](https://yarn.pm/react-fathom)
23
+
24
+ ```sh
25
+ yarn add react-fathom fathom-client
26
+ ```
27
+
28
+ ## Peer Dependencies
29
+
30
+ - `react` >= 16.8
31
+ - `react-dom` >= 16.8
32
+ - `fathom-client` >= 3.0.0
33
+ - `next` >= 10.0.0 (only if using Next.js providers)
34
+
35
+ ## Usage
36
+
37
+ ### Basic React Setup
38
+
39
+ Wrap your app with `FathomProvider`:
40
+
41
+ ```tsx
42
+ import { FathomProvider } from 'react-fathom'
43
+
44
+ function App() {
45
+ return <FathomProvider siteId="YOUR_SITE_ID">{/* Your app */}</FathomProvider>
46
+ }
47
+ ```
48
+
49
+ ### Using the Hook
50
+
51
+ Access Fathom methods via the `useFathom` hook:
52
+
53
+ ```tsx
54
+ import { useFathom } from 'react-fathom'
55
+
56
+ function MyComponent() {
57
+ const { trackPageview, trackEvent, load } = useFathom()
58
+
59
+ const handleClick = () => {
60
+ trackEvent?.('button-click', { id: 'signup-button' })
61
+ }
62
+
63
+ return <button onClick={handleClick}>Sign Up</button>
64
+ }
65
+ ```
66
+
67
+ ### Next.js Pages Router
68
+
69
+ Use `PagesRouterProvider` for automatic route tracking:
70
+
71
+ ```tsx
72
+ // pages/_app.tsx
73
+ import { PagesRouterProvider } from 'react-fathom/next'
74
+
75
+ function MyApp({ Component, pageProps }) {
76
+ return (
77
+ <PagesRouterProvider siteId="YOUR_SITE_ID">
78
+ <Component {...pageProps} />
79
+ </PagesRouterProvider>
80
+ )
81
+ }
82
+
83
+ export default MyApp
84
+ ```
85
+
86
+ Or use the HOC:
87
+
88
+ ```tsx
89
+ // pages/_app.tsx
90
+ import { withPagesRouter } from 'react-fathom/next'
91
+
92
+ function MyApp({ Component, pageProps }) {
93
+ return <Component {...pageProps} />
94
+ }
95
+
96
+ export default withPagesRouter(MyApp, {
97
+ siteId: 'YOUR_SITE_ID',
98
+ clientOptions: {
99
+ spa: 'auto',
100
+ },
101
+ })
102
+ ```
103
+
104
+ ### Next.js App Router
105
+
106
+ Use `AppRouterProvider` for automatic route tracking:
107
+
108
+ ```tsx
109
+ // app/layout.tsx
110
+ import { AppRouterProvider } from 'react-fathom/next'
111
+
112
+ export default function RootLayout({ children }) {
113
+ return (
114
+ <html>
115
+ <body>
116
+ <AppRouterProvider siteId="YOUR_SITE_ID">{children}</AppRouterProvider>
117
+ </body>
118
+ </html>
119
+ )
120
+ }
121
+ ```
122
+
123
+ Or use the HOC:
124
+
125
+ ```tsx
126
+ // app/layout.tsx
127
+ import { withAppRouter } from 'react-fathom/next'
128
+
129
+ function RootLayout({ children }) {
130
+ return (
131
+ <html>
132
+ <body>{children}</body>
133
+ </html>
134
+ )
135
+ }
136
+
137
+ export default withAppRouter(RootLayout, {
138
+ siteId: 'YOUR_SITE_ID',
139
+ clientOptions: {
140
+ spa: 'auto',
141
+ },
142
+ })
143
+ ```
144
+
145
+ ## API
146
+
147
+ ### `FathomProvider`
148
+
149
+ Main provider component for React apps.
150
+
151
+ **Props:**
152
+
153
+ - `siteId` (string, required): Your Fathom Analytics site ID
154
+ - `client` (FathomClient, optional): Custom Fathom client instance
155
+ - `clientOptions` (LoadOptions, optional): Options passed to `fathom-client`
156
+ - `disableDefaultTrack` (boolean, optional): Disable automatic pageview tracking
157
+ - `trackDefaultOptions` (PageViewOptions, optional): Default options for pageview tracking
158
+
159
+ ### `PagesRouterProvider` / `AppRouterProvider`
160
+
161
+ Next.js-specific providers with automatic route tracking.
162
+
163
+ **Props:**
164
+
165
+ - All `FathomProvider` props, plus:
166
+ - `disableAutoTrack` (boolean, optional): Disable automatic pageview tracking on route changes
167
+ - `trackDefaultOptions` (PageViewOptions, optional): Default options for route change pageviews
168
+
169
+ ### `useFathom()`
170
+
171
+ Hook to access Fathom methods.
172
+
173
+ **Returns:**
174
+
175
+ - `trackPageview(options?)`: Track a pageview
176
+ - `trackEvent(eventName, options?)`: Track a custom event
177
+ - `load(siteId, options?)`: Load Fathom with a site ID
178
+ - `setSite(siteId)`: Change the site ID
179
+ - `blockTrackingForMe()`: Block tracking for current user
180
+ - `enableTrackingForMe()`: Enable tracking for current user
181
+ - `isTrackingEnabled()`: Check if tracking is enabled
182
+
183
+ ## Tree-shaking
184
+
185
+ This library is optimized for tree-shaking. When you import only what you need:
186
+
187
+ ```tsx
188
+ import { useFathom } from 'react-fathom'
189
+ ```
190
+
191
+ Bundlers will automatically exclude unused code, keeping your bundle size minimal.
192
+
193
+ ## TypeScript
194
+
195
+ Full TypeScript support is included. Types are automatically generated and exported.
196
+
197
+ ## License
198
+
199
+ [MIT](LICENSE) © [Ryan Hefner](https://www.ryanhefner.com)
@@ -0,0 +1,410 @@
1
+ /*! react-fathom - 0.1.0 !*/
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+ var Fathom = require('fathom-client');
6
+
7
+ function _interopNamespaceDefault(e) {
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+
24
+ var Fathom__namespace = /*#__PURE__*/_interopNamespaceDefault(Fathom);
25
+
26
+ var FathomContext = /*#__PURE__*/React.createContext({});
27
+
28
+ function _typeof(o) {
29
+ "@babel/helpers - typeof";
30
+
31
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
32
+ return typeof o;
33
+ } : function (o) {
34
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
35
+ }, _typeof(o);
36
+ }
37
+
38
+ function toPrimitive(t, r) {
39
+ if ("object" != _typeof(t) || !t) return t;
40
+ var e = t[Symbol.toPrimitive];
41
+ if (void 0 !== e) {
42
+ var i = e.call(t, r);
43
+ if ("object" != _typeof(i)) return i;
44
+ throw new TypeError("@@toPrimitive must return a primitive value.");
45
+ }
46
+ return ("string" === r ? String : Number)(t);
47
+ }
48
+
49
+ function toPropertyKey(t) {
50
+ var i = toPrimitive(t, "string");
51
+ return "symbol" == _typeof(i) ? i : i + "";
52
+ }
53
+
54
+ function _defineProperty(e, r, t) {
55
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
56
+ value: t,
57
+ enumerable: true,
58
+ configurable: true,
59
+ writable: true
60
+ }) : e[r] = t, e;
61
+ }
62
+
63
+ function ownKeys$2(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
64
+ function _objectSpread$2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$2(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$2(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
65
+ var FathomProvider = function FathomProvider(_ref) {
66
+ var children = _ref.children,
67
+ providedClient = _ref.client,
68
+ clientOptions = _ref.clientOptions;
69
+ _ref.disableDefaultTrack;
70
+ var siteId = _ref.siteId,
71
+ providedDefaultPageviewOptions = _ref.defaultPageviewOptions,
72
+ providedDefaultEventOptions = _ref.defaultEventOptions;
73
+ // Read parent context if it exists
74
+ var parentContext = React.useContext(FathomContext);
75
+
76
+ // Use provided client or fall back to parent client or default Fathom
77
+ var client = React.useMemo(function () {
78
+ var _ref2;
79
+ return (_ref2 = providedClient !== null && providedClient !== void 0 ? providedClient : parentContext.client) !== null && _ref2 !== void 0 ? _ref2 : Fathom__namespace;
80
+ }, [providedClient, parentContext.client]);
81
+
82
+ // Merge defaultPageviewOptions: provided > parent > undefined
83
+ var defaultPageviewOptions = React.useMemo(function () {
84
+ return providedDefaultPageviewOptions !== null && providedDefaultPageviewOptions !== void 0 ? providedDefaultPageviewOptions : parentContext.defaultPageviewOptions;
85
+ }, [providedDefaultPageviewOptions, parentContext.defaultPageviewOptions]);
86
+
87
+ // Merge defaultEventOptions: provided > parent > undefined
88
+ var defaultEventOptions = React.useMemo(function () {
89
+ return providedDefaultEventOptions !== null && providedDefaultEventOptions !== void 0 ? providedDefaultEventOptions : parentContext.defaultEventOptions;
90
+ }, [providedDefaultEventOptions, parentContext.defaultEventOptions]);
91
+ var blockTrackingForMe = React.useCallback(function () {
92
+ client.blockTrackingForMe();
93
+ }, [client]);
94
+ var enableTrackingForMe = React.useCallback(function () {
95
+ client.enableTrackingForMe();
96
+ }, [client]);
97
+ var isTrackingEnabled = React.useCallback(function () {
98
+ var _client$isTrackingEna;
99
+ return (_client$isTrackingEna = client.isTrackingEnabled()) !== null && _client$isTrackingEna !== void 0 ? _client$isTrackingEna : false;
100
+ }, [client]);
101
+ var load = React.useCallback(function (siteId, clientOptions) {
102
+ client.load(siteId, clientOptions);
103
+ }, [client]);
104
+ var setSite = React.useCallback(function (siteId) {
105
+ client.setSite(siteId);
106
+ }, [client]);
107
+ var trackEvent = React.useCallback(function (category, options) {
108
+ client.trackEvent(category, _objectSpread$2(_objectSpread$2({}, defaultEventOptions), options));
109
+ }, [client, defaultEventOptions]);
110
+ var trackPageview = React.useCallback(function (options) {
111
+ client.trackPageview(_objectSpread$2(_objectSpread$2({}, defaultPageviewOptions), options));
112
+ }, [client, defaultPageviewOptions]);
113
+ var trackGoal = React.useCallback(function (code, cents) {
114
+ client.trackGoal(code, cents);
115
+ }, [client]);
116
+ React.useEffect(function () {
117
+ if (siteId !== undefined) {
118
+ load(siteId, clientOptions);
119
+ }
120
+ }, [clientOptions, load, siteId]);
121
+ return /*#__PURE__*/React.createElement(FathomContext.Provider, {
122
+ value: {
123
+ blockTrackingForMe: blockTrackingForMe,
124
+ enableTrackingForMe: enableTrackingForMe,
125
+ isTrackingEnabled: isTrackingEnabled,
126
+ load: load,
127
+ setSite: setSite,
128
+ trackEvent: trackEvent,
129
+ trackGoal: trackGoal,
130
+ trackPageview: trackPageview,
131
+ client: client,
132
+ defaultPageviewOptions: defaultPageviewOptions,
133
+ defaultEventOptions: defaultEventOptions
134
+ }
135
+ }, children);
136
+ };
137
+ FathomProvider.displayName = 'FathomProvider';
138
+
139
+ var useFathom = function useFathom() {
140
+ var context = React.useContext(FathomContext);
141
+ return context;
142
+ };
143
+ useFathom.displayName = 'useFathom';
144
+
145
+ /**
146
+ * Hook to track a pageview when a component mounts
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * function MyComponent() {
151
+ * useTrackOnMount({ url: '/custom-page' })
152
+ * return <div>Content</div>
153
+ * }
154
+ * ```
155
+ */
156
+ var useTrackOnMount = function useTrackOnMount(options) {
157
+ var _useFathom = useFathom(),
158
+ trackPageview = _useFathom.trackPageview;
159
+ React.useEffect(function () {
160
+ trackPageview === null || trackPageview === void 0 || trackPageview(options);
161
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
162
+ };
163
+
164
+ function _objectWithoutPropertiesLoose(r, e) {
165
+ if (null == r) return {};
166
+ var t = {};
167
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
168
+ if (-1 !== e.indexOf(n)) continue;
169
+ t[n] = r[n];
170
+ }
171
+ return t;
172
+ }
173
+
174
+ function _objectWithoutProperties(e, t) {
175
+ if (null == e) return {};
176
+ var o,
177
+ r,
178
+ i = _objectWithoutPropertiesLoose(e, t);
179
+ if (Object.getOwnPropertySymbols) {
180
+ var n = Object.getOwnPropertySymbols(e);
181
+ for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
182
+ }
183
+ return i;
184
+ }
185
+
186
+ var _excluded$4 = ["eventName", "preventDefault", "callback"];
187
+ /**
188
+ * Hook that returns a click handler function that tracks an event
189
+ *
190
+ * @example
191
+ * ```tsx
192
+ * function Button() {
193
+ * const handleClick = useTrackOnClick({
194
+ * eventName: 'button-click',
195
+ * id: 'signup-button',
196
+ * callback: (e) => {
197
+ * console.log('Button clicked!')
198
+ * // Your custom logic here
199
+ * },
200
+ * })
201
+ *
202
+ * return <button onClick={handleClick}>Sign Up</button>
203
+ * }
204
+ * ```
205
+ */
206
+ var useTrackOnClick = function useTrackOnClick(options) {
207
+ var _useFathom = useFathom(),
208
+ trackEvent = _useFathom.trackEvent;
209
+ var eventName = options.eventName,
210
+ _options$preventDefau = options.preventDefault,
211
+ preventDefault = _options$preventDefau === void 0 ? false : _options$preventDefau,
212
+ callback = options.callback,
213
+ eventOptions = _objectWithoutProperties(options, _excluded$4);
214
+ return React.useCallback(function (e) {
215
+ if (preventDefault && e) {
216
+ e.preventDefault();
217
+ }
218
+ trackEvent === null || trackEvent === void 0 || trackEvent(eventName, eventOptions);
219
+ callback === null || callback === void 0 || callback(e);
220
+ }, [eventName, preventDefault, trackEvent, eventOptions, callback]);
221
+ };
222
+
223
+ var _excluded$3 = ["eventName", "observerOptions", "trackOnce", "callback"];
224
+ function ownKeys$1(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
225
+ function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$1(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$1(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
226
+ /**
227
+ * Hook to track an event when an element becomes visible (using Intersection Observer)
228
+ *
229
+ * @example
230
+ * ```tsx
231
+ * function Section() {
232
+ * const ref = useTrackOnVisible({
233
+ * eventName: 'section-viewed',
234
+ * section: 'hero',
235
+ * callback: (entry) => {
236
+ * console.log('Section is visible!', entry.isIntersecting)
237
+ * // Your custom logic here
238
+ * },
239
+ * })
240
+ *
241
+ * return <section ref={ref}>Content</section>
242
+ * }
243
+ * ```
244
+ */
245
+ var useTrackOnVisible = function useTrackOnVisible(options) {
246
+ var _useFathom = useFathom(),
247
+ trackEvent = _useFathom.trackEvent;
248
+ var eventName = options.eventName,
249
+ observerOptions = options.observerOptions,
250
+ _options$trackOnce = options.trackOnce,
251
+ trackOnce = _options$trackOnce === void 0 ? true : _options$trackOnce,
252
+ callback = options.callback,
253
+ eventOptions = _objectWithoutProperties(options, _excluded$3);
254
+ var ref = React.useRef(null);
255
+ var hasTracked = React.useRef(false);
256
+ React.useEffect(function () {
257
+ var element = ref.current;
258
+ if (!element) return;
259
+ var observer = new IntersectionObserver(function (entries) {
260
+ entries.forEach(function (entry) {
261
+ if (entry.isIntersecting) {
262
+ if (!trackOnce || !hasTracked.current) {
263
+ trackEvent === null || trackEvent === void 0 || trackEvent(eventName, eventOptions);
264
+ callback === null || callback === void 0 || callback(entry);
265
+ hasTracked.current = true;
266
+ }
267
+ }
268
+ });
269
+ }, _objectSpread$1({
270
+ threshold: 0.1
271
+ }, observerOptions));
272
+ observer.observe(element);
273
+ return function () {
274
+ observer.disconnect();
275
+ };
276
+ }, [eventName, eventOptions, observerOptions, trackOnce, trackEvent, callback]);
277
+ return ref;
278
+ };
279
+
280
+ var _excluded$2 = ["eventName", "children", "preventDefault", "onClick", "as"];
281
+ /**
282
+ * Component wrapper that automatically tracks clicks on its children
283
+ *
284
+ * @example
285
+ * ```tsx
286
+ * <TrackClick eventName="cta-clicked" id="hero-cta">
287
+ * <button>Get Started</button>
288
+ * </TrackClick>
289
+ * ```
290
+ */
291
+ var TrackClick = function TrackClick(_ref) {
292
+ var eventName = _ref.eventName,
293
+ children = _ref.children,
294
+ _ref$preventDefault = _ref.preventDefault,
295
+ preventDefault = _ref$preventDefault === void 0 ? false : _ref$preventDefault,
296
+ onClick = _ref.onClick,
297
+ _ref$as = _ref.as,
298
+ Component = _ref$as === void 0 ? 'div' : _ref$as,
299
+ eventOptions = _objectWithoutProperties(_ref, _excluded$2);
300
+ var _useFathom = useFathom(),
301
+ trackEvent = _useFathom.trackEvent;
302
+ var handleClick = function handleClick(e) {
303
+ if (preventDefault) {
304
+ e.preventDefault();
305
+ }
306
+ onClick === null || onClick === void 0 || onClick(e);
307
+ trackEvent === null || trackEvent === void 0 || trackEvent(eventName, eventOptions);
308
+ };
309
+ return /*#__PURE__*/React.createElement(Component, {
310
+ onClick: handleClick
311
+ }, children);
312
+ };
313
+
314
+ var _excluded$1 = ["children"];
315
+ /**
316
+ * Component that tracks a pageview when it mounts
317
+ *
318
+ * @example
319
+ * ```tsx
320
+ * <TrackPageview url="/custom-page">
321
+ * <div>Page content</div>
322
+ * </TrackPageview>
323
+ * ```
324
+ */
325
+ var TrackPageview = function TrackPageview(_ref) {
326
+ var children = _ref.children,
327
+ pageviewOptions = _objectWithoutProperties(_ref, _excluded$1);
328
+ var _useFathom = useFathom(),
329
+ trackPageview = _useFathom.trackPageview;
330
+ React.useEffect(function () {
331
+ trackPageview === null || trackPageview === void 0 || trackPageview(pageviewOptions);
332
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
333
+
334
+ return /*#__PURE__*/React.createElement(React.Fragment, null, children);
335
+ };
336
+
337
+ var _excluded = ["eventName", "children", "observerOptions", "trackOnce", "as"];
338
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
339
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), true).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
340
+ /**
341
+ * Component that tracks an event when it becomes visible in the viewport
342
+ *
343
+ * @example
344
+ * ```tsx
345
+ * <TrackVisible eventName="section-viewed" section="hero">
346
+ * <HeroSection />
347
+ * </TrackVisible>
348
+ * ```
349
+ */
350
+ var TrackVisible = /*#__PURE__*/React.forwardRef(function TrackVisible(_ref, forwardedRef) {
351
+ var eventName = _ref.eventName,
352
+ children = _ref.children,
353
+ observerOptions = _ref.observerOptions,
354
+ _ref$trackOnce = _ref.trackOnce,
355
+ trackOnce = _ref$trackOnce === void 0 ? true : _ref$trackOnce,
356
+ _ref$as = _ref.as,
357
+ Component = _ref$as === void 0 ? 'div' : _ref$as,
358
+ eventOptions = _objectWithoutProperties(_ref, _excluded);
359
+ var _useFathom = useFathom(),
360
+ trackEvent = _useFathom.trackEvent;
361
+ var internalRef = React.useRef(null);
362
+ var hasTracked = React.useRef(false);
363
+
364
+ // Callback ref that handles both forwarded and internal refs
365
+ var setRef = React.useCallback(function (node) {
366
+ internalRef.current = node;
367
+ if (typeof forwardedRef === 'function') {
368
+ forwardedRef(node);
369
+ } else if (forwardedRef !== null && forwardedRef !== undefined) {
370
+ forwardedRef.current = node;
371
+ }
372
+ }, [forwardedRef]);
373
+ React.useEffect(function () {
374
+ var element = internalRef.current;
375
+ if (element === null) {
376
+ return;
377
+ }
378
+ var observer = new IntersectionObserver(function (entries) {
379
+ entries.forEach(function (entry) {
380
+ if (entry.isIntersecting) {
381
+ if (!trackOnce || !hasTracked.current) {
382
+ trackEvent === null || trackEvent === void 0 || trackEvent(eventName, eventOptions);
383
+ hasTracked.current = true;
384
+ }
385
+ }
386
+ });
387
+ }, _objectSpread({
388
+ threshold: 0.1
389
+ }, observerOptions));
390
+ observer.observe(element);
391
+ return function () {
392
+ observer.disconnect();
393
+ };
394
+ }, [eventName, eventOptions, observerOptions, trackOnce, trackEvent]);
395
+ return /*#__PURE__*/React.createElement(Component, {
396
+ ref: setRef
397
+ }, children);
398
+ });
399
+
400
+ exports.FathomContext = FathomContext;
401
+ exports.FathomProvider = FathomProvider;
402
+ exports.TrackClick = TrackClick;
403
+ exports.TrackPageview = TrackPageview;
404
+ exports.TrackVisible = TrackVisible;
405
+ exports.useFathom = useFathom;
406
+ exports.useTrackOnClick = useTrackOnClick;
407
+ exports.useTrackOnMount = useTrackOnMount;
408
+ exports.useTrackOnVisible = useTrackOnVisible;
409
+ /* Copyright 2025 - Ryan Hefner <hi@ryanhefner.com> (https://www.ryanhefner.com) */
410
+ //# sourceMappingURL=index.cjs.map