-
Notifications
You must be signed in to change notification settings - Fork 66.9k
Expand file tree
/
Copy pathSearchBarButton.tsx
More file actions
100 lines (91 loc) · 3.3 KB
/
SearchBarButton.tsx
File metadata and controls
100 lines (91 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import cx from 'classnames'
import { IconButton } from '@primer/react'
import { CopilotIcon, SearchIcon } from '@primer/octicons-react'
import { useTranslation } from 'src/languages/components/useTranslation'
import { QueryParams } from '@/search/components/hooks/useMultiQueryParams'
import { useCTAPopoverContext } from '@/frame/components/context/CTAContext'
import styles from './SearchBarButton.module.scss'
import { AISearchCTAPopup } from './AISearchCTAPopup'
type Props = {
isSearchOpen: boolean
setIsSearchOpen: (value: boolean) => void
params: QueryParams
searchButtonRef: React.RefObject<HTMLButtonElement>
}
export function SearchBarButton({ isSearchOpen, setIsSearchOpen, params, searchButtonRef }: Props) {
const { t } = useTranslation('search')
const { isOpen, dismiss } = useCTAPopoverContext()
const urlSearchInputQuery = params['search-overlay-input']
// Handle click events
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
setIsSearchOpen(true)
}
// Handle key down events
const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
if (event.key === 'Enter' || event.key === 'Space') {
event.preventDefault()
setIsSearchOpen(true)
} else if (event.key === 'Escape') {
event.preventDefault()
setIsSearchOpen(false)
}
}
const placeHolderElements = t('search.input.placeholder')
.split(/({{[^}]+}})/)
.filter((item) => item.trim() !== '')
.map((item) => <>{item.trim()}</>)
placeHolderElements[1] = <CopilotIcon aria-hidden className="mr-1 ml-1" />
return (
<>
{/* We don't want to show the input when overlay is open */}
{!isSearchOpen ? (
<>
<AISearchCTAPopup isOpen={isOpen} dismiss={dismiss} />
{/* On mobile only the IconButton is shown */}
<IconButton
data-testid="mobile-search-button"
ref={searchButtonRef}
className={styles.searchIconButton}
onClick={handleClick}
tabIndex={0}
aria-label={t('search.input.aria_label')}
icon={SearchIcon}
/>
{/* On large and up the SearchBarButton is shown */}
<button
data-testid="search"
tabIndex={0}
aria-label={t`search.input.aria_label`}
className={styles.searchInputButton}
onKeyDown={handleKeyDown}
onClick={handleClick}
ref={searchButtonRef}
>
{/* Styled to look like an input */}
<div
className={cx('d-flex align-items-center flex-grow-1', styles.searchInputContainer)}
aria-hidden
tabIndex={-1}
>
<span
className={cx(styles.queryText, !urlSearchInputQuery ? styles.placeholder : null)}
>
{urlSearchInputQuery ? (
urlSearchInputQuery
) : (
<>
<span className={styles.placeholderText}>{placeHolderElements}</span>
</>
)}
</span>
</div>
<span className={styles.searchIconContainer} aria-hidden tabIndex={-1}>
<SearchIcon />
</span>
</button>
</>
) : null}
</>
)
}