feat(chat): scroll polish + pin/bubble system#250
Merged
Conversation
Spec covering two work streams: quick fixes (post-stream final scroll, embed gap token, multiline auto-grow) and a pin/unpin state machine driving a centered-bottom scroll bubble. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Eight tasks across Stream A (final scroll, embed gap, viewport-responsive multiline cap) and Stream B (pin signal, bubble primitive, integration, unit tests, manual browser verification). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract pure isPinned helper from onScroll and cover the 150px strict-less-than boundary with 5 unit tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eive it The Task 2 token addition went into the TS-injected ROOT_TOKEN_STYLES, but @ngaf/chat is published with sideEffects: false and the module-level ensureChatRootStyles() call gets tree-shaken in consumer bundles. The canonical surface for consumer-visible :root tokens is chat.css, which the example imports from src/styles.css. The new spacing token belongs there too. Verified via the examples-chat dev server: with the var declared in chat.css, .chat-window__footer now has margin-top: 12px instead of 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace boolean programmaticScroll with a counter to avoid race when multiple programmatic scrolls are queued in quick succession (a stale rAF could clear the flag while a newer scroll was still in flight, causing spurious unpins during fast token streaming). - Mark chat-tokens.ts as side-effectful in package.json so the module-level ensureChatRootStyles() call is preserved through consumer tree-shaking. This restores :root token defaults for the whole SPACING_TOKENS group (edge-pad, space-*, input-gap), not just the new input-gap. - Revert the chat.css duplication of --ngaf-chat-input-gap now that the root-cause fix supersedes it. - Make ChatComponent.pinned protected instead of implicitly public. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a Claude Preview entry for examples-chat-angular on port 4400, used to manually verify chat composition behavior in the browser. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Drop redundant : number annotation on programmaticScrollCount (@typescript-eslint/no-inferrable-types). - Regenerate chat API docs to include the new ChatScrollBubbleComponent and ChatScrollBubbleMode exports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two work streams on the chat composition, spec'd at docs/superpowers/specs/2026-05-11-chat-scroll-and-input-polish-design.md, plan at docs/superpowers/plans/2026-05-11-chat-scroll-and-input-polish.md:
Stream A — Quick fixes
--ngaf-chat-input-gaptoken (default0.75rem) between body and footer; consumer-overridablemin(40vh, 320px)(was a fixed 200 px)Stream B — Pin/unpin + scroll-to-latest bubble
pinnedsignal driven by a 150 px tolerance via the(scroll)listenerprogrammaticScrollCountcounter (not a boolean) suppresses self-scrolls without racing under fast streamingchat-scroll-bubbleprimitive (streaming mode: 3-dot pulse; idle mode: down arrow).chat-footer-wrap, anchored above the inputpinned()— bubble carries the streaming signal when the user is scrolled awayPlus, root-cause fix discovered during browser verification
libs/chat/package.jsonnow declaressideEffects: ["**/chat-tokens.ts", "**/*.css"]soensureChatRootStyles()survives consumer tree-shaking. This restores:rootdefaults for ALLSPACING_TOKENS, not just the new--ngaf-chat-input-gap— a pre-existing latent bug.Public API additions
ChatScrollBubbleComponent,ChatScrollBubbleMode(exported from@ngaf/chat)--ngaf-chat-input-gapCSS custom propertyTest plan
nx run chat:test) — 485/485 passing, including newpin-state.spec.ts(5) andchat-scroll-bubble.component.spec.ts(5)nx run chat:buildclean/embed:min(40vh, 320px)); internal scroll engages past capisLoading → false) — requires longer-running prompt; safe to verify post-merge🤖 Generated with Claude Code