@usefy/hooks 0.0.35

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 ADDED
@@ -0,0 +1,794 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/mirunamu00/usefy/master/assets/logo.png" alt="usefy logo" width="180" />
3
+ </p>
4
+
5
+ <h1 align="center">usefy</h1>
6
+
7
+ <p align="center">
8
+ <strong>๐Ÿช A collection of production-ready React hooks for modern applications</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@usefy/hooks" target="_blank" rel="noopener noreferrer">
13
+ <img src="https://img.shields.io/npm/v/@usefy/hooks.svg?style=flat-square&color=007acc" alt="npm version" />
14
+ </a>
15
+ <a href="https://www.npmjs.com/package/@usefy/hooks" target="_blank" rel="noopener noreferrer">
16
+ <img src="https://img.shields.io/npm/dm/@usefy/hooks.svg?style=flat-square&color=007acc" alt="npm downloads" />
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@usefy/hooks" target="_blank" rel="noopener noreferrer">
19
+ <img src="https://img.shields.io/bundlephobia/minzip/@usefy/hooks?style=flat-square&color=007acc" alt="bundle size" />
20
+ </a>
21
+ <a href="https://github.com/mirunamu00/usefy/blob/master/LICENSE" target="_blank" rel="noopener noreferrer">
22
+ <img src="https://img.shields.io/npm/l/@usefy/hooks.svg?style=flat-square&color=007acc" alt="license" />
23
+ </a>
24
+ </p>
25
+
26
+ <p align="center">
27
+ <a href="#installation">Installation</a> โ€ข
28
+ <a href="#packages">Packages</a> โ€ข
29
+ <a href="#quick-start">Quick Start</a> โ€ข
30
+ <a href="#features">Features</a>
31
+ </p>
32
+
33
+ <p align="center">
34
+ <a href="https://mirunamu00.github.io/usefy/" target="_blank" rel="noopener noreferrer">
35
+ <strong>๐Ÿ“š View Storybook Demo</strong>
36
+ </a>
37
+ </p>
38
+
39
+ ---
40
+
41
+ > โš ๏ธ **Pre-release Notice**: This project is currently in version `0.x.x` (alpha/beta stage). APIs may change between minor versions. While fully functional and tested, please use with caution in production environments.
42
+ >
43
+ > ๐Ÿšง **Actively Developing**: New hooks are being added regularly. Stay tuned for more utilities!
44
+
45
+ ---
46
+
47
+ ## Overview
48
+
49
+ **usefy** is a collection of production-ready custom hooks designed for modern React applications. All hooks are written in TypeScript, providing complete type safety, comprehensive testing, and minimal bundle size.
50
+
51
+ ### โœจ Why usefy?
52
+
53
+ - **๐Ÿš€ Zero Dependencies** โ€” Pure React implementation with no external dependencies
54
+ - **๐Ÿ“ฆ Tree Shakeable** โ€” Import only the hooks you need to optimize bundle size
55
+ - **๐Ÿ”ท TypeScript First** โ€” Complete type safety with full autocomplete support
56
+ - **โšก SSR Compatible** โ€” Works seamlessly with Next.js, Remix, and other SSR frameworks
57
+ - **๐Ÿงช Well Tested** โ€” High test coverage ensures reliability and stability
58
+ - **๐Ÿ“– Well Documented** โ€” Detailed documentation with practical examples
59
+ - **๐ŸŽจ Interactive Demos** โ€” Try all hooks in action with our Storybook playground
60
+
61
+ ---
62
+
63
+ ## Installation
64
+
65
+ ### All-in-One Package
66
+
67
+ Install all hooks at once:
68
+
69
+ ```bash
70
+ # npm
71
+ npm install @usefy/hooks
72
+
73
+ # yarn
74
+ yarn add @usefy/hooks
75
+
76
+ # pnpm
77
+ pnpm add @usefy/hooks
78
+ ```
79
+
80
+ ### Individual Packages
81
+
82
+ You can also install only the hooks you need:
83
+
84
+ ```bash
85
+ # Example: Install only use-toggle
86
+ pnpm add @usefy/use-toggle
87
+
88
+ # Install multiple packages
89
+ pnpm add @usefy/use-debounce @usefy/use-local-storage
90
+ ```
91
+
92
+ ### Peer Dependencies
93
+
94
+ All packages require React 18 or 19:
95
+
96
+ ```json
97
+ {
98
+ "peerDependencies": {
99
+ "react": "^18.0.0 || ^19.0.0"
100
+ }
101
+ }
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Packages
107
+
108
+ ### ๐Ÿ“ฆ Available Hooks
109
+
110
+ | Hook | Description | npm | Coverage |
111
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
112
+ | <a href="https://www.npmjs.com/package/@usefy/use-toggle" target="_blank" rel="noopener noreferrer">@usefy/use-toggle</a> | Boolean state management with toggle, setTrue, setFalse | <a href="https://www.npmjs.com/package/@usefy/use-toggle" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-toggle.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
113
+ | <a href="https://www.npmjs.com/package/@usefy/use-counter" target="_blank" rel="noopener noreferrer">@usefy/use-counter</a> | Counter state with increment, decrement, reset | <a href="https://www.npmjs.com/package/@usefy/use-counter" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-counter.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
114
+ | <a href="https://www.npmjs.com/package/@usefy/use-debounce" target="_blank" rel="noopener noreferrer">@usefy/use-debounce</a> | Value debouncing with leading/trailing edge | <a href="https://www.npmjs.com/package/@usefy/use-debounce" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-debounce.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![92%](https://img.shields.io/badge/coverage-92%25-brightgreen?style=flat-square) |
115
+ | <a href="https://www.npmjs.com/package/@usefy/use-debounce-callback" target="_blank" rel="noopener noreferrer">@usefy/use-debounce-callback</a> | Debounced callbacks with cancel/flush/pending | <a href="https://www.npmjs.com/package/@usefy/use-debounce-callback" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-debounce-callback.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![93%](https://img.shields.io/badge/coverage-93%25-brightgreen?style=flat-square) |
116
+ | <a href="https://www.npmjs.com/package/@usefy/use-throttle" target="_blank" rel="noopener noreferrer">@usefy/use-throttle</a> | Value throttling for rate-limiting updates | <a href="https://www.npmjs.com/package/@usefy/use-throttle" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-throttle.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
117
+ | <a href="https://www.npmjs.com/package/@usefy/use-throttle-callback" target="_blank" rel="noopener noreferrer">@usefy/use-throttle-callback</a> | Throttled callbacks with cancel/flush/pending | <a href="https://www.npmjs.com/package/@usefy/use-throttle-callback" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-throttle-callback.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
118
+ | <a href="https://www.npmjs.com/package/@usefy/use-local-storage" target="_blank" rel="noopener noreferrer">@usefy/use-local-storage</a> | localStorage persistence with cross-tab sync | <a href="https://www.npmjs.com/package/@usefy/use-local-storage" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-local-storage.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![95%](https://img.shields.io/badge/coverage-95%25-brightgreen?style=flat-square) |
119
+ | <a href="https://www.npmjs.com/package/@usefy/use-session-storage" target="_blank" rel="noopener noreferrer">@usefy/use-session-storage</a> | sessionStorage persistence for tab lifetime | <a href="https://www.npmjs.com/package/@usefy/use-session-storage" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-session-storage.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![95%](https://img.shields.io/badge/coverage-95%25-brightgreen?style=flat-square) |
120
+ | <a href="https://www.npmjs.com/package/@usefy/use-click-any-where" target="_blank" rel="noopener noreferrer">@usefy/use-click-any-where</a> | Document-wide click event detection | <a href="https://www.npmjs.com/package/@usefy/use-click-any-where" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-click-any-where.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![92%](https://img.shields.io/badge/coverage-92%25-brightgreen?style=flat-square) |
121
+ | <a href="https://www.npmjs.com/package/@usefy/use-copy-to-clipboard" target="_blank" rel="noopener noreferrer">@usefy/use-copy-to-clipboard</a> | Clipboard copy with fallback support | <a href="https://www.npmjs.com/package/@usefy/use-copy-to-clipboard" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-copy-to-clipboard.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![88%](https://img.shields.io/badge/coverage-88%25-brightgreen?style=flat-square) |
122
+ | <a href="https://www.npmjs.com/package/@usefy/use-event-listener" target="_blank" rel="noopener noreferrer">@usefy/use-event-listener</a> | DOM event listener with auto cleanup | <a href="https://www.npmjs.com/package/@usefy/use-event-listener" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-event-listener.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![96%](https://img.shields.io/badge/coverage-96%25-brightgreen?style=flat-square) |
123
+ | <a href="https://www.npmjs.com/package/@usefy/use-on-click-outside" target="_blank" rel="noopener noreferrer">@usefy/use-on-click-outside</a> | Outside click detection for modals/dropdowns | <a href="https://www.npmjs.com/package/@usefy/use-on-click-outside" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-on-click-outside.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![98%](https://img.shields.io/badge/coverage-98%25-brightgreen?style=flat-square) |
124
+ | <a href="https://www.npmjs.com/package/@usefy/use-unmount" target="_blank" rel="noopener noreferrer">@usefy/use-unmount</a> | Execute callback on component unmount | <a href="https://www.npmjs.com/package/@usefy/use-unmount" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-unmount.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
125
+ | <a href="https://www.npmjs.com/package/@usefy/use-init" target="_blank" rel="noopener noreferrer">@usefy/use-init</a> | One-time initialization with async, retry, timeout | <a href="https://www.npmjs.com/package/@usefy/use-init" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-init.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![96%](https://img.shields.io/badge/coverage-96%25-brightgreen?style=flat-square) |
126
+ | <a href="https://www.npmjs.com/package/@usefy/use-timer" target="_blank" rel="noopener noreferrer">@usefy/use-timer</a> | Countdown timer with drift compensation and formats | <a href="https://www.npmjs.com/package/@usefy/use-timer" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-timer.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![84%](https://img.shields.io/badge/coverage-84%25-brightgreen?style=flat-square) |
127
+ | <a href="https://www.npmjs.com/package/@usefy/use-geolocation" target="_blank" rel="noopener noreferrer">@usefy/use-geolocation</a> | Device geolocation with real-time tracking and distance | <a href="https://www.npmjs.com/package/@usefy/use-geolocation" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-geolocation.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![90%](https://img.shields.io/badge/coverage-90%25-brightgreen?style=flat-square) |
128
+ | <a href="https://www.npmjs.com/package/@usefy/use-intersection-observer" target="_blank" rel="noopener noreferrer">@usefy/use-intersection-observer</a> | Element visibility detection with Intersection Observer | <a href="https://www.npmjs.com/package/@usefy/use-intersection-observer" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-intersection-observer.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![94%](https://img.shields.io/badge/coverage-94%25-brightgreen?style=flat-square) |
129
+ | <a href="https://www.npmjs.com/package/@usefy/use-signal" target="_blank" rel="noopener noreferrer">@usefy/use-signal</a> | Event-driven communication between components | <a href="https://www.npmjs.com/package/@usefy/use-signal" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-signal.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![98%](https://img.shields.io/badge/coverage-98%25-brightgreen?style=flat-square) |
130
+ | <a href="https://www.npmjs.com/package/@usefy/use-memory-monitor" target="_blank" rel="noopener noreferrer">@usefy/use-memory-monitor</a> | Real-time browser memory monitoring with leak detection | <a href="https://www.npmjs.com/package/@usefy/use-memory-monitor" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/npm/v/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="npm version" /></a> | ![90%](https://img.shields.io/badge/coverage-90%25-brightgreen?style=flat-square) |
131
+
132
+ ---
133
+
134
+ ## Quick Start
135
+
136
+ ### Using the All-in-One Package
137
+
138
+ ```tsx
139
+ import {
140
+ useToggle,
141
+ useCounter,
142
+ useDebounce,
143
+ useLocalStorage,
144
+ useCopyToClipboard,
145
+ useEventListener,
146
+ useOnClickOutside,
147
+ useIntersectionObserver,
148
+ useSignal,
149
+ useUnmount,
150
+ useInit,
151
+ } from "@usefy/hooks";
152
+
153
+ function App() {
154
+ // Boolean state management
155
+ const { value: isOpen, toggle, setFalse: close } = useToggle(false);
156
+
157
+ // Counter with controls
158
+ const { count, increment, decrement, reset } = useCounter(0);
159
+
160
+ // Debounced search
161
+ const [query, setQuery] = useState("");
162
+ const debouncedQuery = useDebounce(query, 300);
163
+
164
+ // Persistent theme preference
165
+ const [theme, setTheme] = useLocalStorage("theme", "light");
166
+
167
+ // Copy functionality
168
+ const [copiedText, copy] = useCopyToClipboard();
169
+
170
+ // Lazy loading image
171
+ const { ref: imageRef, inView } = useIntersectionObserver({
172
+ triggerOnce: true,
173
+ rootMargin: "50px",
174
+ });
175
+
176
+ return (
177
+ <div data-theme={theme}>
178
+ {/* Modal */}
179
+ <button onClick={toggle}>Open Modal</button>
180
+ {isOpen && (
181
+ <div className="modal">
182
+ <button onClick={close}>Close</button>
183
+ </div>
184
+ )}
185
+
186
+ {/* Counter */}
187
+ <div>
188
+ <button onClick={decrement}>-</button>
189
+ <span>{count}</span>
190
+ <button onClick={increment}>+</button>
191
+ </div>
192
+
193
+ {/* Search */}
194
+ <input
195
+ value={query}
196
+ onChange={(e) => setQuery(e.target.value)}
197
+ placeholder="Search..."
198
+ />
199
+
200
+ {/* Theme Toggle */}
201
+ <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
202
+ Toggle Theme
203
+ </button>
204
+
205
+ {/* Copy */}
206
+ <button onClick={() => copy("Hello World!")}>
207
+ {copiedText ? "Copied!" : "Copy"}
208
+ </button>
209
+
210
+ {/* Lazy Loading */}
211
+ <div ref={imageRef}>
212
+ {inView && <img src="large-image.jpg" alt="Lazy loaded" />}
213
+ </div>
214
+ </div>
215
+ );
216
+ }
217
+ ```
218
+
219
+ ### Using Individual Packages
220
+
221
+ ```tsx
222
+ import { useToggle } from "@usefy/use-toggle";
223
+ import { useDebounce } from "@usefy/use-debounce";
224
+
225
+ function SearchModal() {
226
+ const { value: isOpen, toggle } = useToggle(false);
227
+ const [query, setQuery] = useState("");
228
+ const debouncedQuery = useDebounce(query, 300);
229
+
230
+ useEffect(() => {
231
+ if (debouncedQuery) {
232
+ searchAPI(debouncedQuery);
233
+ }
234
+ }, [debouncedQuery]);
235
+
236
+ return (
237
+ <>
238
+ <button onClick={toggle}>Search</button>
239
+ {isOpen && (
240
+ <input value={query} onChange={(e) => setQuery(e.target.value)} />
241
+ )}
242
+ </>
243
+ );
244
+ }
245
+ ```
246
+
247
+ ---
248
+
249
+ ## Features
250
+
251
+ ### ๐Ÿ”„ State Management
252
+
253
+ <details>
254
+ <summary><strong>useToggle</strong> โ€” Boolean state with utility functions</summary>
255
+
256
+ ```tsx
257
+ const { value, toggle, setTrue, setFalse, setValue } = useToggle(false);
258
+ ```
259
+
260
+ Perfect for modals, dropdowns, accordions, and switches.
261
+
262
+ </details>
263
+
264
+ <details>
265
+ <summary><strong>useCounter</strong> โ€” Counter state with controls</summary>
266
+
267
+ ```tsx
268
+ const { count, increment, decrement, reset } = useCounter(0);
269
+ ```
270
+
271
+ Ideal for quantity selectors, pagination, and score tracking.
272
+
273
+ </details>
274
+
275
+ ### โฑ๏ธ Timing Utilities
276
+
277
+ <details>
278
+ <summary><strong>useDebounce</strong> โ€” Debounce value updates</summary>
279
+
280
+ ```tsx
281
+ const debouncedValue = useDebounce(value, 300, {
282
+ leading: false,
283
+ trailing: true,
284
+ maxWait: 1000,
285
+ });
286
+ ```
287
+
288
+ Best for search inputs, form validation, and API calls.
289
+
290
+ </details>
291
+
292
+ <details>
293
+ <summary><strong>useDebounceCallback</strong> โ€” Debounce function calls</summary>
294
+
295
+ ```tsx
296
+ const debouncedFn = useDebounceCallback(callback, 300);
297
+
298
+ debouncedFn(args); // Call debounced
299
+ debouncedFn.cancel(); // Cancel pending
300
+ debouncedFn.flush(); // Execute immediately
301
+ debouncedFn.pending(); // Check if pending
302
+ ```
303
+
304
+ </details>
305
+
306
+ <details>
307
+ <summary><strong>useThrottle</strong> โ€” Throttle value updates</summary>
308
+
309
+ ```tsx
310
+ const throttledValue = useThrottle(value, 100, {
311
+ leading: true,
312
+ trailing: true,
313
+ });
314
+ ```
315
+
316
+ Perfect for scroll events, resize handlers, and mouse tracking.
317
+
318
+ </details>
319
+
320
+ <details>
321
+ <summary><strong>useThrottleCallback</strong> โ€” Throttle function calls</summary>
322
+
323
+ ```tsx
324
+ const throttledFn = useThrottleCallback(callback, 100);
325
+ ```
326
+
327
+ </details>
328
+
329
+ <details>
330
+ <summary><strong>useTimer</strong> โ€” Countdown timer with accurate timing</summary>
331
+
332
+ ```tsx
333
+ import { useTimer, ms } from "@usefy/use-timer";
334
+
335
+ const timer = useTimer(ms.minutes(5), {
336
+ format: "MM:SS",
337
+ autoStart: false,
338
+ loop: false,
339
+ onComplete: () => console.log("Time's up!"),
340
+ });
341
+
342
+ // Controls
343
+ timer.start();
344
+ timer.pause();
345
+ timer.reset();
346
+ timer.addTime(ms.seconds(10));
347
+ timer.subtractTime(ms.seconds(5));
348
+
349
+ // State
350
+ timer.time; // "05:00"
351
+ timer.progress; // 0-100
352
+ timer.isRunning; // boolean
353
+ ```
354
+
355
+ Perfect for countdown timers, Pomodoro apps, kitchen timers, and time-based UIs with smart render optimization.
356
+
357
+ </details>
358
+
359
+ ### ๐Ÿ’พ Storage
360
+
361
+ <details>
362
+ <summary><strong>useLocalStorage</strong> โ€” Persistent storage with sync</summary>
363
+
364
+ ```tsx
365
+ const [value, setValue, removeValue] = useLocalStorage("key", initialValue, {
366
+ serializer: JSON.stringify,
367
+ deserializer: JSON.parse,
368
+ syncTabs: true,
369
+ onError: (error) => console.error(error),
370
+ });
371
+ ```
372
+
373
+ Supports cross-tab synchronization and custom serialization.
374
+
375
+ </details>
376
+
377
+ <details>
378
+ <summary><strong>useSessionStorage</strong> โ€” Session-scoped storage</summary>
379
+
380
+ ```tsx
381
+ const [value, setValue, removeValue] = useSessionStorage("key", initialValue);
382
+ ```
383
+
384
+ Data persists during tab lifetime, isolated per tab.
385
+
386
+ </details>
387
+
388
+ ### ๐Ÿ“ก Communication
389
+
390
+ <details>
391
+ <summary><strong>useSignal</strong> โ€” Event-driven communication between components</summary>
392
+
393
+ ```tsx
394
+ import { useSignal } from "@usefy/use-signal";
395
+
396
+ // Emitter component
397
+ function RefreshButton() {
398
+ const { emit, info } = useSignal("dashboard-refresh");
399
+
400
+ return (
401
+ <button onClick={() => emit()}>
402
+ Refresh All ({info.subscriberCount} widgets)
403
+ </button>
404
+ );
405
+ }
406
+
407
+ // Subscriber component
408
+ function DataWidget() {
409
+ const { signal } = useSignal("dashboard-refresh");
410
+
411
+ useEffect(() => {
412
+ fetchData(); // Refetch when signal changes
413
+ }, [signal]);
414
+
415
+ return <div>Widget Content</div>;
416
+ }
417
+
418
+ // With typed data payload
419
+ interface NotificationData {
420
+ type: "success" | "error";
421
+ message: string;
422
+ }
423
+
424
+ function NotificationEmitter() {
425
+ const { emit } = useSignal<NotificationData>("notification");
426
+
427
+ return (
428
+ <button onClick={() => emit({ type: "success", message: "Done!" })}>
429
+ Notify
430
+ </button>
431
+ );
432
+ }
433
+
434
+ function NotificationReceiver() {
435
+ const { signal, info } = useSignal<NotificationData>("notification");
436
+
437
+ useEffect(() => {
438
+ if (signal > 0 && info.data) {
439
+ toast[info.data.type](info.data.message);
440
+ }
441
+ }, [signal]);
442
+
443
+ return null;
444
+ }
445
+ ```
446
+
447
+ **Perfect for:** Dashboard refresh, form reset, cache invalidation, multi-step flows, and event broadcasting.
448
+
449
+ > โš ๏ธ **Note:** `useSignal` is NOT a global state management solution. It's designed for lightweight event-driven communication. For complex state management, use Context, Zustand, Jotai, or Recoil.
450
+
451
+ </details>
452
+
453
+ ### ๐Ÿ–ฑ๏ธ Events
454
+
455
+ <details>
456
+ <summary><strong>useEventListener</strong> โ€” DOM event listener with auto cleanup</summary>
457
+
458
+ ```tsx
459
+ // Window resize event (default target)
460
+ useEventListener("resize", (e) => {
461
+ console.log("Window resized:", window.innerWidth);
462
+ });
463
+
464
+ // Document keydown event
465
+ useEventListener(
466
+ "keydown",
467
+ (e) => {
468
+ if (e.key === "Escape") closeModal();
469
+ },
470
+ document
471
+ );
472
+
473
+ // Element with ref
474
+ const buttonRef = useRef<HTMLButtonElement>(null);
475
+ useEventListener("click", handleClick, buttonRef);
476
+
477
+ // With options
478
+ useEventListener("scroll", handleScroll, window, {
479
+ passive: true,
480
+ capture: false,
481
+ enabled: isTracking,
482
+ });
483
+ ```
484
+
485
+ Supports window, document, HTMLElement, and RefObject targets with full TypeScript type inference.
486
+
487
+ </details>
488
+
489
+ <details>
490
+ <summary><strong>useOnClickOutside</strong> โ€” Outside click detection</summary>
491
+
492
+ ```tsx
493
+ // Basic usage - close modal on outside click
494
+ const modalRef = useRef<HTMLDivElement>(null);
495
+ useOnClickOutside(modalRef, () => onClose(), { enabled: isOpen });
496
+
497
+ // Multiple refs - button and dropdown menu
498
+ const buttonRef = useRef<HTMLButtonElement>(null);
499
+ const menuRef = useRef<HTMLDivElement>(null);
500
+ useOnClickOutside([buttonRef, menuRef], () => setIsOpen(false), {
501
+ enabled: isOpen,
502
+ });
503
+
504
+ // With exclude refs
505
+ useOnClickOutside(modalRef, onClose, {
506
+ excludeRefs: [toastRef], // Clicks on toast won't close modal
507
+ });
508
+ ```
509
+
510
+ Perfect for modals, dropdowns, popovers, tooltips, and context menus with mouse + touch support.
511
+
512
+ </details>
513
+
514
+ <details>
515
+ <summary><strong>useClickAnyWhere</strong> โ€” Global click detection</summary>
516
+
517
+ ```tsx
518
+ useClickAnyWhere(
519
+ (event) => {
520
+ if (!ref.current?.contains(event.target)) {
521
+ closeMenu();
522
+ }
523
+ },
524
+ { enabled: isOpen }
525
+ );
526
+ ```
527
+
528
+ Ideal for closing dropdowns, modals, and context menus.
529
+
530
+ </details>
531
+
532
+ <details>
533
+ <summary><strong>useCopyToClipboard</strong> โ€” Clipboard operations</summary>
534
+
535
+ ```tsx
536
+ const [copiedText, copy] = useCopyToClipboard({
537
+ timeout: 2000,
538
+ onSuccess: (text) => toast.success("Copied!"),
539
+ onError: (error) => toast.error("Failed to copy"),
540
+ });
541
+
542
+ const success = await copy("text to copy");
543
+ ```
544
+
545
+ Modern Clipboard API with automatic fallback for older browsers.
546
+
547
+ </details>
548
+
549
+ ### ๐Ÿ“ Location
550
+
551
+ <details>
552
+ <summary><strong>useGeolocation</strong> โ€” Device geolocation with real-time tracking and distance calculation</summary>
553
+
554
+ ```tsx
555
+ import { useGeolocation } from "@usefy/use-geolocation";
556
+
557
+ // Basic usage - get current position
558
+ const { position, loading, error } = useGeolocation();
559
+
560
+ // Real-time tracking
561
+ const { position, watchPosition, clearWatch } = useGeolocation({
562
+ immediate: false,
563
+ watch: false,
564
+ onPositionChange: (pos) => console.log("Position updated:", pos),
565
+ });
566
+
567
+ // Distance calculation
568
+ const { position, distanceFrom, bearingTo } = useGeolocation();
569
+
570
+ // Calculate distance to New York (in meters)
571
+ const distance = distanceFrom(40.7128, -74.006);
572
+
573
+ // Calculate bearing/direction to London (0-360 degrees)
574
+ const bearing = bearingTo(51.5074, -0.1278);
575
+
576
+ // High accuracy mode
577
+ const { position } = useGeolocation({
578
+ enableHighAccuracy: true,
579
+ timeout: 10000,
580
+ });
581
+
582
+ // Permission tracking
583
+ const { permission } = useGeolocation({
584
+ onPermissionChange: (state) => {
585
+ console.log("Permission:", state); // "prompt" | "granted" | "denied" | "unavailable"
586
+ },
587
+ });
588
+ ```
589
+
590
+ Perfect for location-based apps, maps, navigation, distance tracking, and geofencing with built-in Haversine distance calculation and bearing utilities.
591
+
592
+ </details>
593
+
594
+ ### ๐Ÿ‘๏ธ Visibility
595
+
596
+ <details>
597
+ <summary><strong>useIntersectionObserver</strong> โ€” Efficient element visibility detection with Intersection Observer API</summary>
598
+
599
+ ```tsx
600
+ import { useIntersectionObserver } from "@usefy/use-intersection-observer";
601
+
602
+ // Basic usage - detect when element enters viewport
603
+ const { ref, inView, entry } = useIntersectionObserver();
604
+
605
+ // Lazy loading images
606
+ const { ref, inView } = useIntersectionObserver({
607
+ triggerOnce: true, // Stop observing after first detection
608
+ threshold: 0.1, // Trigger when 10% visible
609
+ rootMargin: "50px", // Start loading 50px before entering viewport
610
+ });
611
+
612
+ // Infinite scroll with sentinel element
613
+ const { ref, inView } = useIntersectionObserver({
614
+ threshold: 1.0,
615
+ rootMargin: "100px", // Preload 100px ahead
616
+ });
617
+
618
+ useEffect(() => {
619
+ if (inView) loadMoreItems();
620
+ }, [inView]);
621
+
622
+ // Scroll animations
623
+ const { ref, inView } = useIntersectionObserver({
624
+ triggerOnce: true,
625
+ threshold: 0.3,
626
+ });
627
+
628
+ // Progress tracking with multiple thresholds
629
+ const thresholds = Array.from({ length: 101 }, (_, i) => i / 100);
630
+ const { ref, entry } = useIntersectionObserver({
631
+ threshold: thresholds,
632
+ onChange: (entry) => {
633
+ setProgress(Math.round(entry.intersectionRatio * 100));
634
+ },
635
+ });
636
+
637
+ // Custom scroll container
638
+ const containerRef = useRef<HTMLDivElement>(null);
639
+ const { ref, inView } = useIntersectionObserver({
640
+ root: containerRef.current,
641
+ rootMargin: "0px",
642
+ });
643
+
644
+ // Delayed observation
645
+ const { ref, inView } = useIntersectionObserver({
646
+ delay: 500, // Wait 500ms before creating observer
647
+ });
648
+ ```
649
+
650
+ Perfect for lazy loading, infinite scroll, scroll animations, progress tracking, and any visibility-based interactions with smart re-render optimization.
651
+
652
+ </details>
653
+
654
+ ### ๐Ÿ”„ Lifecycle
655
+
656
+ <details>
657
+ <summary><strong>useUnmount</strong> โ€” Execute callback on component unmount</summary>
658
+
659
+ ```tsx
660
+ // Basic usage
661
+ useUnmount(() => {
662
+ console.log("Component unmounted");
663
+ });
664
+
665
+ // With latest state access
666
+ const [formData, setFormData] = useState({});
667
+ useUnmount(() => {
668
+ // Always accesses latest formData value
669
+ saveToLocalStorage(formData);
670
+ });
671
+
672
+ // Conditional cleanup
673
+ useUnmount(
674
+ () => {
675
+ sendAnalyticsEvent("component_unmounted");
676
+ },
677
+ { enabled: trackingEnabled }
678
+ );
679
+ ```
680
+
681
+ Perfect for saving data, sending analytics, and cleaning up resources on component removal.
682
+
683
+ </details>
684
+
685
+ <details>
686
+ <summary><strong>useInit</strong> โ€” One-time initialization with async support, retry, timeout, and conditional execution</summary>
687
+
688
+ ```tsx
689
+ // Basic async initialization
690
+ const { isInitialized, isInitializing, error } = useInit(async () => {
691
+ await loadConfiguration();
692
+ });
693
+
694
+ // With retry and timeout
695
+ const { error, reinitialize } = useInit(
696
+ async () => {
697
+ await connectToServer();
698
+ },
699
+ {
700
+ retry: 3,
701
+ retryDelay: 1000,
702
+ timeout: 5000,
703
+ }
704
+ );
705
+
706
+ // Conditional initialization
707
+ useInit(
708
+ () => {
709
+ initializeFeature();
710
+ },
711
+ { when: isEnabled }
712
+ );
713
+
714
+ // With cleanup function
715
+ useInit(() => {
716
+ const subscription = eventBus.subscribe();
717
+ return () => subscription.unsubscribe();
718
+ });
719
+ ```
720
+
721
+ Perfect for initializing services, loading configuration, setting up subscriptions, and any one-time setup tasks with robust error handling.
722
+
723
+ </details>
724
+
725
+ ---
726
+
727
+ ## Test Coverage
728
+
729
+ All packages are comprehensively tested using Vitest to ensure reliability and stability.
730
+
731
+ ๐Ÿ“Š <a href="https://mirunamu00.github.io/usefy/coverage/" target="_blank" rel="noopener noreferrer"><strong>View Detailed Coverage Report</strong></a> (GitHub Pages)
732
+
733
+ > ๐Ÿ’ก To generate coverage report locally, run `pnpm test:coverage`. The report will be available at `coverage/index.html`.
734
+
735
+ | Package | Statements | Branches | Functions | Lines |
736
+ | ------------------------- | ---------- | -------- | --------- | ------ |
737
+ | use-toggle | 100% | 100% | 100% | 100% |
738
+ | use-counter | 100% | 100% | 100% | 100% |
739
+ | use-throttle | 100% | 100% | 100% | 100% |
740
+ | use-throttle-callback | 100% | 100% | 100% | 100% |
741
+ | use-on-click-outside | 97.61% | 93.93% | 100% | 97.61% |
742
+ | use-event-listener | 96.29% | 91.66% | 100% | 96.29% |
743
+ | use-init | 96.1% | 88.63% | 100% | 96% |
744
+ | use-local-storage | 95.18% | 86.84% | 93.75% | 95.12% |
745
+ | use-session-storage | 94.66% | 82.75% | 93.33% | 94.59% |
746
+ | use-debounce-callback | 93.2% | 76% | 93.75% | 93.13% |
747
+ | use-click-any-where | 92.3% | 87.5% | 100% | 92.3% |
748
+ | use-debounce | 90% | 82.6% | 66.66% | 91.95% |
749
+ | use-copy-to-clipboard | 87.87% | 79.16% | 85.71% | 87.87% |
750
+ | use-unmount | 100% | 100% | 100% | 100% |
751
+ | use-timer | 83.8% | 72.63% | 93.93% | 84.13% |
752
+ | use-geolocation | 93.89% | 93.47% | 100% | 93.75% |
753
+ | use-intersection-observer | 94% | 85% | 95% | 93.93% |
754
+ | use-signal | 98.61% | 90.9% | 96.42% | 98.59% |
755
+ | use-memory-monitor | 89.05% | 71.64% | 87.87% | 92.27% |
756
+
757
+ ---
758
+
759
+ ## Browser Support
760
+
761
+ | Browser | Version |
762
+ | ------- | ---------------- |
763
+ | Chrome | 66+ |
764
+ | Firefox | 63+ |
765
+ | Safari | 13.1+ |
766
+ | Edge | 79+ |
767
+ | IE 11 | Fallback support |
768
+
769
+ ---
770
+
771
+ ## Related Links
772
+
773
+ - ๐Ÿ“ฆ <a href="https://www.npmjs.com/org/usefy" target="_blank" rel="noopener noreferrer">npm Organization</a>
774
+ - ๐Ÿ™ <a href="https://github.com/mirunamu00/usefy" target="_blank" rel="noopener noreferrer">GitHub Repository</a>
775
+ - ๐Ÿ“ <a href="https://github.com/mirunamu00/usefy/blob/master/packages/usefy/CHANGELOG.md" target="_blank" rel="noopener noreferrer">Changelog</a>
776
+ - ๐Ÿ› <a href="https://github.com/mirunamu00/usefy/issues" target="_blank" rel="noopener noreferrer">Issue Tracker</a>
777
+
778
+ ---
779
+
780
+ ## License
781
+
782
+ MIT ยฉ <a href="https://github.com/mirunamu00" target="_blank" rel="noopener noreferrer">mirunamu</a>
783
+
784
+ ---
785
+
786
+ <p align="center">
787
+ <sub>Built with โค๏ธ by the usefy team</sub>
788
+ </p>
789
+
790
+ <p align="center">
791
+ <a href="https://github.com/mirunamu00/usefy" target="_blank" rel="noopener noreferrer">
792
+ <img src="https://img.shields.io/github/stars/mirunamu00/usefy?style=social" alt="GitHub stars" />
793
+ </a>
794
+ </p>
@@ -0,0 +1,19 @@
1
+ export { ClickAnyWhereHandler, UseClickAnyWhereOptions, useClickAnyWhere } from '@usefy/use-click-any-where';
2
+ export { CopyFn, UseCopyToClipboardOptions, UseCopyToClipboardReturn, useCopyToClipboard } from '@usefy/use-copy-to-clipboard';
3
+ export { useCounter } from '@usefy/use-counter';
4
+ export { SignalInfo, SignalOptions, UseSignalReturn, useSignal } from '@usefy/use-signal';
5
+ export { UseToggleReturn, useToggle } from '@usefy/use-toggle';
6
+ export { UseDebounceOptions, useDebounce } from '@usefy/use-debounce';
7
+ export { DebouncedFunction, UseDebounceCallbackOptions, useDebounceCallback } from '@usefy/use-debounce-callback';
8
+ export { UseThrottleOptions, useThrottle } from '@usefy/use-throttle';
9
+ export { ThrottledFunction, UseThrottleCallbackOptions, useThrottleCallback } from '@usefy/use-throttle-callback';
10
+ export { InitialValue, UseLocalStorageOptions, UseLocalStorageReturn, useLocalStorage } from '@usefy/use-local-storage';
11
+ export { InitialValue as SessionStorageInitialValue, UseSessionStorageOptions, UseSessionStorageReturn, useSessionStorage } from '@usefy/use-session-storage';
12
+ export { ClickOutsideEvent, MouseEventType, OnClickOutsideHandler, RefTarget, TouchEventType, UseOnClickOutsideOptions, useOnClickOutside } from '@usefy/use-on-click-outside';
13
+ export { EventTargetType, UseEventListenerOptions, useEventListener } from '@usefy/use-event-listener';
14
+ export { TimeFormat, TimeUnit, UseTimerOptions, UseTimerReturn, useTimer } from '@usefy/use-timer';
15
+ export { UseUnmountOptions, useUnmount } from '@usefy/use-unmount';
16
+ export { UseInitOptions, UseInitResult, useInit } from '@usefy/use-init';
17
+ export { GeoCoordinates, GeoPosition, GeolocationError, GeolocationErrorCode, PermissionState, UseGeolocationOptions, UseGeolocationReturn, calculateBearing, haversineDistance, useGeolocation } from '@usefy/use-geolocation';
18
+ export { IntersectionEntry, OnChangeCallback, UseIntersectionObserverOptions, UseIntersectionObserverReturn, createInitialEntry, isIntersectionObserverSupported, toIntersectionEntry, useIntersectionObserver } from '@usefy/use-intersection-observer';
19
+ export { AvailableMetric, BrowserSupport, CircularBuffer, FallbackStrategy, FormattedMemory, LeakAnalysis, LeakSensitivity, MemoryInfo, MemorySnapshot, Severity, SnapshotDiff, SupportLevel, Trend, UnsupportedInfo, UseMemoryMonitorOptions, UseMemoryMonitorReturn, analyzeLeakProbability, calculateTrend, detectSupport, formatBytes, linearRegression, useMemoryMonitor } from '@usefy/use-memory-monitor';
@@ -0,0 +1,19 @@
1
+ export { ClickAnyWhereHandler, UseClickAnyWhereOptions, useClickAnyWhere } from '@usefy/use-click-any-where';
2
+ export { CopyFn, UseCopyToClipboardOptions, UseCopyToClipboardReturn, useCopyToClipboard } from '@usefy/use-copy-to-clipboard';
3
+ export { useCounter } from '@usefy/use-counter';
4
+ export { SignalInfo, SignalOptions, UseSignalReturn, useSignal } from '@usefy/use-signal';
5
+ export { UseToggleReturn, useToggle } from '@usefy/use-toggle';
6
+ export { UseDebounceOptions, useDebounce } from '@usefy/use-debounce';
7
+ export { DebouncedFunction, UseDebounceCallbackOptions, useDebounceCallback } from '@usefy/use-debounce-callback';
8
+ export { UseThrottleOptions, useThrottle } from '@usefy/use-throttle';
9
+ export { ThrottledFunction, UseThrottleCallbackOptions, useThrottleCallback } from '@usefy/use-throttle-callback';
10
+ export { InitialValue, UseLocalStorageOptions, UseLocalStorageReturn, useLocalStorage } from '@usefy/use-local-storage';
11
+ export { InitialValue as SessionStorageInitialValue, UseSessionStorageOptions, UseSessionStorageReturn, useSessionStorage } from '@usefy/use-session-storage';
12
+ export { ClickOutsideEvent, MouseEventType, OnClickOutsideHandler, RefTarget, TouchEventType, UseOnClickOutsideOptions, useOnClickOutside } from '@usefy/use-on-click-outside';
13
+ export { EventTargetType, UseEventListenerOptions, useEventListener } from '@usefy/use-event-listener';
14
+ export { TimeFormat, TimeUnit, UseTimerOptions, UseTimerReturn, useTimer } from '@usefy/use-timer';
15
+ export { UseUnmountOptions, useUnmount } from '@usefy/use-unmount';
16
+ export { UseInitOptions, UseInitResult, useInit } from '@usefy/use-init';
17
+ export { GeoCoordinates, GeoPosition, GeolocationError, GeolocationErrorCode, PermissionState, UseGeolocationOptions, UseGeolocationReturn, calculateBearing, haversineDistance, useGeolocation } from '@usefy/use-geolocation';
18
+ export { IntersectionEntry, OnChangeCallback, UseIntersectionObserverOptions, UseIntersectionObserverReturn, createInitialEntry, isIntersectionObserverSupported, toIntersectionEntry, useIntersectionObserver } from '@usefy/use-intersection-observer';
19
+ export { AvailableMetric, BrowserSupport, CircularBuffer, FallbackStrategy, FormattedMemory, LeakAnalysis, LeakSensitivity, MemoryInfo, MemorySnapshot, Severity, SnapshotDiff, SupportLevel, Trend, UnsupportedInfo, UseMemoryMonitorOptions, UseMemoryMonitorReturn, analyzeLeakProbability, calculateTrend, detectSupport, formatBytes, linearRegression, useMemoryMonitor } from '@usefy/use-memory-monitor';
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ CircularBuffer: () => import_use_memory_monitor.CircularBuffer,
24
+ analyzeLeakProbability: () => import_use_memory_monitor.analyzeLeakProbability,
25
+ calculateBearing: () => import_use_geolocation.calculateBearing,
26
+ calculateTrend: () => import_use_memory_monitor.calculateTrend,
27
+ createInitialEntry: () => import_use_intersection_observer.createInitialEntry,
28
+ detectSupport: () => import_use_memory_monitor.detectSupport,
29
+ formatBytes: () => import_use_memory_monitor.formatBytes,
30
+ haversineDistance: () => import_use_geolocation.haversineDistance,
31
+ isIntersectionObserverSupported: () => import_use_intersection_observer.isIntersectionObserverSupported,
32
+ linearRegression: () => import_use_memory_monitor.linearRegression,
33
+ toIntersectionEntry: () => import_use_intersection_observer.toIntersectionEntry,
34
+ useClickAnyWhere: () => import_use_click_any_where.useClickAnyWhere,
35
+ useCopyToClipboard: () => import_use_copy_to_clipboard.useCopyToClipboard,
36
+ useCounter: () => import_use_counter.useCounter,
37
+ useDebounce: () => import_use_debounce.useDebounce,
38
+ useDebounceCallback: () => import_use_debounce_callback.useDebounceCallback,
39
+ useEventListener: () => import_use_event_listener.useEventListener,
40
+ useGeolocation: () => import_use_geolocation.useGeolocation,
41
+ useInit: () => import_use_init.useInit,
42
+ useIntersectionObserver: () => import_use_intersection_observer.useIntersectionObserver,
43
+ useLocalStorage: () => import_use_local_storage.useLocalStorage,
44
+ useMemoryMonitor: () => import_use_memory_monitor.useMemoryMonitor,
45
+ useOnClickOutside: () => import_use_on_click_outside.useOnClickOutside,
46
+ useSessionStorage: () => import_use_session_storage.useSessionStorage,
47
+ useSignal: () => import_use_signal.useSignal,
48
+ useThrottle: () => import_use_throttle.useThrottle,
49
+ useThrottleCallback: () => import_use_throttle_callback.useThrottleCallback,
50
+ useTimer: () => import_use_timer.useTimer,
51
+ useToggle: () => import_use_toggle.useToggle,
52
+ useUnmount: () => import_use_unmount.useUnmount
53
+ });
54
+ module.exports = __toCommonJS(index_exports);
55
+ var import_use_click_any_where = require("@usefy/use-click-any-where");
56
+ var import_use_copy_to_clipboard = require("@usefy/use-copy-to-clipboard");
57
+ var import_use_counter = require("@usefy/use-counter");
58
+ var import_use_signal = require("@usefy/use-signal");
59
+ var import_use_toggle = require("@usefy/use-toggle");
60
+ var import_use_debounce = require("@usefy/use-debounce");
61
+ var import_use_debounce_callback = require("@usefy/use-debounce-callback");
62
+ var import_use_throttle = require("@usefy/use-throttle");
63
+ var import_use_throttle_callback = require("@usefy/use-throttle-callback");
64
+ var import_use_local_storage = require("@usefy/use-local-storage");
65
+ var import_use_session_storage = require("@usefy/use-session-storage");
66
+ var import_use_on_click_outside = require("@usefy/use-on-click-outside");
67
+ var import_use_event_listener = require("@usefy/use-event-listener");
68
+ var import_use_timer = require("@usefy/use-timer");
69
+ var import_use_unmount = require("@usefy/use-unmount");
70
+ var import_use_init = require("@usefy/use-init");
71
+ var import_use_geolocation = require("@usefy/use-geolocation");
72
+ var import_use_intersection_observer = require("@usefy/use-intersection-observer");
73
+ var import_use_memory_monitor = require("@usefy/use-memory-monitor");
74
+ // Annotate the CommonJS export names for ESM import in node:
75
+ 0 && (module.exports = {
76
+ CircularBuffer,
77
+ analyzeLeakProbability,
78
+ calculateBearing,
79
+ calculateTrend,
80
+ createInitialEntry,
81
+ detectSupport,
82
+ formatBytes,
83
+ haversineDistance,
84
+ isIntersectionObserverSupported,
85
+ linearRegression,
86
+ toIntersectionEntry,
87
+ useClickAnyWhere,
88
+ useCopyToClipboard,
89
+ useCounter,
90
+ useDebounce,
91
+ useDebounceCallback,
92
+ useEventListener,
93
+ useGeolocation,
94
+ useInit,
95
+ useIntersectionObserver,
96
+ useLocalStorage,
97
+ useMemoryMonitor,
98
+ useOnClickOutside,
99
+ useSessionStorage,
100
+ useSignal,
101
+ useThrottle,
102
+ useThrottleCallback,
103
+ useTimer,
104
+ useToggle,
105
+ useUnmount
106
+ });
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Re-export all hooks from individual packages\n\n// useClickAnyWhere\nexport {\n useClickAnyWhere,\n type UseClickAnyWhereOptions,\n type ClickAnyWhereHandler,\n} from \"@usefy/use-click-any-where\";\n\n// useCopyToClipboard\nexport {\n useCopyToClipboard,\n type UseCopyToClipboardOptions,\n type UseCopyToClipboardReturn,\n type CopyFn,\n} from \"@usefy/use-copy-to-clipboard\";\n\n// useCounter\nexport { useCounter } from \"@usefy/use-counter\";\n\n// useSignal\nexport {\n useSignal,\n type UseSignalReturn,\n type SignalOptions,\n type SignalInfo,\n} from \"@usefy/use-signal\";\n\n// useToggle\nexport { useToggle, type UseToggleReturn } from \"@usefy/use-toggle\";\n\n// useDebounce\nexport { useDebounce, type UseDebounceOptions } from \"@usefy/use-debounce\";\n\n// useDebounceCallback\nexport {\n useDebounceCallback,\n type UseDebounceCallbackOptions,\n type DebouncedFunction,\n} from \"@usefy/use-debounce-callback\";\n\n// useThrottle\nexport { useThrottle, type UseThrottleOptions } from \"@usefy/use-throttle\";\n\n// useThrottleCallback\nexport {\n useThrottleCallback,\n type UseThrottleCallbackOptions,\n type ThrottledFunction,\n} from \"@usefy/use-throttle-callback\";\n\n// useLocalStorage\nexport {\n useLocalStorage,\n type UseLocalStorageOptions,\n type UseLocalStorageReturn,\n type InitialValue,\n} from \"@usefy/use-local-storage\";\n\n// useSessionStorage\nexport {\n useSessionStorage,\n type UseSessionStorageOptions,\n type UseSessionStorageReturn,\n type InitialValue as SessionStorageInitialValue,\n} from \"@usefy/use-session-storage\";\n\n// useOnClickOutside\nexport {\n useOnClickOutside,\n type UseOnClickOutsideOptions,\n type OnClickOutsideHandler,\n type ClickOutsideEvent,\n type RefTarget,\n type MouseEventType,\n type TouchEventType,\n} from \"@usefy/use-on-click-outside\";\n\n// useEventListener\nexport {\n useEventListener,\n type UseEventListenerOptions,\n type EventTargetType,\n} from \"@usefy/use-event-listener\";\n\n// useTimer\nexport {\n useTimer,\n type TimeUnit,\n type TimeFormat,\n type UseTimerOptions,\n type UseTimerReturn,\n} from \"@usefy/use-timer\";\n\n// useUnmount\nexport { useUnmount, type UseUnmountOptions } from \"@usefy/use-unmount\";\n\n// useInit\nexport {\n useInit,\n type UseInitOptions,\n type UseInitResult,\n} from \"@usefy/use-init\";\n\n// useGeolocation\nexport {\n useGeolocation,\n haversineDistance,\n calculateBearing,\n type GeoCoordinates,\n type GeoPosition,\n type GeolocationError,\n type GeolocationErrorCode,\n type PermissionState,\n type UseGeolocationOptions,\n type UseGeolocationReturn,\n} from \"@usefy/use-geolocation\";\n\n// useIntersectionObserver\nexport {\n useIntersectionObserver,\n isIntersectionObserverSupported,\n toIntersectionEntry,\n createInitialEntry,\n type UseIntersectionObserverOptions,\n type UseIntersectionObserverReturn,\n type IntersectionEntry,\n type OnChangeCallback,\n} from \"@usefy/use-intersection-observer\";\n\n// useMemoryMonitor\nexport {\n useMemoryMonitor,\n formatBytes,\n detectSupport,\n CircularBuffer,\n linearRegression,\n calculateTrend,\n analyzeLeakProbability,\n type UseMemoryMonitorOptions,\n type UseMemoryMonitorReturn,\n type MemoryInfo,\n type MemorySnapshot,\n type SnapshotDiff,\n type LeakAnalysis,\n type UnsupportedInfo,\n type SupportLevel,\n type AvailableMetric,\n type Severity,\n type Trend,\n type FallbackStrategy,\n type LeakSensitivity,\n type FormattedMemory,\n type BrowserSupport,\n} from \"@usefy/use-memory-monitor\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iCAIO;AAGP,mCAKO;AAGP,yBAA2B;AAG3B,wBAKO;AAGP,wBAAgD;AAGhD,0BAAqD;AAGrD,mCAIO;AAGP,0BAAqD;AAGrD,mCAIO;AAGP,+BAKO;AAGP,iCAKO;AAGP,kCAQO;AAGP,gCAIO;AAGP,uBAMO;AAGP,yBAAmD;AAGnD,sBAIO;AAGP,6BAWO;AAGP,uCASO;AAGP,gCAuBO;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,92 @@
1
+ // src/index.ts
2
+ import {
3
+ useClickAnyWhere
4
+ } from "@usefy/use-click-any-where";
5
+ import {
6
+ useCopyToClipboard
7
+ } from "@usefy/use-copy-to-clipboard";
8
+ import { useCounter } from "@usefy/use-counter";
9
+ import {
10
+ useSignal
11
+ } from "@usefy/use-signal";
12
+ import { useToggle } from "@usefy/use-toggle";
13
+ import { useDebounce } from "@usefy/use-debounce";
14
+ import {
15
+ useDebounceCallback
16
+ } from "@usefy/use-debounce-callback";
17
+ import { useThrottle } from "@usefy/use-throttle";
18
+ import {
19
+ useThrottleCallback
20
+ } from "@usefy/use-throttle-callback";
21
+ import {
22
+ useLocalStorage
23
+ } from "@usefy/use-local-storage";
24
+ import {
25
+ useSessionStorage
26
+ } from "@usefy/use-session-storage";
27
+ import {
28
+ useOnClickOutside
29
+ } from "@usefy/use-on-click-outside";
30
+ import {
31
+ useEventListener
32
+ } from "@usefy/use-event-listener";
33
+ import {
34
+ useTimer
35
+ } from "@usefy/use-timer";
36
+ import { useUnmount } from "@usefy/use-unmount";
37
+ import {
38
+ useInit
39
+ } from "@usefy/use-init";
40
+ import {
41
+ useGeolocation,
42
+ haversineDistance,
43
+ calculateBearing
44
+ } from "@usefy/use-geolocation";
45
+ import {
46
+ useIntersectionObserver,
47
+ isIntersectionObserverSupported,
48
+ toIntersectionEntry,
49
+ createInitialEntry
50
+ } from "@usefy/use-intersection-observer";
51
+ import {
52
+ useMemoryMonitor,
53
+ formatBytes,
54
+ detectSupport,
55
+ CircularBuffer,
56
+ linearRegression,
57
+ calculateTrend,
58
+ analyzeLeakProbability
59
+ } from "@usefy/use-memory-monitor";
60
+ export {
61
+ CircularBuffer,
62
+ analyzeLeakProbability,
63
+ calculateBearing,
64
+ calculateTrend,
65
+ createInitialEntry,
66
+ detectSupport,
67
+ formatBytes,
68
+ haversineDistance,
69
+ isIntersectionObserverSupported,
70
+ linearRegression,
71
+ toIntersectionEntry,
72
+ useClickAnyWhere,
73
+ useCopyToClipboard,
74
+ useCounter,
75
+ useDebounce,
76
+ useDebounceCallback,
77
+ useEventListener,
78
+ useGeolocation,
79
+ useInit,
80
+ useIntersectionObserver,
81
+ useLocalStorage,
82
+ useMemoryMonitor,
83
+ useOnClickOutside,
84
+ useSessionStorage,
85
+ useSignal,
86
+ useThrottle,
87
+ useThrottleCallback,
88
+ useTimer,
89
+ useToggle,
90
+ useUnmount
91
+ };
92
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Re-export all hooks from individual packages\n\n// useClickAnyWhere\nexport {\n useClickAnyWhere,\n type UseClickAnyWhereOptions,\n type ClickAnyWhereHandler,\n} from \"@usefy/use-click-any-where\";\n\n// useCopyToClipboard\nexport {\n useCopyToClipboard,\n type UseCopyToClipboardOptions,\n type UseCopyToClipboardReturn,\n type CopyFn,\n} from \"@usefy/use-copy-to-clipboard\";\n\n// useCounter\nexport { useCounter } from \"@usefy/use-counter\";\n\n// useSignal\nexport {\n useSignal,\n type UseSignalReturn,\n type SignalOptions,\n type SignalInfo,\n} from \"@usefy/use-signal\";\n\n// useToggle\nexport { useToggle, type UseToggleReturn } from \"@usefy/use-toggle\";\n\n// useDebounce\nexport { useDebounce, type UseDebounceOptions } from \"@usefy/use-debounce\";\n\n// useDebounceCallback\nexport {\n useDebounceCallback,\n type UseDebounceCallbackOptions,\n type DebouncedFunction,\n} from \"@usefy/use-debounce-callback\";\n\n// useThrottle\nexport { useThrottle, type UseThrottleOptions } from \"@usefy/use-throttle\";\n\n// useThrottleCallback\nexport {\n useThrottleCallback,\n type UseThrottleCallbackOptions,\n type ThrottledFunction,\n} from \"@usefy/use-throttle-callback\";\n\n// useLocalStorage\nexport {\n useLocalStorage,\n type UseLocalStorageOptions,\n type UseLocalStorageReturn,\n type InitialValue,\n} from \"@usefy/use-local-storage\";\n\n// useSessionStorage\nexport {\n useSessionStorage,\n type UseSessionStorageOptions,\n type UseSessionStorageReturn,\n type InitialValue as SessionStorageInitialValue,\n} from \"@usefy/use-session-storage\";\n\n// useOnClickOutside\nexport {\n useOnClickOutside,\n type UseOnClickOutsideOptions,\n type OnClickOutsideHandler,\n type ClickOutsideEvent,\n type RefTarget,\n type MouseEventType,\n type TouchEventType,\n} from \"@usefy/use-on-click-outside\";\n\n// useEventListener\nexport {\n useEventListener,\n type UseEventListenerOptions,\n type EventTargetType,\n} from \"@usefy/use-event-listener\";\n\n// useTimer\nexport {\n useTimer,\n type TimeUnit,\n type TimeFormat,\n type UseTimerOptions,\n type UseTimerReturn,\n} from \"@usefy/use-timer\";\n\n// useUnmount\nexport { useUnmount, type UseUnmountOptions } from \"@usefy/use-unmount\";\n\n// useInit\nexport {\n useInit,\n type UseInitOptions,\n type UseInitResult,\n} from \"@usefy/use-init\";\n\n// useGeolocation\nexport {\n useGeolocation,\n haversineDistance,\n calculateBearing,\n type GeoCoordinates,\n type GeoPosition,\n type GeolocationError,\n type GeolocationErrorCode,\n type PermissionState,\n type UseGeolocationOptions,\n type UseGeolocationReturn,\n} from \"@usefy/use-geolocation\";\n\n// useIntersectionObserver\nexport {\n useIntersectionObserver,\n isIntersectionObserverSupported,\n toIntersectionEntry,\n createInitialEntry,\n type UseIntersectionObserverOptions,\n type UseIntersectionObserverReturn,\n type IntersectionEntry,\n type OnChangeCallback,\n} from \"@usefy/use-intersection-observer\";\n\n// useMemoryMonitor\nexport {\n useMemoryMonitor,\n formatBytes,\n detectSupport,\n CircularBuffer,\n linearRegression,\n calculateTrend,\n analyzeLeakProbability,\n type UseMemoryMonitorOptions,\n type UseMemoryMonitorReturn,\n type MemoryInfo,\n type MemorySnapshot,\n type SnapshotDiff,\n type LeakAnalysis,\n type UnsupportedInfo,\n type SupportLevel,\n type AvailableMetric,\n type Severity,\n type Trend,\n type FallbackStrategy,\n type LeakSensitivity,\n type FormattedMemory,\n type BrowserSupport,\n} from \"@usefy/use-memory-monitor\";\n"],"mappings":";AAGA;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,OAIK;AAGP,SAAS,kBAAkB;AAG3B;AAAA,EACE;AAAA,OAIK;AAGP,SAAS,iBAAuC;AAGhD,SAAS,mBAA4C;AAGrD;AAAA,EACE;AAAA,OAGK;AAGP,SAAS,mBAA4C;AAGrD;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,OAIK;AAGP;AAAA,EACE;AAAA,OAOK;AAGP;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,OAKK;AAGP,SAAS,kBAA0C;AAGnD;AAAA,EACE;AAAA,OAGK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;AAGP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAgBK;","names":[]}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@usefy/hooks",
3
+ "version": "0.0.35",
4
+ "description": "A collection of useful React hooks",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "sideEffects": false,
19
+ "dependencies": {
20
+ "@usefy/use-click-any-where": "0.0.36",
21
+ "@usefy/use-copy-to-clipboard": "0.0.36",
22
+ "@usefy/use-counter": "0.0.36",
23
+ "@usefy/use-toggle": "0.0.36",
24
+ "@usefy/use-debounce": "0.0.36",
25
+ "@usefy/use-signal": "0.0.36",
26
+ "@usefy/use-debounce-callback": "0.0.36",
27
+ "@usefy/use-throttle": "0.0.36",
28
+ "@usefy/use-throttle-callback": "0.0.36",
29
+ "@usefy/use-local-storage": "0.0.36",
30
+ "@usefy/use-session-storage": "0.0.36",
31
+ "@usefy/use-on-click-outside": "0.0.36",
32
+ "@usefy/use-event-listener": "0.0.36",
33
+ "@usefy/use-timer": "0.0.36",
34
+ "@usefy/use-unmount": "0.0.36",
35
+ "@usefy/use-init": "0.0.36",
36
+ "@usefy/use-geolocation": "0.0.36",
37
+ "@usefy/use-intersection-observer": "0.0.36",
38
+ "@usefy/use-memory-monitor": "0.0.36"
39
+ },
40
+ "peerDependencies": {
41
+ "react": "^18.0.0 || ^19.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/react": "^19.0.0",
45
+ "rimraf": "^6.0.1",
46
+ "tsup": "^8.0.0",
47
+ "typescript": "^5.0.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "https://github.com/mirunamu00/usefy.git",
55
+ "directory": "packages/usefy"
56
+ },
57
+ "license": "MIT",
58
+ "keywords": [
59
+ "react",
60
+ "hooks",
61
+ "custom-hooks",
62
+ "usefy"
63
+ ],
64
+ "scripts": {
65
+ "build": "tsup",
66
+ "dev": "tsup --watch",
67
+ "typecheck": "tsc --noEmit",
68
+ "clean": "rimraf dist"
69
+ }
70
+ }