Skip to content

Commit 005a1d4

Browse files
committed
arrow key controls
1 parent 657e340 commit 005a1d4

File tree

1 file changed

+34
-18
lines changed

1 file changed

+34
-18
lines changed

apps/svelte.dev/src/lib/components/SelectIcon.svelte

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
import { afterNavigate } from '$app/navigation';
33
import { page } from '$app/stores';
4-
import { trap } from '@sveltejs/site-kit/actions';
4+
import { focusable_children, trap } from '@sveltejs/site-kit/actions';
55
import { Icon } from '@sveltejs/site-kit/components';
66
import type { Snippet } from 'svelte';
77
@@ -22,6 +22,7 @@
2222
}}
2323
/>
2424

25+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
2526
<details
2627
class="examples-select"
2728
bind:open
@@ -35,29 +36,44 @@
3536
details.scrollIntoView();
3637
}}
3738
ontoggle={(e) => {
38-
const details = e.currentTarget;
39-
if (!details.open) return;
39+
const details = e.currentTarget;
40+
if (!details.open) return;
4041

41-
// close all details elements...
42-
for (const child of details.querySelectorAll('details[open]')) {
43-
(child as HTMLDetailsElement).open = false;
44-
}
42+
// close all details elements...
43+
for (const child of details.querySelectorAll('details[open]')) {
44+
(child as HTMLDetailsElement).open = false;
45+
}
4546

46-
// except parents of the current one
47-
const current = details.querySelector(`[href="${$page.url.pathname}"]`) as HTMLAnchorElement | null;
48-
if (!current) return;
47+
// except parents of the current one
48+
const current = details.querySelector(`[href="${$page.url.pathname}"]`) as HTMLAnchorElement | null;
49+
if (!current) return;
4950

50-
let node = current as Element;
51+
let node = current as Element;
5152

52-
while ((node = (node.parentNode) as Element) && node !== details) {
53-
if (node.nodeName === 'DETAILS') {
54-
(node as HTMLDetailsElement).open = true;
53+
while ((node = (node.parentNode) as Element) && node !== details) {
54+
if (node.nodeName === 'DETAILS') {
55+
(node as HTMLDetailsElement).open = true;
56+
}
5557
}
56-
}
5758

58-
current.scrollIntoView();
59-
current.focus();
60-
}}
59+
current.scrollIntoView();
60+
current.focus();
61+
}}
62+
onkeydown={(e) => {
63+
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
64+
const children = focusable_children(e.currentTarget);
65+
66+
if (e.key === 'ArrowDown') {
67+
children.next();
68+
} else {
69+
children.prev();
70+
}
71+
}
72+
73+
if (document.activeElement?.nodeName === 'SUMMARY' && (e.key === 'ArrowLeft' || e.key === 'ArrowRight')) {
74+
(document.activeElement.parentNode as HTMLDetailsElement).open = e.key === 'ArrowRight';
75+
}
76+
}}
6177
>
6278
<summary class="raised icon" aria-label={label}><Icon name="menu" /></summary>
6379

0 commit comments

Comments
 (0)