unsloth/studio/frontend
Michael Han cf97faed9f
Studio: keep chat in place when composer attachments resize it (#6070)
* Studio: keep chat in place when composer attachments resize it

Attaching or removing a file in the chat composer could yank the whole
conversation to the bottom, and the grown composer covered the end of
the chat with no way to scroll it back into view.

Root cause: the Viewport composes refs with an identity that changes on
re-render, so React re-runs our scroll ref on unrelated renders and the
autoscroll hook treated every rebind as a fresh mount, pinning to the
bottom. On top of that the viewport reserved a fixed 160px under the
last message regardless of composer size.

- Treat same-element ref rebinds as no-ops in the autoscroll hook; only
  a genuinely new viewport element pins and resets detach state
- Size the bottom spacer from the measured composer height plus a 24px
  gap so the chat can always be scrolled above the composer
- On composer growth, detach from the bottom instead of auto-scrolling;
  the user scrolls down to reveal the covered lines
- On composer shrink, defer the spacer shrink until it cannot clamp
  scrollTop, then release it invisibly on scroll or on bottom-pinning
  moments (run start, thread switch, thread load)

* Studio: release deferred composer spacer when a run owns the bottom

Sending with attachments cleared the chips after thread.runStart had
already fired, so the spacer shrink was deferred while the user sat
pinned at the bottom, leaving a permanent extra gap above the composer.
Apply shrinks immediately while a run is active or within 1s of run
start; the run-start pin owns the bottom then, so the clamp is the
intended glide. Caught by a cross-engine Playwright pass (Chromium,
Firefox, WebKit) over the pre and post builds.

* Studio: track the viewport element in state so listeners survive remounts

The deferred-shrink scroll listener was attached once against a ref, but
the keyed overlay provider remounts the viewport subtree on thread
switches, leaving the listener bound to the unmounted element. Removing
an attachment near the bottom in the new thread then left the oversized
spacer stuck until a run started. Track the viewport element in state so
the listener and the clamp math follow the new element.

Reproduced and verified with a thread-switch scenario on Chromium,
Firefox and WebKit; full matrix re-run green.

* Studio: release deferred composer spacer shrink when at the bottom (#6070)

---------

Co-authored-by: shimmyshimmer <michael@unsloth.ai>
Co-authored-by: Daniel Han <danielhanchen@gmail.com>
2026-06-07 01:58:01 -07:00
..
public Polish/cloud to providers (#5450) 2026-05-15 19:29:21 +04:00
src Studio: keep chat in place when composer attachments resize it (#6070) 2026-06-07 01:58:01 -07:00
.gitignore perf(studio): upgrade to Vite 8 + auto-install bun for faster frontend builds (#4522) 2026-03-25 04:27:41 -07:00
.gitkeep add studio root folder 2026-02-02 09:14:35 +00:00
.npmrc security: NOT affected by Mini Shai-Hulud (May-12 wave) -- forward-looking hardening only (#5397) 2026-05-13 04:58:12 -07:00
biome.json feat: add seed dataset support with configuration, preview, and builder utilities 2026-02-14 18:44:38 +01:00
components.json add studio root folder 2026-02-02 09:14:35 +00:00
data-designer.openapi (1).yaml save and import, and fixes 2026-02-04 14:32:49 +01:00
eslint.config.js Final cleanup 2026-03-12 18:28:04 +00:00
index.html Final cleanup 2026-03-12 18:28:04 +00:00
package-lock.json Update vulnerable dependencies to patched versions 2026-06-03 05:08:00 -07:00
package.json Update vulnerable dependencies to patched versions 2026-06-03 05:08:00 -07:00
tsconfig.app.json Relax frontend unused local check (#4388) 2026-03-17 16:04:11 -07:00
tsconfig.json cleanup 2026-02-04 13:28:39 +01:00
tsconfig.node.json cleanup 2026-02-04 13:28:39 +01:00
vite.config.ts Fix Install commands for Windows + 1 line installs (#4447) 2026-03-19 02:09:09 -07:00