| author | |
| committer | |
| log | 77138cf33194a303adfbbd69cc93efa69f84245d |
| tree | fcc15483469abf1455334f3e2d802add58bc6332 |
| parent | 0869ad648b67a286d7a47af878f1d256d0ff689f |
| signature | Signed by PGP key B5690EEEBB952194 |
7 files changed, 23 insertions(+), 7 deletions(-)
apps/web/src/components/BranchToolbar.tsx+2-1| ... | ... | @@ -40,6 +40,7 @@ import { |
| 40 | 40 | } from "./ui/menu"; |
| 41 | 41 | import { Separator } from "./ui/separator"; |
| 42 | 42 | import { ComposerSurface } from "./chat/ComposerSurface"; |
| 43 | import { composerFloatingLayerProps } from "./chat/composerEventScope"; | |
| 43 | 44 | import { measureRestingComposerControls } from "./chat/restingComposerControlsMeasurement"; |
| 44 | 45 | import { resolveRestingComposerControlsNaturalWidth } from "./composerFooterLayout"; |
| 45 | 46 | import { cn } from "~/lib/utils"; |
| ... | ... | @@ -160,7 +161,7 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({ |
| 160 | 161 | {triggerContent} |
| 161 | 162 | <ChevronDownIcon className="size-3 shrink-0 opacity-50" /> |
| 162 | 163 | </MenuTrigger> |
| 163 | <MenuPopup align="start" side="top" className="w-64"> | |
| 164 | <MenuPopup align="start" side="top" className="w-64" {...composerFloatingLayerProps}> | |
| 164 | 165 | {showEnvironmentPicker && availableEnvironments && onEnvironmentChange ? ( |
| 165 | 166 | <> |
| 166 | 167 | <MenuGroup> |
apps/web/src/components/BranchToolbarBranchSelector.tsx+7-1| ... | ... | @@ -34,6 +34,7 @@ import { vcsEnvironment } from "../state/vcs"; |
| 34 | 34 | import { cn } from "../lib/utils"; |
| 35 | 35 | import { parsePullRequestReference } from "../pullRequestReference"; |
| 36 | 36 | import { getSourceControlPresentation } from "../sourceControlPresentation"; |
| 37 | import { composerFloatingLayerProps } from "./chat/composerEventScope"; | |
| 37 | 38 | import { |
| 38 | 39 | deriveLocalBranchNameFromRemoteRef, |
| 39 | 40 | resolveBranchTriggerLabel, |
| ... | ... | @@ -788,7 +789,12 @@ export function BranchToolbarBranchSelector({ |
| 788 | 789 | </ComboboxTrigger> |
| 789 | 790 | </span> |
| 790 | 791 | </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 | > | |
| 792 | 798 | <div className="shrink-0 px-3 pt-2.5"> |
| 793 | 799 | <div className="relative -translate-y-px border-b border-border/70 pb-1.5 transition-colors focus-within:border-ring"> |
| 794 | 800 | <SearchIcon |
apps/web/src/components/BranchToolbarEnvModeSelector.tsx+2-1| ... | ... | @@ -7,6 +7,7 @@ import { |
| 7 | 7 | resolveLockedWorkspaceLabel, |
| 8 | 8 | type EnvMode, |
| 9 | 9 | } from "./BranchToolbar.logic"; |
| 10 | import { composerFloatingLayerProps } from "./chat/composerEventScope"; | |
| 10 | 11 | import { |
| 11 | 12 | Select, |
| 12 | 13 | SelectGroup, |
| ... | ... | @@ -113,7 +114,7 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe |
| 113 | 114 | </span> |
| 114 | 115 | </span> |
| 115 | 116 | </SelectTrigger> |
| 116 | <SelectPopup> | |
| 117 | <SelectPopup {...composerFloatingLayerProps}> | |
| 117 | 118 | <SelectGroup> |
| 118 | 119 | <SelectGroupLabel>Workspace</SelectGroupLabel> |
| 119 | 120 | <SelectItem value="local"> |
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx+2-1| ... | ... | @@ -3,6 +3,7 @@ import { memo, useMemo } from "react"; |
| 3 | 3 | |
| 4 | 4 | import type { EnvironmentOption } from "./BranchToolbar.logic"; |
| 5 | 5 | import { EnvironmentMachineIcon } from "./EnvironmentMachineIcon"; |
| 6 | import { composerFloatingLayerProps } from "./chat/composerEventScope"; | |
| 6 | 7 | import { |
| 7 | 8 | Select, |
| 8 | 9 | SelectGroup, |
| ... | ... | @@ -101,7 +102,7 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir |
| 101 | 102 | </span> |
| 102 | 103 | </span> |
| 103 | 104 | </SelectTrigger> |
| 104 | <SelectPopup> | |
| 105 | <SelectPopup {...composerFloatingLayerProps}> | |
| 105 | 106 | <SelectGroup> |
| 106 | 107 | <SelectGroupLabel>Run on</SelectGroupLabel> |
| 107 | 108 | {availableEnvironments.map((env) => ( |
apps/web/src/components/chat/ChatComposer.tsx+2-3| ... | ... | @@ -4283,7 +4283,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) |
| 4283 | 4283 | const composerSurface = composerSurfaceRef.current; |
| 4284 | 4284 | const composerForm = composerFormRef.current; |
| 4285 | 4285 | const activeElement = document.activeElement; |
| 4286 | if (activeElement instanceof Element && isInsideComposerFloatingLayer(activeElement)) { | |
| 4286 | if (isInsideRestingComposerControlScope(activeElement)) { | |
| 4287 | 4287 | return; |
| 4288 | 4288 | } |
| 4289 | 4289 | if ( |
| ... | ... | @@ -4303,8 +4303,7 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) |
| 4303 | 4303 | const isInsideDesktopComposerFocusScope = (target: EventTarget | null) => |
| 4304 | 4304 | Boolean( |
| 4305 | 4305 | target instanceof Node && |
| 4306 | (composerFormRef.current?.contains(target) || | |
| 4307 | (target instanceof Element && isInsideComposerFloatingLayer(target))), | |
| 4306 | (composerFormRef.current?.contains(target) || isInsideRestingComposerControlScope(target)), | |
| 4308 | 4307 | ); |
| 4309 | 4308 | const handleFocusIn = (event: FocusEvent) => { |
| 4310 | 4309 | if (!isInsideDesktopComposerFocusScope(event.target)) { |
apps/web/src/components/chat/composerEventScope.test.ts+7| ... | ... | @@ -29,6 +29,13 @@ describe("composer event scopes", () => { |
| 29 | 29 | expect(isInsideRestingComposerControlScope(target as unknown as EventTarget)).toBe(true); |
| 30 | 30 | }); |
| 31 | 31 | |
| 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 | ||
| 32 | 39 | it("keeps resting image previews focused without expanding their subtree", () => { |
| 33 | 40 | vi.stubGlobal("Element", FakeElement); |
| 34 | 41 |
apps/web/src/components/chat/composerEventScope.ts+1| ... | ... | @@ -26,6 +26,7 @@ export function isInsideRestingComposerControlScope(target: EventTarget | null): |
| 26 | 26 | target instanceof Element && |
| 27 | 27 | (target.closest('[data-chat-composer-resting-controls="true"]') !== null || |
| 28 | 28 | target.closest('[data-chat-composer-resting-images="true"]') !== null || |
| 29 | target.closest("[data-composer-context-control]") !== null || | |
| 29 | 30 | isInsideComposerFloatingLayer(target)) |
| 30 | 31 | ); |
| 31 | 32 | } |