authorgravatar for 118054752+extoci@users.noreply.github.comExotic <118054752+extoci@users.noreply.github.com> 2026-09-04 01:23:01+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-03 15:23:01-07:00
log77138cf33194a303adfbbd69cc93efa69f84245d
treefcc15483469abf1455334f3e2d802add58bc6332
parent0869ad648b67a286d7a47af878f1d256d0ff689f
signature Signed by PGP key B5690EEEBB952194

fix(web): dont collapse composer when interacting with bottom row (#9490)


7 files changed, 23 insertions(+), 7 deletions(-)

apps/web/src/components/BranchToolbar.tsx+2-1
......@@ -40,6 +40,7 @@ import {
4040} from "./ui/menu";
4141import { Separator } from "./ui/separator";
4242import { ComposerSurface } from "./chat/ComposerSurface";
43import { composerFloatingLayerProps } from "./chat/composerEventScope";
4344import { measureRestingComposerControls } from "./chat/restingComposerControlsMeasurement";
4445import { resolveRestingComposerControlsNaturalWidth } from "./composerFooterLayout";
4546import { cn } from "~/lib/utils";
......@@ -160,7 +161,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({
160161 {triggerContent}
161162 <ChevronDownIcon className="size-3 shrink-0 opacity-50" />
162163 </MenuTrigger>
163 <MenuPopup align="start" side="top" className="w-64">
164 <MenuPopup align="start" side="top" className="w-64" {...composerFloatingLayerProps}>
164165 {showEnvironmentPicker && availableEnvironments && onEnvironmentChange ? (
165166 <>
166167 <MenuGroup>
apps/web/src/components/BranchToolbarBranchSelector.tsx+7-1
......@@ -34,6 +34,7 @@ import { vcsEnvironment } from "../state/vcs";
3434import { cn } from "../lib/utils";
3535import { parsePullRequestReference } from "../pullRequestReference";
3636import { getSourceControlPresentation } from "../sourceControlPresentation";
37import { composerFloatingLayerProps } from "./chat/composerEventScope";
3738import {
3839 deriveLocalBranchNameFromRemoteRef,
3940 resolveBranchTriggerLabel,
......@@ -788,7 +789,12 @@ export function BranchToolbarBranchSelector({
788789 </ComboboxTrigger>
789790 </span>
790791 </div>
791 <ComboboxPopup align="end" side="top" className="flex w-80 flex-col">
792 <ComboboxPopup
793 align="end"
794 side="top"
795 className="flex w-80 flex-col"
796 {...composerFloatingLayerProps}
797 >
792798 <div className="shrink-0 px-3 pt-2.5">
793799 <div className="relative -translate-y-px border-b border-border/70 pb-1.5 transition-colors focus-within:border-ring">
794800 <SearchIcon
apps/web/src/components/BranchToolbarEnvModeSelector.tsx+2-1
......@@ -7,6 +7,7 @@ import {
77 resolveLockedWorkspaceLabel,
88 type EnvMode,
99} from "./BranchToolbar.logic";
10import { composerFloatingLayerProps } from "./chat/composerEventScope";
1011import {
1112 Select,
1213 SelectGroup,
......@@ -113,7 +114,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe
113114 </span>
114115 </span>
115116 </SelectTrigger>
116 <SelectPopup>
117 <SelectPopup {...composerFloatingLayerProps}>
117118 <SelectGroup>
118119 <SelectGroupLabel>Workspace</SelectGroupLabel>
119120 <SelectItem value="local">
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx+2-1
......@@ -3,6 +3,7 @@ import { memo, useMemo } from "react";
33
44import type { EnvironmentOption } from "./BranchToolbar.logic";
55import { EnvironmentMachineIcon } from "./EnvironmentMachineIcon";
6import { composerFloatingLayerProps } from "./chat/composerEventScope";
67import {
78 Select,
89 SelectGroup,
......@@ -101,7 +102,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir
101102 </span>
102103 </span>
103104 </SelectTrigger>
104 <SelectPopup>
105 <SelectPopup {...composerFloatingLayerProps}>
105106 <SelectGroup>
106107 <SelectGroupLabel>Run on</SelectGroupLabel>
107108 {availableEnvironments.map((env) => (
apps/web/src/components/chat/ChatComposer.tsx+2-3
......@@ -4283,7 +4283,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
42834283 const composerSurface = composerSurfaceRef.current;
42844284 const composerForm = composerFormRef.current;
42854285 const activeElement = document.activeElement;
4286 if (activeElement instanceof Element && isInsideComposerFloatingLayer(activeElement)) {
4286 if (isInsideRestingComposerControlScope(activeElement)) {
42874287 return;
42884288 }
42894289 if (
......@@ -4303,8 +4303,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps)
43034303 const isInsideDesktopComposerFocusScope = (target: EventTarget | null) =>
43044304 Boolean(
43054305 target instanceof Node &&
4306 (composerFormRef.current?.contains(target) ||
4307 (target instanceof Element && isInsideComposerFloatingLayer(target))),
4306 (composerFormRef.current?.contains(target) || isInsideRestingComposerControlScope(target)),
43084307 );
43094308 const handleFocusIn = (event: FocusEvent) => {
43104309 if (!isInsideDesktopComposerFocusScope(event.target)) {
apps/web/src/components/chat/composerEventScope.test.ts+7
......@@ -29,6 +29,13 @@ describe("composer event scopes", () => {
2929 expect(isInsideRestingComposerControlScope(target as unknown as EventTarget)).toBe(true);
3030 });
3131
32 it("recognizes events from the composer context strip controls", () => {
33 vi.stubGlobal("Element", FakeElement);
34
35 const target = new FakeElement("[data-composer-context-control]");
36 expect(isInsideRestingComposerControlScope(target as unknown as EventTarget)).toBe(true);
37 });
38
3239 it("keeps resting image previews focused without expanding their subtree", () => {
3340 vi.stubGlobal("Element", FakeElement);
3441
apps/web/src/components/chat/composerEventScope.ts+1
......@@ -26,6 +26,7 @@ export function isInsideRestingComposerControlScope(target: EventTarget | null):
2626 target instanceof Element &&
2727 (target.closest('[data-chat-composer-resting-controls="true"]') !== null ||
2828 target.closest('[data-chat-composer-resting-images="true"]') !== null ||
29 target.closest("[data-composer-context-control]") !== null ||
2930 isInsideComposerFloatingLayer(target))
3031 );
3132}