11import { nanoid } from "nanoid" ;
2+ import { z } from "zod" ;
23
3- type TabSyncConfig = { tabIds : string [ ] } ;
4+ const tabIdSchema = z . string ( ) . nanoid ( ) ;
5+ type TabId = z . infer < typeof tabIdSchema > ;
6+ type TabSyncConfig = { tabIds : TabId [ ] } ;
47
58/**
69 * Service for syncing data across tabs using `BroadcastChannel`
710 */
811export default class TabSyncService {
912 static storageKey = "btrix.tabSync" ;
1013
11- public tabId = nanoid ( ) ;
14+ public tabId ?: TabId ;
1215 public channel : BroadcastChannel ;
1316 public get tabCount ( ) {
1417 return this . getStoredSyncConfig ( ) ?. tabIds . length ;
@@ -18,36 +21,34 @@ export default class TabSyncService {
1821 // Open channel
1922 this . channel = new BroadcastChannel ( channelName ) ;
2023
21- // Update number of open tabs
24+ // Update number of open tabs based on current tab visibility
25+ this . handleVisibilityChange ( ) ;
26+
27+ // Update tab ID when tab is closed or switched
28+ window . addEventListener ( "visibilitychange" , ( ) => {
29+ this . handleVisibilityChange ( ) ;
30+ } ) ;
31+ }
32+
33+ private handleVisibilityChange ( ) {
2234 const syncConfig = this . getStoredSyncConfig ( ) || { tabIds : [ ] } ;
2335
24- syncConfig . tabIds . push ( this . tabId ) ;
36+ if ( document . visibilityState === "visible" ) {
37+ this . tabId = nanoid ( ) ;
38+
39+ syncConfig . tabIds . push ( this . tabId ) ;
40+ } else if ( this . tabId ) {
41+ syncConfig . tabIds = syncConfig . tabIds . filter ( ( id ) => id === this . tabId ) ;
42+ }
2543
2644 window . localStorage . setItem (
2745 TabSyncService . storageKey ,
2846 JSON . stringify ( {
2947 ...syncConfig ,
30- // Somewhat arbitrary, but only store latest 20 tabs to keep list managable
31- tabIds : syncConfig . tabIds . slice ( - 20 ) ,
48+ // Somewhat arbitrary, but only store latest tabs to keep list managable
49+ tabIds : syncConfig . tabIds . slice ( - 50 ) ,
3250 } ) ,
3351 ) ;
34-
35- // Remove tab ID on page unload
36- window . addEventListener ( "unload" , ( ) => {
37- const syncConfig = this . getStoredSyncConfig ( ) ;
38-
39- if ( syncConfig ) {
40- const tabIds = syncConfig . tabIds . filter ( ( id ) => id === this . tabId ) ;
41-
42- window . localStorage . setItem (
43- TabSyncService . storageKey ,
44- JSON . stringify ( {
45- ...syncConfig ,
46- tabIds,
47- } ) ,
48- ) ;
49- }
50- } ) ;
5152 }
5253
5354 private getStoredSyncConfig ( ) : TabSyncConfig | null {
0 commit comments