Skip to content

Split-drag drop zones for a single pane are measured against <main>, so they change with the right panel #3481

Description

@elb-comt

Summary

In a single-pane workspace, dragging a thread from the left sidebar onto the chat pane splits or replaces depending on whether the right panel is open. With the right panel closed, dropping in the middle of the chat shows Replace this chat and replaces the open chat. With the right panel open, dropping at the same visible spot shows Split left and splits. The drop zone should depend only on where you drop inside the chat pane, not on the right panel.

Versions and environment

  • bb 0.42.1 (desktop app, /Applications/bb.app), macOS (arm64)
  • Single-pane thread view, right secondary panel (⌘J)
  • Reproduced against main at fa1f44ebe9e5676004b669e48c99b3c7606466b6, and against the running 0.42.1 web bundle served by the desktop app on http://127.0.0.1:38886

Steps to reproduce

  1. Open a thread so there is exactly one pane.
  2. Open the right panel (⌘J). The visible chat column is now about half the window.
  3. Drag another thread from the left sidebar and drop it on the visual center of the chat column → overlay reads Split left; a split is created.
  4. Close the right panel (⌘J).
  5. Drag a thread and drop it on the visual center of the chat (now the full width) → overlay reads Replace this chat; the current chat is replaced.

Did not reproduce with two or more panes: each pane carries data-split-pane-id, so the zone is measured against the pane rect.

Expected vs actual

Actual (measured by driving the running UI with Playwright and reading the [data-split-drag-label] overlay text and bb.splitLayout):

  • panel CLOSED, visible center x=881 (50% of <main>): overlay Replace this chat → replace
  • panel OPEN, visible center x=601 (25% of <main>): overlay Split left → split

Expected: for the same relative drop inside the chat pane, the result is identical with the right panel open or closed.

Evidence

The single-pane chat region is not tagged with data-split-pane-id, so the drag falls back to the whole <main>; in the inline single-pane layout <main> also contains the right panel as a sibling react-resizable-panels panel.

  • apps/app/src/components/sidebar/useThreadRowSplitDrag.ts#L33 sets MAIN_CONTENT_SELECTOR = "main", and singlePaneFallback() (#L128-L142) returns container: document.querySelector("main"):
    function singlePaneFallback(
    layout: SplitLayout | null,
    ): SplitDragFallbackTarget | null {
    if (layout === null) {
    return null;
    }
    const panes = listPanes(layout.root);
    const only = panes[0];
    if (panes.length !== 1 || only === undefined) {
    return null;
    }
    return {
    paneId: only.paneId,
    container: document.querySelector<HTMLElement>(MAIN_CONTENT_SELECTOR),
    };
  • The multi-pane branch of SplitThreadArea wraps each pane in data-split-pane-id (#L759), but the single-pane branch (#L605-L626) renders the pane content without a tagged wrapper:
    if (panes.length === 1 && firstPane !== undefined) {
    return (
    <>
    {commandHandlers}
    <WorkspacePaneContent
    content={firstPane.content}
    paneId={firstPane.paneId}
    isFocused
    isSplitPane={false}
    secondaryPanelRegistry={null}
    reservesWindowPanelToggle={false}
    onRequestClose={null}
    isMaximized={false}
    onToggleMaximize={null}
    isBoundedPane={false}
    isTopRow
    ownsWindowTopLeft
    onNavigateInPane={navigateInPane}
    />
    </>
    );
    }
  • In the inline single-pane layout, SecondaryPanelLayout renders a PanelGroup whose chat Panel and right secondary Panel are siblings (#L326-L359); the chat content div (#L298-L312) has no pane id:
    <PanelGroup
    key={panelGroupKey ?? resetKey}
    ref={horizontalPanelGroupRef}
    data-split-resize-grid-root=""
    direction="horizontal"
    className="@container h-full min-w-0 flex-1"
    style={{
    overflow: "clip",
    ...getPanelCollapseTransitionStyle(transitionsReady),
    }}
    >
    <Panel
    id={mainPanelId}
    {...(collapse === undefined
    ? {}
    : { collapsible: true, collapsedSize: 0 })}
    defaultSize={
    isMainCollapsed
    ? 0
    : open && !renderAsDrawer
    ? FULL_PANEL_SIZE_PERCENT - persistedSecondaryWidthPercent
    : FULL_PANEL_SIZE_PERCENT
    }
    minSize={MAIN_PANEL_MIN_SIZE_PERCENT}
    order={1}
    className={cn(
    "min-w-0 overflow-clip transition-[flex-grow,flex-basis]",
    PANEL_COLLAPSE_TRANSITION_CLASS,
    )}
    >
    {mainContent}
    </Panel>
    {inlinePanel}
    </PanelGroup>
  • Zone math uses EDGE_X_FRACTION = 0.28 (zones.ts#L17), so 25% of <main> is "left" and 50% is "center":
    export function decideThreadDrop({
    zone,
    threadAlreadyOpen,
    atMaxPanes,
    }: ThreadDropInput): ZoneDecision {
    if (threadAlreadyOpen) {
    return { zone: "center", label: "Already open — focus pane" };
    }
    if (atMaxPanes) {
    return { zone: "center", label: "Replace this chat" };
    }
    return {
    zone,
    label: zone === "center" ? "Replace this chat" : `Split ${zone}`,
    };
  • Measured with getBoundingClientRect() in the running app: <main> is x=320 w=1120 with the right panel both open and closed, while the visible chat column is the left ~560px (the panel starts at x≈881). The zone divides by 1120, not by the visible chat width.

What you ruled out

  • Not Split-workspace right-panel toggle sits below thread header centerline #3137 (that is the right-panel toggle position, a different symptom).
  • Still happens on main at fa1f44ebe9e5676004b669e48c99b3c7606466b6.
  • Not provider-specific; this is pure UI geometry with no agent involved.
  • Single-pane only; with ≥2 panes the per-pane data-split-pane-id rect is used and the zones are correct.

Suggested priority and effort

Medium — hits the common single-pane + right-panel workflow and makes the drop result depend on an unrelated panel; workaround is to aim at the pane edge. Effort: Low.

Prototype (fork; not a PR — CONTRIBUTING requires sign-off first)

Two commits on elb-comt/bb:fix/single-pane-split-drop-target:

  1. Tag the inline pane content (the chat column, which excludes the right panel) with data-split-pane-id so zones are measured against the pane that owns them; behavior then no longer depends on the right panel.
  2. Optional UX follow-up: when the workspace has exactly one pane, a center drop splits to the right instead of replacing, since dragging a thread in is the common "add a pane" gesture and replace is also reachable by clicking the thread.

AGENT GENERATED

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-reproBug reproduced again from a clean trusted checkout; see linked reportuiApp shell, sidebar, composer, rendering

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions