Skip to content

fix(tooltip): always hide on disconnectedCallback#3997

Closed
albinhallen wants to merge 1 commit intomainfrom
fix/tooltip-hide-on-disconnect
Closed

fix(tooltip): always hide on disconnectedCallback#3997
albinhallen wants to merge 1 commit intomainfrom
fix/tooltip-hide-on-disconnect

Conversation

@albinhallen
Copy link
Copy Markdown

@albinhallen albinhallen commented Apr 2, 2026

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where tooltip cleanup was incomplete during component removal, ensuring tooltip timers are now properly cancelled to prevent unexpected persistence and improve memory management.

Review:

  • Commits are atomic
  • Commits have the correct type for the changes made
  • Commits with breaking changes are marked as such

Browsers tested:

(Check any that applies, it's ok to leave boxes unchecked if testing something didn't seem relevant.)

Windows:

  • Chrome
  • Edge
  • Firefox

Linux:

  • Chrome
  • Firefox

macOS:

  • Chrome
  • Firefox
  • Safari

Mobile:

  • Chrome on Android
  • iOS

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

The disconnectedCallback lifecycle method in the tooltip component now explicitly calls this.tooltipTimer.hide() to ensure any active or pending tooltip timer is properly cancelled when the component is detached from the DOM.

Changes

Cohort / File(s) Summary
Tooltip Lifecycle Cleanup
src/components/tooltip/tooltip.tsx
Added explicit this.tooltipTimer.hide() call in disconnectedCallback to ensure pending tooltip timers are cancelled when the component detaches from the DOM.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(tooltip): always hide on disconnectedCallback' directly matches the main change—ensuring tooltips hide when the component disconnects from the DOM.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tooltip-hide-on-disconnect

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@albinhallen
Copy link
Copy Markdown
Author

Related to #3983

If the tooltip is triggered, i.e. the "label" is shown but the tooltip component is removed from DOM and the "mouseleave" event is never fired, remove the tooltip on disonnectedCallback

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 2, 2026

Documentation has been published to https://lundalogik.github.io/lime-elements/versions/PR-3997/

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/tooltip/tooltip.tsx`:
- Line 123: The disconnectedCallback currently calls this.tooltipTimer.hide(),
which triggers hideCallback() and writes this.open = false on a potentially
detached component; add a cancel-only method (e.g., TooltipTimer.cancel() or
clear()) that stops any pending timers without invoking hideCallback(), update
the TooltipTimer class to implement that cancel method, and replace the call to
this.tooltipTimer.hide() in disconnectedCallback() with the new cancel method so
teardown does not mutate the component state (references: TooltipTimer.hide,
TooltipTimer.hideCallback, TooltipTimer (new cancel), disconnectedCallback,
this.open).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 36beef41-61ec-4b5e-aa29-f6aecec62f6c

📥 Commits

Reviewing files that changed from the base of the PR and between 603788b and 6433db3.

📒 Files selected for processing (1)
  • src/components/tooltip/tooltip.tsx


public disconnectedCallback() {
this.removeListeners();
this.tooltipTimer.hide();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify that disconnectedCallback currently calls hide()
rg -nP --type=tsx -C3 'disconnectedCallback\s*\(\)\s*\{[\s\S]{0,200}tooltipTimer\.hide\s*\('

# Verify TooltipTimer.hide() performs callback side effects
fd -i 'tooltip-timer.ts' -x sh -c 'echo "--- $1 ---"; sed -n "1,120p" "$1"' sh {}

# Verify whether a cancel-only API already exists
rg -nP --type=ts '\bcancel\s*\(\)\s*:\s*void\b|\bclearTimeout\s*\('

Repository: Lundalogik/lime-elements

Length of output: 95


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find tooltip files
fd -e tsx -e ts tooltip | head -20

# Read tooltip.tsx around line 123 (disconnectedCallback context)
echo "=== tooltip.tsx context around line 123 ==="
cat -n src/components/tooltip/tooltip.tsx | sed -n '115,135p'

# Read tooltip-timer.ts to see hide() method
echo -e "\n=== tooltip-timer.ts content ==="
cat -n src/components/tooltip/tooltip-timer.ts

# Check for cancel method existence
echo -e "\n=== Searching for cancel() method in tooltip files ==="
rg 'cancel\s*\(' src/components/tooltip/ -A 2

Repository: Lundalogik/lime-elements

Length of output: 2519


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find hideCallback initialization in tooltip.tsx
echo "=== Searching for hideCallback in tooltip.tsx ==="
rg 'hideCallback|tooltipTimer.*=' src/components/tooltip/tooltip.tsx -B 2 -A 2

# Get constructor and state definitions
echo -e "\n=== Constructor and state in tooltip.tsx ==="
cat -n src/components/tooltip/tooltip.tsx | sed -n '1,80p'

Repository: Lundalogik/lime-elements

Length of output: 4089


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find `@State` declaration for open
echo "=== Finding `@State` open property ==="
cat -n src/components/tooltip/tooltip.tsx | sed -n '80,130p'

# Check if there are other state mutations in disconnectedCallback patterns elsewhere
echo -e "\n=== Checking other components for disconnectedCallback patterns ==="
rg 'disconnectedCallback' src/components/ -A 5 | head -40

Repository: Lundalogik/lime-elements

Length of output: 4286


Avoid @State mutation during teardown via TooltipTimer.hide().

On Line 123, this.tooltipTimer.hide() executes hideCallback(), which sets this.open = false. In disconnectedCallback(), this couples teardown with a state write on a detached component. Add a cancel-only method to TooltipTimer and use it for cleanup instead.

Suggested refactor
// src/components/tooltip/tooltip.tsx
public disconnectedCallback() {
    this.removeListeners();
-   this.tooltipTimer.hide();
+   this.tooltipTimer.cancel();
}
// src/components/tooltip/tooltip-timer.ts
+cancel(): void {
+    clearTimeout(this.timerHandle);
+    this.timerHandle = null;
+}
+
hide(): void {
-    clearTimeout(this.timerHandle);
-    this.timerHandle = null;
+    this.cancel();
    this.hideCallback();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/tooltip/tooltip.tsx` at line 123, The disconnectedCallback
currently calls this.tooltipTimer.hide(), which triggers hideCallback() and
writes this.open = false on a potentially detached component; add a cancel-only
method (e.g., TooltipTimer.cancel() or clear()) that stops any pending timers
without invoking hideCallback(), update the TooltipTimer class to implement that
cancel method, and replace the call to this.tooltipTimer.hide() in
disconnectedCallback() with the new cancel method so teardown does not mutate
the component state (references: TooltipTimer.hide, TooltipTimer.hideCallback,
TooltipTimer (new cancel), disconnectedCallback, this.open).

@albinhallen albinhallen marked this pull request as draft April 2, 2026 15:12
@albinhallen
Copy link
Copy Markdown
Author

Closing this as it doesn't seem to fix the issue. Should already be taken care of through

  • limel-tooltip-content
  • limel-portal

@albinhallen albinhallen closed this Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant