your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { Button, cn, toggleVariants } from '@foxui/core';
3 import { Select, type WithoutChildren } from 'bits-ui';
4 import Icon from './Icon.svelte';
5
6 type Props = WithoutChildren<Select.RootProps> & {
7 placeholder?: string;
8 items: { value: string; label: string; disabled?: boolean }[];
9 contentProps?: WithoutChildren<Select.ContentProps>;
10 };
11
12 let { value = $bindable(), items, contentProps, placeholder, ...restProps }: Props = $props();
13</script>
14
15<Select.Root bind:value={value as never} {...restProps}>
16 <Select.Trigger>
17 {#snippet child({ props })}
18 <button {...props} class={cn(toggleVariants({ size: 'sm' }), 'gap-1')}>
19 {#if value}
20 <Icon name={value as any} />
21 {:else}
22 <span class="size-3.5">?</span>
23 {/if}
24
25 <svg
26 xmlns="http://www.w3.org/2000/svg"
27 fill="none"
28 viewBox="0 0 24 24"
29 stroke-width="1.5"
30 stroke="currentColor"
31 class="!size-2.5"
32 >
33 <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
34 </svg>
35 </button>
36 {/snippet}
37 </Select.Trigger>
38 <Select.Portal>
39 <Select.Content
40 {...contentProps}
41 class={cn(
42 'bg-base-50/50 border-base-500/20 overflow-hidden rounded-2xl border shadow-lg backdrop-blur-xl',
43 'dark:bg-base-900/50 dark:border-base-500/10',
44 'motion-safe:animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
45 contentProps?.class
46 )}
47 sideOffset={6}
48 >
49 <Select.ScrollUpButton>up</Select.ScrollUpButton>
50 <Select.Viewport class="divide-base-300/30 dark:divide-base-800 divide-y text-sm">
51 {#each items as { value, label, disabled } (value)}
52 <Select.Item {value} {label} {disabled}>
53 {#snippet children({ selected })}
54 <div
55 class={cn(
56 'text-base-900 dark:text-base-200 group relative isolate flex min-w-28 cursor-pointer items-center gap-3 px-3 py-2 font-medium [&_svg]:size-3.5',
57 selected
58 ? 'text-accent-700 dark:text-accent-400 bg-accent-500/10'
59 : 'hover:bg-accent-500/10'
60 )}
61 >
62 <Icon name={value as any} />
63 {label}
64 </div>
65 {/snippet}
66 </Select.Item>
67 {/each}
68 </Select.Viewport>
69 <Select.ScrollDownButton>down</Select.ScrollDownButton>
70 </Select.Content>
71 </Select.Portal>
72</Select.Root>