refactor(desktop): extract the channel idle auxiliary surface

Landing the cover drawer on current main pushed `ChannelPane.tsx` to 1003
lines, three over the 1000-line cap. The file was already over the cap on
the cover drawer's original base (1010 lines, so shrinking was permitted),
but main has since brought it down to 982, so it may not grow at all.

Move the caller-owned idle auxiliary surface into its own component, the
same split `ChannelAgentSessionSurface` already uses, which brings the pane
back to 996. Behaviour-preserving: the panel and both of its presentations
are byte-equivalent to the inline version, and the per-presentation React
keys stay on `AnimatePresence`'s direct child rather than moving inside the
new component, so the cover drawer and the split pane keep the distinct
enter/exit identities main gave them.

Co-authored-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
Signed-off-by: ss-dev-00 <a02c4e0850e5e612b4ddf95dbe2f5c56467cf27c6552203bc833ff438fb31971@buzz.block.builderlab.xyz>
This commit is contained in:
ss-dev-00
2026-08-26 15:37:40 -07:00
parent 403de26214
commit 8cea5e15ef
2 changed files with 112 additions and 32 deletions

View File

@@ -0,0 +1,86 @@
import type * as React from "react";
import { FocusThreadDrawer } from "@/features/channels/ui/FocusThreadDrawer";
import {
IdleAuxiliaryPanel,
type IdleAuxiliaryHeaderControls,
} from "@/features/channels/ui/IdleAuxiliaryPanel";
type ChannelIdleAuxiliarySurfaceProps = {
canResetWidth: boolean;
channelName: string;
children: React.ReactNode;
headerControls?: IdleAuxiliaryHeaderControls;
/** Render the panel inside the cover drawer instead of the split pane. */
isCoverDrawer: boolean;
isSinglePanelView: boolean;
onClose: () => void;
onResetWidth: () => void;
onResizeStart: React.PointerEventHandler<HTMLButtonElement>;
title: string;
useSplitAuxiliaryPane: boolean;
widthPx: number;
/**
* Applies the split-pane presentation, including its resize affordances.
* Supplied by `ChannelPane` because that pane owns the resize state; the
* cover-drawer presentation is applied here.
*/
wrapSplitPane: (panel: React.ReactNode) => React.ReactNode;
};
/**
* The channel's caller-owned idle auxiliary surface, in whichever presentation
* was resolved for it.
*
* Split out of `ChannelPane` alongside `ChannelAgentSessionSurface` so each
* auxiliary surface owns its own presentation wiring rather than adding another
* pair of closures to that component.
*
* It reuses `FocusThreadDrawer` rather than `CoverDrawer` directly, so the two
* cover presentations stay one surface with one test id; only the accessible
* label differs, which is why that label is a prop on the thread drawer.
*/
export function ChannelIdleAuxiliarySurface({
canResetWidth,
channelName,
children,
headerControls,
isCoverDrawer,
isSinglePanelView,
onClose,
onResetWidth,
onResizeStart,
title,
useSplitAuxiliaryPane,
widthPx,
wrapSplitPane,
}: ChannelIdleAuxiliarySurfaceProps) {
const panel = (
<IdleAuxiliaryPanel
canResetWidth={canResetWidth}
headerControls={headerControls}
isFocusDrawer={isCoverDrawer}
isSinglePanelView={isSinglePanelView}
onClose={onClose}
onResetWidth={onResetWidth}
onResizeStart={onResizeStart}
title={title}
useSplitAuxiliaryPane={useSplitAuxiliaryPane}
widthPx={widthPx}
>
{children}
</IdleAuxiliaryPanel>
);
return isCoverDrawer ? (
<FocusThreadDrawer
channelName={channelName}
label={title || "Panel"}
onClose={onClose}
>
{panel}
</FocusThreadDrawer>
) : (
wrapSplitPane(panel)
);
}

View File

@@ -27,10 +27,10 @@ import { buildVideoReviewPresentationByMessageId } from "@/features/messages/lib
import { useComposerHeightPadding } from "@/features/messages/ui/useComposerHeightPadding";
import { UserProfilePanel } from "@/features/profile/ui/UserProfilePanel";
import { ChannelManagementAuxiliaryPanel } from "@/features/channels/ui/ChannelManagementAuxiliaryPanel";
import { IdleAuxiliaryPanel } from "@/features/channels/ui/IdleAuxiliaryPanel";
import { RightAuxiliaryPane } from "@/features/channels/ui/RightAuxiliaryPane";
import { ThreadViewModeToggle } from "@/features/channels/ui/ThreadViewModeToggle";
import { ChannelAgentSessionSurface } from "@/features/channels/ui/ChannelAgentSessionSurface";
import { ChannelIdleAuxiliarySurface } from "@/features/channels/ui/ChannelIdleAuxiliarySurface";
import { FocusThreadDrawer } from "@/features/channels/ui/FocusThreadDrawer";
import { AGENT_SESSION_SURFACE_KEY } from "@/features/channels/lib/agentSessionPanelPresentation";
import {
@@ -540,38 +540,32 @@ export const ChannelPane = React.memo(function ChannelPane({
) : (
wrapAux(panel, "message-thread-panel", { key: THREAD_SURFACE_KEY })
);
const wrapIdlePanel = (panel: React.ReactNode) =>
useFocusIdleDrawer && onCloseIdleAuxiliaryPanel ? (
<FocusThreadDrawer
channelName={activeChannel?.name ?? "channel"}
key="idle-auxiliary-surface"
label={idleAuxiliaryTitle || "Panel"}
onClose={onCloseIdleAuxiliaryPanel}
>
{panel}
</FocusThreadDrawer>
) : (
wrapAux(panel, "idle-auxiliary-panel")
);
const idleAuxiliarySurface =
idleAuxiliaryPanel && onCloseIdleAuxiliaryPanel
? wrapIdlePanel(
<IdleAuxiliaryPanel
canResetWidth={canResetThreadPanelWidth}
headerControls={idleAuxiliaryHeaderActions}
isFocusDrawer={useFocusIdleDrawer}
isSinglePanelView={isSinglePanelView}
onClose={onCloseIdleAuxiliaryPanel}
onResetWidth={onResetThreadPanelWidth}
onResizeStart={onThreadPanelResizeStart}
title={idleAuxiliaryTitle}
useSplitAuxiliaryPane={useSplitAuxiliaryPane}
widthPx={threadPanelWidthPx}
>
{idleAuxiliaryPanel}
</IdleAuxiliaryPanel>,
)
: null;
idleAuxiliaryPanel && onCloseIdleAuxiliaryPanel ? (
<ChannelIdleAuxiliarySurface
// Keyed here, on `AnimatePresence`'s direct child, and deliberately
// per-presentation: the cover drawer and the split pane were distinct
// keys before this surface was extracted, so a viewport change that
// flips the presentation remounts exactly as it did then.
key={
useFocusIdleDrawer ? "idle-auxiliary-surface" : "idle-auxiliary-panel"
}
canResetWidth={canResetThreadPanelWidth}
channelName={activeChannel?.name ?? "channel"}
headerControls={idleAuxiliaryHeaderActions}
isCoverDrawer={useFocusIdleDrawer}
isSinglePanelView={isSinglePanelView}
onClose={onCloseIdleAuxiliaryPanel}
onResetWidth={onResetThreadPanelWidth}
onResizeStart={onThreadPanelResizeStart}
title={idleAuxiliaryTitle}
useSplitAuxiliaryPane={useSplitAuxiliaryPane}
widthPx={threadPanelWidthPx}
wrapSplitPane={(panel) => wrapAux(panel, "idle-auxiliary-panel")}
>
{idleAuxiliaryPanel}
</ChannelIdleAuxiliarySurface>
) : null;
const wrapAgentSessionSplitPane = (panel: React.ReactNode) =>
wrapAux(panel, "agent-session-thread-panel", {
key: AGENT_SESSION_SURFACE_KEY,