diff --git a/server/shell.ts b/server/shell.ts index 6913892..d75b91a 100644 --- a/server/shell.ts +++ b/server/shell.ts @@ -419,10 +419,15 @@ export function renderShell(opts: ShellOptions): string { window.__rspaceTabBar = tabBar; // ── CommunitySync: merge with Automerge once connected ── + // NOTE: The TAB LIST is shared via Automerge (which modules are open), + // but the ACTIVE TAB is always local (determined by the URL / currentModuleId). + // This prevents windows from fighting over which tab is highlighted. document.addEventListener('community-sync-ready', (e) => { const sync = e.detail?.sync; if (!sync) return; + const localActiveId = 'layer-' + currentModuleId; + // Merge: Automerge layers win if they exist, otherwise seed from localStorage const remoteLayers = sync.getLayers(); if (remoteLayers.length > 0) { @@ -433,24 +438,21 @@ export function renderShell(opts: ShellOptions): string { } layers = sync.getLayers(); tabBar.setLayers(layers); - const activeId = sync.doc.activeLayerId; - if (activeId) tabBar.setAttribute('active', activeId); tabBar.setFlows(sync.getFlows()); } else { // First connection: push all localStorage tabs into Automerge for (const l of layers) { sync.addLayer(l); } - sync.setActiveLayer('layer-' + currentModuleId); } + // Active tab stays local — always matches the URL + tabBar.setAttribute('active', localActiveId); + // Keep localStorage in sync saveTabs(); - // Sync layer changes back to Automerge - tabBar.addEventListener('layer-switch', (e) => { - sync.setActiveLayer(e.detail.layerId); - }); + // Sync layer list changes to Automerge (not active tab) tabBar.addEventListener('layer-add', (e) => { const { moduleId } = e.detail; const newLayer = makeLayer(moduleId, sync.getLayers().length); @@ -469,13 +471,13 @@ export function renderShell(opts: ShellOptions): string { tabBar.addEventListener('flow-remove', (e) => { sync.removeFlow(e.detail.flowId); }); tabBar.addEventListener('view-toggle', (e) => { sync.setLayerViewMode(e.detail.mode); }); - // Listen for remote changes + // Listen for remote changes — sync tab list and flows only. + // Never touch the active tab: it's managed locally by TabCache + // and the tab-bar component via layer-switch events. sync.addEventListener('change', () => { layers = sync.getLayers(); tabBar.setLayers(layers); tabBar.setFlows(sync.getFlows()); - const activeId = sync.doc.activeLayerId; - if (activeId) tabBar.setAttribute('active', activeId); const viewMode = sync.doc.layerViewMode; if (viewMode) tabBar.setAttribute('view-mode', viewMode); saveTabs(); // keep localStorage in sync