shadcn-vue/apps/www/src/lib/registry/default/ui/select.tsx
2023-08-23 21:17:05 +08:00

113 lines
4.6 KiB
TypeScript

import { defineComponent } from 'vue'
import {
type SelectContentEmits, SelectContent as SelectContentPrimitive, type SelectContentProps,
SelectGroup as SelectGroupPrimitive,
SelectIcon, SelectItemIndicator,
SelectItem as SelectItemPrimitive, type SelectItemProps,
SelectItemText,
SelectLabel as SelectLabelPrimitive, type SelectLabelProps,
SelectPortal, SelectRoot,
SelectSeparator as SelectSeparatorPrimitive, type SelectSeparatorProps,
SelectTrigger as SelectTriggerPrimitive, type SelectTriggerProps,
SelectValue as SelectValuePrimitive, SelectViewport,
} from 'radix-vue'
import { Check, ChevronDown } from 'lucide-vue-next'
import type { ParseEmits } from '@/utils'
import { cn, convertToComponent, useEmitAsProps } from '@/utils'
export const Select = SelectRoot
export const SelectGroup = SelectGroupPrimitive
export const SelectValue = SelectValuePrimitive
// Convert Functional component to valid VNode to be use in JSX
const IChevrondown = convertToComponent(ChevronDown)
const ICheck = convertToComponent(Check)
export const SelectTrigger = defineComponent<SelectTriggerProps>(
(props, { attrs, slots }) => {
return () => (
<SelectTriggerPrimitive {...props} class={cn('flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', attrs.class ?? '')}>
{ slots.default?.() }
<SelectIcon asChild>
<IChevrondown class={'h-4 w-4 opacity-50'} />
</SelectIcon>
</SelectTriggerPrimitive>
)
}, {
name: 'SelectTrigger',
},
)
export const SelectContent = defineComponent<SelectContentProps, ParseEmits<SelectContentEmits>>(
(props, { emit, attrs, slots }) => {
const position = props.position ?? 'popper'
const emitsAsProps = useEmitAsProps(emit)
return () => (
<SelectPortal>
<SelectContentPrimitive
class={cn(
'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md 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',
position === 'popper'
&& 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
attrs.class ?? '',
)}
position='popper'
{...props}
{...emitsAsProps}
>
<SelectViewport class={cn(
'p-1',
position === 'popper'
&& 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]',
)}
>
{ slots.default?.()}
</SelectViewport>
</SelectContentPrimitive>
</SelectPortal>
)
}, { name: 'SelectContent', emits: SelectContentPrimitive.emits },
)
export const SelectLabel = defineComponent<SelectLabelProps>(
(props, { attrs, slots }) => {
return () => (
<SelectLabelPrimitive class={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', attrs.class)} {...props}>
{ slots.default?.() }
</SelectLabelPrimitive>
)
}, { name: 'SelectLabel' },
)
export const SelectItem = defineComponent<SelectItemProps>(
(props, { attrs, slots }) => {
return () => (
<SelectItemPrimitive
class={cn('relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50', attrs.class)}
{...props}
>
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectItemIndicator>
<ICheck class={'w-4 h-4'}></ICheck>
</SelectItemIndicator>
</span>
<SelectItemText>
{ slots.default?.() }
</SelectItemText>
</SelectItemPrimitive>
)
}, { name: 'SelectItem' },
)
export const SelectSeparator = defineComponent<SelectSeparatorProps>(
(props, { attrs, slots }) => {
return () => (
<SelectSeparatorPrimitive class={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', attrs.class)} {...props}>
{ slots.default?.() }
</SelectSeparatorPrimitive>
)
}, { name: 'SelectSeparator' },
)