UNPKG

react-single-tab-enforcer

Version:

A simple React hook for enforcing single-tab behavior with TypeScript support

74 lines (70 loc) 2.7 kB
'use strict'; var react = require('react'); // Generate unique tab ID const generateTabId = () => `tab-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; function useSingleTabEnforcer(config = {}) { const { timeout = 5000, appName = 'my-app' } = config; const storageKey = `single-tab-${appName}`; const [isLeader, setIsLeader] = react.useState(false); const tabId = react.useRef(generateTabId()); react.useEffect(() => { const currentTabId = tabId.current; const checkLeadership = () => { try { const stored = localStorage.getItem(storageKey); const data = stored ? JSON.parse(stored) : null; const now = Date.now(); // No leader or expired, OR this tab is already leader - take/keep leadership if (!data || (now - data.timestamp) > timeout || data.id === currentTabId) { localStorage.setItem(storageKey, JSON.stringify({ id: currentTabId, timestamp: now })); setIsLeader(true); } // Another tab is leader else { setIsLeader(false); } } catch (error) { console.error('SingleTab error:', error); setIsLeader(true); // Fail safe } }; // Initial check checkLeadership(); // Check every 2 seconds const interval = setInterval(checkLeadership, 2000); // Listen for storage changes from other tabs const handleStorage = (e) => { if (e.key === storageKey) { setTimeout(checkLeadership, 100); } }; window.addEventListener('storage', handleStorage); return () => { clearInterval(interval); window.removeEventListener('storage', handleStorage); // Clean up storage when component unmounts if this tab was leader const stored = localStorage.getItem(storageKey); const data = stored ? JSON.parse(stored) : null; if (data && data.id === currentTabId) { localStorage.removeItem(storageKey); } }; }, [storageKey, timeout]); const forceLeadership = () => { localStorage.setItem(storageKey, JSON.stringify({ id: tabId.current, timestamp: Date.now() })); setIsLeader(true); }; return { isLeader, forceLeadership }; } exports.useSingleTabEnforcer = useSingleTabEnforcer; //# sourceMappingURL=index.js.map