Skip to content

Commit

Permalink
fix(Dropdown): allow keyboard navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
N00nDay committed Apr 25, 2023
1 parent 6dee888 commit a8c936b
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 14 deletions.
4 changes: 3 additions & 1 deletion src/lib/components/dropdown/Dropdown.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { twMerge } from 'tailwind-merge';
import { clickOutside } from '../../actions';
import { get_current_component } from 'svelte/internal';
import { get_current_component, setContext } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
Expand All @@ -13,6 +13,8 @@
visible = false;
}
setContext('dropdown-handleClose', handleClose);
const defaultClass = 'relative inline-block';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>
Expand Down
34 changes: 24 additions & 10 deletions src/lib/components/dropdown/Item.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,37 @@
export let label: string;
function handleKeydown(e: KeyboardEvent) {
if (e.key === 'Enter') {
e.preventDefault();
e.stopPropagation();
const { target } = e;
// const enterEvent = new KeyboardEvent('keydown', { key: 'Enter' });
if (target && target instanceof HTMLLIElement) target.click();
}
}
const defaultClass =
'w-full group relative flex items-center px-3 py-2 text-sm font-medium rounded-md overflow-hidden text-secondary-content';
'w-full group relative flex items-center px-3 py-2 text-sm font-medium rounded-md overflow-hidden text-secondary-content !outline-none !border-none !ring-0';
$: finalClass = twMerge(defaultClass, $$props.class);
</script>

<button
aria-label="dropdown item"
<li
class={finalClass}
tabindex="-1"
on:keydown={handleKeydown}
use:useActions={use}
use:forwardEvents
{...exclude($$props, ['use', 'class'])}
>
<span class="flex items-center justify-start flex-grow">
<slot name="icon" />
<span class="truncate" class:ml-3={$$slots.icon}>{label}</span>
</span>
<button type="button" aria-label="select option" class="w-full flex items-center">
<span class="flex items-center justify-start flex-grow">
<slot name="icon" />
<span class="truncate" class:ml-3={$$slots.icon}>{label}</span>
</span>

<slot name="extra" />
<HoverBackground class="rounded-md" />
</button>
<slot name="extra" />
<HoverBackground class="rounded-md" />
</button>
</li>
37 changes: 34 additions & 3 deletions src/lib/components/dropdown/Items.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { scale } from 'svelte/transition';
import { get_current_component } from 'svelte/internal';
import { get_current_component, getContext, onMount } from 'svelte/internal';
import { forwardEventsBuilder, useActions, type ActionArray } from '../../actions';
export let use: ActionArray = [];
import { exclude } from '../../utils/exclude';
Expand All @@ -11,6 +11,29 @@
export let alignment: 'start' | 'center' | 'end' = 'start';
export let offset = 2;
let list: HTMLUListElement;
// eslint-disable-next-line no-undef
let items: NodeListOf<HTMLLIElement> | never[] = [];
let focusIndex = 0;
const handleClose: () => void = getContext('dropdown-handleClose');
function handleKeydown(e: KeyboardEvent) {
e.preventDefault();
e.stopPropagation();
if (e.key === 'ArrowUp') {
focusIndex = focusIndex > 0 ? focusIndex - 1 : items.length - 1;
items[focusIndex].focus();
} else if (e.key === 'ArrowDown') {
focusIndex = focusIndex < items.length - 1 ? focusIndex + 1 : 0;
items[focusIndex].focus();
} else if (e.key === 'Enter') {
console.log('Enter FIRED');
} else if (e.key === 'Escape') {
handleClose();
}
}
const defaultClass =
'origin-top-right absolute z-10 border border-border w-56 p-1 rounded-md shadow-xl py-1 bg-surface';
let positioning: string;
Expand Down Expand Up @@ -54,9 +77,17 @@
}
$: finalClass = twMerge(defaultClass, positioning, $$props.class);
onMount(() => {
items = list.querySelectorAll('li');
items[focusIndex].focus();
});
</script>

<div
<svelte:window on:keydown|preventDefault={handleKeydown} />

<ul
bind:this={list}
class={finalClass}
use:useActions={use}
use:forwardEvents
Expand All @@ -67,4 +98,4 @@
tabindex="-1"
>
<slot />
</div>
</ul>

0 comments on commit a8c936b

Please sign in to comment.