@usefy/use-toggle 0.0.8 → 0.0.10

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 +423 -0
  2. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,423 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/geon0529/usefy/master/assets/logo.png" alt="usefy logo" width="120" />
3
+ </p>
4
+
5
+ <h1 align="center">@usefy/use-toggle</h1>
6
+
7
+ <p align="center">
8
+ <strong>A lightweight, type-safe React hook for boolean state management</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/@usefy/use-toggle">
13
+ <img src="https://img.shields.io/npm/v/@usefy/use-toggle.svg?style=flat-square&color=007acc" alt="npm version" />
14
+ </a>
15
+ <a href="https://www.npmjs.com/package/@usefy/use-toggle">
16
+ <img src="https://img.shields.io/npm/dm/@usefy/use-toggle.svg?style=flat-square&color=007acc" alt="npm downloads" />
17
+ </a>
18
+ <a href="https://bundlephobia.com/package/@usefy/use-toggle">
19
+ <img src="https://img.shields.io/bundlephobia/minzip/@usefy/use-toggle?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/use-toggle.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="#quick-start">Quick Start</a> •
29
+ <a href="#api-reference">API Reference</a> •
30
+ <a href="#examples">Examples</a> •
31
+ <a href="#license">License</a>
32
+ </p>
33
+
34
+ ---
35
+
36
+ ## Overview
37
+
38
+ `@usefy/use-toggle` is a powerful React hook for managing boolean state with helpful utilities. It provides `toggle`, `setTrue`, `setFalse`, and `setValue` functions, making it perfect for modals, dropdowns, accordions, and any UI component with on/off states.
39
+
40
+ **Part of the [@usefy](https://www.npmjs.com/org/usefy) ecosystem** — a collection of production-ready React hooks designed for modern applications.
41
+
42
+ ### Why use-toggle?
43
+
44
+ - **Zero Dependencies** — Pure React implementation with no external dependencies
45
+ - **TypeScript First** — Full type safety with exported interfaces
46
+ - **Stable References** — All functions are memoized with `useCallback` for optimal performance
47
+ - **SSR Compatible** — Works seamlessly with Next.js, Remix, and other SSR frameworks
48
+ - **Lightweight** — Minimal bundle footprint (~300B minified + gzipped)
49
+ - **Well Tested** — Comprehensive test coverage with Vitest
50
+
51
+ ---
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ # npm
57
+ npm install @usefy/use-toggle
58
+
59
+ # yarn
60
+ yarn add @usefy/use-toggle
61
+
62
+ # pnpm
63
+ pnpm add @usefy/use-toggle
64
+ ```
65
+
66
+ ### Peer Dependencies
67
+
68
+ This package requires React 18 or 19:
69
+
70
+ ```json
71
+ {
72
+ "peerDependencies": {
73
+ "react": "^18.0.0 || ^19.0.0"
74
+ }
75
+ }
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Quick Start
81
+
82
+ ```tsx
83
+ import { useToggle } from '@usefy/use-toggle';
84
+
85
+ function Modal() {
86
+ const { value: isOpen, toggle, setTrue, setFalse } = useToggle(false);
87
+
88
+ return (
89
+ <>
90
+ <button onClick={setTrue}>Open Modal</button>
91
+ {isOpen && (
92
+ <div className="modal">
93
+ <h2>Modal Content</h2>
94
+ <button onClick={setFalse}>Close</button>
95
+ </div>
96
+ )}
97
+ </>
98
+ );
99
+ }
100
+ ```
101
+
102
+ ---
103
+
104
+ ## API Reference
105
+
106
+ ### `useToggle(initialValue?)`
107
+
108
+ A hook that manages boolean state with toggle, setTrue, setFalse, and setValue functions.
109
+
110
+ #### Parameters
111
+
112
+ | Parameter | Type | Default | Description |
113
+ |-----------|------|---------|-------------|
114
+ | `initialValue` | `boolean` | `false` | The initial boolean value |
115
+
116
+ #### Returns `UseToggleReturn`
117
+
118
+ | Property | Type | Description |
119
+ |----------|------|-------------|
120
+ | `value` | `boolean` | The current boolean state |
121
+ | `toggle` | `() => void` | Toggles the value (true ↔ false) |
122
+ | `setTrue` | `() => void` | Sets the value to `true` |
123
+ | `setFalse` | `() => void` | Sets the value to `false` |
124
+ | `setValue` | `(value: boolean) => void` | Sets the value to a specific boolean |
125
+
126
+ ---
127
+
128
+ ## Examples
129
+
130
+ ### Modal/Dialog
131
+
132
+ ```tsx
133
+ import { useToggle } from '@usefy/use-toggle';
134
+
135
+ function ConfirmDialog() {
136
+ const { value: isOpen, setTrue: open, setFalse: close } = useToggle(false);
137
+
138
+ return (
139
+ <>
140
+ <button onClick={open}>Delete Item</button>
141
+ {isOpen && (
142
+ <div className="dialog-overlay">
143
+ <div className="dialog">
144
+ <h3>Confirm Deletion</h3>
145
+ <p>Are you sure you want to delete this item?</p>
146
+ <div className="dialog-actions">
147
+ <button onClick={close}>Cancel</button>
148
+ <button onClick={() => { deleteItem(); close(); }}>
149
+ Delete
150
+ </button>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ )}
155
+ </>
156
+ );
157
+ }
158
+ ```
159
+
160
+ ### Accordion
161
+
162
+ ```tsx
163
+ import { useToggle } from '@usefy/use-toggle';
164
+
165
+ function AccordionItem({ title, content }: AccordionItemProps) {
166
+ const { value: isExpanded, toggle } = useToggle(false);
167
+
168
+ return (
169
+ <div className="accordion-item">
170
+ <button
171
+ className="accordion-header"
172
+ onClick={toggle}
173
+ aria-expanded={isExpanded}
174
+ >
175
+ {title}
176
+ <span className={`icon ${isExpanded ? 'rotate' : ''}`}>▼</span>
177
+ </button>
178
+ {isExpanded && (
179
+ <div className="accordion-content">{content}</div>
180
+ )}
181
+ </div>
182
+ );
183
+ }
184
+ ```
185
+
186
+ ### Dark Mode Toggle
187
+
188
+ ```tsx
189
+ import { useToggle } from '@usefy/use-toggle';
190
+
191
+ function ThemeToggle() {
192
+ const { value: isDark, toggle, setValue } = useToggle(false);
193
+
194
+ // Sync with system preference
195
+ useEffect(() => {
196
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
197
+ setValue(mediaQuery.matches);
198
+ }, [setValue]);
199
+
200
+ return (
201
+ <button
202
+ onClick={toggle}
203
+ aria-label={`Switch to ${isDark ? 'light' : 'dark'} mode`}
204
+ >
205
+ {isDark ? '🌙' : '☀️'}
206
+ </button>
207
+ );
208
+ }
209
+ ```
210
+
211
+ ### Dropdown Menu
212
+
213
+ ```tsx
214
+ import { useToggle } from '@usefy/use-toggle';
215
+
216
+ function Dropdown({ items }: DropdownProps) {
217
+ const { value: isOpen, toggle, setFalse: close } = useToggle(false);
218
+
219
+ return (
220
+ <div className="dropdown">
221
+ <button onClick={toggle} aria-haspopup="true" aria-expanded={isOpen}>
222
+ Menu
223
+ </button>
224
+ {isOpen && (
225
+ <ul className="dropdown-menu">
226
+ {items.map((item) => (
227
+ <li key={item.id}>
228
+ <button onClick={() => { item.onClick(); close(); }}>
229
+ {item.label}
230
+ </button>
231
+ </li>
232
+ ))}
233
+ </ul>
234
+ )}
235
+ </div>
236
+ );
237
+ }
238
+ ```
239
+
240
+ ### Controlled from Props
241
+
242
+ ```tsx
243
+ import { useToggle } from '@usefy/use-toggle';
244
+
245
+ function ControlledSwitch({ defaultChecked, onChange }: SwitchProps) {
246
+ const { value, toggle } = useToggle(defaultChecked);
247
+
248
+ const handleToggle = () => {
249
+ toggle();
250
+ onChange?.(!value);
251
+ };
252
+
253
+ return (
254
+ <button
255
+ role="switch"
256
+ aria-checked={value}
257
+ onClick={handleToggle}
258
+ className={`switch ${value ? 'on' : 'off'}`}
259
+ >
260
+ <span className="switch-thumb" />
261
+ </button>
262
+ );
263
+ }
264
+ ```
265
+
266
+ ---
267
+
268
+ ## TypeScript
269
+
270
+ This hook is written in TypeScript and exports the `UseToggleReturn` interface.
271
+
272
+ ```tsx
273
+ import { useToggle, type UseToggleReturn } from '@usefy/use-toggle';
274
+
275
+ // Return type is fully typed
276
+ const { value, toggle, setTrue, setFalse, setValue }: UseToggleReturn = useToggle(false);
277
+
278
+ // value: boolean
279
+ // toggle: () => void
280
+ // setTrue: () => void
281
+ // setFalse: () => void
282
+ // setValue: (value: boolean) => void
283
+ ```
284
+
285
+ ---
286
+
287
+ ## Performance
288
+
289
+ All functions returned by the hook are memoized using `useCallback`, ensuring stable references across re-renders. This makes them safe to use as dependencies in other hooks or as props to child components.
290
+
291
+ ```tsx
292
+ const { toggle, setTrue, setFalse, setValue } = useToggle(false);
293
+
294
+ // These references remain stable across renders
295
+ useEffect(() => {
296
+ // Safe to use as dependencies
297
+ }, [toggle, setTrue, setFalse, setValue]);
298
+ ```
299
+
300
+ ---
301
+
302
+ ## Testing
303
+
304
+ This package maintains comprehensive test coverage to ensure reliability and stability.
305
+
306
+ ### Test Coverage
307
+
308
+ | Category | Tests | Coverage |
309
+ |----------|-------|----------|
310
+ | Initialization | 4 | 100% |
311
+ | Toggle | 5 | 100% |
312
+ | setTrue | 5 | 100% |
313
+ | setFalse | 5 | 100% |
314
+ | setValue | 6 | 100% |
315
+ | Complex Scenarios | 8 | 100% |
316
+ | Function References | 5 | 100% |
317
+ | Edge Cases | 6 | 100% |
318
+ | Type Safety | 2 | 100% |
319
+ | **Total** | **46** | **100%** |
320
+
321
+ ### Test Categories
322
+
323
+ <details>
324
+ <summary><strong>Initialization Tests</strong></summary>
325
+
326
+ - Default value initialization (false)
327
+ - Custom initial value (true/false)
328
+ - Return all required functions
329
+
330
+ </details>
331
+
332
+ <details>
333
+ <summary><strong>Toggle Tests</strong></summary>
334
+
335
+ - Toggle from false to true
336
+ - Toggle from true to false
337
+ - Multiple toggles
338
+ - Rapid successive toggles
339
+
340
+ </details>
341
+
342
+ <details>
343
+ <summary><strong>setTrue/setFalse Tests</strong></summary>
344
+
345
+ - Set value from opposite state
346
+ - Maintain value when already set
347
+ - Multiple consecutive calls
348
+ - After toggle operations
349
+
350
+ </details>
351
+
352
+ <details>
353
+ <summary><strong>Function Reference Tests</strong></summary>
354
+
355
+ - Stable toggle reference across renders
356
+ - Stable setTrue reference across renders
357
+ - Stable setFalse reference across renders
358
+ - Stable setValue reference across renders
359
+ - All references stable after multiple operations
360
+
361
+ </details>
362
+
363
+ ### Running Tests
364
+
365
+ ```bash
366
+ # Run all tests
367
+ pnpm test
368
+
369
+ # Run tests in watch mode
370
+ pnpm test:watch
371
+
372
+ # Run tests with coverage report
373
+ pnpm test --coverage
374
+ ```
375
+
376
+ ---
377
+
378
+ ## Related Packages
379
+
380
+ Explore other hooks in the **@usefy** collection:
381
+
382
+ | Package | Description |
383
+ |---------|-------------|
384
+ | [@usefy/use-counter](https://www.npmjs.com/package/@usefy/use-counter) | Counter state management |
385
+ | [@usefy/use-debounce](https://www.npmjs.com/package/@usefy/use-debounce) | Value debouncing |
386
+ | [@usefy/use-debounce-callback](https://www.npmjs.com/package/@usefy/use-debounce-callback) | Debounced callbacks |
387
+ | [@usefy/use-throttle](https://www.npmjs.com/package/@usefy/use-throttle) | Value throttling |
388
+ | [@usefy/use-throttle-callback](https://www.npmjs.com/package/@usefy/use-throttle-callback) | Throttled callbacks |
389
+ | [@usefy/use-click-any-where](https://www.npmjs.com/package/@usefy/use-click-any-where) | Global click detection |
390
+
391
+ ---
392
+
393
+ ## Contributing
394
+
395
+ We welcome contributions! Please see our [Contributing Guide](https://github.com/geon0529/usefy/blob/master/CONTRIBUTING.md) for details.
396
+
397
+ ```bash
398
+ # Clone the repository
399
+ git clone https://github.com/geon0529/usefy.git
400
+
401
+ # Install dependencies
402
+ pnpm install
403
+
404
+ # Run tests
405
+ pnpm test
406
+
407
+ # Build
408
+ pnpm build
409
+ ```
410
+
411
+ ---
412
+
413
+ ## License
414
+
415
+ MIT © [mirunamu](https://github.com/geon0529)
416
+
417
+ This package is part of the [usefy](https://github.com/geon0529/usefy) monorepo.
418
+
419
+ ---
420
+
421
+ <p align="center">
422
+ <sub>Built with care by the usefy team</sub>
423
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usefy/use-toggle",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "description": "A React hook for boolean state management",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",