@@ -9,6 +9,7 @@ import type {CollectionChildren} from '@react-types/shared';
99import { ListBox } from '@sentry/scraps/compactSelect' ;
1010import { useHotkeys , Hotkey } from '@sentry/scraps/hotkey' ;
1111import { InputGroup } from '@sentry/scraps/input' ;
12+ import { Flex } from '@sentry/scraps/layout' ;
1213import { Text } from '@sentry/scraps/text' ;
1314
1415import { Overlay } from 'sentry/components/overlay' ;
@@ -209,7 +210,7 @@ function SearchComboBox(props: SearchComboBoxProps) {
209210 onInputChange : setInputValue ,
210211 defaultFilter : filter ,
211212 shouldCloseOnBlur : true ,
212- allowsEmptyCollection : false ,
213+ allowsEmptyCollection : true ,
213214 onSelectionChange : handleSelectionChange ,
214215 } ) ;
215216
@@ -233,22 +234,51 @@ function SearchComboBox(props: SearchComboBoxProps) {
233234 < SearchInput ref = { inputRef } placeholder = { props . label } { ...inputProps } />
234235 { state . isOpen && (
235236 < StyledOverlay placement = "bottom-start" ref = { popoverRef } >
236- < ListBox
237- size = "sm"
238- listState = { state }
239- hasSearch = { ! ! state . inputValue }
240- overlayIsOpen = { state . isOpen }
241- { ...listBoxProps }
242- style = { { maxHeight : 320 , minHeight : 64 } }
243- >
244- { props . children }
245- </ ListBox >
237+ { state . collection . size === 0 ? (
238+ inputValue . length === 0 ? (
239+ < SearchEmpty />
240+ ) : (
241+ < SearchNotFound inputValue = { inputValue } />
242+ )
243+ ) : (
244+ < ListBox
245+ size = "sm"
246+ virtualized
247+ listState = { state }
248+ hasSearch = { ! ! state . inputValue }
249+ overlayIsOpen = { state . isOpen }
250+ { ...listBoxProps }
251+ className = "story-search-results"
252+ >
253+ { props . children }
254+ </ ListBox >
255+ ) }
246256 </ StyledOverlay >
247257 ) }
248258 </ StorySearchContainer >
249259 ) ;
250260}
251261
262+ function SearchEmpty ( ) {
263+ return (
264+ < Flex align = "center" justify = "start" padding = "lg" >
265+ < Text variant = "muted" size = "sm" >
266+ { t ( 'Type to search stories...' ) }
267+ </ Text >
268+ </ Flex >
269+ ) ;
270+ }
271+
272+ function SearchNotFound ( { inputValue} : { inputValue : string } ) {
273+ return (
274+ < Flex align = "center" justify = "start" padding = "lg" >
275+ < Text variant = "muted" size = "sm" >
276+ { t ( 'No stories match "%s"' , inputValue ) }
277+ </ Text >
278+ </ Flex >
279+ ) ;
280+ }
281+
252282const StorySearchContainer = styled ( 'div' ) `
253283 position: relative;
254284 width: 320px;
@@ -267,6 +297,12 @@ const StyledOverlay = styled(Overlay)`
267297 p[id][aria-hidden='true'] {
268298 color: ${ p => p . theme . tokens . content . primary } ;
269299 }
300+
301+ .story-search-results {
302+ max-height: 320px;
303+ min-height: 64px;
304+ padding-block-end: calc(${ p => p . theme . space . md } + 1px);
305+ }
270306` ;
271307
272308function getStoryTreeNodeFromKey (
0 commit comments