Skip to content

fix: update folder height when content changes dynamically#604

Open
dinakars777 wants to merge 5 commits intopmndrs:mainfrom
dinakars777:fix/folder-height-dynamic-content
Open

fix: update folder height when content changes dynamically#604
dinakars777 wants to merge 5 commits intopmndrs:mainfrom
dinakars777:fix/folder-height-dynamic-content

Conversation

@dinakars777
Copy link
Copy Markdown

@dinakars777 dinakars777 commented Mar 20, 2026

Summary

  • Add ResizeObserver to useToggle hook to watch for content height changes
  • When folder content is dynamically added while expanded, the folder now automatically resizes to fit the new content

Fixes

Fixes #601

Changes

  • Modified useToggle hook to include a ResizeObserver that updates the wrapper height when content dimensions change
  • Added updateHeight() helper function that recalculates and applies the content height
  • Cleanup properly disconnects the ResizeObserver on effect cleanup

Testing

  • All existing tests pass (18/18)

Summary by CodeRabbit

  • Bug Fixes
    • Text/string inputs update in real time as you type for immediate feedback
    • Number inputs no longer trigger intermediate commits on each keystroke—updates apply on commit (e.g., blur/Enter)
    • Collapsible sections animate more smoothly with tighter height synchronization and better responsiveness to dynamic content

Previously, string inputs only committed changes to the store on blur.
This change makes onUpdate fire on every keystroke for string inputs
only - number inputs retain their original commit behavior (on blur/enter).

Added comment explaining the type !== 'number' guard.

Fixes pmndrs#599
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 20, 2026

🦋 Changeset detected

Latest commit: f32b583

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
leva Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
leva Ready Ready Preview, Comment Mar 23, 2026 4:57am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 20, 2026

📝 Walkthrough

Walkthrough

This PR refines ValueInput change handling (deferring immediate updates for number inputs) and overhauls folder toggle height logic to measure content, use ResizeObserver, and synchronize wrapper height on dynamic content changes.

Changes

Cohort / File(s) Summary
Release Configuration
​.changeset/plenty-spies-provide.md
Adds a new changeset entry declaring a patch release and documenting the fix for folder height updates when content changes dynamically.
Input Change Handling
packages/leva/src/components/ValueInput/ValueInput.tsx
Adjusts StyledInput onChange to call the provided onChange and to invoke onUpdate immediately only for non-number types; number inputs no longer trigger immediate onUpdate on each keystroke.
Dynamic Height Synchronization
packages/leva/src/hooks/useToggle.ts
Reworks the toggle effect to measure content via getBoundingClientRect(), set wrapper height explicitly (0px on collapse), simplify transitionend cleanup, and install a ResizeObserver to keep wrapper height in sync with dynamic content. Removed timeout-based collapse handling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I thumped my paw and gave a hop,

Folders grow without a stop.
ResizeObserver hums the tune,
Numbers wait, strings sing soon.
Hooray — the UI stretches right on top!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix: update folder height when content changes dynamically' accurately describes the main change—adding dynamic height recalculation via ResizeObserver to the useToggle hook.
Linked Issues check ✅ Passed The PR fully addresses issue #601 by implementing ResizeObserver in useToggle hook to watch content changes and recalculate wrapper height, matching the problem description and proposed solution.
Out of Scope Changes check ✅ Passed All changes are scoped to the linked issue: changeset entry, ValueInput onChange refinement for better update handling, and useToggle ResizeObserver implementation for dynamic height updates.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci bot commented Mar 20, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit f32b583:

Sandbox Source
leva-minimal Configuration
leva-busy Configuration
leva-scroll Configuration
leva-advanced-panels Configuration
leva-ui Configuration
leva-theme Configuration
leva-transient Configuration
leva-plugin-plot Configuration
leva-plugin-bezier Configuration
leva-plugin-spring Configuration
leva-plugin-dates Configuration
leva-custom-plugin Configuration

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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/leva/src/hooks/useToggle.ts (1)

120-134: Consider handling ResizeObserver-triggered height updates after initial animation.

After fixHeight clears the inline height/overflow styles (line 121-122), subsequent ResizeObserver callbacks will re-apply an inline height via updateHeight(). This height style remains indefinitely since the transitionend listener was removed after the initial animation ({ once: true }).

This isn't necessarily a bug—the wrapper will keep updating its height as content changes. However, you may want to either:

  1. Accept that post-expansion changes leave inline height (current behavior)
  2. Re-register the fixHeight listener when ResizeObserver detects changes (for consistent cleanup)

If the current behavior is intentional, a brief comment would clarify this design choice.

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

In `@packages/leva/src/hooks/useToggle.ts` around lines 120 - 134, The current
logic clears inline height/overflow in fixHeight after the initial transition
but leaves updateHeight-driven inline heights from the ResizeObserver in place;
either document this intentional behavior or change the flow: inside the
ResizeObserver callback (where updateHeight is called) re-register the
transitionend listener to call fixHeight (or call a shared cleanup function) so
that subsequent size changes also clear inline styles, referencing the fixHeight
function, updateHeight call, the ResizeObserver instance, contentEl and ref (and
the 'transitionend' event) to locate and update the code accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/leva/src/components/ValueInput/ValueInput.tsx`:
- Around line 87-92: The change causes ValueInput's onChange handler (in
ValueInput -> update) to call onUpdate for any non-number type, leaking realtime
commits beyond strings; make realtime commits opt-in by adding a liveUpdate
boolean prop to ValueInput and only call onUpdate inside update when liveUpdate
is true (keep existing number behavior). Update usages: enable liveUpdate from
packages/leva/src/plugins/String/String.tsx (pass liveUpdate={true}) and leave
other call sites (e.g., plugins/Color/Color.tsx) unchanged so they retain the
original commit-on-blur/Enter behavior.

In `@packages/leva/src/hooks/useToggle.ts`:
- Around line 113-118: The early return in useToggle (the block that checks
firstRender.current, sets it false, calls updateHeight(), then returns) prevents
the ResizeObserver from being initialized for components that mount
already-expanded; remove that return (or move the ResizeObserver initialization
earlier) so the observer setup always runs: keep the firstRender.current = false
and the initial updateHeight() call to avoid the first animation, but ensure the
ResizeObserver creation/observe logic and its cleanup (the code that currently
runs after that return) executes regardless of firstRender so dynamic content
will trigger updateHeight; adjust the cleanup to still disconnect the observer
in the effect cleanup.

---

Nitpick comments:
In `@packages/leva/src/hooks/useToggle.ts`:
- Around line 120-134: The current logic clears inline height/overflow in
fixHeight after the initial transition but leaves updateHeight-driven inline
heights from the ResizeObserver in place; either document this intentional
behavior or change the flow: inside the ResizeObserver callback (where
updateHeight is called) re-register the transitionend listener to call fixHeight
(or call a shared cleanup function) so that subsequent size changes also clear
inline styles, referencing the fixHeight function, updateHeight call, the
ResizeObserver instance, contentEl and ref (and the 'transitionend' event) to
locate and update the code accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 95c7a902-d961-408d-8a69-b5d87df2577b

📥 Commits

Reviewing files that changed from the base of the PR and between 402a1e9 and 91c6ba0.

📒 Files selected for processing (3)
  • .changeset/plenty-spies-provide.md
  • packages/leva/src/components/ValueInput/ValueInput.tsx
  • packages/leva/src/hooks/useToggle.ts

- Guard against transitionend not firing when height already matches target
- Update changeset to reflect folder height dynamic update
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 (1)
packages/leva/src/hooks/useToggle.ts (1)

138-145: ResizeObserver implementation looks correct.

This achieves the PR objective—dynamically added content will trigger updateHeight() and recalculate the wrapper height. Cleanup properly disconnects the observer.

Consider: If rapid content changes cause performance concerns, the callback could be wrapped in requestAnimationFrame to batch updates. This is likely unnecessary for typical folder usage but worth noting.

,

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

In `@packages/leva/src/hooks/useToggle.ts` around lines 138 - 145, Wrap the
ResizeObserver callback to batch updates using requestAnimationFrame: in the
ResizeObserver callback that currently calls updateHeight(), schedule
updateHeight via requestAnimationFrame and store the returned raf id (e.g.,
rafId variable); on teardown (the returned cleanup) cancel any pending frame
with cancelAnimationFrame(rafId) in addition to disconnecting resizeObserver and
removing the 'transitionend' listener (fixHeight) so rapid changes don't queue
redundant updates. Ensure you reference the existing symbols resizeObserver,
updateHeight, and fixHeight when adding the rafId handling.
🤖 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/leva/src/hooks/useToggle.ts`:
- Around line 138-145: Wrap the ResizeObserver callback to batch updates using
requestAnimationFrame: in the ResizeObserver callback that currently calls
updateHeight(), schedule updateHeight via requestAnimationFrame and store the
returned raf id (e.g., rafId variable); on teardown (the returned cleanup)
cancel any pending frame with cancelAnimationFrame(rafId) in addition to
disconnecting resizeObserver and removing the 'transitionend' listener
(fixHeight) so rapid changes don't queue redundant updates. Ensure you reference
the existing symbols resizeObserver, updateHeight, and fixHeight when adding the
rafId handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 067d8f86-eb57-4918-9310-2148e396e7ba

📥 Commits

Reviewing files that changed from the base of the PR and between 91c6ba0 and d466d38.

📒 Files selected for processing (2)
  • .changeset/plenty-spies-provide.md
  • packages/leva/src/hooks/useToggle.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/plenty-spies-provide.md

@dinakars777
Copy link
Copy Markdown
Author

Thanks for the review! Addressed by using liveUpdate prop and restricting realtime commits to non-number inputs. Also added transitionend guard for edge case. Resolved.

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.

Folder content height does not update after adding dynamic content

1 participant