1- import { useState , useRef , useMemo , useCallback , useEffect } from "react" ;
1+ import { useState , useMemo , useCallback , useEffect } from "react" ;
22import { Command } from "cmdk" ;
33import { observer } from "mobx-react" ;
44import { useParams } from "next/navigation" ;
55// hooks
6- import { useOutsideClickDetector } from "@plane/hooks" ;
76import { CloseIcon , SearchIcon } from "@plane/propel/icons" ;
87import { cn } from "@plane/utils" ;
98// power-k
@@ -14,6 +13,7 @@ import { useIssueDetail } from "@/hooks/store/use-issue-detail";
1413import { usePowerK } from "@/hooks/store/use-power-k" ;
1514import { useUser } from "@/hooks/store/user" ;
1615import { useAppRouter } from "@/hooks/use-app-router" ;
16+ import { useExpandableSearch } from "@/hooks/use-expandable-search" ;
1717
1818export const TopNavPowerK = observer ( ( ) => {
1919 // router
@@ -22,7 +22,6 @@ export const TopNavPowerK = observer(() => {
2222 const { projectId : routerProjectId , workItem : workItemIdentifier } = params ;
2323
2424 // states
25- const [ isOpen , setIsOpen ] = useState ( false ) ;
2625 const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
2726 const [ activeCommand , setActiveCommand ] = useState < TPowerKCommandConfig | null > ( null ) ;
2827 const [ shouldShowContextBasedActions , setShouldShowContextBasedActions ] = useState ( true ) ;
@@ -32,6 +31,25 @@ export const TopNavPowerK = observer(() => {
3231 const { activeContext, setActivePage, activePage, setTopNavInputRef } = usePowerK ( ) ;
3332 const { data : currentUser } = useUser ( ) ;
3433
34+ const handleOnClose = useCallback ( ( ) => {
35+ setSearchTerm ( "" ) ;
36+ setActivePage ( null ) ;
37+ setActiveCommand ( null ) ;
38+ } , [ setSearchTerm , setActivePage , setActiveCommand ] ) ;
39+
40+ // expandable search hook
41+ const {
42+ isOpen,
43+ containerRef,
44+ inputRef,
45+ handleClose : closePanel ,
46+ handleMouseDown,
47+ handleFocus,
48+ openPanel,
49+ } = useExpandableSearch ( {
50+ onClose : handleOnClose ,
51+ } ) ;
52+
3553 // derived values
3654 const {
3755 issue : { getIssueById, getIssueIdByIdentifier } ,
@@ -54,12 +72,7 @@ export const TopNavPowerK = observer(() => {
5472 projectId,
5573 } ,
5674 router,
57- closePalette : ( ) => {
58- setIsOpen ( false ) ;
59- setSearchTerm ( "" ) ;
60- setActivePage ( null ) ;
61- setActiveCommand ( null ) ;
62- } ,
75+ closePalette : closePanel ,
6376 setActiveCommand,
6477 setActivePage,
6578 } ) ,
@@ -72,12 +85,10 @@ export const TopNavPowerK = observer(() => {
7285 projectId ,
7386 router ,
7487 setActivePage ,
88+ closePanel ,
7589 ]
7690 ) ;
7791
78- const containerRef = useRef < HTMLDivElement > ( null ) ;
79- const inputRef = useRef < HTMLInputElement > ( null ) ;
80-
8192 // Register input ref with PowerK store for keyboard shortcut access
8293 useEffect ( ( ) => {
8394 setTopNavInputRef ( inputRef ) ;
@@ -86,18 +97,6 @@ export const TopNavPowerK = observer(() => {
8697 } ;
8798 } , [ setTopNavInputRef ] ) ;
8899
89- useOutsideClickDetector ( containerRef , ( ) => {
90- if ( isOpen ) {
91- setIsOpen ( false ) ;
92- setActivePage ( null ) ;
93- setActiveCommand ( null ) ;
94- }
95- } ) ;
96-
97- const handleFocus = ( ) => {
98- setIsOpen ( true ) ;
99- } ;
100-
101100 const handleClear = ( ) => {
102101 setSearchTerm ( "" ) ;
103102 inputRef . current ?. focus ( ) ;
@@ -136,10 +135,7 @@ export const TopNavPowerK = observer(() => {
136135 // Cmd/Ctrl+K closes the search dropdown
137136 if ( ( e . metaKey || e . ctrlKey ) && e . key . toLowerCase ( ) === "k" ) {
138137 e . preventDefault ( ) ;
139- setIsOpen ( false ) ;
140- setSearchTerm ( "" ) ;
141- setActivePage ( null ) ;
142- context . setActiveCommand ( null ) ;
138+ closePanel ( ) ;
143139 return ;
144140 }
145141
@@ -148,9 +144,7 @@ export const TopNavPowerK = observer(() => {
148144 if ( searchTerm ) {
149145 setSearchTerm ( "" ) ;
150146 }
151- setIsOpen ( false ) ;
152- inputRef . current ?. blur ( ) ;
153-
147+ closePanel ( ) ;
154148 return ;
155149 }
156150
@@ -203,7 +197,7 @@ export const TopNavPowerK = observer(() => {
203197 return ;
204198 }
205199 } ,
206- [ searchTerm , activePage , context , shouldShowContextBasedActions , setActivePage , isOpen ]
200+ [ searchTerm , activePage , context , shouldShowContextBasedActions , setActivePage , closePanel ]
207201 ) ;
208202
209203 return (
@@ -228,7 +222,11 @@ export const TopNavPowerK = observer(() => {
228222 ref = { inputRef }
229223 type = "text"
230224 value = { searchTerm }
231- onChange = { ( e ) => setSearchTerm ( e . target . value ) }
225+ onChange = { ( e ) => {
226+ setSearchTerm ( e . target . value ) ;
227+ if ( ! isOpen ) openPanel ( ) ;
228+ } }
229+ onMouseDown = { handleMouseDown }
232230 onFocus = { handleFocus }
233231 onKeyDown = { handleKeyDown }
234232 placeholder = "Search commands..."
0 commit comments