Skip to content

Commit 69c202e

Browse files
authored
Merge pull request #1 from dcooney/feature/prevent-focus-jump
Prevent focus jump from other element.
2 parents 1de0b11 + 9ea3d5a commit 69c202e

File tree

5 files changed

+47
-12
lines changed

5 files changed

+47
-12
lines changed

.eslintignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
build/
2+
node_modules/
3+
dist/
4+
src/demo

.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
extends: ['react-app'],
3+
rules: {
4+
'no-console': ['error', {allow: ['warn', 'error']}]
5+
}
6+
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-use-arrows",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"description": "React hook for traversing DOM elements with keyboard arrows.",
55
"homepage": "https://dcooney.github.io/react-use-arrows/",
66
"source": "src/lib/useArrows.tsx",
@@ -44,7 +44,7 @@
4444
"start": "react-scripts start",
4545
"dev": "microbundle watch",
4646
"build": "rm -rf dist && microbundle",
47-
"build:demo": "BUILD_PATH='./docs' react-scripts build"
47+
"build:docs": "BUILD_PATH='./docs' react-scripts build"
4848
},
4949
"keywords": [
5050
"arrows",

src/demo/examples/Dropdown.tsx

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,24 @@ export default function Dropdown() {
1515

1616
/**
1717
* Handle keyboard controls.
18-
*
19-
* @param {Event} event The click event.
2018
*/
21-
function handleEsc(event: KeyboardEvent) {
19+
function handleKeydown(event: any) {
20+
const {key} = event
21+
switch (key) {
22+
case 'ArrowDown':
23+
setActive(true)
24+
event.preventDefault()
25+
break
26+
27+
default:
28+
break
29+
}
30+
}
31+
32+
/**
33+
* Handle keyboard controls.
34+
*/
35+
function handleEsc(event: any) {
2236
const {key} = event
2337
switch (key) {
2438
// Exit if esc and no focusable elements.
@@ -35,7 +49,8 @@ export default function Dropdown() {
3549
useEffect(() => {
3650
if (active) {
3751
// Set focus on first dropdown item.
38-
ref.current?.querySelector('a')?.focus()
52+
const element = ref.current?.querySelector('a') as HTMLElement
53+
element?.focus()
3954
}
4055
}, [active])
4156

@@ -58,6 +73,7 @@ export default function Dropdown() {
5873
<button
5974
className="btn btn-neutral"
6075
onClick={() => setActive(!active)}
76+
onKeyDown={(e) => handleKeydown(e)}
6177
>
6278
Toggle Menu
6379
</button>
@@ -81,7 +97,7 @@ export default function Dropdown() {
8197
<li>
8298
<a
8399
href="https://getinstantimages.com"
84-
className={btnClass}
100+
className={`${btnClass} test`}
85101
>
86102
Instant Images
87103
</a>
@@ -96,10 +112,10 @@ export default function Dropdown() {
96112
</li>
97113
<li>
98114
<a
99-
href="https://dcooney.github.io/react-a11y-dropdown/"
115+
href="https://dcooney.github.io/react-npm-starter/"
100116
className={btnClass}
101117
>
102-
React A11y Dropdown
118+
React NPM Starter
103119
</a>
104120
</li>
105121
</ul>

src/lib/useArrows.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ const defaults = [
1111
'[tabindex]:not([tabindex="-1"])'
1212
]
1313

14-
// 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])'
15-
1614
interface useArrowsProps {
1715
selectors?: string
1816
useUpDown?: boolean
@@ -79,6 +77,17 @@ export default function useArrows(
7977
const last = elements[elements.length - 1]
8078
const index = [...elements].indexOf(activeElement)
8179

80+
/**
81+
* Prevent focus from jumping if the current focus is not in the element array.
82+
*
83+
* This will help prevent focus from jumping to the next focusable element
84+
* when using keydown event on external DOM element.
85+
*/
86+
if (elements.indexOf(event?.target) === -1) {
87+
return
88+
}
89+
90+
// Switch focus based on key pressed.
8291
switch (key) {
8392
case 'ArrowUp':
8493
if (useUpDown) {
@@ -137,7 +146,7 @@ export default function useArrows(
137146
// Dispose of event listener on unmount.
138147
document.removeEventListener('keydown', arrowHandler, false)
139148
}
140-
}, [])
149+
}, []) // eslint-disable-line react-hooks/exhaustive-deps
141150

142151
return ref
143152
}

0 commit comments

Comments
 (0)