Skip to content

Recent PR bugs#13

Merged
cwandev merged 4 commits intomainfrom
cursor/recent-pr-bugs-a8ed
Mar 19, 2026
Merged

Recent PR bugs#13
cwandev merged 4 commits intomainfrom
cursor/recent-pr-bugs-a8ed

Conversation

@cwandev
Copy link
Copy Markdown
Collaborator

@cwandev cwandev commented Mar 15, 2026

Fixes several high-confidence bugs across Avatar, Collapsible, Fieldset, and shared utilities to improve dynamic behavior, prevent memory leaks, and ensure SSR compatibility.

The bugs involved incorrect state management for dynamic props (AvatarFallback), improper cleanup of requestAnimationFrame calls (useCollapsiblePanel), reliance on browser-specific globals in a universal utility (useTimeout), and incorrect shared state management during component unmounts (FieldsetLegend). Each fix addresses a specific edge case or environment incompatibility.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • Bug Fixes

    • Fixed avatar fallback delay state management
    • Fixed fieldset legend ID tracking when legends are removed
  • Tests

    • Added tests for avatar fallback delay prop behavior with reactive property changes
    • Added test for fieldset aria-labelledby attribute preservation during legend unmounting
  • Refactor

    • Improved animation frame resource cleanup in collapsible components
    • Simplified timeout utility implementation

When `delay` changed from undefined to a number, `delayPassed` stayed
true (set at init), so the fallback was never hidden during the new
delay period. Conversely, changing from a number to undefined left
`delayPassed` false, hiding the fallback permanently.

Reset `delayPassed` inside the watchEffect so it tracks prop changes:
- Set false + start timeout when delay becomes defined.
- Set true immediately when delay becomes undefined.
The inner `nextFrame` RAF was declared inside the outer `AnimationFrame.request`
callback. Its return value (a cleanup function) was ignored by `requestAnimationFrame`,
so `nextFrame` was never canceled when the watch re-ran or the component unmounted.

Hoist `nextFrame` to the outer scope and cancel both frames in the watch cleanup,
matching the correct pattern already used in `handlePanelRef`.
`Timeout.start` and `Timeout.clear` referenced `window.setTimeout` and
`window.clearTimeout`, which throw in SSR environments where `window`
is undefined. Use the global `setTimeout`/`clearTimeout` instead, which
are available in both browser and Node.js runtimes.
…egend

FieldsetLegend.onBeforeUnmount unconditionally called setLegendId(undefined),
which cleared aria-labelledby even when another legend was still mounted and
owned the current legendId. Guard the cleanup so it only clears when this
legend's id matches the current legendId.
@cursor
Copy link
Copy Markdown

cursor Bot commented Mar 15, 2026

Cursor Agent can help with this pull request. Just @cursor in comments and I'll start working on changes in this branch.
Learn more about Cursor Agents

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 15, 2026

📝 Walkthrough

Walkthrough

This pull request refines control flow and cleanup logic across several components. It adds tests for delay-based visibility transitions, improves legend ID management during unmounting, enhances animation frame cleanup tracking, and normalizes timeout utility functions to use global scope rather than explicit window references.

Changes

Cohort / File(s) Summary
Avatar Fallback Delay Logic
packages/core/src/avatar/fallback/AvatarFallback.vue, packages/core/src/avatar/fallback/AvatarFallback.test.ts
Modified delayPassed state handling to explicitly reset on delay start and set immediately when no delay is provided. Added tests verifying fallback visibility transitions when delay prop changes from undefined to a number and vice versa.
Fieldset Legend Context
packages/core/src/fieldset/legend/FieldsetLegend.vue, packages/core/src/fieldset/legend/FieldsetLegend.test.ts
Added legendId to fieldset context API. Modified unmount behavior to conditionally clear legendId only when the current ID matches the component's generated ID. Added test for aria-labelledby preservation when non-active legend unmounts.
Timing & Animation Utilities
packages/core/src/collapsible/panel/useCollapsiblePanel.ts, packages/core/src/utils/useTimeout.ts
Improved RAF cleanup tracking in Collapsible panel by tracking nested frames in dedicated variables for proper cancellation. Replaced explicit window.setTimeout and window.clearTimeout with global equivalents in timeout utility.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 With delays now dancing through Avatar's gentle fade,
legends stay polite when siblings make the grade,
frames bow out together in perfect harmony,
timeouts whisper softly—no window dependency! ⏰✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title "Recent PR bugs" is vague and generic, using non-descriptive language that doesn't convey meaningful information about the specific changes in the changeset. Consider a more specific title that highlights the main fix, such as "Fix state management and cleanup issues in Avatar, Collapsible, Fieldset, and utilities" or focus on the primary category of fixes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cursor/recent-pr-bugs-a8ed
📝 Coding Plan
  • Generate coding plan for human review comments

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 15, 2026

Open in StackBlitz

pnpm add https://pkg.pr.new/vuepont/base-ui-vue@13

commit: 5de9e65

@cwandev cwandev marked this pull request as ready for review March 16, 2026 09:08
Copy link
Copy Markdown

@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.

🧹 Nitpick comments (2)
packages/core/src/fieldset/legend/FieldsetLegend.test.ts (1)

72-98: Add a companion test for active legend unmount behavior.

Please add one more case defining expected behavior when the active legend unmounts while another legend is still mounted (should it clear or transfer aria-labelledby). This will lock in the full lifecycle contract.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/fieldset/legend/FieldsetLegend.test.ts` around lines 72 -
98, Add a companion test that verifies behavior when the active legend unmounts
and another legend remains: create a TestComponent using FieldsetRoot and
FieldsetLegend like the existing test but start with only the main legend
mounted, then set showExtra to true so the extra legend mounts after main
(making the extra legend the active one), assert the fieldset aria-labelledby
points to the newly mounted extra legend, then set showExtra back to false to
unmount the active extra legend and assert aria-labelledby transfers back to the
remaining legend (legend-main); reference the same symbols FieldsetRoot,
FieldsetLegend, showExtra, TestComponent and the fieldset variable in the new
test.
packages/core/src/utils/useTimeout.ts (1)

19-22: Prefer portable timer ID typing instead of double-casting.

Line 22's as unknown as TimeoutId bypasses type safety. Use ReturnType<typeof setTimeout> (and a null sentinel) to keep this SSR-safe and avoid unsafe casts. This applies to the timer logic across lines 19–22 and 29–32.

♻️ Suggested refactor
-type TimeoutId = number
-
-const EMPTY = 0 as TimeoutId
+type TimeoutId = ReturnType<typeof setTimeout> | null
+
+const EMPTY: TimeoutId = null
@@
-    this.currentId = setTimeout(() => {
+    this.currentId = setTimeout(() => {
       this.currentId = EMPTY
       fn()
-    }, delay) as unknown as TimeoutId
+    }, delay)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/utils/useTimeout.ts` around lines 19 - 22, The timer IDs
are being double-cast with "as unknown as TimeoutId" for this.currentId in the
setTimeout callback (and similarly in the clear/reset logic around the other
timer assignments), which bypasses type safety; change the type of currentId to
use ReturnType<typeof setTimeout> | null (use null as the sentinel instead of
EMPTY) and assign setTimeout directly without casts, updating any checks/clears
(e.g., places referencing currentId, the setTimeout call, and the clearTimeout
usage around lines like the setTimeout and clear/reset blocks) to handle null
safely and call clearTimeout(currentId) only when currentId is not null.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/core/src/fieldset/legend/FieldsetLegend.test.ts`:
- Around line 72-98: Add a companion test that verifies behavior when the active
legend unmounts and another legend remains: create a TestComponent using
FieldsetRoot and FieldsetLegend like the existing test but start with only the
main legend mounted, then set showExtra to true so the extra legend mounts after
main (making the extra legend the active one), assert the fieldset
aria-labelledby points to the newly mounted extra legend, then set showExtra
back to false to unmount the active extra legend and assert aria-labelledby
transfers back to the remaining legend (legend-main); reference the same symbols
FieldsetRoot, FieldsetLegend, showExtra, TestComponent and the fieldset variable
in the new test.

In `@packages/core/src/utils/useTimeout.ts`:
- Around line 19-22: The timer IDs are being double-cast with "as unknown as
TimeoutId" for this.currentId in the setTimeout callback (and similarly in the
clear/reset logic around the other timer assignments), which bypasses type
safety; change the type of currentId to use ReturnType<typeof setTimeout> | null
(use null as the sentinel instead of EMPTY) and assign setTimeout directly
without casts, updating any checks/clears (e.g., places referencing currentId,
the setTimeout call, and the clearTimeout usage around lines like the setTimeout
and clear/reset blocks) to handle null safely and call clearTimeout(currentId)
only when currentId is not null.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7c4c0e10-aa7f-468e-a162-aacab4581043

📥 Commits

Reviewing files that changed from the base of the PR and between 4588079 and 5de9e65.

📒 Files selected for processing (6)
  • packages/core/src/avatar/fallback/AvatarFallback.test.ts
  • packages/core/src/avatar/fallback/AvatarFallback.vue
  • packages/core/src/collapsible/panel/useCollapsiblePanel.ts
  • packages/core/src/fieldset/legend/FieldsetLegend.test.ts
  • packages/core/src/fieldset/legend/FieldsetLegend.vue
  • packages/core/src/utils/useTimeout.ts

@cwandev cwandev merged commit 69f39e0 into main Mar 19, 2026
6 checks passed
@cwandev cwandev deleted the cursor/recent-pr-bugs-a8ed branch March 19, 2026 16:24
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.

2 participants