Skip to content
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
1 change: 1 addition & 0 deletions demo/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React Accessible Dropdown Menu Hook</title>
<script src="https://kit.fontawesome.com/c7369e5365.js" crossorigin="anonymous"></script>
</head>

<body>
Expand Down
158 changes: 158 additions & 0 deletions demo/src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,161 @@ body {
.app {
text-align: center;
}

h1 {
margin: 0;
padding: 0 2rem;
margin-top: 4rem;
line-height: 1;
color: #333;
font-weight: 500;
font-size: 3rem;
}

h2 {
margin: 0;
padding: 0 2rem;
margin-top: 0.5rem;
line-height: 1;
color: #555;
font-weight: 300;
font-size: 1.5rem;
font-style: italic;
}

#menu-button {
appearance: none;
width: 10rem;
margin: 3rem auto 0;
padding: 1rem 0;
background: #eee;
outline: none;
border: 1px solid #ddd;
border-radius: 0.2rem;
font-size: 1.5rem;
color: #000;
font-weight: 300;
cursor: pointer;
position: relative;
line-height: 1;
transition: all 0.2s ease 0.05s;
display: flex;
}

#menu-button:hover {
background: #fafafa;
}

#menu-button:focus {
box-shadow: 0 0 0 0.15rem #fff, 0 0 0 0.3rem #bbb;
}

#menu-button span {
flex-grow: 1;
text-align: center;
}

#menu-button svg {
margin-right: 1rem;
color: #999;
}

#menu {
background: #fff;
margin: auto;
margin-top: 0.8rem;
padding: 0.8rem 1rem;
border: 1px solid #ddd;
border-radius: 0.25rem;
box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.1);
opacity: 0;
visibility: hidden;
transition: transform 0.2s ease, opacity 0.2s ease, visibility 0s linear 0.2s;
will-change: transform;
text-align: left;
position: absolute;
width: fit-content;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
z-index: 2;
}

#menu.visible {
transform: translateY(-0.3rem);
transition: transform 0.2s ease, opacity 0.2s ease, visibility 0s linear 0s;
visibility: visible;
opacity: 1;
}

#menu a {
display: block;
font-size: 1.2rem;
padding: 0.25rem;
}

#menu a {
color: #3a8eb8;
text-decoration: none;
cursor: pointer;
outline: none;
border: 0.1rem solid transparent;
border-radius: 0.2rem;
}

#menu a:hover {
text-decoration: underline;
}

#menu a:focus {
border-color: #3a8eb8;
}

#menu a svg {
color: #777;
margin-right: 0.5rem;
}

h3 {
margin: 10rem 0 1rem;
font-weight: 300;
font-size: 2rem;
}

ul {
width: fit-content;
max-width: 40rem;
margin: auto;
text-align: left;
line-height: 1.3;
}

ul li {
padding: 0.25rem 0;
}

.footer {
margin-top: 10rem;
color: #999;
font-size: 0.8rem;
}

.footer a {
color: #3a8eb8;
text-decoration: none;
}

.footer a:hover {
text-decoration: underline;
}

.footer a svg {
font-size: 80%;
color: #777;
margin-left: 0.1rem;
}

.footer a:not(:last-child) {
margin-right: 2rem;
}
59 changes: 47 additions & 12 deletions demo/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,66 @@ import useDropdownMenu from 'react-accessible-dropdown-menu-hook';

// Functional component
const App: React.FC = () => {
// Use the Hook
const [buttonProps, itemProps, isOpen] = useDropdownMenu(3);

// Return JSX
return (
<div className='app'>
<button type='button' {...buttonProps} id='menu-button' tabIndex={0}>
Primary
<h1>React Accessible Dropdown Menu Hook</h1>
<h2>A simple Hook for creating fully accessible dropdown menus in React</h2>

<button {...buttonProps} type='button' id='menu-button'>
<span>Try me!</span>
<i className='fal fa-angle-down' />
</button>

<div style={{ display: isOpen ? 'block' : 'none' }} role='menu' id='menu'>
<a style={{ display: 'block' }} {...itemProps[0]} onClick={() => null} id='menu-item-1'>
Item 1
<div className={isOpen ? 'visible' : ''} role='menu' id='menu'>
<a {...itemProps[0]} href='https://github.com/sparksuite/react-accessible-dropdown-menu-hook' id='menu-item-1'>
<i className='fab fa-github fa-fw' />
View on GitHub
</a>

<a style={{ display: 'block' }} href='https://example.com' {...itemProps[1]} id='menu-item-2'>
Item 2
<a {...itemProps[1]} href='https://www.npmjs.com/package/react-accessible-dropdown-menu-hook' id='menu-item-2'>
<i className='fab fa-npm fa-fw' />
View on npm
</a>

<a style={{ display: 'block' }} href='https://example.com' {...itemProps[2]} id='menu-item-3'>
Item 3
<a {...itemProps[2]} onClick={() => alert('Click!')} id='menu-item-3'>
<i className='fas fa-mouse fa-fw' />
Item with click handler
</a>
</div>

<button type='button' id='second-button' tabIndex={0}>
Another Button
</button>
<h3>Behavior:</h3>

<ul>
<li>The menu can be revealed by clicking the button, or by focusing the button and pressing enter / space</li>
<li>When the menu is revealed, the first menu item is automatically focused</li>
<li>
<em>Once focus is in the menu…</em>

<ul>
<li>The up / down arrow keys allow for navigation through the menu items</li>
<li>Pressing tab will close the menu and move the focus to the next focusable element</li>
<li>Pressing escape will close the menu and return the focus to the button</li>
<li>Pressing enter will trigger that item (whether itʼs a link or has a click handler attached)</li>
</ul>
</li>
</ul>

<div className='footer'>
<a href='https://github.com/sparksuite/react-accessible-dropdown-menu-hook' id='first-footer-link'>
View on GitHub <i className='fad fa-external-link' />
</a>
<a href='https://www.npmjs.com/package/react-accessible-dropdown-menu-hook'>
View on npm <i className='fad fa-external-link' />
</a>
Built by&nbsp;
<a href='https://www.sparksuite.com' target='_blank' rel='noopener noreferrer'>
Sparksuite <i className='fad fa-external-link' />
</a>
</div>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion test/puppeteer/demo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ it('focuses on the next item in the tab order after pressing tab', async () => {
await keyboard.down('Enter');
await keyboard.down('Tab');

expect(await currentFocusID()).toBe('second-button');
expect(await currentFocusID()).toBe('first-footer-link');
});

it('focuses on the previous item in the tab order after pressing shift-tab', async () => {
Expand Down