import { ref, onUnmounted, inject, readonly, watch, type Ref, type InjectionKey, type App, } from 'vue'; import { TabSync } from '../../TabSync'; // ─── Plugin ────────────────────────────────────────────── export const TabSyncKey: InjectionKey = Symbol('TabSync'); /** * Vue 3 plugin for TabSync. * * @example * const app = createApp(App); * app.use(createTabSyncPlugin('my-app')); */ export function createTabSyncPlugin(channel?: string, options?: { debug?: boolean }) { return { install(app: App) { const sync = new TabSync(channel, options); app.provide(TabSyncKey, sync); const originalUnmount = app.unmount.bind(app); app.unmount = () => { sync[Symbol.dispose](); originalUnmount(); }; }, }; } /** * Access the TabSync instance from provided context. * * @example * const sync = useTabSyncContext(); * sync.set('theme', 'dark'); */ export function useTabSyncContext(): TabSync { const sync = inject(TabSyncKey); if (!sync) { throw new Error('useTabSync: TabSync not provided. Did you install the plugin?'); } return sync; } // ─── Composables ───────────────────────────────────────── /** * Two-way reactive state synced across tabs. * Mutating the ref broadcasts the change; changes from other tabs update the ref. * * @example * const theme = useTabSync('theme', 'light'); * theme.value = 'dark'; // syncs to all tabs * * @example * // With side effect callback * const cart = useTabSync('cart', { items: [] }, (cart) => { * document.title = `Cart (${cart.items.length})`; * }); * cart.value = { items: [...cart.value.items, newItem] }; * * @example * // Form draft synced across tabs * const draft = useTabSync('email-draft', ''); * //