@@ -13,7 +13,7 @@ import {
1313 PopoverContent ,
1414 PopoverTrigger ,
1515} from "@deco/ui/components/popover.tsx" ;
16- import { Check , Plus , SearchMd , XClose } from "@untitledui/icons" ;
16+ import { Check , Plus , SearchMd } from "@untitledui/icons" ;
1717import { cn } from "@deco/ui/lib/utils.ts" ;
1818import { useActiveOrganizations } from "@/web/lib/auth-client" ;
1919import { CreateOrganizationDialog } from "@/web/components/create-organization-dialog" ;
@@ -82,7 +82,6 @@ function OrganizationsPanel({
8282 return a . name . localeCompare ( b . name ) ;
8383 } ) ;
8484
85- const [ searchOpen , setSearchOpen ] = useState ( false ) ;
8685 const [ query , setQuery ] = useState ( "" ) ;
8786
8887 const q = query . toLowerCase ( ) ;
@@ -96,37 +95,24 @@ function OrganizationsPanel({
9695 const iconBtnClass =
9796 "flex items-center justify-center size-7 rounded-md text-muted-foreground hover:bg-accent/50 hover:text-foreground transition-colors" ;
9897
99- function toggleSearch ( ) {
100- if ( searchOpen ) setQuery ( "" ) ;
101- setSearchOpen ( ( prev ) => ! prev ) ;
102- }
103-
10498 return (
10599 < >
106- < div className = "flex items-center justify-between px-4 py-3" >
107- { searchOpen ? (
108- < input
109- autoFocus
110- type = "text"
111- value = { query }
112- onChange = { ( e ) => setQuery ( e . target . value ) }
113- onKeyDown = { ( e ) => e . key === "Escape" && toggleSearch ( ) }
114- placeholder = "Search organizations..."
115- className = "flex-1 min-w-0 bg-transparent text-sm outline-none placeholder:text-muted-foreground/60"
116- />
117- ) : (
118- < span className = "text-sm font-medium text-muted-foreground/60" >
119- Your Organizations
120- </ span >
121- ) }
122- < div className = "flex items-center gap-1 shrink-0" >
123- < button type = "button" onClick = { toggleSearch } className = { iconBtnClass } >
124- { searchOpen ? < XClose size = { 16 } /> : < SearchMd size = { 16 } /> }
125- </ button >
126- < button type = "button" onClick = { onCreateOrg } className = { iconBtnClass } >
127- < Plus size = { 16 } />
128- </ button >
129- </ div >
100+ { /* Search is always live and focused on open — start typing to filter. */ }
101+ < div className = "flex items-center gap-2 px-3 py-2.5 border-b border-border/50" >
102+ < SearchMd size = { 16 } className = "shrink-0 text-muted-foreground/60" />
103+ < input
104+ data-org-switcher-search
105+ autoFocus
106+ type = "text"
107+ value = { query }
108+ onChange = { ( e ) => setQuery ( e . target . value ) }
109+ onKeyDown = { ( e ) => e . key === "Escape" && query && setQuery ( "" ) }
110+ placeholder = "Search organizations..."
111+ className = "flex-1 min-w-0 bg-transparent text-sm outline-none placeholder:text-muted-foreground/60"
112+ />
113+ < button type = "button" onClick = { onCreateOrg } className = { iconBtnClass } >
114+ < Plus size = { 16 } />
115+ </ button >
130116 </ div >
131117 < div className = "flex-1 min-h-0 overflow-y-auto p-1.5 flex flex-col gap-1" >
132118 { filtered . length === 0 && (
@@ -198,6 +184,14 @@ export function OrgSwitcherPopover({
198184 sideOffset = { 8 }
199185 collisionPadding = { 16 }
200186 className = "w-[300px] p-0 flex flex-col max-h-[440px]"
187+ // Land focus on the search field (not the content wrapper) so typing
188+ // filters immediately.
189+ onOpenAutoFocus = { ( e ) => {
190+ e . preventDefault ( ) ;
191+ ( e . currentTarget as HTMLElement )
192+ ?. querySelector < HTMLInputElement > ( "[data-org-switcher-search]" )
193+ ?. focus ( ) ;
194+ } }
201195 onCloseAutoFocus = { ( e ) => e . preventDefault ( ) }
202196 >
203197 < OrganizationsPanel
0 commit comments