refactor(front): standardize import statements and improve prop handling in Select components

This commit is contained in:
keven1024
2026-04-12 23:31:58 +08:00
parent e37402ff63
commit e9fc260cbc
11 changed files with 141 additions and 172 deletions

View File

@@ -9,10 +9,7 @@ const forwarded = useForwardPropsEmits(props, emits)
</script> </script>
<template> <template>
<SelectRoot <SelectRoot v-slot="slotProps" data-slot="select" v-bind="forwarded">
data-slot="select" <slot v-bind="slotProps" />
v-bind="forwarded" </SelectRoot>
>
<slot />
</SelectRoot>
</template> </template>

View File

@@ -1,55 +1,51 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectContentEmits, SelectContentProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { SelectContent, SelectPortal, SelectViewport, useForwardPropsEmits } from 'reka-ui'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import {
SelectContent,
type SelectContentEmits,
type SelectContentProps,
SelectPortal,
SelectViewport,
useForwardPropsEmits,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
import { SelectScrollDownButton, SelectScrollUpButton } from '.' import { SelectScrollDownButton, SelectScrollUpButton } from '.'
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,
}) })
const props = withDefaults( const props = withDefaults(defineProps<SelectContentProps & { class?: HTMLAttributes['class'] }>(), {
defineProps<SelectContentProps & { class?: HTMLAttributes['class'] }>(),
{
position: 'popper', position: 'popper',
}, })
)
const emits = defineEmits<SelectContentEmits>() const emits = defineEmits<SelectContentEmits>()
const delegatedProps = computed(() => { const delegatedProps = reactiveOmit(props, 'class')
const { class: _, ...delegated } = props
return delegated
})
const forwarded = useForwardPropsEmits(delegatedProps, emits) const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script> </script>
<template> <template>
<SelectPortal> <SelectPortal>
<SelectContent <SelectContent
data-slot="select-content" data-slot="select-content"
v-bind="{ ...forwarded, ...$attrs }" v-bind="{ ...$attrs, ...forwarded }"
:class="cn( :class="
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md', cn(
position === 'popper' 'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
&& 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', position === 'popper' &&
props.class, 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
) props.class
" )
> "
<SelectScrollUpButton /> >
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[var(--reka-select-trigger-height)] w-full min-w-[var(--reka-select-trigger-width)] scroll-my-1')"> <SelectScrollUpButton />
<slot /> <SelectViewport
</SelectViewport> :class="
<SelectScrollDownButton /> cn(
</SelectContent> 'p-1',
</SelectPortal> position === 'popper' && 'h-[var(--reka-select-trigger-height)] w-full min-w-[var(--reka-select-trigger-width)] scroll-my-1'
)
"
>
<slot />
</SelectViewport>
<SelectScrollDownButton />
</SelectContent>
</SelectPortal>
</template> </template>

View File

@@ -1,14 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { SelectGroup, type SelectGroupProps } from 'reka-ui' import type { SelectGroupProps } from 'reka-ui'
import { SelectGroup } from 'reka-ui'
const props = defineProps<SelectGroupProps>() const props = defineProps<SelectGroupProps>()
</script> </script>
<template> <template>
<SelectGroup <SelectGroup data-slot="select-group" v-bind="props">
data-slot="select-group" <slot />
v-bind="props" </SelectGroup>
>
<slot />
</SelectGroup>
</template> </template>

View File

@@ -1,45 +1,39 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import type { SelectItemProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { Check } from 'lucide-vue-next' import { Check } from 'lucide-vue-next'
import { import { SelectItem, SelectItemIndicator, SelectItemText, useForwardProps } from 'reka-ui'
SelectItem, import { cn } from '@/lib/utils'
SelectItemIndicator,
type SelectItemProps,
SelectItemText,
useForwardProps,
} from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectItemProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectItemProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => { const delegatedProps = reactiveOmit(props, 'class')
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps) const forwardedProps = useForwardProps(delegatedProps)
</script> </script>
<template> <template>
<SelectItem <SelectItem
data-slot="select-item" data-slot="select-item"
v-bind="forwardedProps" v-bind="forwardedProps"
:class=" :class="
cn( cn(
`focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2`, 'focus:bg-accent focus:text-accent-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
props.class, props.class
) )
" "
> >
<span class="absolute right-2 flex size-3.5 items-center justify-center"> <span class="absolute right-2 flex size-3.5 items-center justify-center">
<SelectItemIndicator> <SelectItemIndicator>
<Check class="size-4" /> <slot name="indicator-icon">
</SelectItemIndicator> <Check class="size-4" />
</span> </slot>
</SelectItemIndicator>
</span>
<SelectItemText> <SelectItemText>
<slot /> <slot />
</SelectItemText> </SelectItemText>
</SelectItem> </SelectItem>
</template> </template>

View File

@@ -1,14 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { SelectItemText, type SelectItemTextProps } from 'reka-ui' import type { SelectItemTextProps } from 'reka-ui'
import { SelectItemText } from 'reka-ui'
const props = defineProps<SelectItemTextProps>() const props = defineProps<SelectItemTextProps>()
</script> </script>
<template> <template>
<SelectItemText <SelectItemText data-slot="select-item-text" v-bind="props">
data-slot="select-item-text" <slot />
v-bind="props" </SelectItemText>
>
<slot />
</SelectItemText>
</template> </template>

View File

@@ -1,16 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectLabelProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { SelectLabel } from 'reka-ui'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectLabel, type SelectLabelProps } from 'reka-ui'
const props = defineProps<SelectLabelProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectLabelProps & { class?: HTMLAttributes['class'] }>()
</script> </script>
<template> <template>
<SelectLabel <SelectLabel data-slot="select-label" :class="cn('text-muted-foreground px-2 py-1.5 text-xs', props.class)">
data-slot="select-label" <slot />
:class="cn('px-2 py-1.5 text-sm font-medium', props.class)" </SelectLabel>
>
<slot />
</SelectLabel>
</template> </template>

View File

@@ -1,28 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import type { SelectScrollDownButtonProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { ChevronDown } from 'lucide-vue-next' import { ChevronDown } from 'lucide-vue-next'
import { SelectScrollDownButton, type SelectScrollDownButtonProps, useForwardProps } from 'reka-ui' import { SelectScrollDownButton, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { cn } from '@/lib/utils'
const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => { const delegatedProps = reactiveOmit(props, 'class')
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps) const forwardedProps = useForwardProps(delegatedProps)
</script> </script>
<template> <template>
<SelectScrollDownButton <SelectScrollDownButton
data-slot="select-scroll-down-button" data-slot="select-scroll-down-button"
v-bind="forwardedProps" v-bind="forwardedProps"
:class="cn('flex cursor-default items-center justify-center py-1', props.class)" :class="cn('flex cursor-default items-center justify-center py-1', props.class)"
> >
<slot> <slot>
<ChevronDown class="size-4" /> <ChevronDown class="size-4" />
</slot> </slot>
</SelectScrollDownButton> </SelectScrollDownButton>
</template> </template>

View File

@@ -1,28 +1,26 @@
<script setup lang="ts"> <script setup lang="ts">
import { cn } from '@/lib/utils' import type { SelectScrollUpButtonProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { ChevronUp } from 'lucide-vue-next' import { ChevronUp } from 'lucide-vue-next'
import { SelectScrollUpButton, type SelectScrollUpButtonProps, useForwardProps } from 'reka-ui' import { SelectScrollUpButton, useForwardProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue' import { cn } from '@/lib/utils'
const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => { const delegatedProps = reactiveOmit(props, 'class')
const { class: _, ...delegated } = props
return delegated
})
const forwardedProps = useForwardProps(delegatedProps) const forwardedProps = useForwardProps(delegatedProps)
</script> </script>
<template> <template>
<SelectScrollUpButton <SelectScrollUpButton
data-slot="select-scroll-up-button" data-slot="select-scroll-up-button"
v-bind="forwardedProps" v-bind="forwardedProps"
:class="cn('flex cursor-default items-center justify-center py-1', props.class)" :class="cn('flex cursor-default items-center justify-center py-1', props.class)"
> >
<slot> <slot>
<ChevronUp class="size-4" /> <ChevronUp class="size-4" />
</slot> </slot>
</SelectScrollUpButton> </SelectScrollUpButton>
</template> </template>

View File

@@ -1,21 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectSeparatorProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { SelectSeparator } from 'reka-ui'
import { cn } from '@/lib/utils' import { cn } from '@/lib/utils'
import { SelectSeparator, type SelectSeparatorProps } from 'reka-ui'
import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes['class'] }>() const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = computed(() => { const delegatedProps = reactiveOmit(props, 'class')
const { class: _, ...delegated } = props
return delegated
})
</script> </script>
<template> <template>
<SelectSeparator <SelectSeparator data-slot="select-separator" v-bind="delegatedProps" :class="cn('bg-border pointer-events-none -mx-1 my-1 h-px', props.class)" />
data-slot="select-separator"
v-bind="delegatedProps"
:class="cn('bg-border pointer-events-none -mx-1 my-1 h-px', props.class)"
/>
</template> </template>

View File

@@ -1,32 +1,32 @@
<script setup lang="ts"> <script setup lang="ts">
import type { SelectTriggerProps } from 'reka-ui'
import type { HTMLAttributes } from 'vue' import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { reactiveOmit } from '@vueuse/core' import { reactiveOmit } from '@vueuse/core'
import { ChevronDown } from 'lucide-vue-next' import { ChevronDown } from 'lucide-vue-next'
import { SelectIcon, SelectTrigger, type SelectTriggerProps, useForwardProps } from 'reka-ui' import { SelectIcon, SelectTrigger, useForwardProps } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = withDefaults( const props = withDefaults(defineProps<SelectTriggerProps & { class?: HTMLAttributes['class']; size?: 'sm' | 'default' }>(), { size: 'default' })
defineProps<SelectTriggerProps & { class?: HTMLAttributes['class'], size?: 'sm' | 'default' }>(),
{ size: 'default' },
)
const delegatedProps = reactiveOmit(props, 'class', 'size') const delegatedProps = reactiveOmit(props, 'class', 'size')
const forwardedProps = useForwardProps(delegatedProps) const forwardedProps = useForwardProps(delegatedProps)
</script> </script>
<template> <template>
<SelectTrigger <SelectTrigger
data-slot="select-trigger" data-slot="select-trigger"
:data-size="size" :data-size="size"
v-bind="forwardedProps" v-bind="forwardedProps"
:class="cn( :class="
`border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`, cn(
props.class, 'border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
)" props.class
> )
<slot /> "
<SelectIcon as-child> >
<ChevronDown class="size-4 opacity-50" /> <slot />
</SelectIcon> <SelectIcon as-child>
</SelectTrigger> <ChevronDown class="size-4 opacity-50" />
</SelectIcon>
</SelectTrigger>
</template> </template>

View File

@@ -1,14 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { SelectValue, type SelectValueProps } from 'reka-ui' import type { SelectValueProps } from 'reka-ui'
import { SelectValue } from 'reka-ui'
const props = defineProps<SelectValueProps>() const props = defineProps<SelectValueProps>()
</script> </script>
<template> <template>
<SelectValue <SelectValue data-slot="select-value" v-bind="props">
data-slot="select-value" <slot />
v-bind="props" </SelectValue>
>
<slot />
</SelectValue>
</template> </template>