diff --git a/apps/web/src/components/SidebarV2.tsx b/apps/web/src/components/SidebarV2.tsx index 1444d72e60c..e0452b1c87d 100644 --- a/apps/web/src/components/SidebarV2.tsx +++ b/apps/web/src/components/SidebarV2.tsx @@ -1586,10 +1586,18 @@ export default function SidebarV2() { [projectGroupingSettings.sidebarProjectGroupingOverrides, updateSettings], ); + // On macOS, Ctrl+click fires contextmenu and Safari then also fires click on + // the same element, which would activate the radio item and change the scope + // underneath the settings dialog. stopPropagation on contextmenu cannot block + // that separate click, so the next scope change is suppressed instead. The + // flag clears when the menu reopens, and a real selection always starts by + // reopening the menu, so it can never swallow one. + const suppressNextScopeChangeRef = useRef(false); const handleProjectActions = useCallback( - (event: ReactMouseEvent, projectGroup: SidebarProjectSnapshot) => { + (event: ReactMouseEvent, projectGroup: SidebarProjectSnapshot) => { event.preventDefault(); event.stopPropagation(); + suppressNextScopeChangeRef.current = true; setProjectScopeMenuOpen(false); window.requestAnimationFrame(() => setProjectActionsTarget(projectGroup)); }, @@ -2783,7 +2791,13 @@ export default function SidebarV2() { {projectGroups.length > 0 ? (
- + { + if (open) suppressNextScopeChangeRef.current = false; + setProjectScopeMenuOpen(open); + }} + > - setProjectScopeKey(value === "all" ? null : (value as string)) - } + onValueChange={(value) => { + if (suppressNextScopeChangeRef.current) { + suppressNextScopeChangeRef.current = false; + return; + } + setProjectScopeKey(value === "all" ? null : (value as string)); + }} > { + void handleProjectActions(event, project); + }} > {project.displayName} + {/* Mouse-only affordance: hidden from AT because interactive children + are invalid inside menuitemradio and pollute its accessible name. + Keyboard/AT path is Shift+F10 (contextmenu) on the item itself. */}