diff --git a/src/SearchField/SearchField.test.jsx b/src/SearchField/SearchField.test.jsx index 1f6cebba550..4bb237dea9e 100644 --- a/src/SearchField/SearchField.test.jsx +++ b/src/SearchField/SearchField.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { IntlProvider } from 'react-intl'; import SearchField from '.'; @@ -13,14 +14,20 @@ const baseProps = { onSubmit: () => {}, }; +const renderWithIntl = (ui) => render( + + {ui} + , +); + describe(' with basic usage', () => { it('should match the snapshot', () => { - const { container } = render(); + const { container } = renderWithIntl(); expect(container).toMatchSnapshot(); }); it('renders SearchField.Advanced component`', () => { - render(); + renderWithIntl(); const advancedComponent = screen.getByTestId('advanced-component'); expect(advancedComponent).toBeInTheDocument(); }); @@ -28,7 +35,7 @@ describe(' with basic usage', () => { it('should pass correct props to `SearchField.Label`', () => { const label = 'foobar'; let props = { ...baseProps, label }; - const { rerender } = render(); + const { rerender } = renderWithIntl(); const labelElement = screen.getByLabelText(label); expect(labelElement).toBeInTheDocument(); @@ -36,7 +43,11 @@ describe(' with basic usage', () => { ...baseProps, screenReaderText: { label, submitButton: 'submit foobar' }, }; - rerender(); + rerender( + + + , + ); const srOnlyLabelElement = screen.getByText(label); expect(srOnlyLabelElement).toBeInTheDocument(); expect(srOnlyLabelElement).toHaveClass('sr-only'); @@ -46,7 +57,7 @@ describe(' with basic usage', () => { const placeholder = 'foobar'; const inputTestId = 'foo'; const props = { ...baseProps, placeholder, inputProps: { 'data-testid': inputTestId } }; - render(); + renderWithIntl(); const inputElement = screen.getByTestId(inputTestId); expect(inputElement).toBeInTheDocument(); expect(inputElement).toHaveAttribute('placeholder', placeholder); @@ -55,7 +66,7 @@ describe(' with basic usage', () => { it('should use passed in initial `value` prop', () => { const value = 'foobar'; const props = { ...baseProps, value }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); expect(inputElement).toBeInTheDocument(); expect(inputElement).toHaveValue(value); @@ -68,7 +79,7 @@ describe(' with basic usage', () => { clearButton: 'borrar búsqueda', }; const props = { ...baseProps, screenReaderText }; - render(); + renderWithIntl(); const input = screen.getByRole('searchbox', { target: 'submit' }); const submitLabel = screen.getByLabelText(screenReaderText.label); expect(submitLabel).toBeInTheDocument(); @@ -80,9 +91,9 @@ describe(' with basic usage', () => { }); it('should add div if `submitButtonLocation` is passed', () => { - const { container } = render(); + const { container } = renderWithIntl(); expect(container.querySelector('.pgn__searchfield_wrapper')).toBeNull(); - const { container: containerExternal } = render(); + const { container: containerExternal } = renderWithIntl(); expect(containerExternal.querySelector('.pgn__searchfield_wrapper')).toBeInTheDocument(); }); @@ -90,7 +101,7 @@ describe(' with basic usage', () => { it('focus handler', () => { const spy = jest.fn(); const props = { ...baseProps, onFocus: spy }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); inputElement.focus(); expect(spy).toHaveBeenCalledTimes(1); @@ -99,7 +110,7 @@ describe(' with basic usage', () => { it('blur handler', async () => { const spy = jest.fn(); const props = { ...baseProps, onBlur: spy }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); inputElement.focus(); await userEvent.tab(); @@ -110,7 +121,7 @@ describe(' with basic usage', () => { const spy = jest.fn(); const props = { ...baseProps, onChange: spy }; const inputText = 'foobar'; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); await userEvent.type(inputElement, inputText); expect(spy).toHaveBeenCalledTimes(inputText.length); @@ -119,7 +130,7 @@ describe(' with basic usage', () => { it('clear handler', async () => { const spy = jest.fn(); const props = { ...baseProps, onClear: spy }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); await userEvent.type(inputElement, 'foobar'); @@ -132,7 +143,7 @@ describe(' with basic usage', () => { it('submit handler on submit button click', async () => { const spy = jest.fn(); const props = { ...baseProps, onSubmit: spy, submitButtonLocation: BUTTON_LOCATION_VARIANTS[1] }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); const submitButton = screen.getByRole('button', { type: 'submit' }); await userEvent.type(inputElement, 'foobar'); @@ -145,7 +156,7 @@ describe(' with basic usage', () => { describe('clear button', () => { it('should be visible with input value', async () => { const props = { ...baseProps }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox'); expect(screen.queryByRole('button', { name: 'clear search', type: 'reset' })).toBeNull(); await userEvent.type(inputElement, 'foobar'); @@ -154,7 +165,7 @@ describe(' with basic usage', () => { it('should clear input value when clicked', async () => { const props = { ...baseProps }; - render(); + renderWithIntl(); const inputElement = screen.getByRole('searchbox', { target: 'submit' }); await userEvent.type(inputElement, 'foobar'); expect(inputElement).toHaveValue('foobar'); @@ -167,7 +178,7 @@ describe(' with basic usage', () => { describe('advanced usage', () => { it('should pass props to the clear button', async () => { const buttonProps = { variant: 'inline' }; - render( + renderWithIntl( @@ -181,7 +192,7 @@ describe(' with basic usage', () => { it('should pass props to the label', () => { const labelProps = { variant: 'inline' }; - render( + renderWithIntl( Labeled , @@ -196,7 +207,7 @@ describe(' with basic usage', () => { submitButtonLocation: 'external', buttonText, }; - render( + renderWithIntl( , @@ -212,7 +223,7 @@ describe(' with basic usage', () => { submitButtonLocation: 'external', buttonText, }; - render( + renderWithIntl( , diff --git a/src/SearchField/SearchFieldSubmitButton.jsx b/src/SearchField/SearchFieldSubmitButton.jsx index 0edcffb1fd5..58ce34ad279 100644 --- a/src/SearchField/SearchFieldSubmitButton.jsx +++ b/src/SearchField/SearchFieldSubmitButton.jsx @@ -1,10 +1,12 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; +import { useIntl } from 'react-intl'; import { SearchFieldContext } from './SearchFieldAdvanced'; import Button from '../Button'; import IconButton from '../IconButton'; import Icon from '../Icon'; +import messages from './messages'; const STYLE_VARIANTS = [ 'light', @@ -23,6 +25,8 @@ function SearchFieldSubmitButton(props) { const { screenReaderText, icons, refs, value, disabled, } = useContext(SearchFieldContext); + const intl = useIntl(); + const defaultButtonText = buttonText ?? intl.formatMessage(messages.searchButtonText); if (submitButtonLocation === 'internal' && value.length) { return null; @@ -37,7 +41,7 @@ function SearchFieldSubmitButton(props) { disabled={disabled} {...others} > - {buttonText} + {defaultButtonText} {screenReaderText.submitButton} ) : ( @@ -70,7 +74,6 @@ SearchFieldSubmitButton.propTypes = { SearchFieldSubmitButton.defaultProps = { variant: 'light', submitButtonLocation: 'internal', - buttonText: 'Search', }; export default SearchFieldSubmitButton; diff --git a/src/SearchField/index.jsx b/src/SearchField/index.jsx index 1a543275144..f38aa156a3d 100644 --- a/src/SearchField/index.jsx +++ b/src/SearchField/index.jsx @@ -11,7 +11,6 @@ import SearchFieldSubmitButton from './SearchFieldSubmitButton'; export const SEARCH_FIELD_SCREEN_READER_TEXT_LABEL = 'search'; export const SEARCH_FIELD_SCREEN_READER_TEXT_SUBMIT_BUTTON = 'submit search'; export const SEARCH_FIELD_SCREEN_READER_TEXT_CLEAR_BUTTON = 'clear search'; -export const SEARCH_FIELD_BUTTON_TEXT = 'search'; const STYLE_VARIANTS = [ 'light', @@ -178,7 +177,6 @@ SearchField.defaultProps = { variant: 'light', disabled: false, submitButtonLocation: 'internal', - buttonText: SEARCH_FIELD_BUTTON_TEXT, }; SearchField.Advanced = SearchFieldAdvanced; diff --git a/src/SearchField/index.scss b/src/SearchField/index.scss index c0226843188..60bcbe099b4 100644 --- a/src/SearchField/index.scss +++ b/src/SearchField/index.scss @@ -129,6 +129,14 @@ .pgn__searchfield__button.btn[type="submit"] { border-radius: 0; margin-inline-start: var(--pgn-spacing-search-field-margin-button); + + &:focus::before { + border-radius: inherit; + } + + &:focus-visible::after { + content: none; + } } .pgn__searchfield__iconbutton-submit, diff --git a/src/SearchField/messages.ts b/src/SearchField/messages.ts new file mode 100644 index 00000000000..3257c3fbf27 --- /dev/null +++ b/src/SearchField/messages.ts @@ -0,0 +1,11 @@ +import { defineMessages } from 'react-intl'; + +const messages = defineMessages({ + searchButtonText: { + id: 'pgn.SearchField.searchButton', + defaultMessage: 'Search', + description: 'Accessible default text for the search submit button', + }, +}); + +export default messages; diff --git a/src/index.ts b/src/index.ts index 7e11e26a8c4..630421e1f3c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -158,7 +158,6 @@ export { SEARCH_FIELD_SCREEN_READER_TEXT_LABEL, SEARCH_FIELD_SCREEN_READER_TEXT_CLEAR_BUTTON, SEARCH_FIELD_SCREEN_READER_TEXT_SUBMIT_BUTTON, - SEARCH_FIELD_BUTTON_TEXT, // @ts-ignore: has yet to be converted to TypeScript } from './SearchField'; // @ts-ignore: has yet to be converted to TypeScript