import { createContext, useContext, useEffect, useState, useEffectEvent, type ReactNode, createElement, } from 'react'; import { TabSync } from '../../TabSync'; // ─── Context ───────────────────────────────────────────── const TabSyncContext = createContext(null); /** * Provider for TabSync — creates instance, auto-disposes on unmount. * * @example * function App() { * return ( * * * * ); * } */ export interface TabSyncProviderProps { /** BroadcastChannel name (default: "tab-sync"). */ channel?: string; /** Enable debug logging. */ debug?: boolean; children: ReactNode; } export function TabSyncProvider({ channel, debug, children }: TabSyncProviderProps) { const [sync] = useState(() => new TabSync(channel, { debug })); useEffect(() => { return () => sync[Symbol.dispose](); }, [sync]); return createElement(TabSyncContext.Provider, { value: sync }, children); } /** * Access the TabSync instance from context. * * @example * const sync = useTabSyncContext(); * sync.set('theme', 'dark'); */ export function useTabSyncContext(): TabSync { const ctx = useContext(TabSyncContext); if (!ctx) { throw new Error('useTabSync must be used within '); } return ctx; } // ─── Hooks ─────────────────────────────────────────────── /** * Two-way state sync across browser tabs — like useState but shared. * - Without callback: returns [value, setter] synced across tabs. * - With callback: also calls your handler on every change (side effects). * * @example * // Shared state — updates propagate to all tabs * const [theme, setTheme] = useTabSync('theme', 'light'); * * * @example * // With side effect callback * const [cart, setCart] = useTabSync('cart', { items: [] }, (cart) => { * document.title = `Cart (${cart.items.length})`; * }); * * @example * // Form state synced across tabs * const [draft, setDraft] = useTabSync('email-draft', ''); *