@usefy/usefy 0.0.12 โ†’ 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +418 -0
  2. package/package.json +11 -11
package/README.md ADDED
@@ -0,0 +1,418 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/geon0529/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/usefy">
13
+ <img src="https://img.shields.io/npm/v/@usefy/usefy.svg?style=flat-square&color=007acc" alt="npm version" />
14
+ </a>
15
+ <a href="https://www.npmjs.com/package/@usefy/usefy">
16
+ <img src="https://img.shields.io/npm/dm/@usefy/usefy.svg?style=flat-square&color=007acc" alt="npm downloads" />
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@usefy/usefy">
19
+ <img src="https://img.shields.io/bundlephobia/minzip/@usefy/usefy?style=flat-square&color=007acc" alt="bundle size" />
20
+ </a>
21
+ <a href="https://github.com/geon0529/usefy/blob/master/LICENSE">
22
+ <img src="https://img.shields.io/npm/l/@usefy/usefy.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
+ ---
34
+
35
+ > โš ๏ธ **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.
36
+ >
37
+ > ๐Ÿšง **Actively Developing**: New hooks are being added regularly. Stay tuned for more utilities!
38
+
39
+ ---
40
+
41
+ ## Overview
42
+
43
+ **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.
44
+
45
+ ### โœจ Why usefy?
46
+
47
+ - **๐Ÿš€ Zero Dependencies** โ€” Pure React implementation with no external dependencies
48
+ - **๐Ÿ“ฆ Tree Shakeable** โ€” Import only the hooks you need to optimize bundle size
49
+ - **๐Ÿ”ท TypeScript First** โ€” Complete type safety with full autocomplete support
50
+ - **โšก SSR Compatible** โ€” Works seamlessly with Next.js, Remix, and other SSR frameworks
51
+ - **๐Ÿงช Well Tested** โ€” High test coverage ensures reliability and stability
52
+ - **๐Ÿ“– Well Documented** โ€” Detailed documentation with practical examples
53
+
54
+ ---
55
+
56
+ ## Installation
57
+
58
+ ### All-in-One Package
59
+
60
+ Install all hooks at once:
61
+
62
+ ```bash
63
+ # npm
64
+ npm install @usefy/usefy
65
+
66
+ # yarn
67
+ yarn add @usefy/usefy
68
+
69
+ # pnpm
70
+ pnpm add @usefy/usefy
71
+ ```
72
+
73
+ ### Individual Packages
74
+
75
+ You can also install only the hooks you need:
76
+
77
+ ```bash
78
+ # Example: Install only use-toggle
79
+ pnpm add @usefy/use-toggle
80
+
81
+ # Install multiple packages
82
+ pnpm add @usefy/use-debounce @usefy/use-local-storage
83
+ ```
84
+
85
+ ### Peer Dependencies
86
+
87
+ All packages require React 18 or 19:
88
+
89
+ ```json
90
+ {
91
+ "peerDependencies": {
92
+ "react": "^18.0.0 || ^19.0.0"
93
+ }
94
+ }
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Packages
100
+
101
+ ### ๐Ÿ“ฆ Available Hooks
102
+
103
+ | Hook | Description | npm | Coverage |
104
+ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
105
+ | [@usefy/use-toggle](https://www.npmjs.com/package/@usefy/use-toggle) | Boolean state management with toggle, setTrue, setFalse | [![npm](https://img.shields.io/npm/v/@usefy/use-toggle.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-toggle) | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
106
+ | [@usefy/use-counter](https://www.npmjs.com/package/@usefy/use-counter) | Counter state with increment, decrement, reset | [![npm](https://img.shields.io/npm/v/@usefy/use-counter.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-counter) | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
107
+ | [@usefy/use-debounce](https://www.npmjs.com/package/@usefy/use-debounce) | Value debouncing with leading/trailing edge | [![npm](https://img.shields.io/npm/v/@usefy/use-debounce.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-debounce) | ![91%](https://img.shields.io/badge/coverage-91%25-brightgreen?style=flat-square) |
108
+ | [@usefy/use-debounce-callback](https://www.npmjs.com/package/@usefy/use-debounce-callback) | Debounced callbacks with cancel/flush/pending | [![npm](https://img.shields.io/npm/v/@usefy/use-debounce-callback.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-debounce-callback) | ![94%](https://img.shields.io/badge/coverage-94%25-brightgreen?style=flat-square) |
109
+ | [@usefy/use-throttle](https://www.npmjs.com/package/@usefy/use-throttle) | Value throttling for rate-limiting updates | [![npm](https://img.shields.io/npm/v/@usefy/use-throttle.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-throttle) | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
110
+ | [@usefy/use-throttle-callback](https://www.npmjs.com/package/@usefy/use-throttle-callback) | Throttled callbacks with cancel/flush/pending | [![npm](https://img.shields.io/npm/v/@usefy/use-throttle-callback.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-throttle-callback) | ![100%](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square) |
111
+ | [@usefy/use-local-storage](https://www.npmjs.com/package/@usefy/use-local-storage) | localStorage persistence with cross-tab sync | [![npm](https://img.shields.io/npm/v/@usefy/use-local-storage.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-local-storage) | ![95%](https://img.shields.io/badge/coverage-95%25-brightgreen?style=flat-square) |
112
+ | [@usefy/use-session-storage](https://www.npmjs.com/package/@usefy/use-session-storage) | sessionStorage persistence for tab lifetime | [![npm](https://img.shields.io/npm/v/@usefy/use-session-storage.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-session-storage) | ![94%](https://img.shields.io/badge/coverage-94%25-brightgreen?style=flat-square) |
113
+ | [@usefy/use-click-any-where](https://www.npmjs.com/package/@usefy/use-click-any-where) | Document-wide click event detection | [![npm](https://img.shields.io/npm/v/@usefy/use-click-any-where.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-click-any-where) | ![92%](https://img.shields.io/badge/coverage-92%25-brightgreen?style=flat-square) |
114
+ | [@usefy/use-copy-to-clipboard](https://www.npmjs.com/package/@usefy/use-copy-to-clipboard) | Clipboard copy with fallback support | [![npm](https://img.shields.io/npm/v/@usefy/use-copy-to-clipboard.svg?style=flat-square&color=007acc)](https://www.npmjs.com/package/@usefy/use-copy-to-clipboard) | ![88%](https://img.shields.io/badge/coverage-88%25-brightgreen?style=flat-square) |
115
+
116
+ ---
117
+
118
+ ## Quick Start
119
+
120
+ ### Using the All-in-One Package
121
+
122
+ ```tsx
123
+ import {
124
+ useToggle,
125
+ useCounter,
126
+ useDebounce,
127
+ useLocalStorage,
128
+ useCopyToClipboard,
129
+ } from "@usefy/usefy";
130
+
131
+ function App() {
132
+ // Boolean state management
133
+ const { value: isOpen, toggle, setFalse: close } = useToggle(false);
134
+
135
+ // Counter with controls
136
+ const { count, increment, decrement, reset } = useCounter(0);
137
+
138
+ // Debounced search
139
+ const [query, setQuery] = useState("");
140
+ const debouncedQuery = useDebounce(query, 300);
141
+
142
+ // Persistent theme preference
143
+ const [theme, setTheme] = useLocalStorage("theme", "light");
144
+
145
+ // Copy functionality
146
+ const [copiedText, copy] = useCopyToClipboard();
147
+
148
+ return (
149
+ <div data-theme={theme}>
150
+ {/* Modal */}
151
+ <button onClick={toggle}>Open Modal</button>
152
+ {isOpen && (
153
+ <div className="modal">
154
+ <button onClick={close}>Close</button>
155
+ </div>
156
+ )}
157
+
158
+ {/* Counter */}
159
+ <div>
160
+ <button onClick={decrement}>-</button>
161
+ <span>{count}</span>
162
+ <button onClick={increment}>+</button>
163
+ </div>
164
+
165
+ {/* Search */}
166
+ <input
167
+ value={query}
168
+ onChange={(e) => setQuery(e.target.value)}
169
+ placeholder="Search..."
170
+ />
171
+
172
+ {/* Theme Toggle */}
173
+ <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
174
+ Toggle Theme
175
+ </button>
176
+
177
+ {/* Copy */}
178
+ <button onClick={() => copy("Hello World!")}>
179
+ {copiedText ? "Copied!" : "Copy"}
180
+ </button>
181
+ </div>
182
+ );
183
+ }
184
+ ```
185
+
186
+ ### Using Individual Packages
187
+
188
+ ```tsx
189
+ import { useToggle } from "@usefy/use-toggle";
190
+ import { useDebounce } from "@usefy/use-debounce";
191
+
192
+ function SearchModal() {
193
+ const { value: isOpen, toggle } = useToggle(false);
194
+ const [query, setQuery] = useState("");
195
+ const debouncedQuery = useDebounce(query, 300);
196
+
197
+ useEffect(() => {
198
+ if (debouncedQuery) {
199
+ searchAPI(debouncedQuery);
200
+ }
201
+ }, [debouncedQuery]);
202
+
203
+ return (
204
+ <>
205
+ <button onClick={toggle}>Search</button>
206
+ {isOpen && (
207
+ <input value={query} onChange={(e) => setQuery(e.target.value)} />
208
+ )}
209
+ </>
210
+ );
211
+ }
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Features
217
+
218
+ ### ๐Ÿ”„ State Management
219
+
220
+ <details>
221
+ <summary><strong>useToggle</strong> โ€” Boolean state with utility functions</summary>
222
+
223
+ ```tsx
224
+ const { value, toggle, setTrue, setFalse, setValue } = useToggle(false);
225
+ ```
226
+
227
+ Perfect for modals, dropdowns, accordions, and switches.
228
+
229
+ </details>
230
+
231
+ <details>
232
+ <summary><strong>useCounter</strong> โ€” Counter state with controls</summary>
233
+
234
+ ```tsx
235
+ const { count, increment, decrement, reset } = useCounter(0);
236
+ ```
237
+
238
+ Ideal for quantity selectors, pagination, and score tracking.
239
+
240
+ </details>
241
+
242
+ ### โฑ๏ธ Timing Utilities
243
+
244
+ <details>
245
+ <summary><strong>useDebounce</strong> โ€” Debounce value updates</summary>
246
+
247
+ ```tsx
248
+ const debouncedValue = useDebounce(value, 300, {
249
+ leading: false,
250
+ trailing: true,
251
+ maxWait: 1000,
252
+ });
253
+ ```
254
+
255
+ Best for search inputs, form validation, and API calls.
256
+
257
+ </details>
258
+
259
+ <details>
260
+ <summary><strong>useDebounceCallback</strong> โ€” Debounce function calls</summary>
261
+
262
+ ```tsx
263
+ const debouncedFn = useDebounceCallback(callback, 300);
264
+
265
+ debouncedFn(args); // Call debounced
266
+ debouncedFn.cancel(); // Cancel pending
267
+ debouncedFn.flush(); // Execute immediately
268
+ debouncedFn.pending(); // Check if pending
269
+ ```
270
+
271
+ </details>
272
+
273
+ <details>
274
+ <summary><strong>useThrottle</strong> โ€” Throttle value updates</summary>
275
+
276
+ ```tsx
277
+ const throttledValue = useThrottle(value, 100, {
278
+ leading: true,
279
+ trailing: true,
280
+ });
281
+ ```
282
+
283
+ Perfect for scroll events, resize handlers, and mouse tracking.
284
+
285
+ </details>
286
+
287
+ <details>
288
+ <summary><strong>useThrottleCallback</strong> โ€” Throttle function calls</summary>
289
+
290
+ ```tsx
291
+ const throttledFn = useThrottleCallback(callback, 100);
292
+ ```
293
+
294
+ </details>
295
+
296
+ ### ๐Ÿ’พ Storage
297
+
298
+ <details>
299
+ <summary><strong>useLocalStorage</strong> โ€” Persistent storage with sync</summary>
300
+
301
+ ```tsx
302
+ const [value, setValue, removeValue] = useLocalStorage("key", initialValue, {
303
+ serializer: JSON.stringify,
304
+ deserializer: JSON.parse,
305
+ syncTabs: true,
306
+ onError: (error) => console.error(error),
307
+ });
308
+ ```
309
+
310
+ Supports cross-tab synchronization and custom serialization.
311
+
312
+ </details>
313
+
314
+ <details>
315
+ <summary><strong>useSessionStorage</strong> โ€” Session-scoped storage</summary>
316
+
317
+ ```tsx
318
+ const [value, setValue, removeValue] = useSessionStorage("key", initialValue);
319
+ ```
320
+
321
+ Data persists during tab lifetime, isolated per tab.
322
+
323
+ </details>
324
+
325
+ ### ๐Ÿ–ฑ๏ธ Events
326
+
327
+ <details>
328
+ <summary><strong>useClickAnyWhere</strong> โ€” Global click detection</summary>
329
+
330
+ ```tsx
331
+ useClickAnyWhere(
332
+ (event) => {
333
+ if (!ref.current?.contains(event.target)) {
334
+ closeMenu();
335
+ }
336
+ },
337
+ { enabled: isOpen }
338
+ );
339
+ ```
340
+
341
+ Ideal for closing dropdowns, modals, and context menus.
342
+
343
+ </details>
344
+
345
+ <details>
346
+ <summary><strong>useCopyToClipboard</strong> โ€” Clipboard operations</summary>
347
+
348
+ ```tsx
349
+ const [copiedText, copy] = useCopyToClipboard({
350
+ timeout: 2000,
351
+ onSuccess: (text) => toast.success("Copied!"),
352
+ onError: (error) => toast.error("Failed to copy"),
353
+ });
354
+
355
+ const success = await copy("text to copy");
356
+ ```
357
+
358
+ Modern Clipboard API with automatic fallback for older browsers.
359
+
360
+ </details>
361
+
362
+ ---
363
+
364
+ ## Test Coverage
365
+
366
+ All packages are comprehensively tested using Vitest to ensure reliability and stability.
367
+
368
+ | Package | Statements | Branches | Functions | Lines |
369
+ | --------------------- | ---------- | -------- | --------- | ----- |
370
+ | use-toggle | 100% | 100% | 100% | 100% |
371
+ | use-counter | 100% | 100% | 100% | 100% |
372
+ | use-throttle | 100% | 100% | 100% | 100% |
373
+ | use-throttle-callback | 100% | 100% | 100% | 100% |
374
+ | use-local-storage | 95% | 86% | 100% | 95% |
375
+ | use-session-storage | 94% | 79% | 100% | 94% |
376
+ | use-debounce-callback | 94% | 83% | 94% | 94% |
377
+ | use-click-any-where | 92% | 88% | 100% | 92% |
378
+ | use-debounce | 91% | 90% | 67% | 93% |
379
+ | use-copy-to-clipboard | 88% | 79% | 86% | 88% |
380
+
381
+ ---
382
+
383
+ ## Browser Support
384
+
385
+ | Browser | Version |
386
+ | ------- | ---------------- |
387
+ | Chrome | 66+ |
388
+ | Firefox | 63+ |
389
+ | Safari | 13.1+ |
390
+ | Edge | 79+ |
391
+ | IE 11 | Fallback support |
392
+
393
+ ---
394
+
395
+ ## Related Links
396
+
397
+ - ๐Ÿ“ฆ [npm Organization](https://www.npmjs.com/org/usefy)
398
+ - ๐Ÿ™ [GitHub Repository](https://github.com/geon0529/usefy)
399
+ - ๐Ÿ“ [Changelog](https://github.com/geon0529/usefy/blob/master/CHANGELOG.md)
400
+ - ๐Ÿ› [Issue Tracker](https://github.com/geon0529/usefy/issues)
401
+
402
+ ---
403
+
404
+ ## License
405
+
406
+ MIT ยฉ [mirunamu](https://github.com/geon0529)
407
+
408
+ ---
409
+
410
+ <p align="center">
411
+ <sub>Built with โค๏ธ by the usefy team</sub>
412
+ </p>
413
+
414
+ <p align="center">
415
+ <a href="https://github.com/geon0529/usefy">
416
+ <img src="https://img.shields.io/github/stars/geon0529/usefy?style=social" alt="GitHub stars" />
417
+ </a>
418
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefy/usefy",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "A collection of useful React hooks",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -17,16 +17,16 @@
17
17
  ],
18
18
  "sideEffects": false,
19
19
  "dependencies": {
20
- "@usefy/use-copy-to-clipboard": "0.0.12",
21
- "@usefy/use-counter": "0.0.12",
22
- "@usefy/use-toggle": "0.0.12",
23
- "@usefy/use-click-any-where": "0.0.12",
24
- "@usefy/use-debounce-callback": "0.0.12",
25
- "@usefy/use-throttle": "0.0.12",
26
- "@usefy/use-debounce": "0.0.12",
27
- "@usefy/use-throttle-callback": "0.0.12",
28
- "@usefy/use-local-storage": "0.0.12",
29
- "@usefy/use-session-storage": "0.0.12"
20
+ "@usefy/use-click-any-where": "0.0.14",
21
+ "@usefy/use-copy-to-clipboard": "0.0.14",
22
+ "@usefy/use-toggle": "0.0.14",
23
+ "@usefy/use-counter": "0.0.14",
24
+ "@usefy/use-debounce": "0.0.14",
25
+ "@usefy/use-debounce-callback": "0.0.14",
26
+ "@usefy/use-throttle": "0.0.14",
27
+ "@usefy/use-local-storage": "0.0.14",
28
+ "@usefy/use-throttle-callback": "0.0.14",
29
+ "@usefy/use-session-storage": "0.0.14"
30
30
  },
31
31
  "peerDependencies": {
32
32
  "react": "^18.0.0 || ^19.0.0"