@allem-sdk/hooks 0.1.2 → 0.1.3
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 +36 -0
- package/dist/index.d.mts +63 -1
- package/dist/index.d.ts +63 -1
- package/dist/index.js +116 -0
- package/dist/index.mjs +111 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,7 @@ npm install @allem-sdk/hooks
|
|
|
25
25
|
| Hook | Description |
|
|
26
26
|
|------|-------------|
|
|
27
27
|
| `useDebounce` | Debounce a value by a given delay |
|
|
28
|
+
| `useThrottle` | Throttle a value, updating at most once per delay |
|
|
28
29
|
| `useLocalStorage` | Persist state in localStorage with SSR safety |
|
|
29
30
|
| `useMediaQuery` | Reactive CSS media query matching |
|
|
30
31
|
| `useClickOutside` | Detect clicks outside a ref element |
|
|
@@ -32,6 +33,10 @@ npm install @allem-sdk/hooks
|
|
|
32
33
|
| `useCopyToClipboard` | Copy text to clipboard with status |
|
|
33
34
|
| `useIntersectionObserver` | Observe element visibility via IntersectionObserver |
|
|
34
35
|
| `useWindowSize` | Reactive window dimensions |
|
|
36
|
+
| `useFetch` | Data fetching with loading/error states and refetch |
|
|
37
|
+
| `usePrevious` | Track the previous value of a variable |
|
|
38
|
+
| `useKeyPress` | Detect if a specific key is pressed |
|
|
39
|
+
| `useOnlineStatus` | Reactive browser online/offline status |
|
|
35
40
|
|
|
36
41
|
## Usage
|
|
37
42
|
|
|
@@ -63,6 +68,37 @@ function Dropdown() {
|
|
|
63
68
|
}
|
|
64
69
|
```
|
|
65
70
|
|
|
71
|
+
## More Examples
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { useFetch, useThrottle, useKeyPress, useOnlineStatus, usePrevious } from "@allem-sdk/hooks";
|
|
75
|
+
|
|
76
|
+
function UserList() {
|
|
77
|
+
const { data, error, isLoading, refetch } = useFetch<User[]>("/api/users");
|
|
78
|
+
const isOnline = useOnlineStatus();
|
|
79
|
+
const isEscPressed = useKeyPress("Escape");
|
|
80
|
+
|
|
81
|
+
if (!isOnline) return <p>You are offline</p>;
|
|
82
|
+
if (isLoading) return <p>Loading...</p>;
|
|
83
|
+
return <ul>{data?.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function ScrollTracker() {
|
|
87
|
+
const [scroll, setScroll] = useState(0);
|
|
88
|
+
const throttledScroll = useThrottle(scroll, 100);
|
|
89
|
+
const prevScroll = usePrevious(throttledScroll);
|
|
90
|
+
const direction = prevScroll !== undefined && throttledScroll > prevScroll ? "down" : "up";
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
const handler = () => setScroll(window.scrollY);
|
|
94
|
+
window.addEventListener("scroll", handler);
|
|
95
|
+
return () => window.removeEventListener("scroll", handler);
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
return <p>Scrolling {direction}</p>;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
66
102
|
## Part of [Allem SDK](https://github.com/kingofmit/allem-sdk)
|
|
67
103
|
|
|
68
104
|
This package can be used standalone or as part of the full SDK. Install `allem-sdk` to get all packages in one install.
|
package/dist/index.d.mts
CHANGED
|
@@ -28,4 +28,66 @@ interface WindowSize {
|
|
|
28
28
|
}
|
|
29
29
|
declare function useWindowSize(): WindowSize;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
interface UseFetchState<T> {
|
|
32
|
+
data: T | null;
|
|
33
|
+
error: Error | null;
|
|
34
|
+
isLoading: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface UseFetchReturn<T> extends UseFetchState<T> {
|
|
37
|
+
refetch: () => void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Simple data fetching hook with loading/error states and refetch.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const { data, error, isLoading, refetch } = useFetch<User[]>("/api/users");
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function useFetch<T = unknown>(url: string | null, options?: RequestInit): UseFetchReturn<T>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Throttles a value, updating at most once per `delay` ms.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* const throttledScroll = useThrottle(scrollPosition, 100);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
declare function useThrottle<T>(value: T, delay: number): T;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns the previous value of a variable.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const prevCount = usePrevious(count);
|
|
65
|
+
* // On first render: undefined
|
|
66
|
+
* // After count changes: previous count value
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function usePrevious<T>(value: T): T | undefined;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Detects whether a specific key is currently pressed.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* const isEscPressed = useKeyPress("Escape");
|
|
77
|
+
* const isEnterPressed = useKeyPress("Enter");
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function useKeyPress(targetKey: string): boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Tracks the browser's online/offline status reactively.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* const isOnline = useOnlineStatus();
|
|
88
|
+
* // true when connected, false when offline
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function useOnlineStatus(): boolean;
|
|
92
|
+
|
|
93
|
+
export { useClickOutside, useCopyToClipboard, useDebounce, useFetch, useIntersectionObserver, useKeyPress, useLocalStorage, useMediaQuery, useOnlineStatus, usePrevious, useThrottle, useToggle, useWindowSize };
|
package/dist/index.d.ts
CHANGED
|
@@ -28,4 +28,66 @@ interface WindowSize {
|
|
|
28
28
|
}
|
|
29
29
|
declare function useWindowSize(): WindowSize;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
interface UseFetchState<T> {
|
|
32
|
+
data: T | null;
|
|
33
|
+
error: Error | null;
|
|
34
|
+
isLoading: boolean;
|
|
35
|
+
}
|
|
36
|
+
interface UseFetchReturn<T> extends UseFetchState<T> {
|
|
37
|
+
refetch: () => void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Simple data fetching hook with loading/error states and refetch.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* const { data, error, isLoading, refetch } = useFetch<User[]>("/api/users");
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function useFetch<T = unknown>(url: string | null, options?: RequestInit): UseFetchReturn<T>;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Throttles a value, updating at most once per `delay` ms.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* const throttledScroll = useThrottle(scrollPosition, 100);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
declare function useThrottle<T>(value: T, delay: number): T;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns the previous value of a variable.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const prevCount = usePrevious(count);
|
|
65
|
+
* // On first render: undefined
|
|
66
|
+
* // After count changes: previous count value
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
declare function usePrevious<T>(value: T): T | undefined;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Detects whether a specific key is currently pressed.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* const isEscPressed = useKeyPress("Escape");
|
|
77
|
+
* const isEnterPressed = useKeyPress("Enter");
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare function useKeyPress(targetKey: string): boolean;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Tracks the browser's online/offline status reactively.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* const isOnline = useOnlineStatus();
|
|
88
|
+
* // true when connected, false when offline
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
declare function useOnlineStatus(): boolean;
|
|
92
|
+
|
|
93
|
+
export { useClickOutside, useCopyToClipboard, useDebounce, useFetch, useIntersectionObserver, useKeyPress, useLocalStorage, useMediaQuery, useOnlineStatus, usePrevious, useThrottle, useToggle, useWindowSize };
|
package/dist/index.js
CHANGED
|
@@ -24,9 +24,14 @@ __export(index_exports, {
|
|
|
24
24
|
useClickOutside: () => useClickOutside,
|
|
25
25
|
useCopyToClipboard: () => useCopyToClipboard,
|
|
26
26
|
useDebounce: () => useDebounce,
|
|
27
|
+
useFetch: () => useFetch,
|
|
27
28
|
useIntersectionObserver: () => useIntersectionObserver,
|
|
29
|
+
useKeyPress: () => useKeyPress,
|
|
28
30
|
useLocalStorage: () => useLocalStorage,
|
|
29
31
|
useMediaQuery: () => useMediaQuery,
|
|
32
|
+
useOnlineStatus: () => useOnlineStatus,
|
|
33
|
+
usePrevious: () => usePrevious,
|
|
34
|
+
useThrottle: () => useThrottle,
|
|
30
35
|
useToggle: () => useToggle,
|
|
31
36
|
useWindowSize: () => useWindowSize
|
|
32
37
|
});
|
|
@@ -162,14 +167,125 @@ function useWindowSize() {
|
|
|
162
167
|
}, []);
|
|
163
168
|
return size;
|
|
164
169
|
}
|
|
170
|
+
|
|
171
|
+
// src/hooks/useFetch.ts
|
|
172
|
+
var import_react9 = require("react");
|
|
173
|
+
function useFetch(url, options) {
|
|
174
|
+
const [state, setState] = (0, import_react9.useState)({
|
|
175
|
+
data: null,
|
|
176
|
+
error: null,
|
|
177
|
+
isLoading: !!url
|
|
178
|
+
});
|
|
179
|
+
const optionsRef = (0, import_react9.useRef)(options);
|
|
180
|
+
optionsRef.current = options;
|
|
181
|
+
const fetchData = (0, import_react9.useCallback)(async () => {
|
|
182
|
+
if (!url) return;
|
|
183
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
184
|
+
try {
|
|
185
|
+
const res = await fetch(url, optionsRef.current);
|
|
186
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
187
|
+
const data = await res.json();
|
|
188
|
+
setState({ data, error: null, isLoading: false });
|
|
189
|
+
} catch (err) {
|
|
190
|
+
setState({ data: null, error: err, isLoading: false });
|
|
191
|
+
}
|
|
192
|
+
}, [url]);
|
|
193
|
+
(0, import_react9.useEffect)(() => {
|
|
194
|
+
fetchData();
|
|
195
|
+
}, [fetchData]);
|
|
196
|
+
return { ...state, refetch: fetchData };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/hooks/useThrottle.ts
|
|
200
|
+
var import_react10 = require("react");
|
|
201
|
+
function useThrottle(value, delay) {
|
|
202
|
+
const [throttled, setThrottled] = (0, import_react10.useState)(value);
|
|
203
|
+
const lastUpdated = (0, import_react10.useRef)(Date.now());
|
|
204
|
+
const timeoutRef = (0, import_react10.useRef)(void 0);
|
|
205
|
+
(0, import_react10.useEffect)(() => {
|
|
206
|
+
const now = Date.now();
|
|
207
|
+
const elapsed = now - lastUpdated.current;
|
|
208
|
+
if (elapsed >= delay) {
|
|
209
|
+
setThrottled(value);
|
|
210
|
+
lastUpdated.current = now;
|
|
211
|
+
} else {
|
|
212
|
+
clearTimeout(timeoutRef.current);
|
|
213
|
+
timeoutRef.current = setTimeout(() => {
|
|
214
|
+
setThrottled(value);
|
|
215
|
+
lastUpdated.current = Date.now();
|
|
216
|
+
}, delay - elapsed);
|
|
217
|
+
}
|
|
218
|
+
return () => clearTimeout(timeoutRef.current);
|
|
219
|
+
}, [value, delay]);
|
|
220
|
+
return throttled;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/hooks/usePrevious.ts
|
|
224
|
+
var import_react11 = require("react");
|
|
225
|
+
function usePrevious(value) {
|
|
226
|
+
const ref = (0, import_react11.useRef)(void 0);
|
|
227
|
+
(0, import_react11.useEffect)(() => {
|
|
228
|
+
ref.current = value;
|
|
229
|
+
}, [value]);
|
|
230
|
+
return ref.current;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/hooks/useKeyPress.ts
|
|
234
|
+
var import_react12 = require("react");
|
|
235
|
+
function useKeyPress(targetKey) {
|
|
236
|
+
const [isPressed, setIsPressed] = (0, import_react12.useState)(false);
|
|
237
|
+
(0, import_react12.useEffect)(() => {
|
|
238
|
+
if (typeof window === "undefined") return;
|
|
239
|
+
const handleDown = (e) => {
|
|
240
|
+
if (e.key === targetKey) setIsPressed(true);
|
|
241
|
+
};
|
|
242
|
+
const handleUp = (e) => {
|
|
243
|
+
if (e.key === targetKey) setIsPressed(false);
|
|
244
|
+
};
|
|
245
|
+
window.addEventListener("keydown", handleDown);
|
|
246
|
+
window.addEventListener("keyup", handleUp);
|
|
247
|
+
return () => {
|
|
248
|
+
window.removeEventListener("keydown", handleDown);
|
|
249
|
+
window.removeEventListener("keyup", handleUp);
|
|
250
|
+
};
|
|
251
|
+
}, [targetKey]);
|
|
252
|
+
return isPressed;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/hooks/useOnlineStatus.ts
|
|
256
|
+
var import_react13 = require("react");
|
|
257
|
+
function subscribe(callback) {
|
|
258
|
+
if (typeof window === "undefined") return () => {
|
|
259
|
+
};
|
|
260
|
+
window.addEventListener("online", callback);
|
|
261
|
+
window.addEventListener("offline", callback);
|
|
262
|
+
return () => {
|
|
263
|
+
window.removeEventListener("online", callback);
|
|
264
|
+
window.removeEventListener("offline", callback);
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function getSnapshot() {
|
|
268
|
+
return typeof navigator !== "undefined" ? navigator.onLine : true;
|
|
269
|
+
}
|
|
270
|
+
function getServerSnapshot() {
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
function useOnlineStatus() {
|
|
274
|
+
return (0, import_react13.useSyncExternalStore)(subscribe, getSnapshot, getServerSnapshot);
|
|
275
|
+
}
|
|
165
276
|
// Annotate the CommonJS export names for ESM import in node:
|
|
166
277
|
0 && (module.exports = {
|
|
167
278
|
useClickOutside,
|
|
168
279
|
useCopyToClipboard,
|
|
169
280
|
useDebounce,
|
|
281
|
+
useFetch,
|
|
170
282
|
useIntersectionObserver,
|
|
283
|
+
useKeyPress,
|
|
171
284
|
useLocalStorage,
|
|
172
285
|
useMediaQuery,
|
|
286
|
+
useOnlineStatus,
|
|
287
|
+
usePrevious,
|
|
288
|
+
useThrottle,
|
|
173
289
|
useToggle,
|
|
174
290
|
useWindowSize
|
|
175
291
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -130,13 +130,124 @@ function useWindowSize() {
|
|
|
130
130
|
}, []);
|
|
131
131
|
return size;
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
// src/hooks/useFetch.ts
|
|
135
|
+
import { useState as useState8, useEffect as useEffect6, useCallback as useCallback4, useRef } from "react";
|
|
136
|
+
function useFetch(url, options) {
|
|
137
|
+
const [state, setState] = useState8({
|
|
138
|
+
data: null,
|
|
139
|
+
error: null,
|
|
140
|
+
isLoading: !!url
|
|
141
|
+
});
|
|
142
|
+
const optionsRef = useRef(options);
|
|
143
|
+
optionsRef.current = options;
|
|
144
|
+
const fetchData = useCallback4(async () => {
|
|
145
|
+
if (!url) return;
|
|
146
|
+
setState((prev) => ({ ...prev, isLoading: true, error: null }));
|
|
147
|
+
try {
|
|
148
|
+
const res = await fetch(url, optionsRef.current);
|
|
149
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
150
|
+
const data = await res.json();
|
|
151
|
+
setState({ data, error: null, isLoading: false });
|
|
152
|
+
} catch (err) {
|
|
153
|
+
setState({ data: null, error: err, isLoading: false });
|
|
154
|
+
}
|
|
155
|
+
}, [url]);
|
|
156
|
+
useEffect6(() => {
|
|
157
|
+
fetchData();
|
|
158
|
+
}, [fetchData]);
|
|
159
|
+
return { ...state, refetch: fetchData };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// src/hooks/useThrottle.ts
|
|
163
|
+
import { useState as useState9, useEffect as useEffect7, useRef as useRef2 } from "react";
|
|
164
|
+
function useThrottle(value, delay) {
|
|
165
|
+
const [throttled, setThrottled] = useState9(value);
|
|
166
|
+
const lastUpdated = useRef2(Date.now());
|
|
167
|
+
const timeoutRef = useRef2(void 0);
|
|
168
|
+
useEffect7(() => {
|
|
169
|
+
const now = Date.now();
|
|
170
|
+
const elapsed = now - lastUpdated.current;
|
|
171
|
+
if (elapsed >= delay) {
|
|
172
|
+
setThrottled(value);
|
|
173
|
+
lastUpdated.current = now;
|
|
174
|
+
} else {
|
|
175
|
+
clearTimeout(timeoutRef.current);
|
|
176
|
+
timeoutRef.current = setTimeout(() => {
|
|
177
|
+
setThrottled(value);
|
|
178
|
+
lastUpdated.current = Date.now();
|
|
179
|
+
}, delay - elapsed);
|
|
180
|
+
}
|
|
181
|
+
return () => clearTimeout(timeoutRef.current);
|
|
182
|
+
}, [value, delay]);
|
|
183
|
+
return throttled;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/hooks/usePrevious.ts
|
|
187
|
+
import { useRef as useRef3, useEffect as useEffect8 } from "react";
|
|
188
|
+
function usePrevious(value) {
|
|
189
|
+
const ref = useRef3(void 0);
|
|
190
|
+
useEffect8(() => {
|
|
191
|
+
ref.current = value;
|
|
192
|
+
}, [value]);
|
|
193
|
+
return ref.current;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/hooks/useKeyPress.ts
|
|
197
|
+
import { useState as useState10, useEffect as useEffect9 } from "react";
|
|
198
|
+
function useKeyPress(targetKey) {
|
|
199
|
+
const [isPressed, setIsPressed] = useState10(false);
|
|
200
|
+
useEffect9(() => {
|
|
201
|
+
if (typeof window === "undefined") return;
|
|
202
|
+
const handleDown = (e) => {
|
|
203
|
+
if (e.key === targetKey) setIsPressed(true);
|
|
204
|
+
};
|
|
205
|
+
const handleUp = (e) => {
|
|
206
|
+
if (e.key === targetKey) setIsPressed(false);
|
|
207
|
+
};
|
|
208
|
+
window.addEventListener("keydown", handleDown);
|
|
209
|
+
window.addEventListener("keyup", handleUp);
|
|
210
|
+
return () => {
|
|
211
|
+
window.removeEventListener("keydown", handleDown);
|
|
212
|
+
window.removeEventListener("keyup", handleUp);
|
|
213
|
+
};
|
|
214
|
+
}, [targetKey]);
|
|
215
|
+
return isPressed;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/hooks/useOnlineStatus.ts
|
|
219
|
+
import { useSyncExternalStore } from "react";
|
|
220
|
+
function subscribe(callback) {
|
|
221
|
+
if (typeof window === "undefined") return () => {
|
|
222
|
+
};
|
|
223
|
+
window.addEventListener("online", callback);
|
|
224
|
+
window.addEventListener("offline", callback);
|
|
225
|
+
return () => {
|
|
226
|
+
window.removeEventListener("online", callback);
|
|
227
|
+
window.removeEventListener("offline", callback);
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function getSnapshot() {
|
|
231
|
+
return typeof navigator !== "undefined" ? navigator.onLine : true;
|
|
232
|
+
}
|
|
233
|
+
function getServerSnapshot() {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
function useOnlineStatus() {
|
|
237
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
238
|
+
}
|
|
133
239
|
export {
|
|
134
240
|
useClickOutside,
|
|
135
241
|
useCopyToClipboard,
|
|
136
242
|
useDebounce,
|
|
243
|
+
useFetch,
|
|
137
244
|
useIntersectionObserver,
|
|
245
|
+
useKeyPress,
|
|
138
246
|
useLocalStorage,
|
|
139
247
|
useMediaQuery,
|
|
248
|
+
useOnlineStatus,
|
|
249
|
+
usePrevious,
|
|
250
|
+
useThrottle,
|
|
140
251
|
useToggle,
|
|
141
252
|
useWindowSize
|
|
142
253
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@allem-sdk/hooks",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "8 essential React hooks: useDebounce, useLocalStorage, useMediaQuery, useClickOutside, useToggle, useCopyToClipboard, useIntersectionObserver, useWindowSize. SSR-safe, TypeScript strict.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ahmed Allem",
|