feat: 实现Slect组件/样式
This commit is contained in:
15
src/lib/components/ui/select/Select.svelte
Normal file
15
src/lib/components/ui/select/Select.svelte
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Select as BitsSelect, type WithoutChildren } from 'bits-ui';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
type Props = WithoutChildren<BitsSelect.RootProps> & {
|
||||||
|
class?: string;
|
||||||
|
children?: Snippet;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { value = $bindable(), children, ...restProps }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<BitsSelect.Root bind:value={value as never} {...restProps}>
|
||||||
|
{@render children?.()}
|
||||||
|
</BitsSelect.Root>
|
||||||
54
src/lib/components/ui/select/SelectContent.svelte
Normal file
54
src/lib/components/ui/select/SelectContent.svelte
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Select as BitsSelect, type WithoutChildren } from 'bits-ui';
|
||||||
|
|
||||||
|
type Props = WithoutChildren<BitsSelect.ContentProps> & {
|
||||||
|
items: { value: string; label: string; disabled?: boolean }[];
|
||||||
|
class?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { items, class: className = '', ...restProps }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<BitsSelect.Portal>
|
||||||
|
<BitsSelect.Content
|
||||||
|
forceMount
|
||||||
|
sideOffset={4}
|
||||||
|
class={`data=[state=closed]:fade-out-0 select-motion 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}
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</BitsSelect.Content>
|
||||||
|
</BitsSelect.Portal>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
@reference "tailwindcss";
|
||||||
|
|
||||||
|
:global(.select-content-animate) {
|
||||||
|
@apply transition-[opacity,transform] duration-200 ease-out will-change-transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.select-content-animate[data-state='open']) {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.select-content-animate[data-state='closed']) {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
src/lib/components/ui/select/SelectTrigger.svelte
Normal file
17
src/lib/components/ui/select/SelectTrigger.svelte
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Select as BitsSelect, type WithoutChildren } from 'bits-ui';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
type Props = WithoutChildren<BitsSelect.TriggerProps> & {
|
||||||
|
class?: string;
|
||||||
|
children?: Snippet;
|
||||||
|
};
|
||||||
|
|
||||||
|
let { children, class: className = '' }: Props = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<BitsSelect.Trigger
|
||||||
|
class={`select outline-none focus:border-base-content/20 focus-visible:border-primary focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 ${className}`}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</BitsSelect.Trigger>
|
||||||
3
src/lib/components/ui/select/index.ts
Normal file
3
src/lib/components/ui/select/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export { default as Select } from './Select.svelte';
|
||||||
|
export { default as SelectTrigger } from './SelectTrigger.svelte';
|
||||||
|
export { default as SelectContent } from './SelectContent.svelte';
|
||||||
@ -1,4 +1,5 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
@import "../styles/select-motion.css";
|
||||||
@plugin "@tailwindcss/forms";
|
@plugin "@tailwindcss/forms";
|
||||||
@plugin "daisyui" {
|
@plugin "daisyui" {
|
||||||
logs: false;
|
logs: false;
|
||||||
|
|||||||
13
src/styles/select-motion.css
Normal file
13
src/styles/select-motion.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
@layer components {
|
||||||
|
.select-motion {
|
||||||
|
@apply transition-all duration-200 ease-out will-change-transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-motion[data-state="open"] {
|
||||||
|
@apply pointer-events-auto translate-y-0 scale-100 opacity-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-motion[data-state="closed"] {
|
||||||
|
@apply pointer-events-none -translate-y-2 scale-95 opacity-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user