4965dc834a
Fixes #7972. ## Thinking Path - The reporter pinned the post-submit composer-viewport restore in `ui/src/lib/issue-chat-scroll.ts`, which falls back to `window.scrollBy(...)` when `#main-content` is not independently scrollable — exactly the short-thread repro case. - In the desktop shell the body is `overflow: hidden` (set in `Layout.tsx`) inside a fixed-height `h-dvh` flex column, so a window scroll never moves content: it translates the entire shell (sidebar included) off-screen, and a plain reload does not restore it. On mobile (`min-h-dvh`, `body { overflow: visible }`) and the auth-free perf fixture the page genuinely scrolls, so the window IS the correct target there. - A prior attempt forced `resolveIssueChatScrollTarget` to always use `#main-content`; that path is a no-op on a non-overflowing container and is sensitive to a stale `ui/dist`/`.vite` cache, which likely masked the result. Gating the window-scroll itself is the precise root-cause fix and covers both restore call sites (`queueViewportRestore` and the `[messages]` layout effect) since both route through one function. ## What Changed - Added `isWindowScrollable(doc, win)` to `issue-chat-scroll.ts`: the window is a valid scroll target only when the document body is not clipped. It checks both the `overflow` shorthand and the `overflow-y` longhand (some engines, incl. jsdom, do not derive the longhand from the shorthand in computed style). - Gated the `window.scrollBy` fallback in `restoreComposerViewportSnapshot` behind `isWindowScrollable`; on the desktop shell there is nothing to restore, so the scroll position is left untouched. - Added unit tests for the desktop-shell (no window scroll) case and for `isWindowScrollable`. ## Verification - `ui $ vitest run src/lib/issue-chat-scroll.test.ts` → 6 passed (2 new + existing window/element restore tests still green). - `ui $ vitest run src/components/IssueChatThread.test.tsx` → 55 passed (consumer regression). ## Risks - Low. Behaviour only changes when the resolved target is `window` AND the document body is clipped — i.e. the desktop shell, where the previous behaviour was the bug. Mobile and the perf fixture keep window scrolling unchanged (body not clipped → `isWindowScrollable` true). ## Model Used claude-opus-4-8 --- - [x] I searched the GitHub PRs for similar or duplicate PRs and confirmed this is not a duplicate. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@paperclipai/ui
Published static assets for the Paperclip board UI.
What gets published
The npm package contains the production build under dist/. It does not ship the UI source tree or workspace-only dependencies.
Storybook
Storybook config, stories, and fixtures live under ui/storybook/.
pnpm --filter @paperclipai/ui storybook
pnpm --filter @paperclipai/ui build-storybook
Typical use
Install the package, then serve or copy the built files from node_modules/@paperclipai/ui/dist.