feat: add arrow key support to Selector

feat/type-attributes
Tomáš Mládek 2023-01-22 14:53:11 +01:00
parent e5fc315852
commit 8eb4466222
2 changed files with 73 additions and 12 deletions

View File

@ -29,6 +29,7 @@
on:input={onInput}
on:focus={() => (focused = true)}
on:blur={() => (focused = false)}
on:keydown
{disabled}
/>
</div>

View File

@ -182,14 +182,59 @@
visible = false;
}
let inputFocused = false;
let hover = false;
$: visible = (inputFocused || hover) && Boolean(options.length);
let listEl: HTMLUListElement;
let optionFocusIndex: number = -1;
function handleArrowKeys(ev: KeyboardEvent) {
if (!options.length) {
return;
}
const optionEls = Array.from(listEl.children) as HTMLLIElement[];
const currentIndex = optionEls.findIndex(
(el) => document.activeElement === el
);
let targetIndex = currentIndex;
switch (ev.key) {
case "ArrowDown":
targetIndex += 1;
// pressed down on last
if (targetIndex >= optionEls.length) {
targetIndex = 0;
}
break;
case "ArrowUp":
targetIndex -= 1;
// pressed up on input
if (targetIndex == -2) {
targetIndex = optionEls.length - 1;
}
// pressed up on first
if (targetIndex == -1) {
focus();
return;
}
break;
default:
return; // early return, stop processing
}
if (optionEls[targetIndex]) {
optionEls[targetIndex].focus();
}
}
let input: Input;
export function focus() {
input.focus();
}
let inputFocused = false;
$: visible =
(inputFocused || optionFocusIndex > -1) && Boolean(options.length);
</script>
<div class="selector">
@ -206,18 +251,28 @@
bind:value={inputValue}
on:input={onInput}
on:focusChange={(ev) => (inputFocused = ev.detail)}
on:keydown={handleArrowKeys}
{disabled}
{placeholder}
/>
{/if}
<ul
class="options"
class:visible
on:mouseenter={() => (hover = true)}
on:mouseleave={() => (hover = false)}
>
{#each options.slice(0, MAX_OPTIONS) as option}
<li on:click={() => set(option)}>
<ul class="options" class:visible bind:this={listEl}>
{#each options.slice(0, MAX_OPTIONS) as option, idx}
<!-- svelte-ignore a11y-no-noninteractive-tabindex -->
<li
tabindex="0"
on:click={() => set(option)}
on:mousemove={() => focus()}
on:focus={() => (optionFocusIndex = idx)}
on:blur={() => (optionFocusIndex = -1)}
on:keydown={(ev) => {
if (ev.key === "Enter") {
set(option);
} else {
handleArrowKeys(ev);
}
}}
>
{#if option.attribute}
{option.attribute}
{:else if option.value}
@ -282,11 +337,16 @@
cursor: pointer;
padding: 0.5em;
transition: background-color 0.2s;
transition: background-color 0.1s;
&:hover {
background-color: var(--background-lighter);
}
&:focus {
background-color: var(--background-lighter);
outline: none;
}
.type,
.content {
display: inline-block;