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.
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/dist/cjs/index.cjs +410 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/next/index.cjs +910 -0
- package/dist/cjs/next/index.cjs.map +1 -0
- package/dist/es/index.js +381 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/next/index.js +885 -0
- package/dist/es/next/index.js.map +1 -0
- package/dist/react-fathom.js +413 -0
- package/dist/react-fathom.js.map +1 -0
- package/dist/react-fathom.min.js +3 -0
- package/dist/react-fathom.min.js.map +1 -0
- package/package.json +127 -0
- package/src/FathomContext.tsx +5 -0
- package/src/FathomProvider.test.tsx +532 -0
- package/src/FathomProvider.tsx +122 -0
- package/src/components/TrackClick.test.tsx +191 -0
- package/src/components/TrackClick.tsx +62 -0
- package/src/components/TrackPageview.test.tsx +111 -0
- package/src/components/TrackPageview.tsx +36 -0
- package/src/components/TrackVisible.test.tsx +311 -0
- package/src/components/TrackVisible.tsx +105 -0
- package/src/components/index.ts +3 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useFathom.test.tsx +51 -0
- package/src/hooks/useFathom.ts +11 -0
- package/src/hooks/useTrackOnClick.test.tsx +197 -0
- package/src/hooks/useTrackOnClick.ts +65 -0
- package/src/hooks/useTrackOnMount.test.tsx +79 -0
- package/src/hooks/useTrackOnMount.ts +24 -0
- package/src/hooks/useTrackOnVisible.test.tsx +313 -0
- package/src/hooks/useTrackOnVisible.ts +99 -0
- package/src/index.ts +4 -0
- package/src/next/NextFathomProvider.test.tsx +131 -0
- package/src/next/NextFathomProvider.tsx +62 -0
- package/src/next/NextFathomProviderApp.test.tsx +308 -0
- package/src/next/NextFathomProviderApp.tsx +106 -0
- package/src/next/NextFathomProviderPages.test.tsx +330 -0
- package/src/next/NextFathomProviderPages.tsx +112 -0
- package/src/next/compositions/withAppRouter.test.tsx +113 -0
- package/src/next/compositions/withAppRouter.tsx +48 -0
- package/src/next/compositions/withPagesRouter.test.tsx +113 -0
- package/src/next/compositions/withPagesRouter.tsx +44 -0
- package/src/next/index.ts +7 -0
- package/src/next/types.ts +19 -0
- package/src/types.ts +37 -0
- package/types/FathomContext.d.ts +3 -0
- package/types/FathomContext.d.ts.map +1 -0
- package/types/FathomProvider.d.ts +5 -0
- package/types/FathomProvider.d.ts.map +1 -0
- package/types/components/TrackClick.d.ts +39 -0
- package/types/components/TrackClick.d.ts.map +1 -0
- package/types/components/TrackPageview.d.ts +21 -0
- package/types/components/TrackPageview.d.ts.map +1 -0
- package/types/components/TrackVisible.d.ts +39 -0
- package/types/components/TrackVisible.d.ts.map +1 -0
- package/types/components/index.d.ts +4 -0
- package/types/components/index.d.ts.map +1 -0
- package/types/hooks/index.d.ts +5 -0
- package/types/hooks/index.d.ts.map +1 -0
- package/types/hooks/useFathom.d.ts +6 -0
- package/types/hooks/useFathom.d.ts.map +1 -0
- package/types/hooks/useTrackOnClick.d.ts +39 -0
- package/types/hooks/useTrackOnClick.d.ts.map +1 -0
- package/types/hooks/useTrackOnMount.d.ts +14 -0
- package/types/hooks/useTrackOnMount.d.ts.map +1 -0
- package/types/hooks/useTrackOnVisible.d.ts +43 -0
- package/types/hooks/useTrackOnVisible.d.ts.map +1 -0
- package/types/index.d.ts +5 -0
- package/types/index.d.ts.map +1 -0
- package/types/next/AppRouterProvider.d.ts +7 -0
- package/types/next/AppRouterProvider.d.ts.map +1 -0
- package/types/next/NextFathomProvider.d.ts +34 -0
- package/types/next/NextFathomProvider.d.ts.map +1 -0
- package/types/next/NextFathomProviderApp.d.ts +6 -0
- package/types/next/NextFathomProviderApp.d.ts.map +1 -0
- package/types/next/NextFathomProviderPages.d.ts +6 -0
- package/types/next/NextFathomProviderPages.d.ts.map +1 -0
- package/types/next/PagesRouterProvider.d.ts +7 -0
- package/types/next/PagesRouterProvider.d.ts.map +1 -0
- package/types/next/compositions/withAppRouter.d.ts +29 -0
- package/types/next/compositions/withAppRouter.d.ts.map +1 -0
- package/types/next/compositions/withPagesRouter.d.ts +25 -0
- package/types/next/compositions/withPagesRouter.d.ts.map +1 -0
- package/types/next/index.d.ts +6 -0
- package/types/next/index.d.ts.map +1 -0
- package/types/next/types.d.ts +16 -0
- package/types/next/types.d.ts.map +1 -0
- package/types/test-setup.d.ts +2 -0
- package/types/test-setup.d.ts.map +1 -0
- package/types/types.d.ts +34 -0
- package/types/types.d.ts.map +1 -0
- package/types/useFathom.d.ts +7 -0
- 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
|