mirror of
https://github.com/ankitects/anki.git
synced 2025-11-13 08:07:11 -05:00
Have WithAutocomplete export its API
allows it to be used in more contexts
This commit is contained in:
parent
ed1f19048d
commit
bbef2ab6b4
2 changed files with 115 additions and 59 deletions
|
|
@ -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)}
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue