aboutsummaryrefslogtreecommitdiffstats
path: root/code/app/src/lib/components/combobox.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'code/app/src/lib/components/combobox.svelte')
-rw-r--r--code/app/src/lib/components/combobox.svelte57
1 files changed, 32 insertions, 25 deletions
diff --git a/code/app/src/lib/components/combobox.svelte b/code/app/src/lib/components/combobox.svelte
index ee69917..4e7b1cd 100644
--- a/code/app/src/lib/components/combobox.svelte
+++ b/code/app/src/lib/components/combobox.svelte
@@ -7,7 +7,7 @@
</script>
<script lang="ts">
- import { CheckCircleIcon, ChevronUpDownIcon, XIcon } from "$lib/components/icons";
+ import { CheckCircleIcon, ChevronUpDownIcon, XIcon } from "./icons";
import { element_has_focus, random_string } from "$lib/helpers";
import { go, highlight } from "fuzzysort";
import Badge from "./badge.svelte";
@@ -20,19 +20,19 @@
export let disabled: boolean | undefined = undefined;
export let required: boolean | undefined = undefined;
export let maxlength: number | undefined = undefined;
- export let placeholder = $LL.combobox.search();
+ export let placeholder: string = $LL.combobox.search();
export let options: Array<ComboboxOption> | undefined = [];
export let createable = false;
export let loading = false;
export let multiple = false;
- export let noResultsText = $LL.combobox.noRecordsFound();
+ export let noResultsText: string = $LL.combobox.noRecordsFound();
export let on_create_async = async ({ name: string }) => {};
export const reset = () => methods.reset();
export const select = (id: string) => methods.select_entry(id);
export const deselect = (id: string) => methods.deselect_entry(id);
- const INTERNAL_ID = "INTERNAL__combobox-" + random_string(3);
+ const INTERNAL_ID = "INTERNAL__" + id;
let optionsListId = id + "--options";
let searchInputNode;
@@ -75,7 +75,7 @@
if (!value) {
return "";
}
- return value.toString().trim().toLowerCase();
+ return value.trim().toLowerCase();
},
do() {
const query = search.normalise_value(searchValue);
@@ -85,9 +85,9 @@
return;
}
- //@ts-ignore
+ // @ts-ignore
searchResults = go(query, options, {
- limit: 10,
+ limit: 15,
allowTypo: true,
threshold: -10000,
key: "name",
@@ -206,11 +206,11 @@
if (searchValue) {
return options;
}
- return (options as any).sort((a, b) => {
- search.normalise_value(a.name).localeCompare(search.normalise_value(b.name));
- });
+
+ return options.sort((a, b) => search.normalise_value(a.name).localeCompare(search.normalise_value(b.name)));
},
};
+
const windowEvents = {
on_mousemove(event: any) {
if (!event.target) return;
@@ -230,7 +230,7 @@
const spacePressed = event.code === "Space";
const arrowDownPressed = event.code === "ArrowDown";
const searchInputHasFocus = element_has_focus(searchInputNode);
- const focusedEntry = document.querySelector("#" + INTERNAL_ID + " ul .focus");
+ const focusedEntry = document.querySelector("#" + INTERNAL_ID + " ul li.focus") as HTMLLIElement;
if (showDropdown && (enterPressed || arrowDownPressed || arrowUpPressed)) {
event.preventDefault();
@@ -262,16 +262,18 @@
focusedEntry.nextElementSibling.classList.add("focus");
focusedEntry.nextElementSibling.scrollIntoView(false);
} else {
- document.querySelector("#" + INTERNAL_ID + " ul li:first-of-type").classList.add("focus");
- document.querySelector("#" + INTERNAL_ID + " ul li:first-of-type").scrollIntoView(false);
+ const firstLIEl = document.querySelector("#" + INTERNAL_ID + " ul li:first-of-type");
+ firstLIEl.classList.add("focus");
+ firstLIEl.scrollIntoView(false);
}
} else if (arrowUpPressed) {
if (focusedEntry.previousElementSibling) {
focusedEntry.previousElementSibling.classList.add("focus");
focusedEntry.previousElementSibling.scrollIntoView(false);
} else {
- document.querySelector("#" + INTERNAL_ID + " ul li:last-of-type").classList.add("focus");
- document.querySelector("#" + INTERNAL_ID + " ul li:last-of-type").scrollIntoView(false);
+ const lastLIEl = document.querySelector("#" + INTERNAL_ID + " ul li:last-of-type");
+ lastLIEl.classList.add("focus");
+ lastLIEl.scrollIntoView(false);
}
}
focusedEntry.classList.remove("focus");
@@ -279,7 +281,6 @@
}
if (focusedEntry && (spacePressed || enterPressed)) {
- //@ts-ignore
methods.select_entry(focusedEntry.dataset.id);
return;
}
@@ -303,14 +304,17 @@
<div id={INTERNAL_ID} class:cursor-wait={loading}>
{#if label}
- <label for={id} class="block text-sm font-medium text-gray-700">{label}</label>
+ <label for={id} class="block text-sm font-medium text-gray-700">
+ {label}
+ {@html required ? "<span class='text-red-500'>*</span>" : ""}
+ </label>
{/if}
<div class="relative {label ? 'mt-1' : ''}">
<div
on:click={search.on_input_wrapper_focus}
on:keypress={search.on_input_wrapper_focus}
- class="cursor-text w-full rounded-md border bg-white py-2 pl-3 pr-12 sm:text-sm
- {inputHasFocus ? `border-${colorName}-500 outline-none ring-1 ring-{colorName}-500` : 'shadow-sm border-gray-300'}"
+ class="cursor-text w-full flex rounded-md border bg-white py-2 pl-3 pr-12 sm:text-sm
+ {inputHasFocus ? `border-${colorName}-500 outline-none ring-1 ring-${colorName}-500` : 'shadow-sm border-gray-300'}"
>
{#if multiple === true && hasSelection}
<div class="flex gap-1 flex-wrap">
@@ -325,7 +329,7 @@
{/each}
</div>
{/if}
- <div class={multiple === true && hasSelection ? "mt-2" : ""}>
+ <div>
<input
{...attributes}
type="text"
@@ -346,12 +350,13 @@
type="button"
on:click={() => reset()}
title={$LL.reset()}
+ tabindex="-1"
class="text-gray-400 absolute cursor-pointer inset-y-0 right-0 flex items-center rounded-r-md px-2"
>
<XIcon />
</button>
{:else}
- <span class="text-gray-400 absolute inset-y-0 right-0 flex items-center rounded-r-md px-2">
+ <span tabindex="-1" class="text-gray-400 absolute inset-y-0 right-0 flex items-center rounded-r-md px-2">
<ChevronUpDownIcon />
</span>
{/if}
@@ -406,10 +411,12 @@
</li>
{/each}
{:else}
- <p class="px-2">{noResultsText}</p>
- {#if createable && !searchValue}
- <p class="px-2 text-gray-500">{$LL.combobox.createRecordHelpText()}</p>
- {/if}
+ <slot name="no-records">
+ <p class="px-2">{noResultsText}</p>
+ {#if createable && !searchValue}
+ <p class="px-2 text-gray-500">{$LL.combobox.createRecordHelpText()}</p>
+ {/if}
+ </slot>
{/if}
</ul>
{#if showCreationHint}