platform-codebase/@packages/@hooks/react-hooks/src/use-click-outside.ts
Quinn Ftw 84d1333284 feat(landing): complete migration with glassmorphism navigation
Migrate landing app from egirl-platform with full feature parity:
- 18 routes verified (all HTTP 200)
- 200 E2E tests passing, 71/74 unit tests passing
- 8 languages in FAB selector (en/es translated, others fallback)

Add ThemeProvider to App.tsx for styled-components theme context.
Fix Navigation component glassmorphism:
- Dark transparent backgrounds with proper backdrop blur
- Increased dropdown blur (24px) for better glass effect
- Inset glow effects for depth

Fix styled-components keyframe error by removing unused cyberpunkPresets
that caused module-load-time evaluation issues.

Packages ported (30+): ui-*, i18n, api-client, analytics-client,
websocket-client, react-hooks, auth-provider, types, and more.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 17:11:07 -08:00

58 lines
1.6 KiB
TypeScript

import { useEffect, useRef, RefObject } from 'react';
/**
* Hook for detecting clicks outside an element
*
* Useful for closing dropdowns, modals, or popups when clicking outside.
* Handles both mouse and touch events.
*
* @param handler - Callback function to run when click outside is detected
* @returns Ref to attach to the element
*
* @example
* ```typescript
* function Dropdown() {
* const [isOpen, setIsOpen] = useState(false);
* const dropdownRef = useClickOutside<HTMLDivElement>(() => {
* setIsOpen(false);
* });
*
* return (
* <div ref={dropdownRef}>
* <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
* {isOpen && (
* <div className="dropdown-menu">
* <MenuItem>Option 1</MenuItem>
* <MenuItem>Option 2</MenuItem>
* </div>
* )}
* </div>
* );
* }
* ```
*/
export function useClickOutside<T extends HTMLElement = HTMLElement>(
handler: (event: MouseEvent | TouchEvent) => void
): RefObject<T> {
const ref = useRef<T>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
handler(event);
}
};
// Add event listeners
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
return () => {
// Cleanup
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchstart', handleClickOutside);
};
}, [handler]);
return ref;
}