@@ -34,6 +34,9 @@ interface OrganizationPageProps {
3434 tabs ?: readonly OrganizationPageTab [ ]
3535 /** The page's primary action, a chip. Omit for a page without one. */
3636 action ?: ReactNode
37+ /** Keep the search field visible on pages whose main content is a searchable list. */
38+ searchMode ?: 'collapsible' | 'expanded'
39+ searchPlaceholder ?: string
3740 children ?: ReactNode
3841}
3942
@@ -53,6 +56,8 @@ export function OrganizationPage({
5356 description,
5457 tabs,
5558 action,
59+ searchMode = 'collapsible' ,
60+ searchPlaceholder = 'Search' ,
5661 children,
5762} : OrganizationPageProps ) {
5863 const scrollContainerRef = useRef < HTMLDivElement > ( null )
@@ -71,7 +76,7 @@ export function OrganizationPage({
7176 * viewer opened and has not dismissed.
7277 */
7378 const [ searchOpened , setSearchOpened ] = useState ( false )
74- const searchOpen = searchOpened || search . length > 0
79+ const searchOpen = searchMode === 'expanded' || searchOpened || search . length > 0
7580
7681 const closeSearch = ( ) => {
7782 setSearch ( '' )
@@ -99,7 +104,8 @@ export function OrganizationPage({
99104 ref = { tabsRef }
100105 className = { cn (
101106 scrollFadeXClass ,
102- 'flex min-w-0 flex-1 items-center gap-[1px] overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden'
107+ 'flex min-w-0 flex-1 items-center gap-[1px] overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden' ,
108+ searchMode === 'expanded' && ! tabs ?. length && 'hidden'
103109 ) }
104110 { ...scrollFadeAttributes ( tabEdges ) }
105111 >
@@ -119,32 +125,39 @@ export function OrganizationPage({
119125 )
120126 } ) }
121127 </ div >
122- < div className = 'flex shrink-0 items-center gap-1.5' >
128+ < div
129+ className = { cn (
130+ 'flex items-center gap-1.5' ,
131+ searchMode === 'expanded' ? 'min-w-0 flex-1' : 'shrink-0'
132+ ) }
133+ >
123134 { searchOpen ? (
124135 < ChipInput
125- autoFocus
136+ autoFocus = { searchMode === 'collapsible' }
126137 icon = { Search }
127138 value = { search }
128- placeholder = 'Search'
139+ placeholder = { searchPlaceholder }
129140 aria-label = 'Search'
130141 spellCheck = { false }
131142 autoComplete = 'off'
132- className = 'w- [240px]'
143+ className = { searchMode === 'expanded' ? 'w-full' : 'w- [240px]'}
133144 onChange = { ( event ) => setSearch ( event . target . value ) }
134145 onKeyDown = { ( event ) => {
135146 if ( event . key === 'Escape' ) closeSearch ( )
136147 } }
137148 endAdornment = {
138- < Button
139- type = 'button'
140- variant = 'quiet'
141- size = 'icon'
142- className = '-mr-1 shrink-0'
143- aria-label = 'Close search'
144- onClick = { closeSearch }
145- >
146- < X className = 'size-[14px]' />
147- </ Button >
149+ ( searchMode === 'collapsible' || search . length > 0 ) && (
150+ < Button
151+ type = 'button'
152+ variant = 'quiet'
153+ size = 'icon'
154+ className = '-mr-1 shrink-0'
155+ aria-label = { searchMode === 'expanded' ? 'Clear search' : 'Close search' }
156+ onClick = { closeSearch }
157+ >
158+ < X className = 'size-[14px]' />
159+ </ Button >
160+ )
148161 }
149162 />
150163 ) : (
0 commit comments