Spaces:
Running
Running
| <script lang="ts" module> | |
| import type { Snippet } from 'svelte'; | |
| export type SelectFieldOption = { | |
| value: string; | |
| label: string; | |
| }; | |
| export type SelectFieldProps = { | |
| id: string; | |
| label: string; | |
| options: SelectFieldOption[]; | |
| value?: string | string[]; | |
| type?: 'single' | 'multiple'; | |
| triggerLabel: string; | |
| containerClass?: string; | |
| triggerClass?: string; | |
| contentClass?: string; | |
| showLabel?: boolean; | |
| separatorAfterValue?: string; | |
| onValueChange?: ((value: string) => void) | ((value: string[]) => void); | |
| item?: Snippet<[SelectFieldOption]>; | |
| }; | |
| </script> | |
| <script lang="ts"> | |
| import * as Select from '$lib/components/ui/select'; | |
| let { | |
| id, | |
| label, | |
| options, | |
| value = $bindable(), | |
| type = 'single', | |
| triggerLabel, | |
| containerClass = 'min-w-0 space-y-2', | |
| triggerClass = 'w-full', | |
| contentClass, | |
| showLabel = true, | |
| separatorAfterValue, | |
| onValueChange, | |
| item | |
| }: SelectFieldProps = $props(); | |
| function getSingleValue() { | |
| return typeof value === 'string' ? value : undefined; | |
| } | |
| function setSingleValue(nextValue: string | undefined) { | |
| if (nextValue === undefined) return; | |
| value = nextValue; | |
| (onValueChange as ((value: string) => void) | undefined)?.(nextValue); | |
| } | |
| function getMultipleValue() { | |
| return Array.isArray(value) ? value : undefined; | |
| } | |
| function setMultipleValue(nextValue: string[] | undefined) { | |
| if (nextValue === undefined) return; | |
| value = nextValue; | |
| (onValueChange as ((value: string[]) => void) | undefined)?.(nextValue); | |
| } | |
| </script> | |
| <div class={containerClass}> | |
| {#if showLabel} | |
| <span {id} class="block text-xs font-semibold tracking-wider text-muted-foreground uppercase"> | |
| {label} | |
| </span> | |
| {/if} | |
| {#if type === 'multiple'} | |
| <Select.Root type="multiple" bind:value={getMultipleValue, setMultipleValue} items={options}> | |
| <Select.Trigger aria-labelledby={id} class={triggerClass}> | |
| <span data-slot="select-value">{triggerLabel}</span> | |
| </Select.Trigger> | |
| <Select.Content preventScroll={false} class={contentClass}> | |
| <Select.Group> | |
| {#each options as option (option.value)} | |
| {#if item} | |
| <Select.Item value={option.value} label={option.label}> | |
| {@render item(option)} | |
| </Select.Item> | |
| {:else} | |
| <Select.Item value={option.value} label={option.label} /> | |
| {/if} | |
| {#if option.value === separatorAfterValue} | |
| <Select.Separator /> | |
| {/if} | |
| {/each} | |
| </Select.Group> | |
| </Select.Content> | |
| </Select.Root> | |
| {:else} | |
| <Select.Root type="single" bind:value={getSingleValue, setSingleValue} items={options}> | |
| <Select.Trigger aria-labelledby={id} class={triggerClass}> | |
| <span data-slot="select-value">{triggerLabel}</span> | |
| </Select.Trigger> | |
| <Select.Content preventScroll={false} class={contentClass}> | |
| <Select.Group> | |
| {#each options as option (option.value)} | |
| {#if item} | |
| <Select.Item value={option.value} label={option.label}> | |
| {@render item(option)} | |
| </Select.Item> | |
| {:else} | |
| <Select.Item value={option.value} label={option.label} /> | |
| {/if} | |
| {#if option.value === separatorAfterValue} | |
| <Select.Separator /> | |
| {/if} | |
| {/each} | |
| </Select.Group> | |
| </Select.Content> | |
| </Select.Root> | |
| {/if} | |
| </div> | |