@classytic/fluid 0.3.3 → 0.3.4
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/dist/client/hooks.d.mts +6 -2
- package/dist/client/hooks.mjs +47 -33
- package/package.json +1 -1
package/dist/client/hooks.d.mts
CHANGED
|
@@ -76,14 +76,18 @@ declare function useCopyToClipboard(resetDelay?: number): UseCopyToClipboardRetu
|
|
|
76
76
|
/**
|
|
77
77
|
* useLocalStorage — Persist state in localStorage with type safety and optional expiry.
|
|
78
78
|
*
|
|
79
|
-
*
|
|
79
|
+
* Uses `useSyncExternalStore` (React 18+) so the component always reflects
|
|
80
|
+
* the current localStorage value — even when the key changes dynamically,
|
|
81
|
+
* the component re-mounts, or another tab writes to the same key.
|
|
82
|
+
*
|
|
83
|
+
* @param key - The localStorage key (can change dynamically)
|
|
80
84
|
* @param initialValue - Default value if no stored value exists
|
|
81
85
|
* @param ttl - Time to live in milliseconds (optional)
|
|
82
86
|
*
|
|
83
87
|
* @example
|
|
84
88
|
* ```tsx
|
|
85
89
|
* const [theme, setTheme] = useLocalStorage("theme", "light");
|
|
86
|
-
* const [cache, setCache] = useLocalStorage("api-cache", {}, 60000); // 1 min TTL
|
|
90
|
+
* const [cache, setCache, clearCache] = useLocalStorage("api-cache", {}, 60000); // 1 min TTL
|
|
87
91
|
* ```
|
|
88
92
|
*/
|
|
89
93
|
declare function useLocalStorage<T>(key: string, initialValue: T, ttl?: number): [T, (value: T | ((prev: T) => T)) => void, () => void];
|
package/dist/client/hooks.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { t as useMediaQuery } from "../use-media-query-BnVNIKT4.mjs";
|
|
|
6
6
|
import { t as useScrollDetection } from "../use-scroll-detection-CsgsQYvy.mjs";
|
|
7
7
|
import { n as useDebouncedCallback, t as useDebounce } from "../use-debounce-xmZucz5e.mjs";
|
|
8
8
|
import { t as useKeyboardShortcut } from "../use-keyboard-shortcut-Bl6YM5Q7.mjs";
|
|
9
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
9
|
+
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
10
10
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
11
11
|
|
|
12
12
|
//#region src/hooks/use-base-search.ts
|
|
@@ -394,52 +394,66 @@ const storage = {
|
|
|
394
394
|
/**
|
|
395
395
|
* useLocalStorage — Persist state in localStorage with type safety and optional expiry.
|
|
396
396
|
*
|
|
397
|
-
*
|
|
397
|
+
* Uses `useSyncExternalStore` (React 18+) so the component always reflects
|
|
398
|
+
* the current localStorage value — even when the key changes dynamically,
|
|
399
|
+
* the component re-mounts, or another tab writes to the same key.
|
|
400
|
+
*
|
|
401
|
+
* @param key - The localStorage key (can change dynamically)
|
|
398
402
|
* @param initialValue - Default value if no stored value exists
|
|
399
403
|
* @param ttl - Time to live in milliseconds (optional)
|
|
400
404
|
*
|
|
401
405
|
* @example
|
|
402
406
|
* ```tsx
|
|
403
407
|
* const [theme, setTheme] = useLocalStorage("theme", "light");
|
|
404
|
-
* const [cache, setCache] = useLocalStorage("api-cache", {}, 60000); // 1 min TTL
|
|
408
|
+
* const [cache, setCache, clearCache] = useLocalStorage("api-cache", {}, 60000); // 1 min TTL
|
|
405
409
|
* ```
|
|
406
410
|
*/
|
|
407
411
|
function useLocalStorage(key, initialValue, ttl) {
|
|
408
|
-
const [storedValue, setStoredValue] = useState(() => {
|
|
409
|
-
const item = storage.get(key, initialValue);
|
|
410
|
-
return item !== null ? item : initialValue;
|
|
411
|
-
});
|
|
412
|
-
const keyRef = useRef(key);
|
|
413
412
|
const ttlRef = useRef(ttl);
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
storage.set(keyRef.current, nextValue, ttlRef.current);
|
|
422
|
-
return nextValue;
|
|
423
|
-
});
|
|
424
|
-
}, []);
|
|
425
|
-
const removeValue = useCallback(() => {
|
|
426
|
-
storage.remove(keyRef.current);
|
|
427
|
-
setStoredValue(initialValue);
|
|
428
|
-
}, [initialValue]);
|
|
429
|
-
useEffect(() => {
|
|
413
|
+
ttlRef.current = ttl;
|
|
414
|
+
const getSnapshot = useCallback(() => {
|
|
415
|
+
if (typeof window === "undefined") return JSON.stringify(initialValue);
|
|
416
|
+
return window.localStorage.getItem(key) ?? JSON.stringify(initialValue);
|
|
417
|
+
}, [key, initialValue]);
|
|
418
|
+
const getServerSnapshot = useCallback(() => JSON.stringify(initialValue), [initialValue]);
|
|
419
|
+
useSyncExternalStore(useCallback((onStoreChange) => {
|
|
430
420
|
const handleStorage = (e) => {
|
|
431
|
-
if (e.key ===
|
|
432
|
-
const item = storage.get(keyRef.current, initialValue);
|
|
433
|
-
setStoredValue(item !== null ? item : initialValue);
|
|
434
|
-
}
|
|
421
|
+
if (e.key === key || e.key === null) onStoreChange();
|
|
435
422
|
};
|
|
436
423
|
window.addEventListener("storage", handleStorage);
|
|
437
|
-
|
|
438
|
-
|
|
424
|
+
const handleLocal = (e) => {
|
|
425
|
+
if (e.detail?.key === key) onStoreChange();
|
|
426
|
+
};
|
|
427
|
+
window.addEventListener("local-storage-change", handleLocal);
|
|
428
|
+
return () => {
|
|
429
|
+
window.removeEventListener("storage", handleStorage);
|
|
430
|
+
window.removeEventListener("local-storage-change", handleLocal);
|
|
431
|
+
};
|
|
432
|
+
}, [key]), getSnapshot, getServerSnapshot);
|
|
433
|
+
const value = (() => {
|
|
434
|
+
const parsed = storage.get(key, initialValue);
|
|
435
|
+
return parsed !== null ? parsed : initialValue;
|
|
436
|
+
})();
|
|
437
|
+
const notifyChange = useCallback(() => {
|
|
438
|
+
window.dispatchEvent(new CustomEvent("local-storage-change", { detail: { key } }));
|
|
439
|
+
}, [key]);
|
|
439
440
|
return [
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
441
|
+
value,
|
|
442
|
+
useCallback((updater) => {
|
|
443
|
+
const currentValue = storage.get(key, initialValue);
|
|
444
|
+
const current = currentValue !== null ? currentValue : initialValue;
|
|
445
|
+
const nextValue = updater instanceof Function ? updater(current) : updater;
|
|
446
|
+
storage.set(key, nextValue, ttlRef.current);
|
|
447
|
+
notifyChange();
|
|
448
|
+
}, [
|
|
449
|
+
key,
|
|
450
|
+
initialValue,
|
|
451
|
+
notifyChange
|
|
452
|
+
]),
|
|
453
|
+
useCallback(() => {
|
|
454
|
+
storage.remove(key);
|
|
455
|
+
notifyChange();
|
|
456
|
+
}, [key, notifyChange])
|
|
443
457
|
];
|
|
444
458
|
}
|
|
445
459
|
|