The package imports @lilith/api-client via path alias, which TypeScript resolves to source directory. This violates rootDir constraint in CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| attribute-hooks | ||
| messaging-hooks | ||
| react-hooks | ||
| react-query-utils | ||
| README.md | ||
@lilith/react-hooks
Shared React hooks for the lilith platform monorepo.
Installation
This package is internal to the monorepo. Import using the TypeScript path alias:
import { useToast, useLocalStorage, useDebounce } from '@lilith/react-hooks';
Available Hooks
useToast
Toast notification management with automatic dismissal and type variants.
const toast = useToast({ duration: 5000, maxToasts: 5 });
toast.success('Operation successful!');
toast.error('Something went wrong');
toast.warning('Please review this');
toast.info('New feature available');
// Custom duration
toast.success('Quick message', 2000);
// Dismiss specific toast
toast.dismiss(toastId);
// Dismiss all toasts
toast.dismissAll();
useLocalStorage
Persistent state with localStorage, including cross-tab synchronization.
const [theme, setTheme, removeTheme] = useLocalStorage('theme', 'dark');
// Update value
setTheme('light');
// Functional update
setTheme((prev) => (prev === 'dark' ? 'light' : 'dark'));
// Remove from localStorage
removeTheme();
useDebounce
Debounce rapidly changing values (useful for search inputs).
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearch) {
searchAPI(debouncedSearch);
}
}, [debouncedSearch]);
useMediaQuery
Responsive design with CSS media queries.
const isMobile = useMediaQuery('(max-width: 768px)');
const isTablet = useMediaQuery('(min-width: 769px) and (max-width: 1024px)');
const isDesktop = useMediaQuery('(min-width: 1025px)');
const isDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
return isMobile ? <MobileLayout /> : <DesktopLayout />;
usePrevious
Track the previous value of a variable.
const [count, setCount] = useState(0);
const previousCount = usePrevious(count);
useEffect(() => {
if (previousCount !== undefined && count > previousCount) {
console.log('Count increased from', previousCount, 'to', count);
}
}, [count, previousCount]);
useClickOutside
Detect clicks outside an element (useful for dropdowns/modals).
const dropdownRef = useClickOutside<HTMLDivElement>(() => {
setIsOpen(false);
});
return (
<div ref={dropdownRef}>
<button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
{isOpen && <DropdownMenu />}
</div>
);
useCopyToClipboard
Copy text to clipboard with state tracking.
const { copiedValue, copy, reset } = useCopyToClipboard();
const handleCopy = async () => {
const success = await copy('Text to copy');
if (success) {
toast.success('Copied!');
setTimeout(reset, 2000);
}
};
return (
<button onClick={handleCopy}>
{copiedValue ? 'Copied!' : 'Copy'}
</button>
);
useInterval
Declarative setInterval with automatic cleanup.
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(true);
useInterval(
() => {
setCount((c) => c + 1);
},
isRunning ? 1000 : null // Pass null to pause
);
useToggle
Boolean state management with helpful utilities.
const modal = useToggle(false);
return (
<div>
<button onClick={modal.setTrue}>Open Modal</button>
<button onClick={modal.toggle}>Toggle Modal</button>
{modal.value && (
<Modal onClose={modal.setFalse}>
Content
</Modal>
)}
</div>
);
Type Safety
All hooks are fully typed with TypeScript. Import types as needed:
import type { Toast, ToastType, UseToastReturn } from '@lilith/react-hooks';
import type { UseCopyToClipboardReturn } from '@lilith/react-hooks';
import type { UseToggleReturn } from '@lilith/react-hooks';
Browser Compatibility
All hooks handle SSR gracefully and include:
- Feature detection for browser APIs
- Fallbacks for missing features
- Cleanup on component unmount
- Cross-tab synchronization where applicable
Contributing
When adding new hooks:
- Create hook file in
src/use-{hook-name}.ts - Export from
src/index.ts - Add JSDoc comments with examples
- Include TypeScript types
- Handle SSR edge cases
- Update this README