react-visibility-hooks 1.0.13 â 3.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 +376 -87
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +147 -1
- package/dist/index.d.ts +147 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
# react-visibility-hooks
|
|
2
2
|
|
|
3
|
-
> Tiny, SSR-safe React hooks for page visibility, idle detection, smart polling and
|
|
3
|
+
> Tiny, SSR-safe React hooks for page visibility, idle detection, smart polling, network awareness, wake lock, battery status and more
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/react-visibility-hooks)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
[](https://bundlephobia.com/package/react-visibility-hooks)
|
|
8
8
|
[](https://github.com/exewhyz/react-visibility-hooks/actions/workflows/ci.yml)
|
|
9
9
|
|
|
10
|
-
A collection of lightweight React hooks that help you build performance-conscious applications
|
|
10
|
+
A collection of lightweight React hooks that help you build performance-conscious, resource-aware applications. Detect page visibility, user idle state, network conditions, battery status, and more â with zero dependencies.
|
|
11
11
|
|
|
12
12
|
## Features
|
|
13
13
|
|
|
14
|
-
- ðŠķ **Lightweight**
|
|
15
|
-
- ð **SSR-safe**
|
|
16
|
-
- ðĶ **Tree-shakeable**
|
|
17
|
-
- ðŊ **TypeScript**
|
|
18
|
-
- ⥠**Performance-focused**
|
|
19
|
-
- ðŽ **Auto-pause video**
|
|
20
|
-
- ð **Smart polling**
|
|
14
|
+
- ðŠķ **Lightweight** â Zero dependencies, tree-shakeable
|
|
15
|
+
- ð **SSR-safe** â Works with Next.js (App & Pages Router), Remix, Gatsby, and all SSR frameworks
|
|
16
|
+
- ðĶ **Tree-shakeable** â Import only what you need
|
|
17
|
+
- ðŊ **TypeScript** â Fully typed with exported interfaces
|
|
18
|
+
- ⥠**Performance-focused** â Pause expensive operations when users aren't looking
|
|
19
|
+
- ðŽ **Auto-pause video** â Pause/resume `<video>` elements on tab visibility
|
|
20
|
+
- ð **Smart polling** â Visibility-aware data fetching with dedup
|
|
21
|
+
- ð **Network-aware** â Adapt to online/offline state and connection quality
|
|
22
|
+
- ð **Battery-aware** â React to device battery level and charging state
|
|
23
|
+
- ðą **Wake Lock** â Prevent screen dimming during critical tasks
|
|
24
|
+
- âąïļ **Inactivity timeout** â Session management with warning countdowns
|
|
25
|
+
- ð **Focus transitions** â Declarative callbacks on tab show/hide
|
|
21
26
|
|
|
22
27
|
## Installation
|
|
23
28
|
|
|
@@ -25,17 +30,32 @@ A collection of lightweight React hooks that help you build performance-consciou
|
|
|
25
30
|
npm install react-visibility-hooks
|
|
26
31
|
```
|
|
27
32
|
|
|
33
|
+
```bash
|
|
34
|
+
yarn add react-visibility-hooks
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pnpm add react-visibility-hooks
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick Start
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import {
|
|
45
|
+
useDocVisible,
|
|
46
|
+
useSmartPolling,
|
|
47
|
+
useNetworkAwarePolling,
|
|
48
|
+
usePageFocusEffect,
|
|
49
|
+
} from 'react-visibility-hooks';
|
|
50
|
+
```
|
|
51
|
+
|
|
28
52
|
## Hooks
|
|
29
53
|
|
|
30
54
|
### `useDocVisible`
|
|
31
55
|
|
|
32
56
|
Detect when the browser tab is visible or hidden using the [Page Visibility API](https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API).
|
|
33
57
|
|
|
34
|
-
**Use cases:**
|
|
35
|
-
|
|
36
|
-
- Pause animations when tab is hidden
|
|
37
|
-
- Stop fetching data when user isn't viewing the page
|
|
38
|
-
- Save battery and resources
|
|
58
|
+
**Use cases:** Pause animations, stop background fetches, save battery.
|
|
39
59
|
|
|
40
60
|
```tsx
|
|
41
61
|
import { useDocVisible } from 'react-visibility-hooks';
|
|
@@ -43,29 +63,23 @@ import { useDocVisible } from 'react-visibility-hooks';
|
|
|
43
63
|
function MyComponent() {
|
|
44
64
|
const isVisible = useDocVisible();
|
|
45
65
|
|
|
46
|
-
return
|
|
47
|
-
<div>
|
|
48
|
-
Tab is currently: {isVisible ? 'visible' : 'hidden'}
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
66
|
+
return <div>Tab is currently: {isVisible ? 'visible' : 'hidden'}</div>;
|
|
51
67
|
}
|
|
52
68
|
```
|
|
53
69
|
|
|
70
|
+
---
|
|
71
|
+
|
|
54
72
|
### `useIdleVisibility`
|
|
55
73
|
|
|
56
74
|
Detect when the user is idle (no mouse, keyboard, pointer, scroll, or touch activity) combined with page visibility state.
|
|
57
75
|
|
|
58
|
-
**Use cases:**
|
|
59
|
-
|
|
60
|
-
- Show "Are you still there?" prompts
|
|
61
|
-
- Auto-pause media after inactivity
|
|
62
|
-
- Reduce background activity when user is away
|
|
76
|
+
**Use cases:** "Are you still there?" prompts, auto-pause media, reduce background activity.
|
|
63
77
|
|
|
64
78
|
```tsx
|
|
65
79
|
import { useIdleVisibility } from 'react-visibility-hooks';
|
|
66
80
|
|
|
67
81
|
function MyComponent() {
|
|
68
|
-
const { visible, idle } = useIdleVisibility(
|
|
82
|
+
const { visible, idle } = useIdleVisibility(60_000); // 60 seconds
|
|
69
83
|
|
|
70
84
|
return (
|
|
71
85
|
<div>
|
|
@@ -76,19 +90,17 @@ function MyComponent() {
|
|
|
76
90
|
}
|
|
77
91
|
```
|
|
78
92
|
|
|
79
|
-
|
|
93
|
+
| Parameter | Type | Default | Description |
|
|
94
|
+
| --------- | -------- | -------- | --------------------------------------------- |
|
|
95
|
+
| `timeout` | `number` | `60_000` | Ms of inactivity before the user is idle |
|
|
80
96
|
|
|
81
|
-
|
|
97
|
+
---
|
|
82
98
|
|
|
83
99
|
### `useAutoPauseVideo`
|
|
84
100
|
|
|
85
|
-
Automatically pause and resume
|
|
86
|
-
|
|
87
|
-
**Use cases:**
|
|
101
|
+
Automatically pause and resume `<video>` elements on tab visibility. Only resumes if the video was playing before the tab was hidden â never overrides a user's manual pause.
|
|
88
102
|
|
|
89
|
-
|
|
90
|
-
- Better UX for video-heavy applications
|
|
91
|
-
- Save bandwidth and resources
|
|
103
|
+
**Use cases:** Auto-pause videos, save bandwidth, better UX for video-heavy apps.
|
|
92
104
|
|
|
93
105
|
```tsx
|
|
94
106
|
import { useRef } from 'react';
|
|
@@ -98,36 +110,29 @@ function VideoPlayer() {
|
|
|
98
110
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
99
111
|
useAutoPauseVideo(videoRef);
|
|
100
112
|
|
|
101
|
-
return
|
|
102
|
-
<video ref={videoRef} src="video.mp4" controls />
|
|
103
|
-
);
|
|
113
|
+
return <video ref={videoRef} src="video.mp4" controls />;
|
|
104
114
|
}
|
|
105
115
|
```
|
|
106
116
|
|
|
107
|
-
|
|
117
|
+
---
|
|
108
118
|
|
|
109
|
-
|
|
119
|
+
### `useSmartPolling`
|
|
110
120
|
|
|
111
|
-
|
|
121
|
+
Visibility-aware data polling. Automatically pauses when the tab is hidden, resumes when visible, and skips re-renders when data hasn't changed.
|
|
112
122
|
|
|
113
|
-
|
|
114
|
-
- Live notifications
|
|
115
|
-
- Auto-refresh data feeds
|
|
123
|
+
**Use cases:** Real-time dashboards, live notifications, auto-refresh feeds.
|
|
116
124
|
|
|
117
125
|
```tsx
|
|
118
126
|
import { useSmartPolling } from 'react-visibility-hooks';
|
|
119
127
|
|
|
120
128
|
function Dashboard() {
|
|
121
129
|
const { data, isLoading, isError, error, refetch } = useSmartPolling(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return response.json();
|
|
125
|
-
},
|
|
126
|
-
{ interval: 3000 }
|
|
130
|
+
() => fetch('/api/stats').then((r) => r.json()),
|
|
131
|
+
{ interval: 3000 },
|
|
127
132
|
);
|
|
128
133
|
|
|
129
|
-
if (isLoading) return <
|
|
130
|
-
if (isError) return <
|
|
134
|
+
if (isLoading) return <p>LoadingâĶ</p>;
|
|
135
|
+
if (isError) return <p>Error: {error?.message}</p>;
|
|
131
136
|
|
|
132
137
|
return (
|
|
133
138
|
<div>
|
|
@@ -138,48 +143,309 @@ function Dashboard() {
|
|
|
138
143
|
}
|
|
139
144
|
```
|
|
140
145
|
|
|
141
|
-
**Options:**
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
|
145
|
-
| `
|
|
146
|
+
**Options (`SmartPollingOptions`):**
|
|
147
|
+
|
|
148
|
+
| Option | Type | Default | Description |
|
|
149
|
+
| ---------- | --------- | ------- | ------------------------- |
|
|
150
|
+
| `interval` | `number` | `5000` | Polling interval in ms |
|
|
151
|
+
| `enabled` | `boolean` | `true` | Enable / disable polling |
|
|
152
|
+
|
|
153
|
+
**Returns (`SmartPollingResult<T>`):**
|
|
154
|
+
|
|
155
|
+
| Property | Type | Description |
|
|
156
|
+
| ----------- | --------------------- | ------------------------------------- |
|
|
157
|
+
| `data` | `T \| undefined` | The latest fetched data |
|
|
158
|
+
| `isLoading` | `boolean` | `true` until the first fetch completes|
|
|
159
|
+
| `isError` | `boolean` | `true` if the last fetch threw |
|
|
160
|
+
| `error` | `Error \| undefined` | The error object, if any |
|
|
161
|
+
| `refetch` | `() => Promise<void>` | Manually trigger a fetch |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### `usePageFocusEffect` âĻ <sup>NEW</sup>
|
|
166
|
+
|
|
167
|
+
Run side-effect callbacks on visibility **transitions** â not on every render. Think of it as `useEffect` for tab show/hide.
|
|
168
|
+
|
|
169
|
+
**Use cases:** Refetch stale data on tab return, save state on tab leave, track visibility analytics.
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
import { usePageFocusEffect } from 'react-visibility-hooks';
|
|
173
|
+
|
|
174
|
+
function MyComponent() {
|
|
175
|
+
usePageFocusEffect({
|
|
176
|
+
onVisible: () => {
|
|
177
|
+
console.log('Welcome back! RefetchingâĶ');
|
|
178
|
+
refetchData();
|
|
179
|
+
return () => console.log('cleanup on next transition');
|
|
180
|
+
},
|
|
181
|
+
onHidden: () => {
|
|
182
|
+
saveScrollPosition();
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Options (`PageFocusEffectOptions`):**
|
|
189
|
+
|
|
190
|
+
| Option | Type | Description |
|
|
191
|
+
| ----------- | -------------------------------- | ---------------------------------------------------------------- |
|
|
192
|
+
| `onVisible` | `() => void \| (() => void)` | Fires on hidden â visible. May return a cleanup function. |
|
|
193
|
+
| `onHidden` | `() => void` | Fires on visible â hidden. |
|
|
194
|
+
|
|
195
|
+
> The initial render is **not** treated as a transition. Callbacks only fire on actual visibility changes.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### `useNetworkAwarePolling` âĻ <sup>NEW</sup>
|
|
200
|
+
|
|
201
|
+
Extends `useSmartPolling` with network awareness. Pauses when offline and adapts the polling interval on slow connections (2g / slow-2g).
|
|
202
|
+
|
|
203
|
+
**Use cases:** Mobile-first apps, offline-resilient dashboards, bandwidth-conscious polling.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { useNetworkAwarePolling } from 'react-visibility-hooks';
|
|
207
|
+
|
|
208
|
+
function LiveFeed() {
|
|
209
|
+
const { data, isOnline, effectiveInterval } = useNetworkAwarePolling(
|
|
210
|
+
() => fetch('/api/feed').then((r) => r.json()),
|
|
211
|
+
{ interval: 5000, slowMultiplier: 3 },
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<div>
|
|
216
|
+
<p>Status: {isOnline ? 'ðĒ Online' : 'ðī Offline'}</p>
|
|
217
|
+
<p>Polling every {effectiveInterval / 1000}s</p>
|
|
218
|
+
<pre>{JSON.stringify(data, null, 2)}</pre>
|
|
219
|
+
</div>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Options (`NetworkAwarePollingOptions`):**
|
|
225
|
+
|
|
226
|
+
| Option | Type | Default | Description |
|
|
227
|
+
| ----------------- | --------- | ------- | ----------------------------------------------- |
|
|
228
|
+
| `interval` | `number` | `5000` | Base polling interval in ms |
|
|
229
|
+
| `enabled` | `boolean` | `true` | Enable / disable polling |
|
|
230
|
+
| `slowMultiplier` | `number` | `3` | Multiplier applied on 2g/slow-2g connections |
|
|
231
|
+
| `pauseOffline` | `boolean` | `true` | Pause polling when offline |
|
|
146
232
|
|
|
147
|
-
**Returns:**
|
|
148
|
-
| Property | Type | Description |
|
|
149
|
-
|----------|------|-------------|
|
|
150
|
-
| `data` | `T \| undefined` | The latest fetched data |
|
|
151
|
-
| `isLoading` | `boolean` | `true` until the first fetch completes |
|
|
152
|
-
| `isError` | `boolean` | `true` if the last fetch threw |
|
|
153
|
-
| `error` | `Error \| undefined` | The error object, if any |
|
|
154
|
-
| `refetch` | `() => Promise<void>` | Manually trigger a fetch |
|
|
233
|
+
**Returns (`NetworkAwarePollingResult<T>`):**
|
|
155
234
|
|
|
156
|
-
|
|
235
|
+
Inherits all of `SmartPollingResult<T>` plus:
|
|
157
236
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
237
|
+
| Property | Type | Description |
|
|
238
|
+
| ------------------- | --------- | -------------------------------------------------- |
|
|
239
|
+
| `isOnline` | `boolean` | `true` when the browser reports being online |
|
|
240
|
+
| `effectiveInterval` | `number` | Actual polling interval after network adjustment |
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### `useInactivityTimeout` âĻ <sup>NEW</sup>
|
|
245
|
+
|
|
246
|
+
Countdown-based session/inactivity manager with a warning phase. Built on `useIdleVisibility`.
|
|
247
|
+
|
|
248
|
+
**Use cases:** Auto-logout, session expiry warnings, "still there?" modals.
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
import { useInactivityTimeout } from 'react-visibility-hooks';
|
|
252
|
+
|
|
253
|
+
function SessionManager() {
|
|
254
|
+
const { isWarning, isTimedOut, remainingSeconds, resetTimer } =
|
|
255
|
+
useInactivityTimeout({
|
|
256
|
+
timeout: 300_000, // 5 minutes total
|
|
257
|
+
warningBefore: 60_000, // warn 1 minute before
|
|
258
|
+
onWarning: () => showWarningToast(),
|
|
259
|
+
onTimeout: () => logout(),
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
if (isTimedOut) return <p>Session expired.</p>;
|
|
263
|
+
|
|
264
|
+
if (isWarning) {
|
|
265
|
+
return (
|
|
266
|
+
<div>
|
|
267
|
+
<p>Session expires in {remainingSeconds}s</p>
|
|
268
|
+
<button onClick={resetTimer}>Stay logged in</button>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Options (`InactivityTimeoutOptions`):**
|
|
278
|
+
|
|
279
|
+
| Option | Type | Default | Description |
|
|
280
|
+
| --------------- | ------------ | --------- | ------------------------------------------------- |
|
|
281
|
+
| `timeout` | `number` | `300_000` | Total inactivity before timeout (ms) |
|
|
282
|
+
| `warningBefore` | `number` | `60_000` | How long before timeout to start warning (ms) |
|
|
283
|
+
| `onTimeout` | `() => void` | â | Called when the full timeout elapses |
|
|
284
|
+
| `onWarning` | `() => void` | â | Called when entering the warning phase |
|
|
285
|
+
|
|
286
|
+
**Returns (`InactivityTimeoutResult`):**
|
|
287
|
+
|
|
288
|
+
| Property | Type | Description |
|
|
289
|
+
| ------------------ | ------------ | -------------------------------------------------- |
|
|
290
|
+
| `idle` | `boolean` | `true` when the user is idle |
|
|
291
|
+
| `visible` | `boolean` | Current page-visibility state |
|
|
292
|
+
| `isWarning` | `boolean` | `true` during the warning countdown |
|
|
293
|
+
| `isTimedOut` | `boolean` | `true` after the full timeout has elapsed |
|
|
294
|
+
| `remainingSeconds` | `number` | Seconds until timeout (`-1` when not idle) |
|
|
295
|
+
| `resetTimer` | `() => void` | Manually reset the timer |
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### `useWakeLock` âĻ <sup>NEW</sup>
|
|
300
|
+
|
|
301
|
+
Manage the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API) to prevent the screen from dimming or locking.
|
|
302
|
+
|
|
303
|
+
**Use cases:** Video calls, presentations, recipe/reading apps, kiosk mode.
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
import { useWakeLock } from 'react-visibility-hooks';
|
|
307
|
+
|
|
308
|
+
function PresentationMode() {
|
|
309
|
+
const { isActive, isSupported, request, release } = useWakeLock();
|
|
310
|
+
|
|
311
|
+
if (!isSupported) return <p>Wake Lock not supported</p>;
|
|
312
|
+
|
|
313
|
+
return (
|
|
314
|
+
<div>
|
|
315
|
+
<p>Screen lock prevention: {isActive ? 'ON' : 'OFF'}</p>
|
|
316
|
+
<button onClick={isActive ? release : request}>
|
|
317
|
+
{isActive ? 'Allow screen lock' : 'Keep screen on'}
|
|
318
|
+
</button>
|
|
319
|
+
</div>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Parameters:**
|
|
325
|
+
|
|
326
|
+
| Parameter | Type | Default | Description |
|
|
327
|
+
| --------------- | --------- | ------- | --------------------------------------------------- |
|
|
328
|
+
| `autoReacquire` | `boolean` | `true` | Re-request lock when the tab becomes visible again |
|
|
329
|
+
|
|
330
|
+
**Returns (`WakeLockResult`):**
|
|
331
|
+
|
|
332
|
+
| Property | Type | Description |
|
|
333
|
+
| ------------- | --------------------- | ---------------------------------------- |
|
|
334
|
+
| `isActive` | `boolean` | `true` while a Wake Lock is held |
|
|
335
|
+
| `request` | `() => Promise<void>` | Request the screen Wake Lock |
|
|
336
|
+
| `release` | `() => Promise<void>` | Release the current Wake Lock |
|
|
337
|
+
| `isSupported` | `boolean` | `true` if the API is available |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
### `useBatteryAware` âĻ <sup>NEW</sup>
|
|
342
|
+
|
|
343
|
+
Expose device battery status via the [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API).
|
|
344
|
+
|
|
345
|
+
**Use cases:** Reduce polling on low battery, disable animations, show battery indicators.
|
|
346
|
+
|
|
347
|
+
```tsx
|
|
348
|
+
import { useBatteryAware } from 'react-visibility-hooks';
|
|
349
|
+
|
|
350
|
+
function BatteryIndicator() {
|
|
351
|
+
const { charging, level, isLowBattery, isSupported } = useBatteryAware(0.15);
|
|
352
|
+
|
|
353
|
+
if (!isSupported) return null;
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<div>
|
|
357
|
+
<p>ð {Math.round(level * 100)}%{charging ? ' ⥠Charging' : ''}</p>
|
|
358
|
+
{isLowBattery && <p>â ïļ Low battery â reducing activity</p>}
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Parameters:**
|
|
365
|
+
|
|
366
|
+
| Parameter | Type | Default | Description |
|
|
367
|
+
| -------------- | -------- | ------- | ------------------------------------------------------- |
|
|
368
|
+
| `lowThreshold` | `number` | `0.15` | Level (0â1) below which `isLowBattery` is `true` |
|
|
369
|
+
|
|
370
|
+
**Returns (`BatteryState`):**
|
|
371
|
+
|
|
372
|
+
| Property | Type | Description |
|
|
373
|
+
| -------------- | --------- | ---------------------------------------------------- |
|
|
374
|
+
| `charging` | `boolean` | `true` when the device is plugged in |
|
|
375
|
+
| `level` | `number` | Battery level between 0 and 1 |
|
|
376
|
+
| `isLowBattery` | `boolean` | `true` when not charging and below threshold |
|
|
377
|
+
| `isSupported` | `boolean` | `true` when the Battery Status API is available |
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Combining Hooks
|
|
382
|
+
|
|
383
|
+
The real power comes from composing hooks together:
|
|
384
|
+
|
|
385
|
+
```tsx
|
|
386
|
+
import {
|
|
387
|
+
useNetworkAwarePolling,
|
|
388
|
+
useBatteryAware,
|
|
389
|
+
useInactivityTimeout,
|
|
390
|
+
} from 'react-visibility-hooks';
|
|
391
|
+
|
|
392
|
+
function SmartDashboard() {
|
|
393
|
+
const { isLowBattery } = useBatteryAware();
|
|
394
|
+
const { isTimedOut } = useInactivityTimeout({ timeout: 300_000 });
|
|
395
|
+
|
|
396
|
+
const { data } = useNetworkAwarePolling(
|
|
397
|
+
() => fetch('/api/metrics').then((r) => r.json()),
|
|
398
|
+
{
|
|
399
|
+
interval: isLowBattery ? 30_000 : 5_000,
|
|
400
|
+
enabled: !isTimedOut,
|
|
401
|
+
},
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
return <pre>{JSON.stringify(data, null, 2)}</pre>;
|
|
405
|
+
}
|
|
406
|
+
```
|
|
161
407
|
|
|
162
408
|
## SSR Support
|
|
163
409
|
|
|
164
|
-
All hooks are SSR-safe and
|
|
410
|
+
All hooks are SSR-safe and work correctly with:
|
|
165
411
|
|
|
166
|
-
- Next.js (App Router & Pages Router)
|
|
167
|
-
- Remix
|
|
168
|
-
- Gatsby
|
|
412
|
+
- **Next.js** (App Router & Pages Router)
|
|
413
|
+
- **Remix**
|
|
414
|
+
- **Gatsby**
|
|
169
415
|
- Any other React SSR framework
|
|
170
416
|
|
|
171
|
-
The hooks check for `document` availability and
|
|
417
|
+
The hooks check for `document`/`window`/`navigator` availability and return sensible defaults on the server (e.g., `visible = true`, `online = true`, `charging = true`).
|
|
172
418
|
|
|
173
419
|
## TypeScript
|
|
174
420
|
|
|
175
|
-
|
|
421
|
+
Written in TypeScript with full type definitions. All interfaces are exported:
|
|
422
|
+
|
|
423
|
+
```tsx
|
|
424
|
+
import type {
|
|
425
|
+
IdleVisibilityResult,
|
|
426
|
+
SmartPollingOptions,
|
|
427
|
+
SmartPollingResult,
|
|
428
|
+
PageFocusEffectOptions,
|
|
429
|
+
NetworkAwarePollingOptions,
|
|
430
|
+
NetworkAwarePollingResult,
|
|
431
|
+
InactivityTimeoutOptions,
|
|
432
|
+
InactivityTimeoutResult,
|
|
433
|
+
WakeLockResult,
|
|
434
|
+
BatteryState,
|
|
435
|
+
} from 'react-visibility-hooks';
|
|
436
|
+
```
|
|
176
437
|
|
|
177
438
|
## Browser Support
|
|
178
439
|
|
|
179
|
-
|
|
440
|
+
| Feature | API | Support |
|
|
441
|
+
| ---------------------- | ----------------------- | ----------------------------------------------------------------------- |
|
|
442
|
+
| Visibility detection | Page Visibility API | [All modern browsers](https://caniuse.com/pagevisibility) |
|
|
443
|
+
| Network detection | `navigator.onLine` | [All modern browsers](https://caniuse.com/online-status) |
|
|
444
|
+
| Connection quality | Network Information API | [Chrome, Edge, Opera](https://caniuse.com/netinfo) |
|
|
445
|
+
| Wake Lock | Screen Wake Lock API | [Chrome, Edge, Opera](https://caniuse.com/wake-lock) |
|
|
446
|
+
| Battery status | Battery Status API | [Chrome, Edge, Opera](https://caniuse.com/battery-status) |
|
|
180
447
|
|
|
181
|
-
|
|
182
|
-
- React >=16.8.0 (hooks)
|
|
448
|
+
> All hooks degrade gracefully â `isSupported` flags let you build progressive UIs.
|
|
183
449
|
|
|
184
450
|
## Examples
|
|
185
451
|
|
|
@@ -193,38 +459,61 @@ function ExpensiveComponent() {
|
|
|
193
459
|
const isVisible = useDocVisible();
|
|
194
460
|
|
|
195
461
|
useEffect(() => {
|
|
196
|
-
if (!isVisible) return;
|
|
462
|
+
if (!isVisible) return;
|
|
197
463
|
|
|
198
464
|
const interval = setInterval(() => {
|
|
199
|
-
// Expensive operation
|
|
200
465
|
performCalculation();
|
|
201
466
|
}, 1000);
|
|
202
467
|
|
|
203
468
|
return () => clearInterval(interval);
|
|
204
469
|
}, [isVisible]);
|
|
205
470
|
|
|
206
|
-
return <div
|
|
471
|
+
return <div>âĶ</div>;
|
|
207
472
|
}
|
|
208
473
|
```
|
|
209
474
|
|
|
210
|
-
###
|
|
475
|
+
### Session timeout with warning modal
|
|
211
476
|
|
|
212
477
|
```tsx
|
|
213
|
-
import {
|
|
214
|
-
|
|
215
|
-
function IdleWarning() {
|
|
216
|
-
const { idle } = useIdleVisibility(300000); // 5 minutes
|
|
478
|
+
import { useInactivityTimeout } from 'react-visibility-hooks';
|
|
217
479
|
|
|
218
|
-
|
|
480
|
+
function App() {
|
|
481
|
+
const { isWarning, remainingSeconds, resetTimer, isTimedOut } =
|
|
482
|
+
useInactivityTimeout({
|
|
483
|
+
timeout: 600_000,
|
|
484
|
+
warningBefore: 120_000,
|
|
485
|
+
onTimeout: () => window.location.href = '/login',
|
|
486
|
+
});
|
|
219
487
|
|
|
220
488
|
return (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
489
|
+
<>
|
|
490
|
+
<MainContent />
|
|
491
|
+
{isWarning && (
|
|
492
|
+
<Modal>
|
|
493
|
+
<p>Session expires in {remainingSeconds}s</p>
|
|
494
|
+
<button onClick={resetTimer}>I'm still here</button>
|
|
495
|
+
</Modal>
|
|
496
|
+
)}
|
|
497
|
+
</>
|
|
224
498
|
);
|
|
225
499
|
}
|
|
226
500
|
```
|
|
227
501
|
|
|
502
|
+
### Battery-aware polling
|
|
503
|
+
|
|
504
|
+
```tsx
|
|
505
|
+
import { useSmartPolling, useBatteryAware } from 'react-visibility-hooks';
|
|
506
|
+
|
|
507
|
+
function Feed() {
|
|
508
|
+
const { isLowBattery } = useBatteryAware();
|
|
509
|
+
const { data } = useSmartPolling(fetchFeed, {
|
|
510
|
+
interval: isLowBattery ? 30_000 : 5_000,
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
return <FeedList items={data} />;
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
228
517
|
## Contributing
|
|
229
518
|
|
|
230
519
|
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a Pull Request.
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var react=require('react');function
|
|
1
|
+
'use strict';var react=require('react');function m(){let[i,n]=react.useState(()=>typeof document=="undefined"?true:document.visibilityState==="visible"),t=react.useCallback(()=>{n(document.visibilityState==="visible");},[]);return react.useEffect(()=>{if(typeof document!="undefined")return t(),document.addEventListener("visibilitychange",t),()=>document.removeEventListener("visibilitychange",t)},[t]),i}function T(i=6e4){let n=m(),[t,r]=react.useState(false),e=react.useRef(void 0),o=react.useCallback(()=>{r(false),clearTimeout(e.current),e.current=setTimeout(()=>r(true),i);},[i]);return react.useEffect(()=>{if(typeof window=="undefined")return;let s=["mousemove","keydown","pointerdown","scroll","touchstart"];return s.forEach(u=>window.addEventListener(u,o,{passive:true})),o(),()=>{s.forEach(u=>window.removeEventListener(u,o)),clearTimeout(e.current);}},[o]),react.useEffect(()=>{n&&o();},[n,o]),{visible:n,idle:t}}function Q(i){let n=m(),t=react.useRef(false);react.useEffect(()=>{let r=i.current;r&&(!n&&!r.paused?(r.pause(),t.current=true):n&&t.current&&(r.play().catch(()=>{}),t.current=false));},[n,i]);}function I(i,n){let{interval:t=5e3,enabled:r=true}=n!=null?n:{},e=m(),[o,s]=react.useState(void 0),[u,l]=react.useState(true),[c,b]=react.useState(void 0),g=react.useRef(i),p=react.useRef(void 0),f=react.useRef(false),w=react.useRef(void 0),v=react.useRef(true);g.current=i,react.useEffect(()=>(v.current=true,()=>{v.current=false;}),[]);let d=react.useCallback(async()=>{if(!f.current){f.current=true;try{let a=await g.current();if(!v.current)return;let x=JSON.stringify(a);x!==w.current&&(w.current=x,s(a)),b(k=>k!==void 0?void 0:k);}catch(a){if(!v.current)return;b(a instanceof Error?a:new Error(String(a)));}finally{f.current=false,v.current&&l(a=>a&&false);}}},[]),y=react.useRef(false);return react.useEffect(()=>{y.current||(y.current=true,d());},[d]),react.useEffect(()=>{if(!r||!e){clearInterval(p.current),p.current=void 0;return}return d(),p.current=setInterval(d,t),()=>{clearInterval(p.current),p.current=void 0;}},[e,r,t,d]),{data:o,isLoading:u,isError:c!==void 0,error:c,refetch:d}}function Y(i){let n=m(),t=react.useRef(void 0),r=react.useRef(void 0),e=react.useRef(i.onVisible),o=react.useRef(i.onHidden);e.current=i.onVisible,o.current=i.onHidden,react.useEffect(()=>{var s,u,l;if(t.current===void 0){t.current=n;return}if(n&&!t.current){(s=r.current)==null||s.call(r),r.current=void 0;let c=(u=e.current)==null?void 0:u.call(e);typeof c=="function"&&(r.current=c);}else !n&&t.current&&((l=o.current)==null||l.call(o));t.current=n;},[n]),react.useEffect(()=>()=>{var s;(s=r.current)==null||s.call(r);},[]);}function ee(i,n){let{interval:t=5e3,enabled:r=true,slowMultiplier:e=3,pauseOffline:o=true,...s}=n!=null?n:{},u=te(),l=ne(t,e);return {...I(i,{...s,interval:l,enabled:o?r&&u:r}),isOnline:u,effectiveInterval:l}}function te(){let[i,n]=react.useState(()=>typeof navigator=="undefined"?true:navigator.onLine),t=react.useCallback(()=>n(true),[]),r=react.useCallback(()=>n(false),[]);return react.useEffect(()=>{if(typeof window!="undefined")return window.addEventListener("online",t),window.addEventListener("offline",r),()=>{window.removeEventListener("online",t),window.removeEventListener("offline",r);}},[t,r]),i}function ne(i,n){if(typeof navigator=="undefined")return i;let t=navigator.connection;return (t==null?void 0:t.effectiveType)==="2g"||(t==null?void 0:t.effectiveType)==="slow-2g"?i*n:i}function oe(i){let{timeout:n=3e5,warningBefore:t=6e4,onTimeout:r,onWarning:e}=i!=null?i:{},o=Math.min(t,n),s=n-o,{idle:u,visible:l}=T(s),[c,b]=react.useState(-1),[g,p]=react.useState(false),f=react.useRef(void 0),w=react.useRef(void 0),v=react.useRef(false),d=react.useRef(r),y=react.useRef(e);d.current=r,y.current=e;let a=react.useCallback(()=>{clearInterval(f.current),f.current=void 0,w.current=void 0,v.current=false,b(-1),p(false);},[]);react.useEffect(()=>{var L;if(!u||g){u||a();return}w.current=Date.now(),v.current||(v.current=true,(L=y.current)==null||L.call(y));let k=o;return f.current=setInterval(()=>{var B,V;let H=Date.now()-((B=w.current)!=null?B:Date.now()),O=Math.max(0,Math.ceil((k-H)/1e3));b(O),O<=0&&(clearInterval(f.current),f.current=void 0,p(true),(V=d.current)==null||V.call(d));},1e3),()=>{clearInterval(f.current),f.current=void 0;}},[u,g,o,a]);let x=u&&!g&&c>=0;return {idle:u||g,visible:l,isWarning:x,isTimedOut:g,remainingSeconds:c,resetTimer:a}}function se(i=true){let n=m(),[t,r]=react.useState(false),e=react.useRef(void 0),o=react.useRef(false),s=typeof navigator!="undefined"&&navigator.wakeLock!=null,u=react.useCallback(async()=>{if(s&&!(e.current&&!e.current.released))try{let c=await navigator.wakeLock.request("screen");e.current=c,o.current=!0,r(!0),c.addEventListener("release",()=>{r(!1),e.current=void 0;});}catch{}},[s]),l=react.useCallback(async()=>{o.current=false,e.current&&!e.current.released&&await e.current.release();},[]);return react.useEffect(()=>{i&&n&&o.current&&!e.current&&u();},[n,i,u]),react.useEffect(()=>()=>{e.current&&!e.current.released&&e.current.release().catch(()=>{});},[]),{isActive:t,request:u,release:l,isSupported:s}}function fe(i=.15){let[n,t]=react.useState({charging:true,level:1,isLowBattery:false,isSupported:false}),r=react.useCallback(e=>{t({charging:e.charging,level:e.level,isLowBattery:!e.charging&&e.level<i,isSupported:true});},[i]);return react.useEffect(()=>{if(typeof navigator=="undefined"||typeof navigator.getBattery!="function")return;let e,o=false,s=()=>{e&&!o&&r(e);};return navigator.getBattery().then(u=>{o||(e=u,r(u),u.addEventListener("chargingchange",s),u.addEventListener("levelchange",s));}).catch(()=>{}),()=>{o=true,e&&(e.removeEventListener("chargingchange",s),e.removeEventListener("levelchange",s));}},[r]),n}exports.useAutoPauseVideo=Q;exports.useBatteryAware=fe;exports.useDocVisible=m;exports.useIdleVisibility=T;exports.useInactivityTimeout=oe;exports.useNetworkAwarePolling=ee;exports.usePageFocusEffect=Y;exports.useSmartPolling=I;exports.useWakeLock=se;//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useDocVisible.ts","../src/useIdleVisibility.ts","../src/useAutoPauseVideo.ts","../src/useSmartPolling.ts"],"names":["useDocVisible","visible","setVisible","useState","handler","useCallback","useEffect","useIdleVisibility","timeout","idle","setIdle","timerRef","useRef","reset","events","e","useAutoPauseVideo","ref","wasPausedByUs","video","useSmartPolling","fetchFn","options","interval","enabled","data","setData","isLoading","setIsLoading","error","setError","fetchRef","isFetchingRef","lastJsonRef","mountedRef","execute","result","json","prev","err","hasFetchedRef"],"mappings":"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","file":"index.cjs","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Returns `true` when the page is visible, `false` when hidden.\n * SSR-safe â defaults to `true` on the server.\n */\nexport function useDocVisible(): boolean {\n const [visible, setVisible] = useState(() =>\n typeof document === \"undefined\" ? true : document.visibilityState === \"visible\",\n );\n\n const handler = useCallback(() => {\n setVisible(document.visibilityState === \"visible\");\n }, []);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n // Sync in case value changed between SSR hydration and effect\n handler();\n\n document.addEventListener(\"visibilitychange\", handler);\n return () => document.removeEventListener(\"visibilitychange\", handler);\n }, [handler]);\n\n return visible;\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface IdleVisibilityResult {\n /** Whether the page is visible */\n visible: boolean;\n /** Whether the user is idle (no interaction for `timeout` ms) */\n idle: boolean;\n}\n\n/**\n * Combines page-visibility with idle detection.\n *\n * @param timeout - Milliseconds of inactivity before the user is\n * considered idle (default `60_000`).\n */\nexport function useIdleVisibility(timeout = 60_000): IdleVisibilityResult {\n const visible = useDocVisible();\n const [idle, setIdle] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const reset = useCallback(() => {\n setIdle(false);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setIdle(true), timeout);\n }, [timeout]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const events: Array<keyof WindowEventMap> = [\n \"mousemove\",\n \"keydown\",\n \"pointerdown\",\n \"scroll\",\n \"touchstart\",\n ];\n\n events.forEach((e) => window.addEventListener(e, reset, { passive: true }));\n reset();\n\n return () => {\n events.forEach((e) => window.removeEventListener(e, reset));\n clearTimeout(timerRef.current);\n };\n }, [reset]);\n\n // Reset idle timer when tab becomes visible again\n useEffect(() => {\n if (visible) reset();\n }, [visible, reset]);\n\n return { visible, idle };\n}\n","import { useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\n/**\n * Automatically pauses a `<video>` when the page becomes hidden\n * and resumes playback when the page becomes visible again.\n *\n * Only resumes if the video was playing before it was paused by this hook.\n */\nexport function useAutoPauseVideo(ref: React.RefObject<HTMLVideoElement | null>): void {\n const visible = useDocVisible();\n const wasPausedByUs = useRef(false);\n\n useEffect(() => {\n const video = ref.current;\n if (!video) return;\n\n if (!visible && !video.paused) {\n video.pause();\n wasPausedByUs.current = true;\n } else if (visible && wasPausedByUs.current) {\n video.play().catch(() => {\n /* autoplay may be blocked */\n });\n wasPausedByUs.current = false;\n }\n }, [visible, ref]);\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface SmartPollingOptions {\n /** Polling interval in ms (default `5000`) */\n interval?: number;\n /** Enable / disable polling (default `true`). The initial fetch always fires. */\n enabled?: boolean;\n}\n\nexport interface SmartPollingResult<T> {\n data: T | undefined;\n isLoading: boolean;\n isError: boolean;\n error: Error | undefined;\n /** Manually trigger a fetch */\n refetch: () => Promise<void>;\n}\n\n/**\n * Visibility-aware polling hook.\n *\n * - Pauses when the tab is hidden.\n * - Skips re-renders when data hasn't changed (shallow JSON comparison).\n * - Prevents overlapping fetches.\n *\n * @param fetchFn - Async function that returns data.\n * @param options - Optional configuration.\n */\nexport function useSmartPolling<T = unknown>(\n fetchFn: () => Promise<T>,\n options?: SmartPollingOptions,\n): SmartPollingResult<T> {\n const { interval = 5000, enabled = true } = options ?? {};\n const visible = useDocVisible();\n\n const [data, setData] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const fetchRef = useRef(fetchFn);\n const timerRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);\n const isFetchingRef = useRef(false);\n const lastJsonRef = useRef<string | undefined>(undefined);\n const mountedRef = useRef(true);\n\n // Always keep the latest fetchFn\n fetchRef.current = fetchFn;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const execute = useCallback(async () => {\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n try {\n const result = await fetchRef.current();\n if (!mountedRef.current) return;\n\n const json = JSON.stringify(result);\n if (json !== lastJsonRef.current) {\n lastJsonRef.current = json;\n setData(result);\n }\n setError((prev) => (prev !== undefined ? undefined : prev));\n } catch (err) {\n if (!mountedRef.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n isFetchingRef.current = false;\n if (mountedRef.current) {\n setIsLoading((prev) => (prev ? false : prev));\n }\n }\n }, []);\n\n // Initial fetch â always runs once regardless of `enabled`\n const hasFetchedRef = useRef(false);\n useEffect(() => {\n if (hasFetchedRef.current) return;\n hasFetchedRef.current = true;\n execute();\n }, [execute]);\n\n // Polling â only when visible AND enabled\n useEffect(() => {\n if (!enabled || !visible) {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n return;\n }\n\n // Immediately fetch when re-enabled / tab returns\n execute();\n\n timerRef.current = setInterval(execute, interval);\n return () => {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n };\n }, [visible, enabled, interval, execute]);\n\n return {\n data,\n isLoading,\n isError: error !== undefined,\n error,\n refetch: execute,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useDocVisible.ts","../src/useIdleVisibility.ts","../src/useAutoPauseVideo.ts","../src/useSmartPolling.ts","../src/usePageFocusEffect.ts","../src/useNetworkAwarePolling.ts","../src/useInactivityTimeout.ts","../src/useWakeLock.ts","../src/useBatteryAware.ts"],"names":["useDocVisible","visible","setVisible","useState","handler","useCallback","useEffect","useIdleVisibility","timeout","idle","setIdle","timerRef","useRef","reset","events","e","useAutoPauseVideo","ref","wasPausedByUs","video","useSmartPolling","fetchFn","options","interval","enabled","data","setData","isLoading","setIsLoading","error","setError","fetchRef","isFetchingRef","lastJsonRef","mountedRef","execute","result","json","prev","err","hasFetchedRef","usePageFocusEffect","prevRef","cleanupRef","onVisibleRef","onHiddenRef","_a","_b","_c","useNetworkAwarePolling","slowMultiplier","pauseOffline","rest","online","useOnline","effectiveInterval","getEffectiveInterval","setOnline","handleOnline","handleOffline","base","multiplier","conn","useInactivityTimeout","warningBefore","onTimeout","onWarning","clampedWarning","idleThreshold","remaining","setRemaining","timedOut","setTimedOut","intervalRef","startRef","warnedRef","onTimeoutRef","onWarningRef","clear","warningMs","elapsed","left","isWarning","useWakeLock","autoReacquire","isActive","setIsActive","sentinelRef","wantedRef","isSupported","request","sentinel","release","useBatteryAware","lowThreshold","state","setState","update","battery","cancelled","onChange","b"],"mappings":"wCAMO,SAASA,CAAAA,EAAyB,CACvC,GAAM,CAACC,CAAAA,CAASC,CAAU,CAAA,CAAIC,cAAAA,CAAS,IACrC,OAAO,QAAA,EAAa,WAAA,CAAc,IAAA,CAAO,SAAS,eAAA,GAAoB,SACxE,CAAA,CAEMC,CAAAA,CAAUC,kBAAY,IAAM,CAChCH,CAAAA,CAAW,QAAA,CAAS,kBAAoB,SAAS,EACnD,EAAG,EAAE,EAEL,OAAAI,eAAAA,CAAU,IAAM,CACd,GAAI,OAAO,QAAA,EAAa,WAAA,CAGxB,OAAAF,GAAQ,CAER,QAAA,CAAS,gBAAA,CAAiB,kBAAA,CAAoBA,CAAO,CAAA,CAC9C,IAAM,SAAS,mBAAA,CAAoB,kBAAA,CAAoBA,CAAO,CACvE,CAAA,CAAG,CAACA,CAAO,CAAC,CAAA,CAELH,CACT,CCVO,SAASM,CAAAA,CAAkBC,CAAAA,CAAU,IAA8B,CACxE,IAAMP,CAAAA,CAAUD,CAAAA,GACV,CAACS,CAAAA,CAAMC,CAAO,CAAA,CAAIP,eAAS,KAAK,CAAA,CAChCQ,CAAAA,CAAWC,YAAAA,CAAkD,MAAS,CAAA,CAEtEC,CAAAA,CAAQR,kBAAY,IAAM,CAC9BK,EAAQ,KAAK,CAAA,CACb,YAAA,CAAaC,CAAAA,CAAS,OAAO,CAAA,CAC7BA,CAAAA,CAAS,OAAA,CAAU,UAAA,CAAW,IAAMD,CAAAA,CAAQ,IAAI,CAAA,CAAGF,CAAO,EAC5D,CAAA,CAAG,CAACA,CAAO,CAAC,CAAA,CAEZ,OAAAF,eAAAA,CAAU,IAAM,CACd,GAAI,OAAO,MAAA,EAAW,WAAA,CAAa,OAEnC,IAAMQ,EAAsC,CAC1C,WAAA,CACA,SAAA,CACA,aAAA,CACA,SACA,YACF,CAAA,CAEA,OAAAA,CAAAA,CAAO,OAAA,CAASC,GAAM,MAAA,CAAO,gBAAA,CAAiBA,CAAAA,CAAGF,CAAAA,CAAO,CAAE,OAAA,CAAS,IAAK,CAAC,CAAC,CAAA,CAC1EA,GAAM,CAEC,IAAM,CACXC,CAAAA,CAAO,QAASC,CAAAA,EAAM,MAAA,CAAO,oBAAoBA,CAAAA,CAAGF,CAAK,CAAC,CAAA,CAC1D,YAAA,CAAaF,CAAAA,CAAS,OAAO,EAC/B,CACF,CAAA,CAAG,CAACE,CAAK,CAAC,CAAA,CAGVP,eAAAA,CAAU,IAAM,CACVL,GAASY,CAAAA,GACf,EAAG,CAACZ,CAAAA,CAASY,CAAK,CAAC,CAAA,CAEZ,CAAE,OAAA,CAAAZ,EAAS,IAAA,CAAAQ,CAAK,CACzB,CC5CO,SAASO,CAAAA,CAAkBC,EAAqD,CACrF,IAAMhB,EAAUD,CAAAA,EAAc,CACxBkB,CAAAA,CAAgBN,YAAAA,CAAO,KAAK,CAAA,CAElCN,eAAAA,CAAU,IAAM,CACd,IAAMa,CAAAA,CAAQF,CAAAA,CAAI,OAAA,CACbE,CAAAA,GAED,CAAClB,CAAAA,EAAW,CAACkB,EAAM,MAAA,EACrBA,CAAAA,CAAM,OAAM,CACZD,CAAAA,CAAc,OAAA,CAAU,IAAA,EACfjB,GAAWiB,CAAAA,CAAc,OAAA,GAClCC,EAAM,IAAA,EAAK,CAAE,MAAM,IAAM,CAEzB,CAAC,CAAA,CACDD,EAAc,OAAA,CAAU,KAAA,CAAA,EAE5B,EAAG,CAACjB,CAAAA,CAASgB,CAAG,CAAC,EACnB,CCEO,SAASG,EACdC,CAAAA,CACAC,CAAAA,CACuB,CACvB,GAAM,CAAE,SAAAC,CAAAA,CAAW,GAAA,CAAM,OAAA,CAAAC,CAAAA,CAAU,IAAK,CAAA,CAAIF,CAAAA,EAAA,KAAAA,CAAAA,CAAW,GACjDrB,CAAAA,CAAUD,CAAAA,EAAc,CAExB,CAACyB,EAAMC,CAAO,CAAA,CAAIvB,eAAwB,MAAS,CAAA,CACnD,CAACwB,CAAAA,CAAWC,CAAY,CAAA,CAAIzB,cAAAA,CAAS,IAAI,CAAA,CACzC,CAAC0B,CAAAA,CAAOC,CAAQ,EAAI3B,cAAAA,CAA4B,MAAS,CAAA,CAEzD4B,CAAAA,CAAWnB,aAAOS,CAAO,CAAA,CACzBV,EAAWC,YAAAA,CAAmD,MAAS,EACvEoB,CAAAA,CAAgBpB,YAAAA,CAAO,KAAK,CAAA,CAC5BqB,EAAcrB,YAAAA,CAA2B,MAAS,EAClDsB,CAAAA,CAAatB,YAAAA,CAAO,IAAI,CAAA,CAG9BmB,CAAAA,CAAS,OAAA,CAAUV,CAAAA,CAEnBf,gBAAU,KACR4B,CAAAA,CAAW,QAAU,IAAA,CACd,IAAM,CACXA,CAAAA,CAAW,OAAA,CAAU,MACvB,CAAA,CAAA,CACC,EAAE,CAAA,CAEL,IAAMC,CAAAA,CAAU9B,kBAAY,SAAY,CACtC,GAAI,CAAA2B,EAAc,OAAA,CAClB,CAAAA,EAAc,OAAA,CAAU,IAAA,CAExB,GAAI,CACF,IAAMI,CAAAA,CAAS,MAAML,EAAS,OAAA,EAAQ,CACtC,GAAI,CAACG,EAAW,OAAA,CAAS,OAEzB,IAAMG,CAAAA,CAAO,KAAK,SAAA,CAAUD,CAAM,EAC9BC,CAAAA,GAASJ,CAAAA,CAAY,UACvBA,CAAAA,CAAY,OAAA,CAAUI,CAAAA,CACtBX,CAAAA,CAAQU,CAAM,CAAA,CAAA,CAEhBN,CAAAA,CAAUQ,CAAAA,EAAUA,CAAAA,GAAS,OAAY,KAAA,CAAA,CAAYA,CAAK,EAC5D,CAAA,MAASC,EAAK,CACZ,GAAI,CAACL,CAAAA,CAAW,OAAA,CAAS,OACzBJ,CAAAA,CAASS,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAM,IAAI,KAAA,CAAM,MAAA,CAAOA,CAAG,CAAC,CAAC,EAC9D,CAAA,OAAE,CACAP,CAAAA,CAAc,OAAA,CAAU,MACpBE,CAAAA,CAAW,OAAA,EACbN,EAAcU,CAAAA,EAAUA,CAAAA,EAAO,KAAa,EAEhD,CAAA,CACF,CAAA,CAAG,EAAE,CAAA,CAGCE,CAAAA,CAAgB5B,YAAAA,CAAO,KAAK,EAClC,OAAAN,eAAAA,CAAU,IAAM,CACVkC,EAAc,OAAA,GAClBA,CAAAA,CAAc,QAAU,IAAA,CACxBL,CAAAA,IACF,CAAA,CAAG,CAACA,CAAO,CAAC,EAGZ7B,eAAAA,CAAU,IAAM,CACd,GAAI,CAACkB,GAAW,CAACvB,CAAAA,CAAS,CACxB,aAAA,CAAcU,EAAS,OAAO,CAAA,CAC9BA,EAAS,OAAA,CAAU,MAAA,CACnB,MACF,CAGA,OAAAwB,CAAAA,EAAQ,CAERxB,EAAS,OAAA,CAAU,WAAA,CAAYwB,CAAAA,CAASZ,CAAQ,EACzC,IAAM,CACX,aAAA,CAAcZ,CAAAA,CAAS,OAAO,CAAA,CAC9BA,CAAAA,CAAS,QAAU,OACrB,CACF,EAAG,CAACV,CAAAA,CAASuB,CAAAA,CAASD,CAAAA,CAAUY,CAAO,CAAC,CAAA,CAEjC,CACL,IAAA,CAAAV,CAAAA,CACA,UAAAE,CAAAA,CACA,OAAA,CAASE,CAAAA,GAAU,MAAA,CACnB,MAAAA,CAAAA,CACA,OAAA,CAASM,CACX,CACF,CCrFO,SAASM,CAAAA,CAAmBnB,CAAAA,CAAuC,CACxE,IAAMrB,CAAAA,CAAUD,CAAAA,EAAc,CACxB0C,CAAAA,CAAU9B,aAA4B,MAAS,CAAA,CAC/C+B,EAAa/B,YAAAA,CAAiC,MAAS,EAGvDgC,CAAAA,CAAehC,YAAAA,CAAOU,CAAAA,CAAQ,SAAS,EACvCuB,CAAAA,CAAcjC,YAAAA,CAAOU,CAAAA,CAAQ,QAAQ,EAC3CsB,CAAAA,CAAa,OAAA,CAAUtB,CAAAA,CAAQ,SAAA,CAC/BuB,EAAY,OAAA,CAAUvB,CAAAA,CAAQ,SAE9BhB,eAAAA,CAAU,IAAM,CAxClB,IAAAwC,CAAAA,CAAAC,CAAAA,CAAAC,CAAAA,CA0CI,GAAIN,CAAAA,CAAQ,OAAA,GAAY,MAAA,CAAW,CACjCA,EAAQ,OAAA,CAAUzC,CAAAA,CAClB,MACF,CAEA,GAAIA,CAAAA,EAAW,CAACyC,EAAQ,OAAA,CAAS,CAAA,CAE/BI,EAAAH,CAAAA,CAAW,OAAA,GAAX,IAAA,EAAAG,CAAAA,CAAA,KAAAH,CAAAA,CAAAA,CACAA,CAAAA,CAAW,QAAU,MAAA,CACrB,IAAMP,GAASW,CAAAA,CAAAH,CAAAA,CAAa,OAAA,GAAb,IAAA,CAAA,MAAA,CAAAG,EAAA,IAAA,CAAAH,CAAAA,CAAAA,CACX,OAAOR,CAAAA,EAAW,UAAA,GACpBO,EAAW,OAAA,CAAUP,CAAAA,EAEzB,CAAA,KAAW,CAACnC,GAAWyC,CAAAA,CAAQ,OAAA,GAAA,CAE7BM,CAAAA,CAAAH,CAAAA,CAAY,UAAZ,IAAA,EAAAG,CAAAA,CAAA,IAAA,CAAAH,CAAAA,CAAAA,CAAAA,CAGFH,EAAQ,OAAA,CAAUzC,EACpB,EAAG,CAACA,CAAO,CAAC,CAAA,CAGZK,eAAAA,CAAU,IACD,IAAM,CAjEjB,IAAAwC,CAAAA,CAAAA,CAkEMA,EAAAH,CAAAA,CAAW,OAAA,GAAX,MAAAG,CAAAA,CAAA,IAAA,CAAAH,CAAAA,EACF,CAAA,CACC,EAAE,EACP,CCvCO,SAASM,EAAAA,CACd5B,CAAAA,CACAC,CAAAA,CAC8B,CAC9B,GAAM,CACJ,QAAA,CAAAC,CAAAA,CAAW,IACX,OAAA,CAAAC,CAAAA,CAAU,KACV,cAAA,CAAA0B,CAAAA,CAAiB,EACjB,YAAA,CAAAC,CAAAA,CAAe,IAAA,CACf,GAAGC,CACL,CAAA,CAAI9B,CAAAA,EAAA,KAAAA,CAAAA,CAAW,GAET+B,CAAAA,CAASC,EAAAA,EAAU,CACnBC,CAAAA,CAAoBC,GAAqBjC,CAAAA,CAAU2B,CAAc,EAUvE,OAAO,CAAE,GANM9B,CAAAA,CAAgBC,CAAAA,CAAS,CACtC,GAAG+B,EACH,QAAA,CAAUG,CAAAA,CACV,OAAA,CALiBJ,CAAAA,CAAe3B,GAAW6B,CAAAA,CAAS7B,CAMtD,CAAC,CAAA,CAEmB,SAAU6B,CAAAA,CAAQ,iBAAA,CAAAE,CAAkB,CAC1D,CAOA,SAASD,EAAAA,EAAqB,CAC5B,GAAM,CAACD,EAAQI,CAAS,CAAA,CAAItD,cAAAA,CAAS,IACnC,OAAO,SAAA,EAAc,WAAA,CAAc,IAAA,CAAO,SAAA,CAAU,MACtD,CAAA,CAEMuD,CAAAA,CAAerD,kBAAY,IAAMoD,CAAAA,CAAU,IAAI,CAAA,CAAG,EAAE,CAAA,CACpDE,EAAgBtD,iBAAAA,CAAY,IAAMoD,CAAAA,CAAU,KAAK,EAAG,EAAE,CAAA,CAE5D,OAAAnD,gBAAU,IAAM,CACd,GAAI,OAAO,MAAA,EAAW,YAEtB,OAAA,MAAA,CAAO,gBAAA,CAAiB,QAAA,CAAUoD,CAAY,EAC9C,MAAA,CAAO,gBAAA,CAAiB,UAAWC,CAAa,CAAA,CACzC,IAAM,CACX,MAAA,CAAO,mBAAA,CAAoB,QAAA,CAAUD,CAAY,CAAA,CACjD,MAAA,CAAO,oBAAoB,SAAA,CAAWC,CAAa,EACrD,CACF,CAAA,CAAG,CAACD,CAAAA,CAAcC,CAAa,CAAC,CAAA,CAEzBN,CACT,CAGA,SAASG,EAAAA,CAAqBI,CAAAA,CAAcC,CAAAA,CAA4B,CACtE,GAAI,OAAO,SAAA,EAAc,YAAa,OAAOD,CAAAA,CAE7C,IAAME,CAAAA,CACJ,SAAA,CAGA,UAAA,CAEF,OAAA,CAAIA,GAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAM,aAAA,IAAkB,IAAA,EAAA,CAAQA,GAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAM,aAAA,IAAkB,SAAA,CACnDF,EAAOC,CAAAA,CAETD,CACT,CCnDO,SAASG,EAAAA,CACdzC,EACyB,CACzB,GAAM,CACJ,OAAA,CAAAd,EAAU,GAAA,CACV,aAAA,CAAAwD,EAAgB,GAAA,CAChB,SAAA,CAAAC,EACA,SAAA,CAAAC,CACF,CAAA,CAAI5C,CAAAA,EAAA,KAAAA,CAAAA,CAAW,GAGT6C,CAAAA,CAAiB,IAAA,CAAK,IAAIH,CAAAA,CAAexD,CAAO,CAAA,CAChD4D,CAAAA,CAAgB5D,EAAU2D,CAAAA,CAE1B,CAAE,KAAA1D,CAAAA,CAAM,OAAA,CAAAR,CAAQ,CAAA,CAAIM,CAAAA,CAAkB6D,CAAa,CAAA,CAEnD,CAACC,CAAAA,CAAWC,CAAY,CAAA,CAAInE,cAAAA,CAAS,EAAE,CAAA,CACvC,CAACoE,CAAAA,CAAUC,CAAW,EAAIrE,cAAAA,CAAS,KAAK,EACxCsE,CAAAA,CAAc7D,YAAAA,CAAmD,MAAS,CAAA,CAC1E8D,CAAAA,CAAW9D,YAAAA,CAA2B,MAAS,EAC/C+D,CAAAA,CAAY/D,YAAAA,CAAO,KAAK,CAAA,CAGxBgE,EAAehE,YAAAA,CAAOqD,CAAS,CAAA,CAC/BY,CAAAA,CAAejE,aAAOsD,CAAS,CAAA,CACrCU,EAAa,OAAA,CAAUX,CAAAA,CACvBY,EAAa,OAAA,CAAUX,CAAAA,CAEvB,IAAMY,CAAAA,CAAQzE,kBAAY,IAAM,CAC9B,aAAA,CAAcoE,CAAAA,CAAY,OAAO,CAAA,CACjCA,CAAAA,CAAY,OAAA,CAAU,MAAA,CACtBC,EAAS,OAAA,CAAU,MAAA,CACnBC,EAAU,OAAA,CAAU,KAAA,CACpBL,EAAa,EAAE,CAAA,CACfE,CAAAA,CAAY,KAAK,EACnB,CAAA,CAAG,EAAE,CAAA,CAELlE,eAAAA,CAAU,IAAM,CAnFlB,IAAAwC,CAAAA,CAoFI,GAAI,CAACrC,CAAAA,EAAQ8D,CAAAA,CAAU,CAChB9D,CAAAA,EAAMqE,CAAAA,GACX,MACF,CAEAJ,CAAAA,CAAS,OAAA,CAAU,KAAK,GAAA,EAAI,CAGvBC,CAAAA,CAAU,OAAA,GACbA,EAAU,OAAA,CAAU,IAAA,CAAA,CACpB7B,CAAAA,CAAA+B,CAAAA,CAAa,UAAb,IAAA,EAAA/B,CAAAA,CAAA,KAAA+B,CAAAA,CAAAA,CAAAA,CAGF,IAAME,EAAYZ,CAAAA,CAElB,OAAAM,CAAAA,CAAY,OAAA,CAAU,YAAY,IAAM,CAnG5C,IAAA3B,CAAAA,CAAAC,CAAAA,CAoGM,IAAMiC,CAAAA,CAAU,IAAA,CAAK,GAAA,EAAI,EAAA,CAAKlC,EAAA4B,CAAAA,CAAS,OAAA,GAAT,KAAA5B,CAAAA,CAAoB,IAAA,CAAK,KAAI,CAAA,CACrDmC,CAAAA,CAAO,IAAA,CAAK,GAAA,CAAI,EAAG,IAAA,CAAK,IAAA,CAAA,CAAMF,CAAAA,CAAYC,CAAAA,EAAW,GAAI,CAAC,CAAA,CAChEV,CAAAA,CAAaW,CAAI,EAEbA,CAAAA,EAAQ,CAAA,GACV,cAAcR,CAAAA,CAAY,OAAO,EACjCA,CAAAA,CAAY,OAAA,CAAU,MAAA,CACtBD,CAAAA,CAAY,IAAI,CAAA,CAAA,CAChBzB,CAAAA,CAAA6B,EAAa,OAAA,GAAb,IAAA,EAAA7B,EAAA,IAAA,CAAA6B,CAAAA,CAAAA,EAEJ,CAAA,CAAG,GAAI,EAEA,IAAM,CACX,cAAcH,CAAAA,CAAY,OAAO,EACjCA,CAAAA,CAAY,OAAA,CAAU,OACxB,CACF,EAAG,CAAChE,CAAAA,CAAM8D,CAAAA,CAAUJ,CAAAA,CAAgBW,CAAK,CAAC,CAAA,CAE1C,IAAMI,CAAAA,CAAYzE,GAAQ,CAAC8D,CAAAA,EAAYF,GAAa,CAAA,CAEpD,OAAO,CACL,IAAA,CAAM5D,CAAAA,EAAQ8D,CAAAA,CACd,OAAA,CAAAtE,EACA,SAAA,CAAAiF,CAAAA,CACA,UAAA,CAAYX,CAAAA,CACZ,iBAAkBF,CAAAA,CAClB,UAAA,CAAYS,CACd,CACF,CCtGO,SAASK,EAAAA,CAAYC,CAAAA,CAAgB,IAAA,CAAsB,CAChE,IAAMnF,CAAAA,CAAUD,CAAAA,EAAc,CACxB,CAACqF,EAAUC,CAAW,CAAA,CAAInF,eAAS,KAAK,CAAA,CACxCoF,EAAc3E,YAAAA,CAAqC,MAAS,CAAA,CAC5D4E,CAAAA,CAAY5E,aAAO,KAAK,CAAA,CAExB6E,EAAc,OAAO,SAAA,EAAc,aAAe,SAAA,CAAU,QAAA,EAAY,IAAA,CAExEC,CAAAA,CAAUrF,kBAAY,SAAY,CACtC,GAAKoF,CAAAA,EAED,EAAAF,EAAY,OAAA,EAAW,CAACA,CAAAA,CAAY,OAAA,CAAQ,UAEhD,GAAI,CACF,IAAMI,CAAAA,CAAW,MAAM,SAAA,CAAU,QAAA,CAAS,OAAA,CAAQ,QAAQ,EAC1DJ,CAAAA,CAAY,OAAA,CAAUI,EACtBH,CAAAA,CAAU,OAAA,CAAU,GACpBF,CAAAA,CAAY,CAAA,CAAI,CAAA,CAEhBK,CAAAA,CAAS,iBAAiB,SAAA,CAAW,IAAM,CACzCL,CAAAA,CAAY,CAAA,CAAK,EACjBC,CAAAA,CAAY,OAAA,CAAU,KAAA,EACxB,CAAC,EACH,CAAA,KAAQ,CAER,CACF,CAAA,CAAG,CAACE,CAAW,CAAC,CAAA,CAEVG,CAAAA,CAAUvF,iBAAAA,CAAY,SAAY,CACtCmF,CAAAA,CAAU,OAAA,CAAU,KAAA,CAChBD,EAAY,OAAA,EAAW,CAACA,CAAAA,CAAY,OAAA,CAAQ,UAC9C,MAAMA,CAAAA,CAAY,QAAQ,OAAA,GAE9B,EAAG,EAAE,CAAA,CAGL,OAAAjF,gBAAU,IAAM,CACV8E,GAAiBnF,CAAAA,EAAWuF,CAAAA,CAAU,SAAW,CAACD,CAAAA,CAAY,OAAA,EAC3DG,CAAAA,GAET,CAAA,CAAG,CAACzF,EAASmF,CAAAA,CAAeM,CAAO,CAAC,CAAA,CAGpCpF,eAAAA,CAAU,IACD,IAAM,CACPiF,CAAAA,CAAY,OAAA,EAAW,CAACA,CAAAA,CAAY,QAAQ,QAAA,EAC9CA,CAAAA,CAAY,OAAA,CAAQ,OAAA,GAAU,KAAA,CAAM,IAAM,CAAC,CAAC,EAEhD,EACC,EAAE,CAAA,CAEE,CAAE,SAAAF,CAAAA,CAAU,OAAA,CAAAK,CAAAA,CAAS,OAAA,CAAAE,EAAS,WAAA,CAAAH,CAAY,CACnD,CC9CO,SAASI,EAAAA,CAAgBC,CAAAA,CAAe,IAAoB,CACjE,GAAM,CAACC,CAAAA,CAAOC,CAAQ,CAAA,CAAI7F,cAAAA,CAAuB,CAC/C,QAAA,CAAU,KACV,KAAA,CAAO,CAAA,CACP,aAAc,KAAA,CACd,WAAA,CAAa,KACf,CAAC,CAAA,CAEK8F,CAAAA,CAAS5F,iBAAAA,CACZ6F,GAA4B,CAC3BF,CAAAA,CAAS,CACP,QAAA,CAAUE,CAAAA,CAAQ,SAClB,KAAA,CAAOA,CAAAA,CAAQ,KAAA,CACf,YAAA,CAAc,CAACA,CAAAA,CAAQ,QAAA,EAAYA,EAAQ,KAAA,CAAQJ,CAAAA,CACnD,YAAa,IACf,CAAC,EACH,CAAA,CACA,CAACA,CAAY,CACf,CAAA,CAEA,OAAAxF,gBAAU,IAAM,CACd,GACE,OAAO,WAAc,WAAA,EACrB,OAAQ,UAAmD,UAAA,EAAe,UAAA,CAE1E,OAGF,IAAI4F,CAAAA,CACAC,CAAAA,CAAY,KAAA,CAEVC,EAAW,IAAM,CACjBF,GAAW,CAACC,CAAAA,EAAWF,EAAOC,CAAO,EAC3C,CAAA,CAEA,OAAC,UACE,UAAA,EAAW,CACX,KAAMG,CAAAA,EAAM,CACPF,IACJD,CAAAA,CAAUG,CAAAA,CACVJ,CAAAA,CAAOI,CAAC,EACRA,CAAAA,CAAE,gBAAA,CAAiB,gBAAA,CAAkBD,CAAQ,EAC7CC,CAAAA,CAAE,gBAAA,CAAiB,aAAA,CAAeD,CAAQ,GAC5C,CAAC,CAAA,CACA,MAAM,IAAM,CAEb,CAAC,CAAA,CAEI,IAAM,CACXD,CAAAA,CAAY,KACRD,CAAAA,GACFA,CAAAA,CAAQ,oBAAoB,gBAAA,CAAkBE,CAAQ,EACtDF,CAAAA,CAAQ,mBAAA,CAAoB,aAAA,CAAeE,CAAQ,GAEvD,CACF,CAAA,CAAG,CAACH,CAAM,CAAC,EAEJF,CACT","file":"index.cjs","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Returns `true` when the page is visible, `false` when hidden.\n * SSR-safe â defaults to `true` on the server.\n */\nexport function useDocVisible(): boolean {\n const [visible, setVisible] = useState(() =>\n typeof document === \"undefined\" ? true : document.visibilityState === \"visible\",\n );\n\n const handler = useCallback(() => {\n setVisible(document.visibilityState === \"visible\");\n }, []);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n // Sync in case value changed between SSR hydration and effect\n handler();\n\n document.addEventListener(\"visibilitychange\", handler);\n return () => document.removeEventListener(\"visibilitychange\", handler);\n }, [handler]);\n\n return visible;\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface IdleVisibilityResult {\n /** Whether the page is visible */\n visible: boolean;\n /** Whether the user is idle (no interaction for `timeout` ms) */\n idle: boolean;\n}\n\n/**\n * Combines page-visibility with idle detection.\n *\n * @param timeout - Milliseconds of inactivity before the user is\n * considered idle (default `60_000`).\n */\nexport function useIdleVisibility(timeout = 60_000): IdleVisibilityResult {\n const visible = useDocVisible();\n const [idle, setIdle] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const reset = useCallback(() => {\n setIdle(false);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setIdle(true), timeout);\n }, [timeout]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const events: Array<keyof WindowEventMap> = [\n \"mousemove\",\n \"keydown\",\n \"pointerdown\",\n \"scroll\",\n \"touchstart\",\n ];\n\n events.forEach((e) => window.addEventListener(e, reset, { passive: true }));\n reset();\n\n return () => {\n events.forEach((e) => window.removeEventListener(e, reset));\n clearTimeout(timerRef.current);\n };\n }, [reset]);\n\n // Reset idle timer when tab becomes visible again\n useEffect(() => {\n if (visible) reset();\n }, [visible, reset]);\n\n return { visible, idle };\n}\n","import { useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\n/**\n * Automatically pauses a `<video>` when the page becomes hidden\n * and resumes playback when the page becomes visible again.\n *\n * Only resumes if the video was playing before it was paused by this hook.\n */\nexport function useAutoPauseVideo(ref: React.RefObject<HTMLVideoElement | null>): void {\n const visible = useDocVisible();\n const wasPausedByUs = useRef(false);\n\n useEffect(() => {\n const video = ref.current;\n if (!video) return;\n\n if (!visible && !video.paused) {\n video.pause();\n wasPausedByUs.current = true;\n } else if (visible && wasPausedByUs.current) {\n video.play().catch(() => {\n /* autoplay may be blocked */\n });\n wasPausedByUs.current = false;\n }\n }, [visible, ref]);\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface SmartPollingOptions {\n /** Polling interval in ms (default `5000`) */\n interval?: number;\n /** Enable / disable polling (default `true`). The initial fetch always fires. */\n enabled?: boolean;\n}\n\nexport interface SmartPollingResult<T> {\n data: T | undefined;\n isLoading: boolean;\n isError: boolean;\n error: Error | undefined;\n /** Manually trigger a fetch */\n refetch: () => Promise<void>;\n}\n\n/**\n * Visibility-aware polling hook.\n *\n * - Pauses when the tab is hidden.\n * - Skips re-renders when data hasn't changed (shallow JSON comparison).\n * - Prevents overlapping fetches.\n *\n * @param fetchFn - Async function that returns data.\n * @param options - Optional configuration.\n */\nexport function useSmartPolling<T = unknown>(\n fetchFn: () => Promise<T>,\n options?: SmartPollingOptions,\n): SmartPollingResult<T> {\n const { interval = 5000, enabled = true } = options ?? {};\n const visible = useDocVisible();\n\n const [data, setData] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const fetchRef = useRef(fetchFn);\n const timerRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);\n const isFetchingRef = useRef(false);\n const lastJsonRef = useRef<string | undefined>(undefined);\n const mountedRef = useRef(true);\n\n // Always keep the latest fetchFn\n fetchRef.current = fetchFn;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const execute = useCallback(async () => {\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n try {\n const result = await fetchRef.current();\n if (!mountedRef.current) return;\n\n const json = JSON.stringify(result);\n if (json !== lastJsonRef.current) {\n lastJsonRef.current = json;\n setData(result);\n }\n setError((prev) => (prev !== undefined ? undefined : prev));\n } catch (err) {\n if (!mountedRef.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n isFetchingRef.current = false;\n if (mountedRef.current) {\n setIsLoading((prev) => (prev ? false : prev));\n }\n }\n }, []);\n\n // Initial fetch â always runs once regardless of `enabled`\n const hasFetchedRef = useRef(false);\n useEffect(() => {\n if (hasFetchedRef.current) return;\n hasFetchedRef.current = true;\n execute();\n }, [execute]);\n\n // Polling â only when visible AND enabled\n useEffect(() => {\n if (!enabled || !visible) {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n return;\n }\n\n // Immediately fetch when re-enabled / tab returns\n execute();\n\n timerRef.current = setInterval(execute, interval);\n return () => {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n };\n }, [visible, enabled, interval, execute]);\n\n return {\n data,\n isLoading,\n isError: error !== undefined,\n error,\n refetch: execute,\n };\n}\n","import { useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface PageFocusEffectOptions {\n /** Callback fired when the page transitions from hidden â visible. May return a cleanup function. */\n onVisible?: () => void | (() => void);\n /** Callback fired when the page transitions from visible â hidden. */\n onHidden?: () => void;\n}\n\n/**\n * Runs side-effect callbacks on visibility **transitions** rather than\n * on every render.\n *\n * - `onVisible` fires when the tab goes from hidden â visible.\n * - `onHidden` fires when the tab goes from visible â hidden.\n * - The very first render is **not** treated as a transition.\n * - `onVisible` may return a cleanup function (like `useEffect`).\n *\n * SSR-safe â no-ops on the server.\n *\n * @example\n * ```tsx\n * usePageFocusEffect({\n * onVisible: () => { refetchStaleData(); },\n * onHidden: () => { saveScrollPosition(); },\n * });\n * ```\n */\nexport function usePageFocusEffect(options: PageFocusEffectOptions): void {\n const visible = useDocVisible();\n const prevRef = useRef<boolean | undefined>(undefined);\n const cleanupRef = useRef<(() => void) | undefined>(undefined);\n\n // Keep latest callbacks in refs to avoid re-triggering the effect\n const onVisibleRef = useRef(options.onVisible);\n const onHiddenRef = useRef(options.onHidden);\n onVisibleRef.current = options.onVisible;\n onHiddenRef.current = options.onHidden;\n\n useEffect(() => {\n // Skip the initial mount â only fire on actual transitions\n if (prevRef.current === undefined) {\n prevRef.current = visible;\n return;\n }\n\n if (visible && !prevRef.current) {\n // hidden â visible\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n const result = onVisibleRef.current?.();\n if (typeof result === \"function\") {\n cleanupRef.current = result;\n }\n } else if (!visible && prevRef.current) {\n // visible â hidden\n onHiddenRef.current?.();\n }\n\n prevRef.current = visible;\n }, [visible]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n cleanupRef.current?.();\n };\n }, []);\n}\n","import { useState, useEffect, useCallback } from \"react\";\nimport { useSmartPolling } from \"./useSmartPolling\";\nimport type { SmartPollingOptions, SmartPollingResult } from \"./useSmartPolling\";\n\nexport interface NetworkAwarePollingOptions extends SmartPollingOptions {\n /** Multiplier applied to `interval` on slow connections like 2g (default `3`). */\n slowMultiplier?: number;\n /** Whether to pause polling when the browser is offline (default `true`). */\n pauseOffline?: boolean;\n}\n\nexport interface NetworkAwarePollingResult<T> extends SmartPollingResult<T> {\n /** `true` when the browser reports being online. */\n isOnline: boolean;\n /** The effective polling interval after network-quality adjustment. */\n effectiveInterval: number;\n}\n\n/**\n * Network + visibility-aware polling.\n *\n * Extends `useSmartPolling` with:\n * - Automatic pause when the browser goes offline.\n * - Adaptive interval â polls slower on poor connections (2g / slow-2g).\n *\n * SSR-safe â defaults to online on the server.\n *\n * @param fetchFn - Async function that returns data.\n * @param options - Optional configuration.\n */\nexport function useNetworkAwarePolling<T = unknown>(\n fetchFn: () => Promise<T>,\n options?: NetworkAwarePollingOptions,\n): NetworkAwarePollingResult<T> {\n const {\n interval = 5000,\n enabled = true,\n slowMultiplier = 3,\n pauseOffline = true,\n ...rest\n } = options ?? {};\n\n const online = useOnline();\n const effectiveInterval = getEffectiveInterval(interval, slowMultiplier);\n\n const shouldPoll = pauseOffline ? enabled && online : enabled;\n\n const result = useSmartPolling(fetchFn, {\n ...rest,\n interval: effectiveInterval,\n enabled: shouldPoll,\n });\n\n return { ...result, isOnline: online, effectiveInterval };\n}\n\n/* ------------------------------------------------------------------ */\n/* Internal helpers */\n/* ------------------------------------------------------------------ */\n\n/** SSR-safe hook that tracks `navigator.onLine`. */\nfunction useOnline(): boolean {\n const [online, setOnline] = useState(() =>\n typeof navigator === \"undefined\" ? true : navigator.onLine,\n );\n\n const handleOnline = useCallback(() => setOnline(true), []);\n const handleOffline = useCallback(() => setOnline(false), []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, [handleOnline, handleOffline]);\n\n return online;\n}\n\n/** Returns a longer interval when the connection is slow. */\nfunction getEffectiveInterval(base: number, multiplier: number): number {\n if (typeof navigator === \"undefined\") return base;\n\n const conn = (\n navigator as Navigator & {\n connection?: { effectiveType?: string };\n }\n ).connection;\n\n if (conn?.effectiveType === \"2g\" || conn?.effectiveType === \"slow-2g\") {\n return base * multiplier;\n }\n return base;\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useIdleVisibility } from \"./useIdleVisibility\";\n\nexport interface InactivityTimeoutOptions {\n /** Total inactivity before `onTimeout` fires, in ms (default `300_000` â 5 min). */\n timeout?: number;\n /**\n * How long before the final timeout to enter the \"warning\" phase, in ms\n * (default `60_000` â 1 min).\n *\n * Set to `0` to disable the warning phase.\n */\n warningBefore?: number;\n /** Called once when the full timeout elapses. */\n onTimeout?: () => void;\n /** Called when entering the warning phase. */\n onWarning?: () => void;\n}\n\nexport interface InactivityTimeoutResult {\n /** `true` once the user has been idle long enough to start counting down. */\n idle: boolean;\n /** Current page-visibility state. */\n visible: boolean;\n /** `true` during the warning countdown (before final timeout). */\n isWarning: boolean;\n /** `true` after the full timeout has elapsed. */\n isTimedOut: boolean;\n /** Seconds remaining until timeout (`-1` when the user is not idle). */\n remainingSeconds: number;\n /** Manually reset the timer and cancel any pending timeout. */\n resetTimer: () => void;\n}\n\n/**\n * Countdown-based session/inactivity manager built on top of\n * `useIdleVisibility`.\n *\n * 1. After `timeout - warningBefore` ms of inactivity the hook enters\n * the **warning** phase and starts a per-second countdown.\n * 2. When the countdown hits zero `onTimeout` fires and `isTimedOut`\n * becomes `true`.\n * 3. Any user interaction resets the timer.\n *\n * SSR-safe â all timers only run in the browser.\n */\nexport function useInactivityTimeout(\n options?: InactivityTimeoutOptions,\n): InactivityTimeoutResult {\n const {\n timeout = 300_000,\n warningBefore = 60_000,\n onTimeout,\n onWarning,\n } = options ?? {};\n\n // Clamp so warningBefore never exceeds timeout\n const clampedWarning = Math.min(warningBefore, timeout);\n const idleThreshold = timeout - clampedWarning;\n\n const { idle, visible } = useIdleVisibility(idleThreshold);\n\n const [remaining, setRemaining] = useState(-1);\n const [timedOut, setTimedOut] = useState(false);\n const intervalRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);\n const startRef = useRef<number | undefined>(undefined);\n const warnedRef = useRef(false);\n\n // Keep callback refs stable\n const onTimeoutRef = useRef(onTimeout);\n const onWarningRef = useRef(onWarning);\n onTimeoutRef.current = onTimeout;\n onWarningRef.current = onWarning;\n\n const clear = useCallback(() => {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n startRef.current = undefined;\n warnedRef.current = false;\n setRemaining(-1);\n setTimedOut(false);\n }, []);\n\n useEffect(() => {\n if (!idle || timedOut) {\n if (!idle) clear();\n return;\n }\n\n startRef.current = Date.now();\n\n // Fire the warning callback once at the start of the countdown\n if (!warnedRef.current) {\n warnedRef.current = true;\n onWarningRef.current?.();\n }\n\n const warningMs = clampedWarning;\n\n intervalRef.current = setInterval(() => {\n const elapsed = Date.now() - (startRef.current ?? Date.now());\n const left = Math.max(0, Math.ceil((warningMs - elapsed) / 1000));\n setRemaining(left);\n\n if (left <= 0) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n setTimedOut(true);\n onTimeoutRef.current?.();\n }\n }, 1000);\n\n return () => {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n };\n }, [idle, timedOut, clampedWarning, clear]);\n\n const isWarning = idle && !timedOut && remaining >= 0;\n\n return {\n idle: idle || timedOut,\n visible,\n isWarning,\n isTimedOut: timedOut,\n remainingSeconds: remaining,\n resetTimer: clear,\n };\n}\n","import { useState, useCallback, useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface WakeLockResult {\n /** `true` while a Wake Lock is actively held. */\n isActive: boolean;\n /** Request the screen Wake Lock. No-ops if unsupported. */\n request: () => Promise<void>;\n /** Release the current Wake Lock. */\n release: () => Promise<void>;\n /** `true` when the Screen Wake Lock API is available in this browser. */\n isSupported: boolean;\n}\n\n/**\n * Manages the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API)\n * to prevent the screen from dimming or locking.\n *\n * Features:\n * - Automatic re-acquire on tab re-focus when `autoReacquire` is `true`.\n * - Cleans up the Wake Lock on unmount.\n * - SSR-safe â `isSupported` will be `false` on the server.\n *\n * @param autoReacquire - Re-request the lock when the tab becomes visible\n * again after being hidden (default `true`).\n */\nexport function useWakeLock(autoReacquire = true): WakeLockResult {\n const visible = useDocVisible();\n const [isActive, setIsActive] = useState(false);\n const sentinelRef = useRef<WakeLockSentinel | undefined>(undefined);\n const wantedRef = useRef(false);\n\n const isSupported = typeof navigator !== \"undefined\" && navigator.wakeLock != null;\n\n const request = useCallback(async () => {\n if (!isSupported) return;\n // Already holding a lock â skip\n if (sentinelRef.current && !sentinelRef.current.released) return;\n\n try {\n const sentinel = await navigator.wakeLock.request(\"screen\");\n sentinelRef.current = sentinel;\n wantedRef.current = true;\n setIsActive(true);\n\n sentinel.addEventListener(\"release\", () => {\n setIsActive(false);\n sentinelRef.current = undefined;\n });\n } catch {\n // Permission denied, low battery, or other platform error\n }\n }, [isSupported]);\n\n const release = useCallback(async () => {\n wantedRef.current = false;\n if (sentinelRef.current && !sentinelRef.current.released) {\n await sentinelRef.current.release();\n }\n }, []);\n\n // Re-acquire on tab visibility change\n useEffect(() => {\n if (autoReacquire && visible && wantedRef.current && !sentinelRef.current) {\n void request();\n }\n }, [visible, autoReacquire, request]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (sentinelRef.current && !sentinelRef.current.released) {\n sentinelRef.current.release().catch(() => {});\n }\n };\n }, []);\n\n return { isActive, request, release, isSupported };\n}\n","import { useState, useEffect, useCallback } from \"react\";\n\nexport interface BatteryState {\n /** `true` when the device is plugged in. Defaults to `true` (optimistic). */\n charging: boolean;\n /** Battery level between 0 and 1. Defaults to `1`. */\n level: number;\n /** `true` when the device is **not** charging and `level` is below `lowThreshold`. */\n isLowBattery: boolean;\n /** `true` when the Battery Status API is available. */\n isSupported: boolean;\n}\n\ninterface BatteryManager extends EventTarget {\n charging: boolean;\n level: number;\n}\n\n/**\n * Exposes device battery status via the\n * [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API).\n *\n * Use cases:\n * - Reduce polling frequency on low battery.\n * - Disable animations / heavy computations when the battery is low.\n * - Show a battery-aware UI indicator.\n *\n * SSR-safe â returns optimistic defaults on the server.\n *\n * @param lowThreshold - Level (0â1) below which `isLowBattery` becomes `true`\n * when the device is not charging (default `0.15`).\n */\nexport function useBatteryAware(lowThreshold = 0.15): BatteryState {\n const [state, setState] = useState<BatteryState>({\n charging: true,\n level: 1,\n isLowBattery: false,\n isSupported: false,\n });\n\n const update = useCallback(\n (battery: BatteryManager) => {\n setState({\n charging: battery.charging,\n level: battery.level,\n isLowBattery: !battery.charging && battery.level < lowThreshold,\n isSupported: true,\n });\n },\n [lowThreshold],\n );\n\n useEffect(() => {\n if (\n typeof navigator === \"undefined\" ||\n typeof (navigator as Navigator & { getBattery?: unknown }).getBattery !== \"function\"\n ) {\n return;\n }\n\n let battery: BatteryManager | undefined;\n let cancelled = false;\n\n const onChange = () => {\n if (battery && !cancelled) update(battery);\n };\n\n (navigator as Navigator & { getBattery: () => Promise<BatteryManager> })\n .getBattery()\n .then((b) => {\n if (cancelled) return;\n battery = b;\n update(b);\n b.addEventListener(\"chargingchange\", onChange);\n b.addEventListener(\"levelchange\", onChange);\n })\n .catch(() => {\n // API exists but call failed â leave defaults\n });\n\n return () => {\n cancelled = true;\n if (battery) {\n battery.removeEventListener(\"chargingchange\", onChange);\n battery.removeEventListener(\"levelchange\", onChange);\n }\n };\n }, [update]);\n\n return state;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -52,4 +52,150 @@ interface SmartPollingResult<T> {
|
|
|
52
52
|
*/
|
|
53
53
|
declare function useSmartPolling<T = unknown>(fetchFn: () => Promise<T>, options?: SmartPollingOptions): SmartPollingResult<T>;
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
interface PageFocusEffectOptions {
|
|
56
|
+
/** Callback fired when the page transitions from hidden â visible. May return a cleanup function. */
|
|
57
|
+
onVisible?: () => void | (() => void);
|
|
58
|
+
/** Callback fired when the page transitions from visible â hidden. */
|
|
59
|
+
onHidden?: () => void;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Runs side-effect callbacks on visibility **transitions** rather than
|
|
63
|
+
* on every render.
|
|
64
|
+
*
|
|
65
|
+
* - `onVisible` fires when the tab goes from hidden â visible.
|
|
66
|
+
* - `onHidden` fires when the tab goes from visible â hidden.
|
|
67
|
+
* - The very first render is **not** treated as a transition.
|
|
68
|
+
* - `onVisible` may return a cleanup function (like `useEffect`).
|
|
69
|
+
*
|
|
70
|
+
* SSR-safe â no-ops on the server.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* usePageFocusEffect({
|
|
75
|
+
* onVisible: () => { refetchStaleData(); },
|
|
76
|
+
* onHidden: () => { saveScrollPosition(); },
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function usePageFocusEffect(options: PageFocusEffectOptions): void;
|
|
81
|
+
|
|
82
|
+
interface NetworkAwarePollingOptions extends SmartPollingOptions {
|
|
83
|
+
/** Multiplier applied to `interval` on slow connections like 2g (default `3`). */
|
|
84
|
+
slowMultiplier?: number;
|
|
85
|
+
/** Whether to pause polling when the browser is offline (default `true`). */
|
|
86
|
+
pauseOffline?: boolean;
|
|
87
|
+
}
|
|
88
|
+
interface NetworkAwarePollingResult<T> extends SmartPollingResult<T> {
|
|
89
|
+
/** `true` when the browser reports being online. */
|
|
90
|
+
isOnline: boolean;
|
|
91
|
+
/** The effective polling interval after network-quality adjustment. */
|
|
92
|
+
effectiveInterval: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Network + visibility-aware polling.
|
|
96
|
+
*
|
|
97
|
+
* Extends `useSmartPolling` with:
|
|
98
|
+
* - Automatic pause when the browser goes offline.
|
|
99
|
+
* - Adaptive interval â polls slower on poor connections (2g / slow-2g).
|
|
100
|
+
*
|
|
101
|
+
* SSR-safe â defaults to online on the server.
|
|
102
|
+
*
|
|
103
|
+
* @param fetchFn - Async function that returns data.
|
|
104
|
+
* @param options - Optional configuration.
|
|
105
|
+
*/
|
|
106
|
+
declare function useNetworkAwarePolling<T = unknown>(fetchFn: () => Promise<T>, options?: NetworkAwarePollingOptions): NetworkAwarePollingResult<T>;
|
|
107
|
+
|
|
108
|
+
interface InactivityTimeoutOptions {
|
|
109
|
+
/** Total inactivity before `onTimeout` fires, in ms (default `300_000` â 5 min). */
|
|
110
|
+
timeout?: number;
|
|
111
|
+
/**
|
|
112
|
+
* How long before the final timeout to enter the "warning" phase, in ms
|
|
113
|
+
* (default `60_000` â 1 min).
|
|
114
|
+
*
|
|
115
|
+
* Set to `0` to disable the warning phase.
|
|
116
|
+
*/
|
|
117
|
+
warningBefore?: number;
|
|
118
|
+
/** Called once when the full timeout elapses. */
|
|
119
|
+
onTimeout?: () => void;
|
|
120
|
+
/** Called when entering the warning phase. */
|
|
121
|
+
onWarning?: () => void;
|
|
122
|
+
}
|
|
123
|
+
interface InactivityTimeoutResult {
|
|
124
|
+
/** `true` once the user has been idle long enough to start counting down. */
|
|
125
|
+
idle: boolean;
|
|
126
|
+
/** Current page-visibility state. */
|
|
127
|
+
visible: boolean;
|
|
128
|
+
/** `true` during the warning countdown (before final timeout). */
|
|
129
|
+
isWarning: boolean;
|
|
130
|
+
/** `true` after the full timeout has elapsed. */
|
|
131
|
+
isTimedOut: boolean;
|
|
132
|
+
/** Seconds remaining until timeout (`-1` when the user is not idle). */
|
|
133
|
+
remainingSeconds: number;
|
|
134
|
+
/** Manually reset the timer and cancel any pending timeout. */
|
|
135
|
+
resetTimer: () => void;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Countdown-based session/inactivity manager built on top of
|
|
139
|
+
* `useIdleVisibility`.
|
|
140
|
+
*
|
|
141
|
+
* 1. After `timeout - warningBefore` ms of inactivity the hook enters
|
|
142
|
+
* the **warning** phase and starts a per-second countdown.
|
|
143
|
+
* 2. When the countdown hits zero `onTimeout` fires and `isTimedOut`
|
|
144
|
+
* becomes `true`.
|
|
145
|
+
* 3. Any user interaction resets the timer.
|
|
146
|
+
*
|
|
147
|
+
* SSR-safe â all timers only run in the browser.
|
|
148
|
+
*/
|
|
149
|
+
declare function useInactivityTimeout(options?: InactivityTimeoutOptions): InactivityTimeoutResult;
|
|
150
|
+
|
|
151
|
+
interface WakeLockResult {
|
|
152
|
+
/** `true` while a Wake Lock is actively held. */
|
|
153
|
+
isActive: boolean;
|
|
154
|
+
/** Request the screen Wake Lock. No-ops if unsupported. */
|
|
155
|
+
request: () => Promise<void>;
|
|
156
|
+
/** Release the current Wake Lock. */
|
|
157
|
+
release: () => Promise<void>;
|
|
158
|
+
/** `true` when the Screen Wake Lock API is available in this browser. */
|
|
159
|
+
isSupported: boolean;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Manages the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API)
|
|
163
|
+
* to prevent the screen from dimming or locking.
|
|
164
|
+
*
|
|
165
|
+
* Features:
|
|
166
|
+
* - Automatic re-acquire on tab re-focus when `autoReacquire` is `true`.
|
|
167
|
+
* - Cleans up the Wake Lock on unmount.
|
|
168
|
+
* - SSR-safe â `isSupported` will be `false` on the server.
|
|
169
|
+
*
|
|
170
|
+
* @param autoReacquire - Re-request the lock when the tab becomes visible
|
|
171
|
+
* again after being hidden (default `true`).
|
|
172
|
+
*/
|
|
173
|
+
declare function useWakeLock(autoReacquire?: boolean): WakeLockResult;
|
|
174
|
+
|
|
175
|
+
interface BatteryState {
|
|
176
|
+
/** `true` when the device is plugged in. Defaults to `true` (optimistic). */
|
|
177
|
+
charging: boolean;
|
|
178
|
+
/** Battery level between 0 and 1. Defaults to `1`. */
|
|
179
|
+
level: number;
|
|
180
|
+
/** `true` when the device is **not** charging and `level` is below `lowThreshold`. */
|
|
181
|
+
isLowBattery: boolean;
|
|
182
|
+
/** `true` when the Battery Status API is available. */
|
|
183
|
+
isSupported: boolean;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Exposes device battery status via the
|
|
187
|
+
* [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API).
|
|
188
|
+
*
|
|
189
|
+
* Use cases:
|
|
190
|
+
* - Reduce polling frequency on low battery.
|
|
191
|
+
* - Disable animations / heavy computations when the battery is low.
|
|
192
|
+
* - Show a battery-aware UI indicator.
|
|
193
|
+
*
|
|
194
|
+
* SSR-safe â returns optimistic defaults on the server.
|
|
195
|
+
*
|
|
196
|
+
* @param lowThreshold - Level (0â1) below which `isLowBattery` becomes `true`
|
|
197
|
+
* when the device is not charging (default `0.15`).
|
|
198
|
+
*/
|
|
199
|
+
declare function useBatteryAware(lowThreshold?: number): BatteryState;
|
|
200
|
+
|
|
201
|
+
export { type BatteryState, type IdleVisibilityResult, type InactivityTimeoutOptions, type InactivityTimeoutResult, type NetworkAwarePollingOptions, type NetworkAwarePollingResult, type PageFocusEffectOptions, type SmartPollingOptions, type SmartPollingResult, type WakeLockResult, useAutoPauseVideo, useBatteryAware, useDocVisible, useIdleVisibility, useInactivityTimeout, useNetworkAwarePolling, usePageFocusEffect, useSmartPolling, useWakeLock };
|
package/dist/index.d.ts
CHANGED
|
@@ -52,4 +52,150 @@ interface SmartPollingResult<T> {
|
|
|
52
52
|
*/
|
|
53
53
|
declare function useSmartPolling<T = unknown>(fetchFn: () => Promise<T>, options?: SmartPollingOptions): SmartPollingResult<T>;
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
interface PageFocusEffectOptions {
|
|
56
|
+
/** Callback fired when the page transitions from hidden â visible. May return a cleanup function. */
|
|
57
|
+
onVisible?: () => void | (() => void);
|
|
58
|
+
/** Callback fired when the page transitions from visible â hidden. */
|
|
59
|
+
onHidden?: () => void;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Runs side-effect callbacks on visibility **transitions** rather than
|
|
63
|
+
* on every render.
|
|
64
|
+
*
|
|
65
|
+
* - `onVisible` fires when the tab goes from hidden â visible.
|
|
66
|
+
* - `onHidden` fires when the tab goes from visible â hidden.
|
|
67
|
+
* - The very first render is **not** treated as a transition.
|
|
68
|
+
* - `onVisible` may return a cleanup function (like `useEffect`).
|
|
69
|
+
*
|
|
70
|
+
* SSR-safe â no-ops on the server.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```tsx
|
|
74
|
+
* usePageFocusEffect({
|
|
75
|
+
* onVisible: () => { refetchStaleData(); },
|
|
76
|
+
* onHidden: () => { saveScrollPosition(); },
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function usePageFocusEffect(options: PageFocusEffectOptions): void;
|
|
81
|
+
|
|
82
|
+
interface NetworkAwarePollingOptions extends SmartPollingOptions {
|
|
83
|
+
/** Multiplier applied to `interval` on slow connections like 2g (default `3`). */
|
|
84
|
+
slowMultiplier?: number;
|
|
85
|
+
/** Whether to pause polling when the browser is offline (default `true`). */
|
|
86
|
+
pauseOffline?: boolean;
|
|
87
|
+
}
|
|
88
|
+
interface NetworkAwarePollingResult<T> extends SmartPollingResult<T> {
|
|
89
|
+
/** `true` when the browser reports being online. */
|
|
90
|
+
isOnline: boolean;
|
|
91
|
+
/** The effective polling interval after network-quality adjustment. */
|
|
92
|
+
effectiveInterval: number;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Network + visibility-aware polling.
|
|
96
|
+
*
|
|
97
|
+
* Extends `useSmartPolling` with:
|
|
98
|
+
* - Automatic pause when the browser goes offline.
|
|
99
|
+
* - Adaptive interval â polls slower on poor connections (2g / slow-2g).
|
|
100
|
+
*
|
|
101
|
+
* SSR-safe â defaults to online on the server.
|
|
102
|
+
*
|
|
103
|
+
* @param fetchFn - Async function that returns data.
|
|
104
|
+
* @param options - Optional configuration.
|
|
105
|
+
*/
|
|
106
|
+
declare function useNetworkAwarePolling<T = unknown>(fetchFn: () => Promise<T>, options?: NetworkAwarePollingOptions): NetworkAwarePollingResult<T>;
|
|
107
|
+
|
|
108
|
+
interface InactivityTimeoutOptions {
|
|
109
|
+
/** Total inactivity before `onTimeout` fires, in ms (default `300_000` â 5 min). */
|
|
110
|
+
timeout?: number;
|
|
111
|
+
/**
|
|
112
|
+
* How long before the final timeout to enter the "warning" phase, in ms
|
|
113
|
+
* (default `60_000` â 1 min).
|
|
114
|
+
*
|
|
115
|
+
* Set to `0` to disable the warning phase.
|
|
116
|
+
*/
|
|
117
|
+
warningBefore?: number;
|
|
118
|
+
/** Called once when the full timeout elapses. */
|
|
119
|
+
onTimeout?: () => void;
|
|
120
|
+
/** Called when entering the warning phase. */
|
|
121
|
+
onWarning?: () => void;
|
|
122
|
+
}
|
|
123
|
+
interface InactivityTimeoutResult {
|
|
124
|
+
/** `true` once the user has been idle long enough to start counting down. */
|
|
125
|
+
idle: boolean;
|
|
126
|
+
/** Current page-visibility state. */
|
|
127
|
+
visible: boolean;
|
|
128
|
+
/** `true` during the warning countdown (before final timeout). */
|
|
129
|
+
isWarning: boolean;
|
|
130
|
+
/** `true` after the full timeout has elapsed. */
|
|
131
|
+
isTimedOut: boolean;
|
|
132
|
+
/** Seconds remaining until timeout (`-1` when the user is not idle). */
|
|
133
|
+
remainingSeconds: number;
|
|
134
|
+
/** Manually reset the timer and cancel any pending timeout. */
|
|
135
|
+
resetTimer: () => void;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Countdown-based session/inactivity manager built on top of
|
|
139
|
+
* `useIdleVisibility`.
|
|
140
|
+
*
|
|
141
|
+
* 1. After `timeout - warningBefore` ms of inactivity the hook enters
|
|
142
|
+
* the **warning** phase and starts a per-second countdown.
|
|
143
|
+
* 2. When the countdown hits zero `onTimeout` fires and `isTimedOut`
|
|
144
|
+
* becomes `true`.
|
|
145
|
+
* 3. Any user interaction resets the timer.
|
|
146
|
+
*
|
|
147
|
+
* SSR-safe â all timers only run in the browser.
|
|
148
|
+
*/
|
|
149
|
+
declare function useInactivityTimeout(options?: InactivityTimeoutOptions): InactivityTimeoutResult;
|
|
150
|
+
|
|
151
|
+
interface WakeLockResult {
|
|
152
|
+
/** `true` while a Wake Lock is actively held. */
|
|
153
|
+
isActive: boolean;
|
|
154
|
+
/** Request the screen Wake Lock. No-ops if unsupported. */
|
|
155
|
+
request: () => Promise<void>;
|
|
156
|
+
/** Release the current Wake Lock. */
|
|
157
|
+
release: () => Promise<void>;
|
|
158
|
+
/** `true` when the Screen Wake Lock API is available in this browser. */
|
|
159
|
+
isSupported: boolean;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Manages the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API)
|
|
163
|
+
* to prevent the screen from dimming or locking.
|
|
164
|
+
*
|
|
165
|
+
* Features:
|
|
166
|
+
* - Automatic re-acquire on tab re-focus when `autoReacquire` is `true`.
|
|
167
|
+
* - Cleans up the Wake Lock on unmount.
|
|
168
|
+
* - SSR-safe â `isSupported` will be `false` on the server.
|
|
169
|
+
*
|
|
170
|
+
* @param autoReacquire - Re-request the lock when the tab becomes visible
|
|
171
|
+
* again after being hidden (default `true`).
|
|
172
|
+
*/
|
|
173
|
+
declare function useWakeLock(autoReacquire?: boolean): WakeLockResult;
|
|
174
|
+
|
|
175
|
+
interface BatteryState {
|
|
176
|
+
/** `true` when the device is plugged in. Defaults to `true` (optimistic). */
|
|
177
|
+
charging: boolean;
|
|
178
|
+
/** Battery level between 0 and 1. Defaults to `1`. */
|
|
179
|
+
level: number;
|
|
180
|
+
/** `true` when the device is **not** charging and `level` is below `lowThreshold`. */
|
|
181
|
+
isLowBattery: boolean;
|
|
182
|
+
/** `true` when the Battery Status API is available. */
|
|
183
|
+
isSupported: boolean;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Exposes device battery status via the
|
|
187
|
+
* [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API).
|
|
188
|
+
*
|
|
189
|
+
* Use cases:
|
|
190
|
+
* - Reduce polling frequency on low battery.
|
|
191
|
+
* - Disable animations / heavy computations when the battery is low.
|
|
192
|
+
* - Show a battery-aware UI indicator.
|
|
193
|
+
*
|
|
194
|
+
* SSR-safe â returns optimistic defaults on the server.
|
|
195
|
+
*
|
|
196
|
+
* @param lowThreshold - Level (0â1) below which `isLowBattery` becomes `true`
|
|
197
|
+
* when the device is not charging (default `0.15`).
|
|
198
|
+
*/
|
|
199
|
+
declare function useBatteryAware(lowThreshold?: number): BatteryState;
|
|
200
|
+
|
|
201
|
+
export { type BatteryState, type IdleVisibilityResult, type InactivityTimeoutOptions, type InactivityTimeoutResult, type NetworkAwarePollingOptions, type NetworkAwarePollingResult, type PageFocusEffectOptions, type SmartPollingOptions, type SmartPollingResult, type WakeLockResult, useAutoPauseVideo, useBatteryAware, useDocVisible, useIdleVisibility, useInactivityTimeout, useNetworkAwarePolling, usePageFocusEffect, useSmartPolling, useWakeLock };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {useState,useCallback,useEffect,useRef}from'react';function
|
|
1
|
+
import {useState,useCallback,useEffect,useRef}from'react';function m(){let[i,n]=useState(()=>typeof document=="undefined"?true:document.visibilityState==="visible"),t=useCallback(()=>{n(document.visibilityState==="visible");},[]);return useEffect(()=>{if(typeof document!="undefined")return t(),document.addEventListener("visibilitychange",t),()=>document.removeEventListener("visibilitychange",t)},[t]),i}function T(i=6e4){let n=m(),[t,r]=useState(false),e=useRef(void 0),o=useCallback(()=>{r(false),clearTimeout(e.current),e.current=setTimeout(()=>r(true),i);},[i]);return useEffect(()=>{if(typeof window=="undefined")return;let s=["mousemove","keydown","pointerdown","scroll","touchstart"];return s.forEach(u=>window.addEventListener(u,o,{passive:true})),o(),()=>{s.forEach(u=>window.removeEventListener(u,o)),clearTimeout(e.current);}},[o]),useEffect(()=>{n&&o();},[n,o]),{visible:n,idle:t}}function Q(i){let n=m(),t=useRef(false);useEffect(()=>{let r=i.current;r&&(!n&&!r.paused?(r.pause(),t.current=true):n&&t.current&&(r.play().catch(()=>{}),t.current=false));},[n,i]);}function I(i,n){let{interval:t=5e3,enabled:r=true}=n!=null?n:{},e=m(),[o,s]=useState(void 0),[u,l]=useState(true),[c,b]=useState(void 0),g=useRef(i),p=useRef(void 0),f=useRef(false),w=useRef(void 0),v=useRef(true);g.current=i,useEffect(()=>(v.current=true,()=>{v.current=false;}),[]);let d=useCallback(async()=>{if(!f.current){f.current=true;try{let a=await g.current();if(!v.current)return;let x=JSON.stringify(a);x!==w.current&&(w.current=x,s(a)),b(k=>k!==void 0?void 0:k);}catch(a){if(!v.current)return;b(a instanceof Error?a:new Error(String(a)));}finally{f.current=false,v.current&&l(a=>a&&false);}}},[]),y=useRef(false);return useEffect(()=>{y.current||(y.current=true,d());},[d]),useEffect(()=>{if(!r||!e){clearInterval(p.current),p.current=void 0;return}return d(),p.current=setInterval(d,t),()=>{clearInterval(p.current),p.current=void 0;}},[e,r,t,d]),{data:o,isLoading:u,isError:c!==void 0,error:c,refetch:d}}function Y(i){let n=m(),t=useRef(void 0),r=useRef(void 0),e=useRef(i.onVisible),o=useRef(i.onHidden);e.current=i.onVisible,o.current=i.onHidden,useEffect(()=>{var s,u,l;if(t.current===void 0){t.current=n;return}if(n&&!t.current){(s=r.current)==null||s.call(r),r.current=void 0;let c=(u=e.current)==null?void 0:u.call(e);typeof c=="function"&&(r.current=c);}else !n&&t.current&&((l=o.current)==null||l.call(o));t.current=n;},[n]),useEffect(()=>()=>{var s;(s=r.current)==null||s.call(r);},[]);}function ee(i,n){let{interval:t=5e3,enabled:r=true,slowMultiplier:e=3,pauseOffline:o=true,...s}=n!=null?n:{},u=te(),l=ne(t,e);return {...I(i,{...s,interval:l,enabled:o?r&&u:r}),isOnline:u,effectiveInterval:l}}function te(){let[i,n]=useState(()=>typeof navigator=="undefined"?true:navigator.onLine),t=useCallback(()=>n(true),[]),r=useCallback(()=>n(false),[]);return useEffect(()=>{if(typeof window!="undefined")return window.addEventListener("online",t),window.addEventListener("offline",r),()=>{window.removeEventListener("online",t),window.removeEventListener("offline",r);}},[t,r]),i}function ne(i,n){if(typeof navigator=="undefined")return i;let t=navigator.connection;return (t==null?void 0:t.effectiveType)==="2g"||(t==null?void 0:t.effectiveType)==="slow-2g"?i*n:i}function oe(i){let{timeout:n=3e5,warningBefore:t=6e4,onTimeout:r,onWarning:e}=i!=null?i:{},o=Math.min(t,n),s=n-o,{idle:u,visible:l}=T(s),[c,b]=useState(-1),[g,p]=useState(false),f=useRef(void 0),w=useRef(void 0),v=useRef(false),d=useRef(r),y=useRef(e);d.current=r,y.current=e;let a=useCallback(()=>{clearInterval(f.current),f.current=void 0,w.current=void 0,v.current=false,b(-1),p(false);},[]);useEffect(()=>{var L;if(!u||g){u||a();return}w.current=Date.now(),v.current||(v.current=true,(L=y.current)==null||L.call(y));let k=o;return f.current=setInterval(()=>{var B,V;let H=Date.now()-((B=w.current)!=null?B:Date.now()),O=Math.max(0,Math.ceil((k-H)/1e3));b(O),O<=0&&(clearInterval(f.current),f.current=void 0,p(true),(V=d.current)==null||V.call(d));},1e3),()=>{clearInterval(f.current),f.current=void 0;}},[u,g,o,a]);let x=u&&!g&&c>=0;return {idle:u||g,visible:l,isWarning:x,isTimedOut:g,remainingSeconds:c,resetTimer:a}}function se(i=true){let n=m(),[t,r]=useState(false),e=useRef(void 0),o=useRef(false),s=typeof navigator!="undefined"&&navigator.wakeLock!=null,u=useCallback(async()=>{if(s&&!(e.current&&!e.current.released))try{let c=await navigator.wakeLock.request("screen");e.current=c,o.current=!0,r(!0),c.addEventListener("release",()=>{r(!1),e.current=void 0;});}catch{}},[s]),l=useCallback(async()=>{o.current=false,e.current&&!e.current.released&&await e.current.release();},[]);return useEffect(()=>{i&&n&&o.current&&!e.current&&u();},[n,i,u]),useEffect(()=>()=>{e.current&&!e.current.released&&e.current.release().catch(()=>{});},[]),{isActive:t,request:u,release:l,isSupported:s}}function fe(i=.15){let[n,t]=useState({charging:true,level:1,isLowBattery:false,isSupported:false}),r=useCallback(e=>{t({charging:e.charging,level:e.level,isLowBattery:!e.charging&&e.level<i,isSupported:true});},[i]);return useEffect(()=>{if(typeof navigator=="undefined"||typeof navigator.getBattery!="function")return;let e,o=false,s=()=>{e&&!o&&r(e);};return navigator.getBattery().then(u=>{o||(e=u,r(u),u.addEventListener("chargingchange",s),u.addEventListener("levelchange",s));}).catch(()=>{}),()=>{o=true,e&&(e.removeEventListener("chargingchange",s),e.removeEventListener("levelchange",s));}},[r]),n}export{Q as useAutoPauseVideo,fe as useBatteryAware,m as useDocVisible,T as useIdleVisibility,oe as useInactivityTimeout,ee as useNetworkAwarePolling,Y as usePageFocusEffect,I as useSmartPolling,se as useWakeLock};//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useDocVisible.ts","../src/useIdleVisibility.ts","../src/useAutoPauseVideo.ts","../src/useSmartPolling.ts"],"names":["useDocVisible","visible","setVisible","useState","handler","useCallback","useEffect","useIdleVisibility","timeout","idle","setIdle","timerRef","useRef","reset","events","e","useAutoPauseVideo","ref","wasPausedByUs","video","useSmartPolling","fetchFn","options","interval","enabled","data","setData","isLoading","setIsLoading","error","setError","fetchRef","isFetchingRef","lastJsonRef","mountedRef","execute","result","json","prev","err","hasFetchedRef"],"mappings":"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","file":"index.js","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Returns `true` when the page is visible, `false` when hidden.\n * SSR-safe â defaults to `true` on the server.\n */\nexport function useDocVisible(): boolean {\n const [visible, setVisible] = useState(() =>\n typeof document === \"undefined\" ? true : document.visibilityState === \"visible\",\n );\n\n const handler = useCallback(() => {\n setVisible(document.visibilityState === \"visible\");\n }, []);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n // Sync in case value changed between SSR hydration and effect\n handler();\n\n document.addEventListener(\"visibilitychange\", handler);\n return () => document.removeEventListener(\"visibilitychange\", handler);\n }, [handler]);\n\n return visible;\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface IdleVisibilityResult {\n /** Whether the page is visible */\n visible: boolean;\n /** Whether the user is idle (no interaction for `timeout` ms) */\n idle: boolean;\n}\n\n/**\n * Combines page-visibility with idle detection.\n *\n * @param timeout - Milliseconds of inactivity before the user is\n * considered idle (default `60_000`).\n */\nexport function useIdleVisibility(timeout = 60_000): IdleVisibilityResult {\n const visible = useDocVisible();\n const [idle, setIdle] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const reset = useCallback(() => {\n setIdle(false);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setIdle(true), timeout);\n }, [timeout]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const events: Array<keyof WindowEventMap> = [\n \"mousemove\",\n \"keydown\",\n \"pointerdown\",\n \"scroll\",\n \"touchstart\",\n ];\n\n events.forEach((e) => window.addEventListener(e, reset, { passive: true }));\n reset();\n\n return () => {\n events.forEach((e) => window.removeEventListener(e, reset));\n clearTimeout(timerRef.current);\n };\n }, [reset]);\n\n // Reset idle timer when tab becomes visible again\n useEffect(() => {\n if (visible) reset();\n }, [visible, reset]);\n\n return { visible, idle };\n}\n","import { useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\n/**\n * Automatically pauses a `<video>` when the page becomes hidden\n * and resumes playback when the page becomes visible again.\n *\n * Only resumes if the video was playing before it was paused by this hook.\n */\nexport function useAutoPauseVideo(ref: React.RefObject<HTMLVideoElement | null>): void {\n const visible = useDocVisible();\n const wasPausedByUs = useRef(false);\n\n useEffect(() => {\n const video = ref.current;\n if (!video) return;\n\n if (!visible && !video.paused) {\n video.pause();\n wasPausedByUs.current = true;\n } else if (visible && wasPausedByUs.current) {\n video.play().catch(() => {\n /* autoplay may be blocked */\n });\n wasPausedByUs.current = false;\n }\n }, [visible, ref]);\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface SmartPollingOptions {\n /** Polling interval in ms (default `5000`) */\n interval?: number;\n /** Enable / disable polling (default `true`). The initial fetch always fires. */\n enabled?: boolean;\n}\n\nexport interface SmartPollingResult<T> {\n data: T | undefined;\n isLoading: boolean;\n isError: boolean;\n error: Error | undefined;\n /** Manually trigger a fetch */\n refetch: () => Promise<void>;\n}\n\n/**\n * Visibility-aware polling hook.\n *\n * - Pauses when the tab is hidden.\n * - Skips re-renders when data hasn't changed (shallow JSON comparison).\n * - Prevents overlapping fetches.\n *\n * @param fetchFn - Async function that returns data.\n * @param options - Optional configuration.\n */\nexport function useSmartPolling<T = unknown>(\n fetchFn: () => Promise<T>,\n options?: SmartPollingOptions,\n): SmartPollingResult<T> {\n const { interval = 5000, enabled = true } = options ?? {};\n const visible = useDocVisible();\n\n const [data, setData] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const fetchRef = useRef(fetchFn);\n const timerRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);\n const isFetchingRef = useRef(false);\n const lastJsonRef = useRef<string | undefined>(undefined);\n const mountedRef = useRef(true);\n\n // Always keep the latest fetchFn\n fetchRef.current = fetchFn;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const execute = useCallback(async () => {\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n try {\n const result = await fetchRef.current();\n if (!mountedRef.current) return;\n\n const json = JSON.stringify(result);\n if (json !== lastJsonRef.current) {\n lastJsonRef.current = json;\n setData(result);\n }\n setError((prev) => (prev !== undefined ? undefined : prev));\n } catch (err) {\n if (!mountedRef.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n isFetchingRef.current = false;\n if (mountedRef.current) {\n setIsLoading((prev) => (prev ? false : prev));\n }\n }\n }, []);\n\n // Initial fetch â always runs once regardless of `enabled`\n const hasFetchedRef = useRef(false);\n useEffect(() => {\n if (hasFetchedRef.current) return;\n hasFetchedRef.current = true;\n execute();\n }, [execute]);\n\n // Polling â only when visible AND enabled\n useEffect(() => {\n if (!enabled || !visible) {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n return;\n }\n\n // Immediately fetch when re-enabled / tab returns\n execute();\n\n timerRef.current = setInterval(execute, interval);\n return () => {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n };\n }, [visible, enabled, interval, execute]);\n\n return {\n data,\n isLoading,\n isError: error !== undefined,\n error,\n refetch: execute,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/useDocVisible.ts","../src/useIdleVisibility.ts","../src/useAutoPauseVideo.ts","../src/useSmartPolling.ts","../src/usePageFocusEffect.ts","../src/useNetworkAwarePolling.ts","../src/useInactivityTimeout.ts","../src/useWakeLock.ts","../src/useBatteryAware.ts"],"names":["useDocVisible","visible","setVisible","useState","handler","useCallback","useEffect","useIdleVisibility","timeout","idle","setIdle","timerRef","useRef","reset","events","e","useAutoPauseVideo","ref","wasPausedByUs","video","useSmartPolling","fetchFn","options","interval","enabled","data","setData","isLoading","setIsLoading","error","setError","fetchRef","isFetchingRef","lastJsonRef","mountedRef","execute","result","json","prev","err","hasFetchedRef","usePageFocusEffect","prevRef","cleanupRef","onVisibleRef","onHiddenRef","_a","_b","_c","useNetworkAwarePolling","slowMultiplier","pauseOffline","rest","online","useOnline","effectiveInterval","getEffectiveInterval","setOnline","handleOnline","handleOffline","base","multiplier","conn","useInactivityTimeout","warningBefore","onTimeout","onWarning","clampedWarning","idleThreshold","remaining","setRemaining","timedOut","setTimedOut","intervalRef","startRef","warnedRef","onTimeoutRef","onWarningRef","clear","warningMs","elapsed","left","isWarning","useWakeLock","autoReacquire","isActive","setIsActive","sentinelRef","wantedRef","isSupported","request","sentinel","release","useBatteryAware","lowThreshold","state","setState","update","battery","cancelled","onChange","b"],"mappings":"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","file":"index.js","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Returns `true` when the page is visible, `false` when hidden.\n * SSR-safe â defaults to `true` on the server.\n */\nexport function useDocVisible(): boolean {\n const [visible, setVisible] = useState(() =>\n typeof document === \"undefined\" ? true : document.visibilityState === \"visible\",\n );\n\n const handler = useCallback(() => {\n setVisible(document.visibilityState === \"visible\");\n }, []);\n\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n\n // Sync in case value changed between SSR hydration and effect\n handler();\n\n document.addEventListener(\"visibilitychange\", handler);\n return () => document.removeEventListener(\"visibilitychange\", handler);\n }, [handler]);\n\n return visible;\n}\n","import { useEffect, useRef, useState, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface IdleVisibilityResult {\n /** Whether the page is visible */\n visible: boolean;\n /** Whether the user is idle (no interaction for `timeout` ms) */\n idle: boolean;\n}\n\n/**\n * Combines page-visibility with idle detection.\n *\n * @param timeout - Milliseconds of inactivity before the user is\n * considered idle (default `60_000`).\n */\nexport function useIdleVisibility(timeout = 60_000): IdleVisibilityResult {\n const visible = useDocVisible();\n const [idle, setIdle] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n const reset = useCallback(() => {\n setIdle(false);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setIdle(true), timeout);\n }, [timeout]);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const events: Array<keyof WindowEventMap> = [\n \"mousemove\",\n \"keydown\",\n \"pointerdown\",\n \"scroll\",\n \"touchstart\",\n ];\n\n events.forEach((e) => window.addEventListener(e, reset, { passive: true }));\n reset();\n\n return () => {\n events.forEach((e) => window.removeEventListener(e, reset));\n clearTimeout(timerRef.current);\n };\n }, [reset]);\n\n // Reset idle timer when tab becomes visible again\n useEffect(() => {\n if (visible) reset();\n }, [visible, reset]);\n\n return { visible, idle };\n}\n","import { useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\n/**\n * Automatically pauses a `<video>` when the page becomes hidden\n * and resumes playback when the page becomes visible again.\n *\n * Only resumes if the video was playing before it was paused by this hook.\n */\nexport function useAutoPauseVideo(ref: React.RefObject<HTMLVideoElement | null>): void {\n const visible = useDocVisible();\n const wasPausedByUs = useRef(false);\n\n useEffect(() => {\n const video = ref.current;\n if (!video) return;\n\n if (!visible && !video.paused) {\n video.pause();\n wasPausedByUs.current = true;\n } else if (visible && wasPausedByUs.current) {\n video.play().catch(() => {\n /* autoplay may be blocked */\n });\n wasPausedByUs.current = false;\n }\n }, [visible, ref]);\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface SmartPollingOptions {\n /** Polling interval in ms (default `5000`) */\n interval?: number;\n /** Enable / disable polling (default `true`). The initial fetch always fires. */\n enabled?: boolean;\n}\n\nexport interface SmartPollingResult<T> {\n data: T | undefined;\n isLoading: boolean;\n isError: boolean;\n error: Error | undefined;\n /** Manually trigger a fetch */\n refetch: () => Promise<void>;\n}\n\n/**\n * Visibility-aware polling hook.\n *\n * - Pauses when the tab is hidden.\n * - Skips re-renders when data hasn't changed (shallow JSON comparison).\n * - Prevents overlapping fetches.\n *\n * @param fetchFn - Async function that returns data.\n * @param options - Optional configuration.\n */\nexport function useSmartPolling<T = unknown>(\n fetchFn: () => Promise<T>,\n options?: SmartPollingOptions,\n): SmartPollingResult<T> {\n const { interval = 5000, enabled = true } = options ?? {};\n const visible = useDocVisible();\n\n const [data, setData] = useState<T | undefined>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | undefined>(undefined);\n\n const fetchRef = useRef(fetchFn);\n const timerRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);\n const isFetchingRef = useRef(false);\n const lastJsonRef = useRef<string | undefined>(undefined);\n const mountedRef = useRef(true);\n\n // Always keep the latest fetchFn\n fetchRef.current = fetchFn;\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const execute = useCallback(async () => {\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n try {\n const result = await fetchRef.current();\n if (!mountedRef.current) return;\n\n const json = JSON.stringify(result);\n if (json !== lastJsonRef.current) {\n lastJsonRef.current = json;\n setData(result);\n }\n setError((prev) => (prev !== undefined ? undefined : prev));\n } catch (err) {\n if (!mountedRef.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n isFetchingRef.current = false;\n if (mountedRef.current) {\n setIsLoading((prev) => (prev ? false : prev));\n }\n }\n }, []);\n\n // Initial fetch â always runs once regardless of `enabled`\n const hasFetchedRef = useRef(false);\n useEffect(() => {\n if (hasFetchedRef.current) return;\n hasFetchedRef.current = true;\n execute();\n }, [execute]);\n\n // Polling â only when visible AND enabled\n useEffect(() => {\n if (!enabled || !visible) {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n return;\n }\n\n // Immediately fetch when re-enabled / tab returns\n execute();\n\n timerRef.current = setInterval(execute, interval);\n return () => {\n clearInterval(timerRef.current);\n timerRef.current = undefined;\n };\n }, [visible, enabled, interval, execute]);\n\n return {\n data,\n isLoading,\n isError: error !== undefined,\n error,\n refetch: execute,\n };\n}\n","import { useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface PageFocusEffectOptions {\n /** Callback fired when the page transitions from hidden â visible. May return a cleanup function. */\n onVisible?: () => void | (() => void);\n /** Callback fired when the page transitions from visible â hidden. */\n onHidden?: () => void;\n}\n\n/**\n * Runs side-effect callbacks on visibility **transitions** rather than\n * on every render.\n *\n * - `onVisible` fires when the tab goes from hidden â visible.\n * - `onHidden` fires when the tab goes from visible â hidden.\n * - The very first render is **not** treated as a transition.\n * - `onVisible` may return a cleanup function (like `useEffect`).\n *\n * SSR-safe â no-ops on the server.\n *\n * @example\n * ```tsx\n * usePageFocusEffect({\n * onVisible: () => { refetchStaleData(); },\n * onHidden: () => { saveScrollPosition(); },\n * });\n * ```\n */\nexport function usePageFocusEffect(options: PageFocusEffectOptions): void {\n const visible = useDocVisible();\n const prevRef = useRef<boolean | undefined>(undefined);\n const cleanupRef = useRef<(() => void) | undefined>(undefined);\n\n // Keep latest callbacks in refs to avoid re-triggering the effect\n const onVisibleRef = useRef(options.onVisible);\n const onHiddenRef = useRef(options.onHidden);\n onVisibleRef.current = options.onVisible;\n onHiddenRef.current = options.onHidden;\n\n useEffect(() => {\n // Skip the initial mount â only fire on actual transitions\n if (prevRef.current === undefined) {\n prevRef.current = visible;\n return;\n }\n\n if (visible && !prevRef.current) {\n // hidden â visible\n cleanupRef.current?.();\n cleanupRef.current = undefined;\n const result = onVisibleRef.current?.();\n if (typeof result === \"function\") {\n cleanupRef.current = result;\n }\n } else if (!visible && prevRef.current) {\n // visible â hidden\n onHiddenRef.current?.();\n }\n\n prevRef.current = visible;\n }, [visible]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n cleanupRef.current?.();\n };\n }, []);\n}\n","import { useState, useEffect, useCallback } from \"react\";\nimport { useSmartPolling } from \"./useSmartPolling\";\nimport type { SmartPollingOptions, SmartPollingResult } from \"./useSmartPolling\";\n\nexport interface NetworkAwarePollingOptions extends SmartPollingOptions {\n /** Multiplier applied to `interval` on slow connections like 2g (default `3`). */\n slowMultiplier?: number;\n /** Whether to pause polling when the browser is offline (default `true`). */\n pauseOffline?: boolean;\n}\n\nexport interface NetworkAwarePollingResult<T> extends SmartPollingResult<T> {\n /** `true` when the browser reports being online. */\n isOnline: boolean;\n /** The effective polling interval after network-quality adjustment. */\n effectiveInterval: number;\n}\n\n/**\n * Network + visibility-aware polling.\n *\n * Extends `useSmartPolling` with:\n * - Automatic pause when the browser goes offline.\n * - Adaptive interval â polls slower on poor connections (2g / slow-2g).\n *\n * SSR-safe â defaults to online on the server.\n *\n * @param fetchFn - Async function that returns data.\n * @param options - Optional configuration.\n */\nexport function useNetworkAwarePolling<T = unknown>(\n fetchFn: () => Promise<T>,\n options?: NetworkAwarePollingOptions,\n): NetworkAwarePollingResult<T> {\n const {\n interval = 5000,\n enabled = true,\n slowMultiplier = 3,\n pauseOffline = true,\n ...rest\n } = options ?? {};\n\n const online = useOnline();\n const effectiveInterval = getEffectiveInterval(interval, slowMultiplier);\n\n const shouldPoll = pauseOffline ? enabled && online : enabled;\n\n const result = useSmartPolling(fetchFn, {\n ...rest,\n interval: effectiveInterval,\n enabled: shouldPoll,\n });\n\n return { ...result, isOnline: online, effectiveInterval };\n}\n\n/* ------------------------------------------------------------------ */\n/* Internal helpers */\n/* ------------------------------------------------------------------ */\n\n/** SSR-safe hook that tracks `navigator.onLine`. */\nfunction useOnline(): boolean {\n const [online, setOnline] = useState(() =>\n typeof navigator === \"undefined\" ? true : navigator.onLine,\n );\n\n const handleOnline = useCallback(() => setOnline(true), []);\n const handleOffline = useCallback(() => setOnline(false), []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n window.addEventListener(\"online\", handleOnline);\n window.addEventListener(\"offline\", handleOffline);\n return () => {\n window.removeEventListener(\"online\", handleOnline);\n window.removeEventListener(\"offline\", handleOffline);\n };\n }, [handleOnline, handleOffline]);\n\n return online;\n}\n\n/** Returns a longer interval when the connection is slow. */\nfunction getEffectiveInterval(base: number, multiplier: number): number {\n if (typeof navigator === \"undefined\") return base;\n\n const conn = (\n navigator as Navigator & {\n connection?: { effectiveType?: string };\n }\n ).connection;\n\n if (conn?.effectiveType === \"2g\" || conn?.effectiveType === \"slow-2g\") {\n return base * multiplier;\n }\n return base;\n}\n","import { useState, useEffect, useRef, useCallback } from \"react\";\nimport { useIdleVisibility } from \"./useIdleVisibility\";\n\nexport interface InactivityTimeoutOptions {\n /** Total inactivity before `onTimeout` fires, in ms (default `300_000` â 5 min). */\n timeout?: number;\n /**\n * How long before the final timeout to enter the \"warning\" phase, in ms\n * (default `60_000` â 1 min).\n *\n * Set to `0` to disable the warning phase.\n */\n warningBefore?: number;\n /** Called once when the full timeout elapses. */\n onTimeout?: () => void;\n /** Called when entering the warning phase. */\n onWarning?: () => void;\n}\n\nexport interface InactivityTimeoutResult {\n /** `true` once the user has been idle long enough to start counting down. */\n idle: boolean;\n /** Current page-visibility state. */\n visible: boolean;\n /** `true` during the warning countdown (before final timeout). */\n isWarning: boolean;\n /** `true` after the full timeout has elapsed. */\n isTimedOut: boolean;\n /** Seconds remaining until timeout (`-1` when the user is not idle). */\n remainingSeconds: number;\n /** Manually reset the timer and cancel any pending timeout. */\n resetTimer: () => void;\n}\n\n/**\n * Countdown-based session/inactivity manager built on top of\n * `useIdleVisibility`.\n *\n * 1. After `timeout - warningBefore` ms of inactivity the hook enters\n * the **warning** phase and starts a per-second countdown.\n * 2. When the countdown hits zero `onTimeout` fires and `isTimedOut`\n * becomes `true`.\n * 3. Any user interaction resets the timer.\n *\n * SSR-safe â all timers only run in the browser.\n */\nexport function useInactivityTimeout(\n options?: InactivityTimeoutOptions,\n): InactivityTimeoutResult {\n const {\n timeout = 300_000,\n warningBefore = 60_000,\n onTimeout,\n onWarning,\n } = options ?? {};\n\n // Clamp so warningBefore never exceeds timeout\n const clampedWarning = Math.min(warningBefore, timeout);\n const idleThreshold = timeout - clampedWarning;\n\n const { idle, visible } = useIdleVisibility(idleThreshold);\n\n const [remaining, setRemaining] = useState(-1);\n const [timedOut, setTimedOut] = useState(false);\n const intervalRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);\n const startRef = useRef<number | undefined>(undefined);\n const warnedRef = useRef(false);\n\n // Keep callback refs stable\n const onTimeoutRef = useRef(onTimeout);\n const onWarningRef = useRef(onWarning);\n onTimeoutRef.current = onTimeout;\n onWarningRef.current = onWarning;\n\n const clear = useCallback(() => {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n startRef.current = undefined;\n warnedRef.current = false;\n setRemaining(-1);\n setTimedOut(false);\n }, []);\n\n useEffect(() => {\n if (!idle || timedOut) {\n if (!idle) clear();\n return;\n }\n\n startRef.current = Date.now();\n\n // Fire the warning callback once at the start of the countdown\n if (!warnedRef.current) {\n warnedRef.current = true;\n onWarningRef.current?.();\n }\n\n const warningMs = clampedWarning;\n\n intervalRef.current = setInterval(() => {\n const elapsed = Date.now() - (startRef.current ?? Date.now());\n const left = Math.max(0, Math.ceil((warningMs - elapsed) / 1000));\n setRemaining(left);\n\n if (left <= 0) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n setTimedOut(true);\n onTimeoutRef.current?.();\n }\n }, 1000);\n\n return () => {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n };\n }, [idle, timedOut, clampedWarning, clear]);\n\n const isWarning = idle && !timedOut && remaining >= 0;\n\n return {\n idle: idle || timedOut,\n visible,\n isWarning,\n isTimedOut: timedOut,\n remainingSeconds: remaining,\n resetTimer: clear,\n };\n}\n","import { useState, useCallback, useEffect, useRef } from \"react\";\nimport { useDocVisible } from \"./useDocVisible\";\n\nexport interface WakeLockResult {\n /** `true` while a Wake Lock is actively held. */\n isActive: boolean;\n /** Request the screen Wake Lock. No-ops if unsupported. */\n request: () => Promise<void>;\n /** Release the current Wake Lock. */\n release: () => Promise<void>;\n /** `true` when the Screen Wake Lock API is available in this browser. */\n isSupported: boolean;\n}\n\n/**\n * Manages the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API)\n * to prevent the screen from dimming or locking.\n *\n * Features:\n * - Automatic re-acquire on tab re-focus when `autoReacquire` is `true`.\n * - Cleans up the Wake Lock on unmount.\n * - SSR-safe â `isSupported` will be `false` on the server.\n *\n * @param autoReacquire - Re-request the lock when the tab becomes visible\n * again after being hidden (default `true`).\n */\nexport function useWakeLock(autoReacquire = true): WakeLockResult {\n const visible = useDocVisible();\n const [isActive, setIsActive] = useState(false);\n const sentinelRef = useRef<WakeLockSentinel | undefined>(undefined);\n const wantedRef = useRef(false);\n\n const isSupported = typeof navigator !== \"undefined\" && navigator.wakeLock != null;\n\n const request = useCallback(async () => {\n if (!isSupported) return;\n // Already holding a lock â skip\n if (sentinelRef.current && !sentinelRef.current.released) return;\n\n try {\n const sentinel = await navigator.wakeLock.request(\"screen\");\n sentinelRef.current = sentinel;\n wantedRef.current = true;\n setIsActive(true);\n\n sentinel.addEventListener(\"release\", () => {\n setIsActive(false);\n sentinelRef.current = undefined;\n });\n } catch {\n // Permission denied, low battery, or other platform error\n }\n }, [isSupported]);\n\n const release = useCallback(async () => {\n wantedRef.current = false;\n if (sentinelRef.current && !sentinelRef.current.released) {\n await sentinelRef.current.release();\n }\n }, []);\n\n // Re-acquire on tab visibility change\n useEffect(() => {\n if (autoReacquire && visible && wantedRef.current && !sentinelRef.current) {\n void request();\n }\n }, [visible, autoReacquire, request]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (sentinelRef.current && !sentinelRef.current.released) {\n sentinelRef.current.release().catch(() => {});\n }\n };\n }, []);\n\n return { isActive, request, release, isSupported };\n}\n","import { useState, useEffect, useCallback } from \"react\";\n\nexport interface BatteryState {\n /** `true` when the device is plugged in. Defaults to `true` (optimistic). */\n charging: boolean;\n /** Battery level between 0 and 1. Defaults to `1`. */\n level: number;\n /** `true` when the device is **not** charging and `level` is below `lowThreshold`. */\n isLowBattery: boolean;\n /** `true` when the Battery Status API is available. */\n isSupported: boolean;\n}\n\ninterface BatteryManager extends EventTarget {\n charging: boolean;\n level: number;\n}\n\n/**\n * Exposes device battery status via the\n * [Battery Status API](https://developer.mozilla.org/en-US/docs/Web/API/Battery_Status_API).\n *\n * Use cases:\n * - Reduce polling frequency on low battery.\n * - Disable animations / heavy computations when the battery is low.\n * - Show a battery-aware UI indicator.\n *\n * SSR-safe â returns optimistic defaults on the server.\n *\n * @param lowThreshold - Level (0â1) below which `isLowBattery` becomes `true`\n * when the device is not charging (default `0.15`).\n */\nexport function useBatteryAware(lowThreshold = 0.15): BatteryState {\n const [state, setState] = useState<BatteryState>({\n charging: true,\n level: 1,\n isLowBattery: false,\n isSupported: false,\n });\n\n const update = useCallback(\n (battery: BatteryManager) => {\n setState({\n charging: battery.charging,\n level: battery.level,\n isLowBattery: !battery.charging && battery.level < lowThreshold,\n isSupported: true,\n });\n },\n [lowThreshold],\n );\n\n useEffect(() => {\n if (\n typeof navigator === \"undefined\" ||\n typeof (navigator as Navigator & { getBattery?: unknown }).getBattery !== \"function\"\n ) {\n return;\n }\n\n let battery: BatteryManager | undefined;\n let cancelled = false;\n\n const onChange = () => {\n if (battery && !cancelled) update(battery);\n };\n\n (navigator as Navigator & { getBattery: () => Promise<BatteryManager> })\n .getBattery()\n .then((b) => {\n if (cancelled) return;\n battery = b;\n update(b);\n b.addEventListener(\"chargingchange\", onChange);\n b.addEventListener(\"levelchange\", onChange);\n })\n .catch(() => {\n // API exists but call failed â leave defaults\n });\n\n return () => {\n cancelled = true;\n if (battery) {\n battery.removeEventListener(\"chargingchange\", onChange);\n battery.removeEventListener(\"levelchange\", onChange);\n }\n };\n }, [update]);\n\n return state;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-visibility-hooks",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Tiny, SSR-safe React hooks for page visibility, idle detection, smart polling and
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Tiny, SSR-safe React hooks for page visibility, idle detection, smart polling, network awareness, wake lock, battery status and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -50,7 +50,14 @@
|
|
|
50
50
|
"ssr",
|
|
51
51
|
"ssr-safe",
|
|
52
52
|
"nextjs",
|
|
53
|
-
"typescript"
|
|
53
|
+
"typescript",
|
|
54
|
+
"wake-lock",
|
|
55
|
+
"battery",
|
|
56
|
+
"network-aware",
|
|
57
|
+
"session-timeout",
|
|
58
|
+
"focus-effect",
|
|
59
|
+
"online-offline",
|
|
60
|
+
"inactivity"
|
|
54
61
|
],
|
|
55
62
|
"author": "Aniket Raj",
|
|
56
63
|
"license": "MIT",
|
|
@@ -92,7 +99,7 @@
|
|
|
92
99
|
"size-limit": [
|
|
93
100
|
{
|
|
94
101
|
"path": "dist/index.js",
|
|
95
|
-
"limit": "
|
|
102
|
+
"limit": "3 kB"
|
|
96
103
|
}
|
|
97
104
|
],
|
|
98
105
|
"engines": {
|