Use our DropdownMenu component for TagAutocomplete

This commit is contained in:
Henrik Giesel 2021-06-24 20:41:50 +02:00
parent 50519ea5c8
commit 3ad86dfb33
5 changed files with 32 additions and 62 deletions

View File

@ -7,11 +7,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { dropdownKey } from "./context-keys"; import { dropdownKey } from "./context-keys";
export let id: string | undefined = undefined; export let id: string | undefined = undefined;
export let labelledby: string | undefined = undefined;
setContext(dropdownKey, null); setContext(dropdownKey, null);
</script> </script>
<div {id} class="dropdown-menu"> <div {id} class="dropdown-menu" aria-labelledby={labelledby}>
<slot /> <slot />
</div> </div>

View File

@ -17,10 +17,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
function checkForActivation(): void { function checkForActivation(): void {
const selection = window.getSelection()!; const selection = window.getSelection()!;
if (selection.isCollapsed) { active = selection.isCollapsed;
active = true;
input.focus();
}
} }
function deleteTag(event: Event): void { function deleteTag(event: Event): void {

View File

@ -4,28 +4,22 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
--> -->
<script lang="typescript"> <script lang="typescript">
import { createEventDispatcher, onMount, onDestroy } from "svelte"; import { createEventDispatcher, onMount, onDestroy } from "svelte";
import Dropdown from "bootstrap/js/dist/dropdown";
import DropdownMenu from "components/DropdownMenu.svelte";
import DropdownItem from "components/DropdownItem.svelte";
export let name: string; export let name: string;
export const suggestions = ["en::idioms", "anki::functionality", "math"];
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const triggerId = "tagLabel" + String(Math.random()).slice(2); const triggerId = "tagLabel" + String(Math.random()).slice(2);
const triggerClass = "dropdown-toggle"; const triggerClass = "dropdown-toggle";
let originalName = name;
let menu: HTMLDivElement; let menu: HTMLDivElement;
let dropdown; let dropdown;
let activeItem = -1; let activeItem = -1;
const tagSuggestions = ["en::idioms", "anki::functionality", "math"]; $: tagValues = [...suggestions, name];
$: tagValues = [...tagSuggestions, originalName];
onMount(() => {
const toggle = menu.querySelector(`#${triggerId}`)!;
dropdown = new Dropdown(toggle, {
reference: "parent",
});
});
function onItemClick(event: Event) { function onItemClick(event: Event) {
dispatch("nameChosen", { name: event.currentTarget!.innerText }); dispatch("nameChosen", { name: event.currentTarget!.innerText });
@ -43,56 +37,33 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
name = tagValues[activeItem]; name = tagValues[activeItem];
event.preventDefault(); event.preventDefault();
} else if (event.code === "Enter") { } else if (event.code === "Enter") {
const dropdownActive = dropdown._element.classList.contains("show"); /* const dropdownActive = dropdown._element.classList.contains("show"); */
if (dropdownActive) { /* if (dropdownActive) { */
if (typeof activeItem === "number") { /* if (typeof activeItem === "number") { */
name = tagValues[activeItem]; /* name = tagValues[activeItem]; */
activeItem = null; /* activeItem = null; */
} /* } */
dropdown.hide(); /* dropdown.hide(); */
} else { /* } else { */
dispatch("accept"); /* dispatch("accept"); */
} /* } */
} }
} }
</script> </script>
<div class="dropdown" bind:this={menu} on:keydown={onKeydown}> <div bind:this={menu} class="dropdown dropdown-reverse" on:keydown={onKeydown}>
<slot {triggerId} {triggerClass} {dropdown} /> <slot {triggerId} {triggerClass} {dropdown} />
<ul class="dropdown-menu" aria-labelledby={triggerId}> <DropdownMenu labelledby={triggerId}>
{#each tagSuggestions as tag, index} {#each suggestions as tag}
<li> <DropdownItem>{tag}</DropdownItem>
<a
href="#/"
class="dropdown-item"
class:dropdown-item-active={activeItem === index}
on:click={onItemClick}
>
{tag}
</a>
</li>
{/each} {/each}
</ul> </DropdownMenu>
</div> </div>
<style lang="scss"> <style lang="scss">
:global(.show).dropdown-menu { .dropdown-reverse :global(.dropdown-menu) {
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
} }
.dropdown-item {
padding: 0rem 0.3rem;
font-size: smaller;
&:focus {
outline: none;
}
}
.dropdown-item:hover {
background-color: #c3c5c7;
}
.dropdown-item-active {
color: #1e2125;
background-color: #c3c5c7;
}
</style> </style>

View File

@ -22,10 +22,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
tags = tags; tags = tags;
} }
function addTag({ detail }: CustomEvent) { function addTag() {
if (!tags.includes(detail.name) && detail.name.length > 0) { if (!tags.includes(newName) && newName.length > 0) {
tags.push(detail.name); tags.push(newName);
} }
newName = "";
tags = tags; tags = tags;
} }
</script> </script>

View File

@ -16,17 +16,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
function onFocus(event: FocusEvent, dropdown: Dropdown): void { function onFocus(event: FocusEvent, dropdown: Dropdown): void {
dropdown.show(); /* dropdown.show(); */
} }
function onAccept(event: Event): void { function onAccept(event: Event): void {
dispatch("tagupdate", { name: normalizeTagname(name) }); name = normalizeTagname(name);
input.value = ""; dispatch("tagupdate", { name });
} }
function dropdownBlur(event: Event, dropdown: Dropdown): void { function dropdownBlur(event: Event, dropdown: Dropdown): void {
onAccept(event); onAccept(event);
dropdown.hide(); /* dropdown.hide(); */
} }
function onKeydown(event: KeyboardEvent, dropdown: Dropdown): void { function onKeydown(event: KeyboardEvent, dropdown: Dropdown): void {