diff --git a/web/src/lib/components/ui/Combobox.svelte b/web/src/lib/components/ui/Combobox.svelte index 94f8fbde..eafc1a4c 100644 --- a/web/src/lib/components/ui/Combobox.svelte +++ b/web/src/lib/components/ui/Combobox.svelte @@ -7,13 +7,12 @@ slots: { root: "relative inline-block w-full", trigger: "flex min-h-9 cursor-pointer items-center gap-2 px-2.5 py-1", - value: "min-w-0 flex-1 truncate typography-paragraph-regular text-left", + value: "min-w-0 flex-1 truncate text-left typography-paragraph-regular", panel: "combobox-panel fixed z-50 m-0 hidden max-h-[min(24rem,calc(100dvh-1rem))] w-72 max-w-[calc(100vw-1rem)] flex-col overflow-hidden rounded-sm border border-border-default bg-background-default p-0 text-foreground-default shadow-regular open:flex dark:shadow-none", search: "shrink-0 border-b border-border-default p-2", list: "min-h-0 flex-1 overflow-y-auto p-1", - groupHeading: - "px-2 pt-2 pb-1 font-semibold text-foreground-muted first:pt-1", + groupHeading: "px-2 pt-2 pb-1 font-semibold text-foreground-muted first:pt-1", option: "flex w-full cursor-pointer items-center gap-2 rounded-sm bg-transparent px-2 py-1.5 text-left aria-disabled:cursor-not-allowed aria-disabled:text-foreground-disabled data-active:bg-background-subtle dark:data-active:bg-background-subtle", check: "size-4 shrink-0 text-foreground-default", @@ -36,7 +35,8 @@ import Check from "$icon/check"; import ChevronsUpDown from "$icon/chevrons-up-down"; import Search from "$icon/search"; - import type { Snippet } from "svelte"; + import type { Component, Snippet } from "svelte"; + import type { SvelteHTMLElements } from "svelte/elements"; import { tick } from "svelte"; import Input from "./Input.svelte"; import { selectField, type SelectAlign, type SelectOption } from "./selectField"; @@ -53,6 +53,8 @@ emptyLabel?: string; /** names the trigger and the listbox for screen readers */ label?: string; + /** decorative glyph on the trigger's leading edge, standing for the current selection */ + icon?: Component; /** take filtering over, e.g. to query a server: `options` is then rendered as given */ onSearch?: (query: string) => void; loading?: boolean; @@ -75,6 +77,7 @@ searchPlaceholder = "Filter…", emptyLabel = "No matches", label, + icon: Icon, onSearch, loading = false, error = false, @@ -259,6 +262,9 @@ aria-label={label} style="anchor-name: {anchorName}" > + {#if Icon} +