mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
@@ -379,6 +379,7 @@ function onSelect(e: Event, item: InputMenuItem) {
|
||||
function isInputItem(item: InputMenuItem): item is _InputMenuItem {
|
||||
return typeof item === 'object' && item !== null
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
inputRef
|
||||
})
|
||||
|
||||
@@ -92,6 +92,8 @@ export interface SelectProps<T extends ArrayOrNested<SelectItem> = ArrayOrNested
|
||||
multiple?: M & boolean
|
||||
/** Highlight the ring color like a focus state. */
|
||||
highlight?: boolean
|
||||
autofocus?: boolean
|
||||
autofocusDelay?: number
|
||||
class?: any
|
||||
ui?: Select['slots']
|
||||
}
|
||||
@@ -134,7 +136,7 @@ export interface SelectSlots<
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends ArrayOrNested<SelectItem>, VK extends GetItemKeys<T> = 'value', M extends boolean = false">
|
||||
import { computed, toRef } from 'vue'
|
||||
import { ref, computed, onMounted, toRef } from 'vue'
|
||||
import { SelectRoot, SelectArrow, SelectTrigger, SelectPortal, SelectContent, SelectLabel, SelectGroup, SelectItem, SelectItemIndicator, SelectItemText, SelectSeparator, useForwardPropsEmits } from 'reka-ui'
|
||||
import { defu } from 'defu'
|
||||
import { reactivePick } from '@vueuse/core'
|
||||
@@ -154,7 +156,8 @@ defineOptions({ inheritAttrs: false })
|
||||
const props = withDefaults(defineProps<SelectProps<T, VK, M>>(), {
|
||||
valueKey: 'value' as never,
|
||||
labelKey: 'label' as never,
|
||||
portal: true
|
||||
portal: true,
|
||||
autofocusDelay: 0
|
||||
})
|
||||
const emits = defineEmits<SelectEmits<T, VK, M>>()
|
||||
const slots = defineSlots<SelectSlots<T, VK, M>>()
|
||||
@@ -203,6 +206,22 @@ function displayValue(value: GetItemValue<T, VK> | GetItemValue<T, VK>[]): strin
|
||||
return item && (typeof item === 'object' ? get(item, props.labelKey as string) : item)
|
||||
}
|
||||
|
||||
const triggerRef = ref<InstanceType<typeof SelectTrigger> | null>(null)
|
||||
|
||||
function autoFocus() {
|
||||
if (props.autofocus) {
|
||||
triggerRef.value?.$el?.focus({
|
||||
focusVisible: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
autoFocus()
|
||||
}, props.autofocusDelay)
|
||||
})
|
||||
|
||||
function onUpdate(value: any) {
|
||||
// @ts-expect-error - 'target' does not exist in type 'EventInit'
|
||||
const event = new Event('change', { target: { value } })
|
||||
@@ -241,7 +260,7 @@ function isSelectItem(item: SelectItem): item is SelectItemBase {
|
||||
@update:model-value="onUpdate"
|
||||
@update:open="onUpdateOpen"
|
||||
>
|
||||
<SelectTrigger :id="id" :class="ui.base({ class: [props.ui?.base, props.class] })" v-bind="{ ...$attrs, ...ariaAttrs }">
|
||||
<SelectTrigger :id="id" ref="triggerRef" :class="ui.base({ class: [props.ui?.base, props.class] })" v-bind="{ ...$attrs, ...ariaAttrs }">
|
||||
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
|
||||
@@ -115,6 +115,8 @@ export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = Array
|
||||
* @defaultValue false
|
||||
*/
|
||||
ignoreFilter?: boolean
|
||||
autofocus?: boolean
|
||||
autofocusDelay?: number
|
||||
class?: any
|
||||
ui?: SelectMenu['slots']
|
||||
}
|
||||
@@ -165,7 +167,7 @@ export interface SelectMenuSlots<
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends ArrayOrNested<SelectMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false">
|
||||
import { computed, toRef, toRaw } from 'vue'
|
||||
import { ref, computed, onMounted, toRef, toRaw } from 'vue'
|
||||
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, FocusScope, useForwardPropsEmits, useFilter } from 'reka-ui'
|
||||
import { defu } from 'defu'
|
||||
import { reactivePick, createReusableTemplate } from '@vueuse/core'
|
||||
@@ -189,7 +191,8 @@ const props = withDefaults(defineProps<SelectMenuProps<T, VK, M>>(), {
|
||||
searchInput: true,
|
||||
labelKey: 'label' as never,
|
||||
resetSearchTermOnBlur: true,
|
||||
resetSearchTermOnSelect: true
|
||||
resetSearchTermOnSelect: true,
|
||||
autofocusDelay: 0
|
||||
})
|
||||
const emits = defineEmits<SelectMenuEmits<T, VK, M>>()
|
||||
const slots = defineSlots<SelectMenuSlots<T, VK, M>>()
|
||||
@@ -287,6 +290,22 @@ const createItem = computed(() => {
|
||||
})
|
||||
const createItemPosition = computed(() => typeof props.createItem === 'object' ? props.createItem.position : 'bottom')
|
||||
|
||||
const triggerRef = ref<InstanceType<typeof ComboboxTrigger> | null>(null)
|
||||
|
||||
function autoFocus() {
|
||||
if (props.autofocus) {
|
||||
triggerRef.value?.$el?.focus({
|
||||
focusVisible: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
autoFocus()
|
||||
}, props.autofocusDelay)
|
||||
})
|
||||
|
||||
function onUpdate(value: any) {
|
||||
if (toRaw(props.modelValue) === value) {
|
||||
return
|
||||
@@ -376,7 +395,7 @@ function isSelectItem(item: SelectMenuItem): item is _SelectMenuItem {
|
||||
@update:open="onUpdateOpen"
|
||||
>
|
||||
<ComboboxAnchor as-child>
|
||||
<ComboboxTrigger :class="ui.base({ class: [props.ui?.base, props.class] })" tabindex="0">
|
||||
<ComboboxTrigger ref="triggerRef" :class="ui.base({ class: [props.ui?.base, props.class] })" tabindex="0">
|
||||
<span v-if="isLeading || !!avatar || !!slots.leading" :class="ui.leading({ class: props.ui?.leading })">
|
||||
<slot name="leading" :model-value="(modelValue as GetModelValue<T, VK, M>)" :open="open" :ui="ui">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
|
||||
|
||||
Reference in New Issue
Block a user