Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
ba92ed1b
Commit
ba92ed1b
authored
Apr 21, 2023
by
Alejandro Celaya
Committed by
Alejandro Celaya
Apr 25, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate keyboard-navigation to TS
parent
22dd6fd6
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
31 additions
and
34 deletions
+31
-34
keyboard-navigation.ts
src/shared/keyboard-navigation.ts
+31
-34
No files found.
src/shared/keyboard-navigation.
j
s
→
src/shared/keyboard-navigation.
t
s
View file @
ba92ed1b
import
type
{
RefObject
}
from
'preact'
;
import
{
useEffect
}
from
'preact/hooks'
;
import
{
useEffect
}
from
'preact/hooks'
;
import
{
ListenerCollection
}
from
'./listener-collection'
;
import
{
ListenerCollection
}
from
'./listener-collection'
;
/**
function
isElementDisabled
(
* @param {HTMLElement & { disabled?: boolean }} element
element
:
HTMLElement
&
{
disabled
?:
boolean
}
*/
):
element
is
HTMLElement
&
{
disabled
:
true
}
{
function
isElementDisabled
(
element
)
{
return
typeof
element
.
disabled
===
'boolean'
&&
element
.
disabled
;
return
typeof
element
.
disabled
===
'boolean'
&&
element
.
disabled
;
}
}
/** @param {HTMLElement} element */
function
isElementVisible
(
element
:
HTMLElement
):
boolean
{
function
isElementVisible
(
element
)
{
return
element
.
offsetParent
!==
null
;
return
element
.
offsetParent
!==
null
;
}
}
export
type
ArrowKeyNavigationOptions
=
{
/**
* Whether to focus the first element in the set of matching elements when the
* component is mounted
*/
autofocus
?:
boolean
;
/** Enable navigating elements using left/right arrow keys */
horizontal
?:
boolean
;
/** Enable navigating elements using up/down arrow keys */
vertical
?:
boolean
;
/** CSS selector which specifies the elements that navigation moves between */
selector
?:
string
;
};
/**
/**
* Enable arrow key navigation between interactive descendants of a
* Enable arrow key navigation between interactive descendants of a
* container element.
* container element.
...
@@ -45,24 +59,15 @@ function isElementVisible(element) {
...
@@ -45,24 +59,15 @@ function isElementVisible(element) {
*
*
* [1] https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex
* [1] https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex
* [2] https://www.w3.org/TR/wai-aria-practices/#keyboard
* [2] https://www.w3.org/TR/wai-aria-practices/#keyboard
*
* @param {import('preact').RefObject<HTMLElement>} containerRef
* @param {object} options
* @param {boolean} [options.autofocus] - Whether to focus the first element
* in the set of matching elements when the component is mounted
* @param {boolean} [options.horizontal] - Enable navigating elements using left/right arrow keys
* @param {boolean} [options.vertical] - Enable navigating elements using up/down arrow keys
* @param {string} [options.selector] - CSS selector which specifies the
* elements that navigation moves between
*/
*/
export
function
useArrowKeyNavigation
(
export
function
useArrowKeyNavigation
(
containerRef
,
containerRef
:
RefObject
<
HTMLElement
>
,
{
{
autofocus
=
false
,
autofocus
=
false
,
horizontal
=
true
,
horizontal
=
true
,
vertical
=
true
,
vertical
=
true
,
selector
=
'a,button'
,
selector
=
'a,button'
,
}
=
{}
}
:
ArrowKeyNavigationOptions
=
{}
)
{
)
{
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
!
containerRef
.
current
)
{
if
(
!
containerRef
.
current
)
{
...
@@ -71,8 +76,8 @@ export function useArrowKeyNavigation(
...
@@ -71,8 +76,8 @@ export function useArrowKeyNavigation(
const
container
=
containerRef
.
current
;
const
container
=
containerRef
.
current
;
const
getNavigableElements
=
()
=>
{
const
getNavigableElements
=
()
=>
{
const
elements
=
/** @type {HTMLElement[]} */
(
const
elements
:
HTMLElement
[]
=
Array
.
from
(
Array
.
from
(
container
.
querySelectorAll
(
selector
)
)
container
.
querySelectorAll
(
selector
)
);
);
return
elements
.
filter
(
return
elements
.
filter
(
el
=>
isElementVisible
(
el
)
&&
!
isElementDisabled
(
el
)
el
=>
isElementVisible
(
el
)
&&
!
isElementDisabled
(
el
)
...
@@ -85,14 +90,13 @@ export function useArrowKeyNavigation(
...
@@ -85,14 +90,13 @@ export function useArrowKeyNavigation(
* Exactly one element will have `tabindex=0` and all others will have
* Exactly one element will have `tabindex=0` and all others will have
* `tabindex=1`.
* `tabindex=1`.
*
*
* @param {HTMLElement[]} elements
* @param currentIndex - Index of element in `elements` to make current.
* @param {number} currentIndex - Index of element in `elements` to make current.
* Defaults to the current element if there is one, or the first element
* Defaults to the current element if there is one, or the first element
* otherwise.
* otherwise.
* @param
{boolean}
setFocus - Whether to focus the current element
* @param setFocus - Whether to focus the current element
*/
*/
const
updateTabIndexes
=
(
const
updateTabIndexes
=
(
elements
=
getNavigableElements
(),
elements
:
HTMLElement
[]
=
getNavigableElements
(),
currentIndex
=
-
1
,
currentIndex
=
-
1
,
setFocus
=
false
setFocus
=
false
)
=>
{
)
=>
{
...
@@ -103,7 +107,7 @@ export function useArrowKeyNavigation(
...
@@ -103,7 +107,7 @@ export function useArrowKeyNavigation(
}
}
}
}
for
(
le
t
[
index
,
element
]
of
elements
.
entries
())
{
for
(
cons
t
[
index
,
element
]
of
elements
.
entries
())
{
element
.
tabIndex
=
index
===
currentIndex
?
0
:
-
1
;
element
.
tabIndex
=
index
===
currentIndex
?
0
:
-
1
;
if
(
index
===
currentIndex
&&
setFocus
)
{
if
(
index
===
currentIndex
&&
setFocus
)
{
element
.
focus
();
element
.
focus
();
...
@@ -111,8 +115,7 @@ export function useArrowKeyNavigation(
...
@@ -111,8 +115,7 @@ export function useArrowKeyNavigation(
}
}
};
};
/** @param {KeyboardEvent} event */
const
onKeyDown
=
(
event
:
KeyboardEvent
)
=>
{
const
onKeyDown
=
event
=>
{
const
elements
=
getNavigableElements
();
const
elements
=
getNavigableElements
();
let
currentIndex
=
elements
.
findIndex
(
item
=>
item
.
tabIndex
===
0
);
let
currentIndex
=
elements
.
findIndex
(
item
=>
item
.
tabIndex
===
0
);
...
@@ -164,19 +167,13 @@ export function useArrowKeyNavigation(
...
@@ -164,19 +167,13 @@ export function useArrowKeyNavigation(
// is triggered.
// is triggered.
listeners
.
add
(
container
,
'focusin'
,
event
=>
{
listeners
.
add
(
container
,
'focusin'
,
event
=>
{
const
elements
=
getNavigableElements
();
const
elements
=
getNavigableElements
();
const
targetIndex
=
elements
.
indexOf
(
const
targetIndex
=
elements
.
indexOf
(
event
.
target
as
HTMLElement
);
/** @type {HTMLElement} */
(
event
.
target
)
);
if
(
targetIndex
>=
0
)
{
if
(
targetIndex
>=
0
)
{
updateTabIndexes
(
elements
,
targetIndex
);
updateTabIndexes
(
elements
,
targetIndex
);
}
}
});
});
listeners
.
add
(
listeners
.
add
(
container
,
'keydown'
,
onKeyDown
);
container
,
'keydown'
,
/** @type {EventListener} */
(
onKeyDown
)
);
// Update the tab indexes of elements as they are added, removed, enabled
// Update the tab indexes of elements as they are added, removed, enabled
// or disabled.
// or disabled.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment