From 45ecad89bbbff6a2bc08b5525dd070c06606d807 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 9 Mar 2026 19:31:58 +0000 Subject: [PATCH] fix: store tooltip cleanup functions and call on destroy Prevents orphaned tooltip divs when panels are torn down while a tooltip is visible. Co-Authored-By: Claude Opus 4.6 --- client/src/ui/LeftPanel.ts | 10 ++++++---- client/src/ui/NpcInfoPanel.ts | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/client/src/ui/LeftPanel.ts b/client/src/ui/LeftPanel.ts index d1ebab2..cf1b755 100644 --- a/client/src/ui/LeftPanel.ts +++ b/client/src/ui/LeftPanel.ts @@ -13,6 +13,7 @@ export class LeftPanel { private resourcesContent: HTMLDivElement; private resourcesNotificationDot: HTMLDivElement; private notificationDot: HTMLDivElement; + private tooltipCleanups: (() => void)[] = []; private expanded = false; private activeTab: 'stats' | 'events' | 'inventions' | 'resources' | null = null; private superlativesContent: HTMLDivElement; @@ -171,10 +172,10 @@ export class LeftPanel { tabContainer.appendChild(this.inventionsTab); tabContainer.appendChild(this.resourcesTab); - attachTooltip(this.statsTab, 'Superlatives', 'right'); - attachTooltip(this.eventsTab, 'Event Log', 'right'); - attachTooltip(this.inventionsTab, 'Inventions', 'right'); - attachTooltip(this.resourcesTab, 'Resources', 'right'); + this.tooltipCleanups.push(attachTooltip(this.statsTab, 'Superlatives', 'right')); + this.tooltipCleanups.push(attachTooltip(this.eventsTab, 'Event Log', 'right')); + this.tooltipCleanups.push(attachTooltip(this.inventionsTab, 'Inventions', 'right')); + this.tooltipCleanups.push(attachTooltip(this.resourcesTab, 'Resources', 'right')); this.container.appendChild(this.panel); this.container.appendChild(tabContainer); @@ -316,6 +317,7 @@ export class LeftPanel { } destroy(): void { + this.tooltipCleanups.forEach(fn => fn()); this.container.remove(); } } diff --git a/client/src/ui/NpcInfoPanel.ts b/client/src/ui/NpcInfoPanel.ts index 7e14ca5..30eaf3f 100644 --- a/client/src/ui/NpcInfoPanel.ts +++ b/client/src/ui/NpcInfoPanel.ts @@ -60,6 +60,7 @@ export class NpcInfoPanel { private inventoryContent!: HTMLDivElement; private activeTab: 'status' | 'relationships' | 'history' | 'inventory' = 'status'; private expandedTiers: Set = new Set(); + private tooltipCleanups: (() => void)[] = []; private visible = false; constructor() { @@ -101,10 +102,10 @@ export class NpcInfoPanel { this.historyTab.addEventListener('click', () => this.switchTab('history')); this.inventoryTab.addEventListener('click', () => this.switchTab('inventory')); - attachTooltip(this.statusTab, 'Status', 'left'); - attachTooltip(this.relationshipsTab, 'Relationships', 'left'); - attachTooltip(this.historyTab, 'History', 'left'); - attachTooltip(this.inventoryTab, 'Inventory', 'left'); + this.tooltipCleanups.push(attachTooltip(this.statusTab, 'Status', 'left')); + this.tooltipCleanups.push(attachTooltip(this.relationshipsTab, 'Relationships', 'left')); + this.tooltipCleanups.push(attachTooltip(this.historyTab, 'History', 'left')); + this.tooltipCleanups.push(attachTooltip(this.inventoryTab, 'Inventory', 'left')); tabColumn.appendChild(this.statusTab); tabColumn.appendChild(this.relationshipsTab); @@ -676,7 +677,7 @@ export class NpcInfoPanel { this.statsContainer.appendChild(el); this.statElements.set(label, el); if (STAT_FULL_NAMES[label]) { - attachTooltip(el, STAT_FULL_NAMES[label], 'above'); + this.tooltipCleanups.push(attachTooltip(el, STAT_FULL_NAMES[label], 'above')); } } const valueEl = el.querySelector('[data-role="value"]') as HTMLSpanElement; @@ -981,6 +982,7 @@ export class NpcInfoPanel { } destroy(): void { + this.tooltipCleanups.forEach(fn => fn()); this.outerFrame.remove(); } }