UI search UI a11y changes (#1253)
* fix: Updated UI a11y changes in Courseware Search * feat: Removed result count for search * fix: Added new line at the end of course-tabs-navigation.scss
This commit is contained in:
@@ -44,6 +44,7 @@ export const CoursewareSearchResultsFilter = ({ intl }) => {
|
||||
return (
|
||||
<Tabs
|
||||
id="courseware-search-results-tabs"
|
||||
className="courseware-search-results-tabs"
|
||||
data-testid="courseware-search-results-tabs"
|
||||
variant="tabs"
|
||||
activeKey={activeKey}
|
||||
|
||||
@@ -103,7 +103,7 @@ const CoursewareSearch = ({ intl, ...sectionProps }) => {
|
||||
</div>
|
||||
<div className="courseware-search__outer-content">
|
||||
<div className="courseware-search__content">
|
||||
<h2>{intl.formatMessage(messages.searchModuleTitle)}</h2>
|
||||
<h1 class="h2">{intl.formatMessage(messages.searchModuleTitle)}</h1>
|
||||
<CoursewareSearchForm
|
||||
searchTerm={searchKeyword}
|
||||
onSubmit={handleSubmit}
|
||||
@@ -122,15 +122,15 @@ const CoursewareSearch = ({ intl, ...sectionProps }) => {
|
||||
)}
|
||||
{status === 'results' ? (
|
||||
<>
|
||||
<div className="courseware-search__results-summary" data-testid="courseware-search-summary">{total > 0
|
||||
? (
|
||||
intl.formatMessage(
|
||||
total === 1
|
||||
? messages.searchResultsSingular
|
||||
: messages.searchResultsPlural,
|
||||
{ total, keyword: lastSearchKeyword },
|
||||
)
|
||||
) : intl.formatMessage(messages.searchResultsNone)}
|
||||
<div
|
||||
className="courseware-search__results-summary"
|
||||
aria-live="polite"
|
||||
aria-relevant="all"
|
||||
aria-atomic="true"
|
||||
data-testid="courseware-search-summary"
|
||||
>{total > 0
|
||||
? intl.formatMessage(messages.searchResultsLabel, { total, keyword: lastSearchKeyword })
|
||||
: intl.formatMessage(messages.searchResultsNone)}
|
||||
</div>
|
||||
<CoursewareSearchResultsFilterContainer />
|
||||
</>
|
||||
|
||||
@@ -246,24 +246,14 @@ describe('CoursewareSearch', () => {
|
||||
expect(screen.queryByTestId('courseware-search-summary').textContent).toBe('No results found.');
|
||||
});
|
||||
|
||||
it('should show a summary for a single result', () => {
|
||||
it('should show a summary for the results', () => {
|
||||
mockModels({
|
||||
searchKeyword: 'fubar',
|
||||
total: 1,
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
expect(screen.queryByTestId('courseware-search-summary').textContent).toBe('1 match found for "fubar":');
|
||||
});
|
||||
|
||||
it('should show a summary for multiple results', () => {
|
||||
mockModels({
|
||||
searchKeyword: 'fubar',
|
||||
total: 2,
|
||||
});
|
||||
renderComponent();
|
||||
|
||||
expect(screen.queryByTestId('courseware-search-summary').textContent).toBe('2 matches found for "fubar":');
|
||||
expect(screen.queryByTestId('courseware-search-summary').textContent).toBe('Results for "fubar":');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import React from 'react';
|
||||
import { SearchField } from '@edx/paragon';
|
||||
import PropTypes from 'prop-types';
|
||||
import { SearchField } from '@edx/paragon';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import messages from './messages';
|
||||
|
||||
const CoursewareSearchForm = ({
|
||||
intl,
|
||||
searchTerm,
|
||||
onSubmit,
|
||||
onChange,
|
||||
@@ -14,17 +17,27 @@ const CoursewareSearchForm = ({
|
||||
onChange={onChange}
|
||||
submitButtonLocation="external"
|
||||
className="courseware-search-form"
|
||||
screenReaderText={{
|
||||
label: intl.formatMessage(messages.searchSubmitLabel),
|
||||
clearButton: intl.formatMessage(messages.searchClearAction),
|
||||
submitButton: null, // Remove the sr-only label in the button.
|
||||
}}
|
||||
>
|
||||
<div className="pgn__searchfield_wrapper" data-testid="courseware-search-form">
|
||||
<SearchField.Label />
|
||||
<SearchField.Input placeholder={placeholder} autoFocus />
|
||||
<SearchField.ClearButton />
|
||||
</div>
|
||||
<SearchField.SubmitButton submitButtonLocation="external" data-testid="courseware-search-form-submit" />
|
||||
<SearchField.SubmitButton
|
||||
buttonText={intl.formatMessage(messages.searchSubmitLabel)}
|
||||
submitButtonLocation="external"
|
||||
data-testid="courseware-search-form-submit"
|
||||
/>
|
||||
</SearchField.Advanced>
|
||||
);
|
||||
|
||||
CoursewareSearchForm.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
searchTerm: PropTypes.string,
|
||||
onSubmit: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
@@ -38,4 +51,4 @@ CoursewareSearchForm.defaultProps = {
|
||||
placeholder: undefined,
|
||||
};
|
||||
|
||||
export default CoursewareSearchForm;
|
||||
export default injectIntl(CoursewareSearchForm);
|
||||
|
||||
@@ -47,8 +47,8 @@ describe('CoursewareSearchToggle', () => {
|
||||
|
||||
it('should call onSubmit handler when submit is clicked', async () => {
|
||||
await act(async () => renderComponent(placeholderText, onSubmitHandlerMock, onChangeHandlerMock));
|
||||
await waitFor(() => {
|
||||
const element = screen.queryAllByText('Search')[0];
|
||||
await waitFor(async () => {
|
||||
const element = await screen.findByTestId('courseware-search-form-submit');
|
||||
fireEvent.click(element);
|
||||
expect(onSubmitHandlerMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
&__results-summary {
|
||||
font-size: .9rem;
|
||||
color: $gray-400;
|
||||
color: $gray-500;
|
||||
padding: 1rem 0 .5rem;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
&__breadcrumbs {
|
||||
display: flex;
|
||||
gap: 1.25rem;
|
||||
color: $gray-400;
|
||||
color: $gray-500;
|
||||
overflow: hidden;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
@@ -141,6 +141,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.courseware-search-results-tabs {
|
||||
border-bottom-color: $gray-400 !important;
|
||||
|
||||
&.nav-tabs .nav-link.active {
|
||||
border-bottom-width: 4px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: map-get($grid-breakpoints, 'md')) {
|
||||
.courseware-search__content {
|
||||
padding-top: 8rem;
|
||||
|
||||
@@ -6,6 +6,16 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Search within this course',
|
||||
description: 'Aria-label for a button that will pop up Courseware Search.',
|
||||
},
|
||||
searchSubmitLabel: {
|
||||
id: 'learn.coursewareSerch.submitLabel',
|
||||
defaultMessage: 'Search',
|
||||
description: 'Button label that will submit Courseware Search.',
|
||||
},
|
||||
searchClearAction: {
|
||||
id: 'learn.coursewareSerch.clearAction',
|
||||
defaultMessage: 'Clear search',
|
||||
description: 'Button label that will the current Courseware Search input.',
|
||||
},
|
||||
searchCloseAction: {
|
||||
id: 'learn.coursewareSerch.closeAction',
|
||||
defaultMessage: 'Close the search form',
|
||||
@@ -31,15 +41,10 @@ const messages = defineMessages({
|
||||
defaultMessage: 'No results found.',
|
||||
description: 'Text to show when the Courseware Search found no results matching the criteria.',
|
||||
},
|
||||
searchResultsSingular: {
|
||||
id: 'learn.coursewareSerch.searchResultsSingular',
|
||||
defaultMessage: '1 match found for "{keyword}":',
|
||||
description: 'Text to show when the Courseware Search found only one result matching the criteria.',
|
||||
},
|
||||
searchResultsPlural: {
|
||||
id: 'learn.coursewareSerch.searchResultsPlural',
|
||||
defaultMessage: '{total} matches found for "{keyword}":',
|
||||
description: 'Text to show when the Courseware Search found multiple results matching the criteria.',
|
||||
searchResultsLabel: {
|
||||
id: 'learn.coursewareSerch.searchResultsLabel',
|
||||
defaultMessage: 'Results for "{keyword}":',
|
||||
description: 'Text to show above the search results response list.',
|
||||
},
|
||||
searchResultsError: {
|
||||
id: 'learn.coursewareSerch.searchResultsError',
|
||||
|
||||
@@ -15,9 +15,6 @@ const CourseTabsNavigation = ({
|
||||
|
||||
return (
|
||||
<div id="courseTabsNavigation" className={classNames('course-tabs-navigation', className)}>
|
||||
<div className="float-right">
|
||||
<CoursewareSearchToggle />
|
||||
</div>
|
||||
<div className="container-xl">
|
||||
<Tabs
|
||||
className="nav-underline-tabs"
|
||||
@@ -34,6 +31,9 @@ const CourseTabsNavigation = ({
|
||||
))}
|
||||
</Tabs>
|
||||
</div>
|
||||
<div className="course-tabs-navigation__search-toggle">
|
||||
<CoursewareSearchToggle />
|
||||
</div>
|
||||
{show && <CoursewareSearch />}
|
||||
</div>
|
||||
);
|
||||
|
||||
24
src/course-tabs/course-tabs-navigation.scss
Normal file
24
src/course-tabs/course-tabs-navigation.scss
Normal file
@@ -0,0 +1,24 @@
|
||||
.course-tabs-navigation {
|
||||
position: relative;
|
||||
border-bottom: solid 1px #eaeaea;
|
||||
|
||||
.nav a,
|
||||
.nav button {
|
||||
&:hover {
|
||||
background-color: $light-400;
|
||||
}
|
||||
}
|
||||
|
||||
.nav a {
|
||||
&:not(.active):hover {
|
||||
background-color: $light-400;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__search-toggle {
|
||||
position: absolute;
|
||||
top: .05rem;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
@@ -38,24 +38,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.course-tabs-navigation {
|
||||
border-bottom: solid 1px #eaeaea;
|
||||
|
||||
.nav a,
|
||||
.nav button {
|
||||
&:hover {
|
||||
background-color: $light-400;
|
||||
}
|
||||
}
|
||||
|
||||
.nav a {
|
||||
&:not(.active):hover {
|
||||
background-color: $light-400;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-underline-tabs {
|
||||
margin: 0 0 -1px;
|
||||
|
||||
@@ -396,3 +378,4 @@
|
||||
@import "courseware/course/course-exit/CourseRecommendations";
|
||||
@import "product-tours/newUserCourseHomeTour/NewUserCourseHomeTourModal.scss";
|
||||
@import "course-home/courseware-search/courseware-search.scss";
|
||||
@import "course-tabs/course-tabs-navigation.scss";
|
||||
|
||||
Reference in New Issue
Block a user