@@ -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,23 +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- virtualized
239- listState = { state }
240- hasSearch = { ! ! state . inputValue }
241- overlayIsOpen = { state . isOpen }
242- { ...listBoxProps }
243- style = { { maxHeight : 320 , minHeight : 132 } }
244- >
245- { props . children }
246- </ 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+ ) }
247256 </ StyledOverlay >
248257 ) }
249258 </ StorySearchContainer >
250259 ) ;
251260}
252261
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+
253282const StorySearchContainer = styled ( 'div' ) `
254283 position: relative;
255284 width: 320px;
@@ -259,23 +288,21 @@ const StorySearchContainer = styled('div')`
259288` ;
260289
261290const StyledOverlay = styled ( Overlay ) `
262- overflow: hidden;
263- position: fixed;
264- top: 48px;
265- left: 256px;
291+ position: absolute;
292+ top: 100%;
293+ left: 0;
266294 width: 320px;
267295
268- max-height: 320px;
269- min-height: 132px;
270- > div {
271- max-height: 320px !important;
272- min-height: 132px !important;
273- }
274-
275296 /* Make section headers darker in this component */
276297 p[id][aria-hidden='true'] {
277298 color: ${ p => p . theme . tokens . content . primary } ;
278299 }
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+ }
279306` ;
280307
281308function getStoryTreeNodeFromKey (
0 commit comments