Skip to content

Unrelated side-chat scrolling dismisses the primary timeline selection menu #2302

Description

@kongenpei

Summary

When a side chat streams Markdown in the secondary panel, its follow-to-bottom scrolling dismisses an open text-selection menu in the primary timeline. The unrelated scroll removes both "Add to chat" and "Reply in side chat" before the user can click them. The menu should stay open when a sibling panel scrolls.

Versions and environment

  • bb 0.39.0, running from source on main at fff3ae82fe61578e582ca5cd5b070cd6a80ed438
  • macOS 26.3, build 25D125
  • Node.js v24.6.0
  • Codex provider
  • Side chat experiment enabled, side chat rendered as a contained secondary-panel ThreadChat

Steps to reproduce

  1. Open a thread and start a side chat in the secondary panel.
  2. Ask the side chat to produce enough incremental Markdown to keep the panel scrolling, for example: Write 50 short Markdown paragraphs, one paragraph at a time.
  3. While the side chat is streaming, select text in an assistant message in the primary timeline.
  4. Confirm that the selection menu shows "Add to chat" and "Reply in side chat".
  5. Do not interact with the primary timeline. Wait for the next side-chat chunk to make the secondary panel follow the bottom.

Smallest source-level reproduction:

  1. Render TimelineSelectionMenu with a non-null selection and an onDismiss spy.
  2. Dispatch scroll from an unrelated sibling element.
  3. Observe that onDismiss is called once even though the selection and its panel did not move.

Did not reproduce with a parent rerender alone. Rerendering TimelineSelectionMenu with an equivalent selection does not call onDismiss.

Expected vs actual

Expected:

The primary timeline selection menu remains open when the side-chat panel scrolls. It closes only when the selected timeline or one of its scroll ancestors moves, the selection is cleared, the viewport resizes, or the user dismisses it.

Actual:

The menu disappears as soon as the streaming side chat produces a scroll event. Both actions disappear together.

The focused regression test failed with:

FAIL  TimelineSelectionMenu > keeps a valid selection menu open when streaming auto-scrolls the timeline
AssertionError: expected "vi.fn()" to not be called at all, but actually been called 1 times
Number of calls: 1

Evidence

Observed cause:

The reproduction command was:

pnpm exec turbo run test --filter=@bb/app -- --run src/components/thread/timeline/TimelineSelectionMenu.test.tsx

Investigation thread: thr_6kvafkfm3m. The local bb server is not connected to getbb.app, so this thread has no externally reachable URL.

Suggested fix:

Carry the selection's source element in MessageProseSelection, then dismiss on scroll only when the event target is the source element's scroll ancestor. A sibling side-chat scroll should be ignored. Add tests for both cases: sibling scroll keeps the menu open, source-ancestor scroll closes it.

What you ruled out

  • No duplicate found in open or closed issues for the action labels, selection-menu scrolling, or side-chat streaming terms.
  • A React parent rerender alone does not dismiss the menu.
  • This is not specific to the side-chat plugin action. "Add to chat" disappears in the same state transition.
  • The focused source-level reproduction fails on main at fff3ae82fe61578e582ca5cd5b070cd6a80ed438.

Suggested priority and effort

Medium priority, low effort. It interrupts a common selection action during concurrent side-chat work but does not lose data. The workaround is to wait for streaming to finish and select the text again.

AGENT GENERATED

Metadata

Metadata

Assignees

No one assigned

    Labels

    side-chatBuilt-in plugin: side-chatuiApp shell, sidebar, composer, rendering

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions