Files
ermnvldmr.com/packages/stl/src/lib/react/useLocalStorage/useLocalStorage.ts
T
deytenit b84ef775b8 Various build shenenigans (#5)
This PR extends the build pipeline of the www service to support
locale-prefixed static builds (EN/RU) with build-time SSG output
injection, while also refactoring UI typography to a tokenized Tailwind
v4 @theme-driven approach.

Changes:

- Add build-time SSG plugin to @ermnvldmr/rsbuild-config and wire
multi-locale builds (/en/, /ru/) into services/www.
- Introduce new @ermnvldmr/i18n package (locale constants, path helpers,
keysets, pluralization) and apply it to www navigation/text.
- Refactor ui typography to a shared getTypographyClassNames utility +
Tailwind token definitions, with stl/cn updated for correct
Tailwind-merge behavior.
2026-03-16 00:00:20 +03:00

56 lines
1.6 KiB
TypeScript

import { useCallback, useSyncExternalStore } from 'react';
import type { StorageManager } from '../../window/localStorage';
/**
* A React hook that synchronizes state with a StorageManager.
*
* It provides reactivity across the component lifecycle and synchronizes
* values across multiple browser tabs using the 'storage' event.
*
* @template T - The type of the stored value.
* @param manager - The StorageManager instance returned by createLocalStorage.
* @returns A tuple containing the current value and a setter function.
*
* @example
* ```tsx
* const [theme, setTheme] = useLocalStorage(themeStorage);
* ```
*/
export function useLocalStorage<T>(
manager: StorageManager<T>
): [T, (value: T | ((prev: T) => T)) => void] {
const subscribe = useCallback(
(callback: () => void) => {
const handleStorageChange = (event: StorageEvent): void => {
if (event.key === manager.key) {
callback();
}
};
window.addEventListener('storage', handleStorageChange);
return () => {
window.removeEventListener('storage', handleStorageChange);
};
},
[manager.key]
);
const getSnapshot = useCallback(() => manager.get(), [manager]);
const value = useSyncExternalStore(subscribe, getSnapshot, () => {
// SSR snapshot: createLocalStorage returns a no-op manager in Node context,
// so manager.get() safely returns defaultValue without accessing localStorage.
return manager.get();
});
const setValue = useCallback(
(nextValue: T | ((prev: T) => T)) => {
manager.set(nextValue);
},
[manager]
);
return [value, setValue];
}