diff --git a/apps/web/core/components/navigation/top-nav-power-k.tsx b/apps/web/core/components/navigation/top-nav-power-k.tsx index 054aceaf3..aeb02f3ef 100644 --- a/apps/web/core/components/navigation/top-nav-power-k.tsx +++ b/apps/web/core/components/navigation/top-nav-power-k.tsx @@ -272,6 +272,7 @@ export const TopNavPowerK = observer(() => { isWorkspaceLevel={isWorkspaceLevel} searchTerm={searchTerm} setSearchTerm={setSearchTerm} + handleSearchMenuClose={() => closePanel()} /> void; + handleSearchMenuClose?: () => void; }; export function ProjectsAppPowerKCommandsList(props: TPowerKCommandsListProps) { @@ -22,6 +23,7 @@ export function ProjectsAppPowerKCommandsList(props: TPowerKCommandsListProps) { isWorkspaceLevel, searchTerm, setSearchTerm, + handleSearchMenuClose, } = props; return ( @@ -32,6 +34,7 @@ export function ProjectsAppPowerKCommandsList(props: TPowerKCommandsListProps) { isWorkspaceLevel={!context.params.projectId || isWorkspaceLevel} searchTerm={searchTerm} updateSearchTerm={setSearchTerm} + handleSearchMenuClose={handleSearchMenuClose} /> void; + handleSearchMenuClose?: () => void; }; export function PowerKModalSearchMenu(props: Props) { - const { activePage, context, isWorkspaceLevel, searchTerm, updateSearchTerm } = props; + const { activePage, context, isWorkspaceLevel, searchTerm, updateSearchTerm, handleSearchMenuClose } = props; // states const [resultsCount, setResultsCount] = useState(0); const [isSearching, setIsSearching] = useState(false); @@ -68,6 +69,11 @@ export function PowerKModalSearchMenu(props: Props) { if (activePage) return null; + const handleClosePalette = () => { + handleSearchMenuClose?.(); + togglePowerKModal(false); + }; + return ( <> {searchTerm.trim() !== "" && ( @@ -97,9 +103,7 @@ export function PowerKModalSearchMenu(props: Props) { /> )} - {searchTerm.trim() !== "" && ( - togglePowerKModal(false)} results={results} /> - )} + {searchTerm.trim() !== "" && } ); } diff --git a/apps/web/core/hooks/use-expandable-search.ts b/apps/web/core/hooks/use-expandable-search.ts index 583a35c3c..3b9c38068 100644 --- a/apps/web/core/hooks/use-expandable-search.ts +++ b/apps/web/core/hooks/use-expandable-search.ts @@ -1,4 +1,4 @@ -import { useCallback, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useOutsideClickDetector } from "@plane/hooks"; type UseExpandableSearchOptions = { @@ -8,6 +8,7 @@ type UseExpandableSearchOptions = { /** * Custom hook for expandable search input behavior * Handles focus management to prevent unwanted opening on programmatic focus restoration + * Opens on click, typing, or keyboard shortcut (via PowerK Cmd+F) */ export const useExpandableSearch = (options?: UseExpandableSearchOptions) => { const { onClose } = options || {}; @@ -19,6 +20,7 @@ export const useExpandableSearch = (options?: UseExpandableSearchOptions) => { const containerRef = useRef(null); const inputRef = useRef(null); const wasClickedRef = useRef(false); + const wasKeyboardTriggeredRef = useRef(false); // Handle close const handleClose = useCallback(() => { @@ -37,16 +39,32 @@ export const useExpandableSearch = (options?: UseExpandableSearchOptions) => { // Outside click detection useOutsideClickDetector(containerRef, handleOutsideClick); + // Track keyboard shortcuts that trigger focus (Cmd+F / Ctrl+F) + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if ((e.metaKey || e.ctrlKey) && e.key === "f") { + // Mark as keyboard triggered so handleFocus knows to open + wasKeyboardTriggeredRef.current = true; + } + }; + + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, []); + // Track explicit clicks const handleMouseDown = useCallback(() => { wasClickedRef.current = true; }, []); - // Only open on explicit clicks, not programmatic focus + // Open on explicit clicks or keyboard shortcut, not programmatic focus restoration const handleFocus = useCallback(() => { - if (wasClickedRef.current) { + if (wasClickedRef.current || wasKeyboardTriggeredRef.current) { setIsOpen(true); wasClickedRef.current = false; + wasKeyboardTriggeredRef.current = false; } }, []);