| import React from 'react' |
| import cx from 'classnames' |
| import { IconButton } from '@primer/react' |
| import { CopilotIcon, SearchIcon } from '@primer/octicons-react' |
|
|
| import { useTranslation } from '@/languages/components/useTranslation' |
| import { QueryParams } from '@/search/components/hooks/useMultiQueryParams' |
|
|
| import styles from './SearchBarButton.module.scss' |
|
|
| type Props = { |
| isSearchOpen: boolean |
| setIsSearchOpen: (value: boolean) => void |
| params: QueryParams |
| searchButtonRef: React.RefObject<HTMLButtonElement> |
| instanceId?: string |
| } |
|
|
| export function SearchBarButton({ |
| isSearchOpen, |
| setIsSearchOpen, |
| params, |
| searchButtonRef, |
| instanceId, |
| }: Props) { |
| const { t } = useTranslation('search') |
|
|
| const urlSearchInputQuery = params['search-overlay-input'] |
|
|
| |
| const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => { |
| e.preventDefault() |
| setIsSearchOpen(true) |
| } |
|
|
| |
| 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, index) => <span key={`${item.trim()}-${index}`}>{item.trim()}</span>) |
| placeHolderElements[1] = <CopilotIcon key="copilot-icon" aria-hidden className="mr-1 ml-1" /> |
|
|
| return ( |
| <> |
| {/* We don't want to show the input when overlay is open */} |
| {!isSearchOpen ? ( |
| <> |
| {/* On mobile only the IconButton is shown */} |
| <IconButton |
| data-testid="mobile-search-button" |
| data-instance={instanceId} |
| ref={searchButtonRef} |
| className={styles.searchIconButton} |
| onClick={handleClick} |
| tabIndex={0} |
| aria-label={t('search.input.placeholder_no_icon')} |
| icon={SearchIcon} |
| /> |
| {/* On large and up the SearchBarButton is shown */} |
| <button |
| data-testid="search" |
| data-instance={instanceId} |
| tabIndex={0} |
| aria-label={t('search.input.placeholder_no_icon')} |
| 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} |
| </> |
| ) |
| } |
|
|