Rename TagAutocomplete to WithAutocomplete

It's general enough to be used in other cases too
This commit is contained in:
Henrik Giesel 2021-06-28 17:40:04 +02:00
parent a9538ce6a7
commit ed1f19048d
2 changed files with 28 additions and 27 deletions

View file

@ -10,7 +10,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import AddTagBadge from "./AddTagBadge.svelte"; import AddTagBadge from "./AddTagBadge.svelte";
import Tag from "./Tag.svelte"; import Tag from "./Tag.svelte";
import TagInput from "./TagInput.svelte"; import TagInput from "./TagInput.svelte";
import TagAutocomplete from "./TagAutocomplete.svelte"; import WithAutocomplete from "./WithAutocomplete.svelte";
import ButtonToolbar from "components/ButtonToolbar.svelte"; import ButtonToolbar from "components/ButtonToolbar.svelte";
import type { Tag as TagType } from "./tags"; import type { Tag as TagType } from "./tags";
import { attachId, getName } from "./tags"; import { attachId, getName } from "./tags";
@ -45,6 +45,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
} }
function updateSuggestions(): void {}
function updateWithTagName(tag: TagType): void { function updateWithTagName(tag: TagType): void {
tag.name = activeName; tag.name = activeName;
tags = tags; tags = tags;
@ -217,11 +219,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{#each tags as tag, index (tag.id)} {#each tags as tag, index (tag.id)}
{#if index === active} {#if index === active}
<TagAutocomplete <WithAutocomplete
class="d-flex flex-column-reverse" class="d-flex flex-column-reverse"
{suggestions} {suggestions}
search={tags[active ?? -1]?.name ?? ""}
on:autocomplete={onAutocomplete} on:autocomplete={onAutocomplete}
on:update={updateSuggestions}
let:updateAutocomplete let:updateAutocomplete
> >
<TagInput <TagInput
@ -248,7 +250,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
decideNextActive(); decideNextActive();
}} }}
/> />
</TagAutocomplete> </WithAutocomplete>
{:else} {:else}
<Tag <Tag
name={tag.name} name={tag.name}

View file

@ -3,7 +3,7 @@ Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
--> -->
<script lang="typescript"> <script lang="typescript">
import { createEventDispatcher, onDestroy } from "svelte"; import { createEventDispatcher, onDestroy, tick } from "svelte";
import type Dropdown from "bootstrap/js/dist/dropdown"; import type Dropdown from "bootstrap/js/dist/dropdown";
@ -15,11 +15,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export { className as class }; export { className as class };
export let suggestions: string[]; export let suggestions: string[];
export let search: string;
let autocomplete: Dropdown | undefined; let autocomplete: Dropdown | undefined;
let displayed: string[] = [];
let selected: number | null = null; let selected: number | null = null;
// blue highlight // blue highlight
@ -29,12 +26,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const updateAutocomplete = const updateAutocomplete =
(createDropdown: (element: HTMLElement) => Dropdown) => (createDropdown: (element: HTMLElement) => Dropdown) =>
(event: KeyboardEvent): Dropdown => { async (event: KeyboardEvent): Promise<void> => {
const target = event.target as HTMLInputElement; const target = event.target as HTMLInputElement;
autocomplete = createDropdown(target);
autocomplete.show();
displayed = suggestions; if (!autocomplete) {
autocomplete = createDropdown(target);
}
autocomplete.update();
if ( if (
event.code === "ArrowDown" || event.code === "ArrowDown" ||
@ -42,55 +41,55 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
) { ) {
event.preventDefault(); event.preventDefault();
if (selected === null) { if (selected === null) {
selected = displayed.length - 1; selected = suggestions.length - 1;
} else if (selected === 0) { } else if (selected === 0) {
selected = null; selected = null;
} else { } else {
selected--; selected--;
} }
const choice = displayed[selected ?? -1]; const choice = suggestions[selected ?? -1];
dispatch("autocomplete", { choice }); dispatch("autocomplete", { choice });
} else if (event.code === "ArrowUp" || event.code === "Tab") { } else if (event.code === "ArrowUp" || event.code === "Tab") {
event.preventDefault(); event.preventDefault();
if (selected === null) { if (selected === null) {
selected = 0; selected = 0;
} else if (selected >= displayed.length - 1) { } else if (selected >= suggestions.length - 1) {
selected = null; selected = null;
} else { } else {
selected++; selected++;
} }
const choice = displayed[selected ?? -1]; const choice = suggestions[selected ?? -1];
dispatch("autocomplete", { choice }); dispatch("autocomplete", { choice });
} else if (event.code === "Enter") { } else if (event.code === "Enter") {
event.preventDefault(); event.preventDefault();
active = true; active = true;
} else { } else {
search = target.value; dispatch("update");
} }
return autocomplete; await tick();
if (suggestions.length > 0) {
autocomplete.show();
} else {
autocomplete.hide();
}
}; };
onDestroy(() => { onDestroy(() => autocomplete?.dispose());
if (!autocomplete) {
return;
}
autocomplete.hide();
});
</script> </script>
<WithDropdownMenu let:menuId let:createDropdown> <WithDropdownMenu let:menuId let:createDropdown>
<slot updateAutocomplete={updateAutocomplete(createDropdown)} /> <slot updateAutocomplete={updateAutocomplete(createDropdown)} />
<DropdownMenu id={menuId} class={className}> <DropdownMenu id={menuId} class={className}>
{#each displayed as tag, i} {#each suggestions as suggestion, i}
<div class="suggestion-item"> <div class="suggestion-item">
<DropdownItem <DropdownItem
class={i === selected ? (active ? "active" : "focus") : ""} class={i === selected ? (active ? "active" : "focus") : ""}
on:click>{tag}</DropdownItem on:click>{suggestion}</DropdownItem
> >
</div> </div>
{/each} {/each}