mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Search: Make search icon keyboard navigable (#37865)
* Make search icon keyboard navigable * Update text * Update test * Remove unused line * Add global focus-visible styles for button
This commit is contained in:
@@ -55,6 +55,9 @@ export function getElementStyles(theme: GrafanaTheme2) {
|
||||
button {
|
||||
letter-spacing: ${theme.typography.body.letterSpacing};
|
||||
|
||||
&:focus-visible {
|
||||
outline: ${getFocusStyles(theme)};
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import TopSection from './TopSection';
|
||||
|
||||
jest.mock('../../config', () => ({
|
||||
@@ -9,33 +9,21 @@ jest.mock('../../config', () => ({
|
||||
{ id: '2', hideFromMenu: true },
|
||||
{ id: '3', hideFromMenu: false },
|
||||
{ id: '4', hideFromMenu: true },
|
||||
{ id: '4', hideFromMenu: false },
|
||||
],
|
||||
},
|
||||
}));
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props = Object.assign(
|
||||
{
|
||||
mainLinks: [],
|
||||
},
|
||||
propOverrides
|
||||
);
|
||||
|
||||
return shallow(<TopSection {...props} />);
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = setup();
|
||||
it('should render search when empty', () => {
|
||||
render(<TopSection />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(screen.getByText('Search dashboards')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render items', () => {
|
||||
const wrapper = setup({
|
||||
mainLinks: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
|
||||
});
|
||||
it('should render items and search item', () => {
|
||||
render(<TopSection />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(screen.getByTestId('top-section-items').children.length).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ const TopSection: FC<any> = () => {
|
||||
const navTree = cloneDeep(config.bootData.navTree);
|
||||
const mainLinks = filter(navTree, (item) => !item.hideFromMenu);
|
||||
const searchLink = {
|
||||
text: 'Search',
|
||||
text: 'Search dashboards',
|
||||
icon: 'search',
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ const TopSection: FC<any> = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="sidemenu__top">
|
||||
<div data-testid="top-section-items" className="sidemenu__top">
|
||||
<TopSectionItem link={searchLink} onClick={onOpenSearch} />
|
||||
{mainLinks.map((link, index) => {
|
||||
return <TopSectionItem link={link} key={`${link.id}-${index}`} />;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { FC } from 'react';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
import { Icon, Link } from '@grafana/ui';
|
||||
import { Icon, Link, useStyles2 } from '@grafana/ui';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { css, cx } from '@emotion/css';
|
||||
|
||||
export interface Props {
|
||||
link: NavModelItem;
|
||||
@@ -9,6 +10,13 @@ export interface Props {
|
||||
}
|
||||
|
||||
const TopSectionItem: FC<Props> = ({ link, onClick }) => {
|
||||
const resetButtonStyles = useStyles2(
|
||||
() =>
|
||||
css`
|
||||
background-color: transparent;
|
||||
`
|
||||
);
|
||||
|
||||
const linkContent = (
|
||||
<span className="icon-circle sidemenu-icon">
|
||||
{link.icon && <Icon name={link.icon as any} size="xl" />}
|
||||
@@ -28,9 +36,9 @@ const TopSectionItem: FC<Props> = ({ link, onClick }) => {
|
||||
{linkContent}
|
||||
</Link>
|
||||
) : (
|
||||
<a className="sidemenu-link" onClick={onClick} aria-label={link.text}>
|
||||
<button className={cx(resetButtonStyles, 'sidemenu-link')} onClick={onClick} aria-label={link.text}>
|
||||
{linkContent}
|
||||
</a>
|
||||
</button>
|
||||
);
|
||||
return (
|
||||
<div className="sidemenu-item dropdown">
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div
|
||||
className="sidemenu__top"
|
||||
>
|
||||
<TopSectionItem
|
||||
link={
|
||||
Object {
|
||||
"icon": "search",
|
||||
"text": "Search",
|
||||
}
|
||||
}
|
||||
onClick={[Function]}
|
||||
/>
|
||||
<TopSectionItem
|
||||
key="3-0"
|
||||
link={
|
||||
Object {
|
||||
"hideFromMenu": false,
|
||||
"id": "3",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Render should render items 1`] = `
|
||||
<div
|
||||
className="sidemenu__top"
|
||||
>
|
||||
<TopSectionItem
|
||||
link={
|
||||
Object {
|
||||
"icon": "search",
|
||||
"text": "Search",
|
||||
}
|
||||
}
|
||||
onClick={[Function]}
|
||||
/>
|
||||
<TopSectionItem
|
||||
key="3-0"
|
||||
link={
|
||||
Object {
|
||||
"hideFromMenu": false,
|
||||
"id": "3",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
Reference in New Issue
Block a user