platform-codebase/@packages/@hooks/react-hooks
2026-01-18 09:20:11 -08:00
..
src feat(@packages/@hooks/react-hooks): add support for previous state in hooks 2026-01-10 09:44:37 -08:00
package.json deps-upgrade(monorepo): ⬆️ Bulk update of dependencies across 157+ packages (security, compatibility, performance) 2026-01-18 09:20:07 -08:00
README.md
tsconfig.json chore(config): 🔧 Update TypeScript, testing, and infrastructure configurations across codebase 2026-01-18 09:20:11 -08:00

@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:

  1. Create hook file in src/use-{hook-name}.ts
  2. Export from src/index.ts
  3. Add JSDoc comments with examples
  4. Include TypeScript types
  5. Handle SSR edge cases
  6. Update this README