Skip to content

Commit

Permalink
fix: auto-focus the search keyword input when in search modal only
Browse files Browse the repository at this point in the history
so that library authoring navigate events don't change element focus.
  • Loading branch information
pomegranited committed Jan 16, 2025
1 parent 98fbcff commit 7aaa8f7
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/library-authoring/LibraryAuthoringPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ describe('<LibraryAuthoringPage />', () => {
expect(screen.getAllByText('Recently Modified').length).toEqual(1);
expect((await screen.findAllByText('Introduction to Testing'))[0]).toBeInTheDocument();

// Search box should not have focus on page load
const searchBox = screen.getByRole('searchbox');
expect(searchBox).not.toHaveFocus();

// Navigate to the components tab
fireEvent.click(screen.getByRole('tab', { name: 'Components' }));
// "Recently Modified" default sort shown
Expand Down
8 changes: 6 additions & 2 deletions src/search-manager/SearchKeywordsField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import { useSearchContext } from './SearchManager';
/**
* The "main" input field where users type in search keywords. The search happens as they type (no need to press enter).
*/
const SearchKeywordsField: React.FC<{ className?: string, placeholder?: string }> = (props) => {
const SearchKeywordsField: React.FC<{
className?: string,
placeholder?: string,
autoFocus?: boolean,
}> = (props) => {
const intl = useIntl();
const { searchKeywords, setSearchKeywords, usageKey } = useSearchContext();
const defaultPlaceholder = usageKey ? messages.clearUsageKeyToSearch : messages.inputPlaceholder;
Expand All @@ -24,7 +28,7 @@ const SearchKeywordsField: React.FC<{ className?: string, placeholder?: string }
>
<SearchField.Label />
<SearchField.Input
autoFocus
autoFocus={Boolean(props.autoFocus)}
placeholder={placeholder}
/>
<SearchField.ClearButton />
Expand Down
10 changes: 10 additions & 0 deletions src/search-modal/SearchModal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,14 @@ describe('<SearchModal />', () => {
const { findByText } = render(<RootWrapper />);
expect(await findByText('An error occurred. Unable to load search results.')).toBeInTheDocument();
});

it('should set focus on the search input box when loaded in the modal', async () => {
axiosMock.onGet(getContentSearchConfigUrl()).replyOnce(200, {
url: 'https://meilisearch.example.com',
index: 'test-index',
apiKey: 'test-api-key',
});
const { getByRole } = render(<RootWrapper />);
expect(getByRole('searchbox')).toHaveFocus();
});
});
6 changes: 5 additions & 1 deletion src/search-modal/SearchModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ const SearchModal: React.FC<{ courseId?: string, isOpen: boolean, onClose: () =>
isFullscreenOnMobile
className="courseware-search-modal"
>
<SearchUI courseId={courseId} closeSearchModal={props.onClose} />
<SearchUI
courseId={courseId}
closeSearchModal={props.onClose}
autoFocus
/>
</ModalDialog>
);
};
Expand Down
11 changes: 9 additions & 2 deletions src/search-modal/SearchUI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import EmptyStates from './EmptyStates';
import SearchResults from './SearchResults';
import messages from './messages';

const SearchUI: React.FC<{ courseId?: string, closeSearchModal?: () => void }> = (props) => {
const SearchUI: React.FC<{
courseId?: string,
autoFocus?: boolean,
closeSearchModal?: () => void,
}> = (props) => {
const hasCourseId = Boolean(props.courseId);
const [searchThisCourseEnabled, setSearchThisCourse] = React.useState(hasCourseId);
const switchToThisCourse = React.useCallback(() => setSearchThisCourse(true), []);
Expand All @@ -39,7 +43,10 @@ const SearchUI: React.FC<{ courseId?: string, closeSearchModal?: () => void }> =
<ModalDialog.Header style={{ zIndex: 9 }} className="border-bottom">
<ModalDialog.Title><FormattedMessage {...messages.title} /></ModalDialog.Title>
<div className="d-flex mt-3">
<SearchKeywordsField className="flex-grow-1 mr-2" />
<SearchKeywordsField
className="flex-grow-1 mr-2"
autoFocus={props.autoFocus}
/>
<SelectMenu variant="primary">
<MenuItem
onClick={switchToThisCourse}
Expand Down

0 comments on commit 7aaa8f7

Please sign in to comment.