From 117173d3080aff77982427fd621f018a8cff1c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Mon, 15 Nov 2021 16:47:44 +0100 Subject: [PATCH 1/2] feat(v3): allow overriding default toggle key --- packages/docsearch-react/src/DocSearch.tsx | 4 ++++ .../docsearch-react/src/DocSearchButton.tsx | 7 ++++-- .../src/__tests__/api.test.tsx | 23 +++++++++++++++++++ .../src/useDocSearchKeyboardEvents.ts | 10 ++++---- packages/website/docs/api.mdx | 11 +++++++++ 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/packages/docsearch-react/src/DocSearch.tsx b/packages/docsearch-react/src/DocSearch.tsx index d6d8474ff..c4d5d503e 100644 --- a/packages/docsearch-react/src/DocSearch.tsx +++ b/packages/docsearch-react/src/DocSearch.tsx @@ -41,6 +41,7 @@ export interface DocSearchProps { initialQuery?: string; navigator?: AutocompleteOptions['navigator']; translations?: DocSearchTranslations; + toggleKey?: string; } export function DocSearch(props: DocSearchProps) { @@ -49,6 +50,7 @@ export function DocSearch(props: DocSearchProps) { const [initialQuery, setInitialQuery] = React.useState( props?.initialQuery || undefined ); + const toggleKey = props?.toggleKey || 'k'; const onOpen = React.useCallback(() => { setIsOpen(true); @@ -72,6 +74,7 @@ export function DocSearch(props: DocSearchProps) { onClose, onInput, searchButtonRef, + toggleKey, }); return ( @@ -79,6 +82,7 @@ export function DocSearch(props: DocSearchProps) { diff --git a/packages/docsearch-react/src/DocSearchButton.tsx b/packages/docsearch-react/src/DocSearchButton.tsx index fd6acbf8b..8ff916f9e 100644 --- a/packages/docsearch-react/src/DocSearchButton.tsx +++ b/packages/docsearch-react/src/DocSearchButton.tsx @@ -10,6 +10,7 @@ export type ButtonTranslations = Partial<{ export type DocSearchButtonProps = React.ComponentProps<'button'> & { translations?: ButtonTranslations; + toggleKey?: string; }; const ACTION_KEY_DEFAULT = 'Ctrl' as const; @@ -22,7 +23,7 @@ function isAppleDevice() { export const DocSearchButton = React.forwardRef< HTMLButtonElement, DocSearchButtonProps ->(({ translations = {}, ...props }, ref) => { +>(({ translations = {}, toggleKey = 'k', ...props }, ref) => { const { buttonText = 'Search', buttonAriaLabel = 'Search' } = translations; const key = useMemo< @@ -53,7 +54,9 @@ export const DocSearchButton = React.forwardRef< {key === ACTION_KEY_DEFAULT ? : key} - K + + {toggleKey.toLocaleUpperCase()} + )} diff --git a/packages/docsearch-react/src/__tests__/api.test.tsx b/packages/docsearch-react/src/__tests__/api.test.tsx index 3b9dea95a..cba84af9f 100644 --- a/packages/docsearch-react/src/__tests__/api.test.tsx +++ b/packages/docsearch-react/src/__tests__/api.test.tsx @@ -5,6 +5,7 @@ import { screen, act, } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; import React from 'react'; import '@testing-library/jest-dom'; @@ -27,6 +28,28 @@ describe('api', () => { expect(document.querySelector('.DocSearch')).toBeInTheDocument(); }); + describe('toggleKey', () => { + it('opens the modal with the default shortcut', async () => { + render(); + + await waitFor(() => { + userEvent.keyboard('{meta}{k}'); + }); + + expect(document.querySelector('.DocSearch-Modal')).toBeInTheDocument(); + }); + + it('overrides the default shortcut', async () => { + render(); + + await waitFor(() => { + userEvent.keyboard('{meta}{u}'); + }); + + expect(document.querySelector('.DocSearch-Modal')).toBeInTheDocument(); + }); + }); + describe('translations', () => { it('overrides the default DocSearchButton text', () => { render( diff --git a/packages/docsearch-react/src/useDocSearchKeyboardEvents.ts b/packages/docsearch-react/src/useDocSearchKeyboardEvents.ts index 8a9919456..536d258d9 100644 --- a/packages/docsearch-react/src/useDocSearchKeyboardEvents.ts +++ b/packages/docsearch-react/src/useDocSearchKeyboardEvents.ts @@ -6,6 +6,7 @@ export interface UseDocSearchKeyboardEventsProps { onClose: () => void; onInput?: (event: KeyboardEvent) => void; searchButtonRef?: React.RefObject; + toggleKey: string; } function isEditingContent(event: KeyboardEvent): boolean { @@ -26,6 +27,7 @@ export function useDocSearchKeyboardEvents({ onClose, onInput, searchButtonRef, + toggleKey = 'k', }: UseDocSearchKeyboardEventsProps) { React.useEffect(() => { function onKeyDown(event: KeyboardEvent) { @@ -37,9 +39,9 @@ export function useDocSearchKeyboardEvents({ } } if ( - (event.keyCode === 27 && isOpen) || - // The `Cmd+K` shortcut both opens and closes the modal. - (event.key === 'k' && (event.metaKey || event.ctrlKey)) || + (event.key === 'Escape' && isOpen) || + // The `Cmd+toggleKey` shortcut both opens and closes the modal. + (event.key === toggleKey && (event.metaKey || event.ctrlKey)) || // The `/` shortcut opens but doesn't close the modal because it's // a character. (!isEditingContent(event) && event.key === '/' && !isOpen) @@ -69,5 +71,5 @@ export function useDocSearchKeyboardEvents({ return () => { window.removeEventListener('keydown', onKeyDown); }; - }, [isOpen, onOpen, onClose, onInput, searchButtonRef]); + }, [isOpen, onOpen, onClose, onInput, searchButtonRef, toggleKey]); } diff --git a/packages/website/docs/api.mdx b/packages/website/docs/api.mdx index 6f270aa44..7a8d0a87b 100644 --- a/packages/website/docs/api.mdx +++ b/packages/website/docs/api.mdx @@ -169,6 +169,11 @@ const translations: DocSearchTranslations = { +## `toggleKey` + +> `type: string` | `default: "k"` | **optional** + +Allow overriding the default key to open/close the DocSearch modal. @@ -309,6 +314,12 @@ const translations: DocSearchTranslations = { +## `toggleKey` + +> `type: string` | `default: "k"` | **optional** + +Allow overriding the default key to open/close the DocSearch modal. + From 23475f924394de37a2fefa73a7cd250b60b64d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vannicatte?= Date: Mon, 29 Nov 2021 16:04:11 +0100 Subject: [PATCH 2/2] tests: adds `close` case --- .../docsearch-react/src/__tests__/api.test.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/docsearch-react/src/__tests__/api.test.tsx b/packages/docsearch-react/src/__tests__/api.test.tsx index cba84af9f..1d1b673a2 100644 --- a/packages/docsearch-react/src/__tests__/api.test.tsx +++ b/packages/docsearch-react/src/__tests__/api.test.tsx @@ -29,7 +29,7 @@ describe('api', () => { }); describe('toggleKey', () => { - it('opens the modal with the default shortcut', async () => { + it('opens and close the modal with the default shortcut', async () => { render(); await waitFor(() => { @@ -37,6 +37,14 @@ describe('api', () => { }); expect(document.querySelector('.DocSearch-Modal')).toBeInTheDocument(); + + await waitFor(() => { + userEvent.keyboard('{meta}{k}'); + }); + + expect( + document.querySelector('.DocSearch-Modal') + ).not.toBeInTheDocument(); }); it('overrides the default shortcut', async () => { @@ -47,6 +55,14 @@ describe('api', () => { }); expect(document.querySelector('.DocSearch-Modal')).toBeInTheDocument(); + + await waitFor(() => { + userEvent.keyboard('{meta}{u}'); + }); + + expect( + document.querySelector('.DocSearch-Modal') + ).not.toBeInTheDocument(); }); });