Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix / header navigation list (accessibility) #491

Merged
merged 4 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion packages/ui-react/src/components/Header/Header.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,17 @@
flex: 1;
align-items: center;

> a {
> ul {
margin: 0;
padding: 0;
list-style-type: none;

li {
display: inline-block;
}
}

a {
height: 36px;
min-height: 36px;
margin: 0 6px;
Expand Down Expand Up @@ -177,6 +187,24 @@
}
}

.navButton {
overflow: visible;

&::after {
position: absolute;
bottom: calc(((variables.$header-height - 36px) / 2) * -1);
left: 0;
width: 100%;
height: 2px;
background-color: variables.$white;
content: '';
}

body:global(.is-tabbing) &:focus::after {
display: none;
}
}

//
// mediaQueries
// --------------------------------
Expand Down
41 changes: 39 additions & 2 deletions packages/ui-react/src/components/Header/Header.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('<Header />', () => {
});

test('renders header', () => {
const playlistMenuItems = [<Button key="key" label="Home" to="/" />];
const homeButton = [<Button key="key" label="Home" to="/" />];
const { container } = render(
<Header
onMenuButtonClick={vi.fn()}
Expand All @@ -46,10 +46,47 @@ describe('<Header />', () => {
currentLanguage={undefined}
onLanguageClick={vi.fn()}
>
{playlistMenuItems}
{homeButton}
</Header>,
);

expect(container).toMatchSnapshot();
});

test('renders header with nav buttons', () => {
const navItems = [
{ label: 'Home', to: '/' },
{ label: 'Button test', to: '/test' },
];
const { container } = render(
<Header
onMenuButtonClick={vi.fn()}
searchBarProps={{
query: '',
onQueryChange: vi.fn(),
}}
searchEnabled
searchActive={false}
onSearchButtonClick={vi.fn()}
onCloseSearchButtonClick={vi.fn()}
onLoginButtonClick={vi.fn()}
userMenuOpen={false}
sideBarOpen={false}
openUserPanel={vi.fn()}
closeUserPanel={vi.fn()}
openLanguageMenu={vi.fn()}
closeLanguageMenu={vi.fn()}
isLoggedIn={false}
canLogin={true}
showPaymentsMenuItem={true}
supportedLanguages={[]}
languageMenuOpen={false}
currentLanguage={undefined}
onLanguageClick={vi.fn()}
navItems={navItems}
/>,
);

expect(container).toMatchSnapshot();
});
});
24 changes: 23 additions & 1 deletion packages/ui-react/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import styles from './Header.module.scss';

type TypeHeader = 'static' | 'fixed';

type NavItem = {
label: string;
to: string;
};

type Props = {
headerType?: TypeHeader;
onMenuButtonClick: () => void;
Expand Down Expand Up @@ -52,6 +57,7 @@ type Props = {
onLanguageClick: (code: string) => void;
favoritesEnabled?: boolean;
siteName?: string;
navItems?: NavItem[];

profilesData?: {
currentProfile: Profile | null;
Expand Down Expand Up @@ -90,6 +96,7 @@ const Header: React.FC<Props> = ({
favoritesEnabled,
siteName,
profilesData: { currentProfile, profiles, profilesEnabled, selectProfile, isSelectingProfile } = {},
navItems = [],
}) => {
const { t } = useTranslation('menu');
const [logoLoaded, setLogoLoaded] = useState(false);
Expand Down Expand Up @@ -197,6 +204,21 @@ const Header: React.FC<Props> = ({
);
};

const renderNav = () => {
if (navItems.length === 0) {
return children;
}
return (
<ul>
{navItems.map((item, index) => (
<li key={index}>
<Button activeClassname={styles.navButton} label={item.label} to={item.to} variant="text" />
</li>
))}
</ul>
);
};

return (
<header className={headerClassName}>
<div className={styles.container}>
Expand All @@ -220,7 +242,7 @@ const Header: React.FC<Props> = ({
<Logo alt={t('logo_alt', { siteName })} src={logoSrc} onLoad={() => setLogoLoaded(true)} />
</div>
)}
<nav className={styles.nav}>{logoLoaded || !logoSrc ? children : null}</nav>
<nav className={styles.nav}>{logoLoaded || !logoSrc ? renderNav() : null}</nav>
<div className={styles.actions}>
{renderSearch()}
{renderLanguageDropdown()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,105 @@ exports[`<Header /> > renders header 1`] = `
</header>
</div>
`;

exports[`<Header /> > renders header with nav buttons 1`] = `
<div>
<header
class="_header_f4f7a7 _static_f4f7a7"
>
<div
class="_container_f4f7a7"
>
<a
class="_skipToContent_f4f7a7"
href="#content"
>
skip_to_content
</a>
<div
class="_menu_f4f7a7"
>
<div
aria-controls="sidebar"
aria-expanded="false"
aria-haspopup="true"
aria-label="open_menu"
class="_iconButton_0fef65 _iconButton_f4f7a7"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
class="_icon_585b29"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M0 0h24v24H0V0z"
fill="none"
/>
<path
d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"
/>
</svg>
</div>
</div>
<nav
class="_nav_f4f7a7"
>
<ul>
<li>
a
</li>
<li>
a
</li>
</ul>
</nav>
<div
class="_actions_f4f7a7"
>
<div
aria-label="Open search"
class="_iconButton_0fef65 _iconButton_f4f7a7 _actionButton_f4f7a7"
role="button"
tabindex="0"
>
<svg
aria-hidden="true"
class="_icon_585b29"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"
/>
</svg>
</div>
<div
class="_buttonContainer_f4f7a7"
>
<button
aria-haspopup="dialog"
class="_button_f8f296 _default_f8f296 _outlined_f8f296"
type="button"
>
<span>
sign_in
</span>
</button>
<button
aria-haspopup="dialog"
class="_button_f8f296 _primary_f8f296"
type="button"
>
<span>
sign_up
</span>
</button>
</div>
</div>
</div>
</header>
</div>
`;
22 changes: 0 additions & 22 deletions packages/ui-react/src/containers/Layout/Layout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,3 @@
.main {
height: 100%;
}

.headerButton {
overflow: visible;

&::after {
position: absolute;
bottom: calc(((variables.$header-height - 36px) / 2) * -1);
left: 0;
width: 100%;
height: 2px;
background-color: variables.$white;
content: '';
}

body:global(.is-tabbing) & {
&:focus {
&::after {
display: none;
}
}
}
}
10 changes: 4 additions & 6 deletions packages/ui-react/src/containers/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ const Layout = () => {
);
};

const navItems = [{ label: t('home'), to: '/' }, ...menu.map((item) => ({ label: item.label, to: playlistURL(item.contentId) }))];

const containerProps = { inert: sideBarOpen ? '' : undefined }; // inert is not yet officially supported in react

return (
Expand Down Expand Up @@ -197,12 +199,8 @@ const Layout = () => {
selectProfile: ({ avatarUrl, id }) => selectProfile.mutate({ id, avatarUrl }),
isSelectingProfile: selectProfile.isLoading,
}}
>
<Button activeClassname={styles.headerButton} label={t('home')} to="/" variant="text" />
{menu.map((item) => (
<Button activeClassname={styles.headerButton} key={item.contentId} label={item.label} to={playlistURL(item.contentId)} variant="text" />
))}
</Header>
navItems={navItems}
/>
<main id="content" className={styles.main} tabIndex={-1}>
<Outlet />
</main>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,19 @@ exports[`<Layout /> > renders layout 1`] = `
<nav
class="_nav_f4f7a7"
>
<a
aria-current="page"
class="_button_f8f296 _default_f8f296 _text_f8f296 _active_f8f296 _headerButton_c71437"
href="/"
>
<span>
home
</span>
</a>
<ul>
<li>
<a
aria-current="page"
class="_button_f8f296 _default_f8f296 _text_f8f296 _active_f8f296 _navButton_f4f7a7"
href="/"
>
<span>
home
</span>
</a>
</li>
</ul>
</nav>
<div
class="_actions_f4f7a7"
Expand Down
Loading