83 lines
2.3 KiB
Svelte
83 lines
2.3 KiB
Svelte
<script lang="ts">
|
|
import { Select as BitsSelect, type WithoutChildren } from 'bits-ui';
|
|
import { cubicOut } from 'svelte/easing';
|
|
|
|
type Props = WithoutChildren<BitsSelect.ContentProps> & {
|
|
items: { value: string; label: string; disabled?: boolean }[];
|
|
class?: string;
|
|
};
|
|
|
|
let { items, class: className = '', ...restProps }: Props = $props();
|
|
|
|
function selectTransition(
|
|
node: HTMLElement,
|
|
params: {
|
|
delay?: number;
|
|
duration?: number;
|
|
easing?: (t: number) => number;
|
|
y?: number;
|
|
start?: number;
|
|
} = {}
|
|
) {
|
|
const {
|
|
delay = 0,
|
|
duration = 200,
|
|
easing = cubicOut,
|
|
y = -6,
|
|
start = 0.95,
|
|
} = params;
|
|
|
|
const existingTransform = getComputedStyle(node).transform.replace(
|
|
'none',
|
|
''
|
|
);
|
|
|
|
return {
|
|
delay,
|
|
duration,
|
|
easing,
|
|
css: (t: number, u: number) => {
|
|
const translate = `translateY(${u * y}px)`;
|
|
const scale = `scale(${start + t * (1 - start)})`;
|
|
|
|
return `
|
|
opacity: ${t};
|
|
transform: ${existingTransform} ${translate} ${scale};
|
|
`;
|
|
},
|
|
};
|
|
}
|
|
</script>
|
|
|
|
<BitsSelect.Portal>
|
|
<BitsSelect.Content
|
|
forceMount
|
|
sideOffset={4}
|
|
class={`w-(--bits-select-anchor-width) min-w-(--bits-select-anchor-width) rounded-xl border-[1.5px] border-base-content/20 bg-base-100 select-none ${className}`}
|
|
{...restProps}
|
|
>
|
|
{#snippet child({ wrapperProps, props, open })}
|
|
{#if open}
|
|
<div {...wrapperProps}>
|
|
<div {...props} transition:selectTransition>
|
|
<BitsSelect.ScrollUpButton>up</BitsSelect.ScrollUpButton>
|
|
<BitsSelect.Viewport class="p-1">
|
|
{#each items as { value, label, disabled } (value)}
|
|
<BitsSelect.Item
|
|
{value}
|
|
{label}
|
|
{disabled}
|
|
class="outlined-hidden flex h-10 w-full items-center rounded-lg p-2 text-sm capitalize select-none data-disabled:opacity-50 data-highlighted:bg-gray-200"
|
|
>
|
|
{label}
|
|
</BitsSelect.Item>
|
|
{/each}
|
|
</BitsSelect.Viewport>
|
|
<BitsSelect.ScrollDownButton>down</BitsSelect.ScrollDownButton>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
{/snippet}
|
|
</BitsSelect.Content>
|
|
</BitsSelect.Portal>
|