Have WithAutocomplete export its API

allows it to be used in more contexts
This commit is contained in:
Henrik Giesel 2021-06-28 19:21:01 +02:00
parent ed1f19048d
commit bbef2ab6b4
2 changed files with 115 additions and 59 deletions

View file

@ -45,7 +45,21 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
} }
function updateSuggestions(): void {} let addOrPop = true;
function updateSuggestions(): void {
if (suggestions.length === 0) {
addOrPop = false;
} else if (suggestions.length > 3) {
addOrPop = true;
}
if (addOrPop) {
suggestions.pop();
suggestions = suggestions;
} else {
suggestions = suggestions.concat(["another"]);
}
}
function updateWithTagName(tag: TagType): void { function updateWithTagName(tag: TagType): void {
tag.name = activeName; tag.name = activeName;
@ -210,6 +224,38 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
active = activeAfterBlur; active = activeAfterBlur;
activeAfterBlur = null; activeAfterBlur = null;
} }
function update(event: KeyboardEvent, autocomplete): void {
switch (event.code) {
case "ArrowUp":
autocomplete.selectNext();
event.preventDefault();
break;
case "ArrowDown":
autocomplete.selectPrevious();
event.preventDefault();
break;
case "Tab":
if (event.shiftKey) {
autocomplete.selectNext();
} else {
autocomplete.selectPrevious();
}
event.preventDefault();
break;
case "Enter":
autocomplete.chooseSelected();
event.preventDefault();
break;
default:
autocomplete.update();
break;
}
}
</script> </script>
<StickyBottom> <StickyBottom>
@ -224,14 +270,18 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{suggestions} {suggestions}
on:autocomplete={onAutocomplete} on:autocomplete={onAutocomplete}
on:update={updateSuggestions} on:update={updateSuggestions}
let:updateAutocomplete let:createAutocomplete
let:autocomplete
> >
<TagInput <TagInput
id={tag.id} id={tag.id}
bind:name={activeName} bind:name={activeName}
bind:input={activeInput} bind:input={activeInput}
on:focus={() => (activeName = tag.name)} on:focus={() => {
on:keydown={updateAutocomplete} activeName = tag.name;
createAutocomplete(activeInput);
}}
on:keydown={(event) => update(event, autocomplete)}
on:input={() => updateWithTagName(tag)} on:input={() => updateWithTagName(tag)}
on:tagsplit={({ detail }) => on:tagsplit={({ detail }) =>
splitTag(index, detail.start, detail.end)} splitTag(index, detail.start, detail.end)}

View file

@ -16,7 +16,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let suggestions: string[]; export let suggestions: string[];
let autocomplete: Dropdown | undefined; let dropdown: Dropdown | undefined;
let selected: number | null = null; let selected: number | null = null;
// blue highlight // blue highlight
@ -24,22 +24,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const updateAutocomplete = const createAutocomplete =
(createDropdown: (element: HTMLElement) => Dropdown) => (createDropdown: (target: HTMLElement) => Dropdown) =>
async (event: KeyboardEvent): Promise<void> => { (target: HTMLElement): void => {
const target = event.target as HTMLInputElement; dropdown = createDropdown(target);
};
if (!autocomplete) { function selectPrevious() {
autocomplete = createDropdown(target);
}
autocomplete.update();
if (
event.code === "ArrowDown" ||
(event.code === "Tab" && event.shiftKey)
) {
event.preventDefault();
if (selected === null) { if (selected === null) {
selected = suggestions.length - 1; selected = suggestions.length - 1;
} else if (selected === 0) { } else if (selected === 0) {
@ -49,9 +40,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
const choice = suggestions[selected ?? -1]; const choice = suggestions[selected ?? -1];
dispatch("autocomplete", { choice }); dispatch("dropdown", { choice });
} else if (event.code === "ArrowUp" || event.code === "Tab") { }
event.preventDefault();
function selectNext() {
if (selected === null) { if (selected === null) {
selected = 0; selected = 0;
} else if (selected >= suggestions.length - 1) { } else if (selected >= suggestions.length - 1) {
@ -62,27 +54,41 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const choice = suggestions[selected ?? -1]; const choice = suggestions[selected ?? -1];
dispatch("autocomplete", { choice }); dispatch("autocomplete", { choice });
} else if (event.code === "Enter") {
event.preventDefault();
active = true;
} else {
dispatch("update");
} }
function chooseSelected() {
active = true;
}
async function update() {
dropdown = dropdown as Dropdown;
dropdown.update();
dispatch("update");
await tick(); await tick();
if (suggestions.length > 0) { if (suggestions.length > 0) {
autocomplete.show(); dropdown.show();
} else { } else {
autocomplete.hide(); dropdown.hide();
} }
}
const autocomplete = {
hide: () => dropdown!.hide(),
show: () => dropdown!.show(),
toggle: () => dropdown!.toggle(),
selectPrevious,
selectNext,
chooseSelected,
update,
}; };
onDestroy(() => autocomplete?.dispose()); onDestroy(() => dropdown?.dispose());
</script> </script>
<WithDropdownMenu let:menuId let:createDropdown> <WithDropdownMenu let:menuId let:createDropdown>
<slot updateAutocomplete={updateAutocomplete(createDropdown)} /> <slot createAutocomplete={createAutocomplete(createDropdown)} {autocomplete} />
<DropdownMenu id={menuId} class={className}> <DropdownMenu id={menuId} class={className}>
{#each suggestions as suggestion, i} {#each suggestions as suggestion, i}