mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-30 19:57:55 +01:00
feat(InputMenu/SelectMenu): handle resetSearchTermOnSelect
Resolves #3782
This commit is contained in:
@@ -44,7 +44,7 @@ export type InputMenuItem = _InputMenuItem | AcceptableValue | boolean
|
|||||||
|
|
||||||
type InputMenuVariants = VariantProps<typeof inputMenu>
|
type InputMenuVariants = VariantProps<typeof inputMenu>
|
||||||
|
|
||||||
export interface InputMenuProps<T extends ArrayOrNested<InputMenuItem> = ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'highlightOnHover'>, UseComponentIconsProps {
|
export interface InputMenuProps<T extends ArrayOrNested<InputMenuItem> = ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'resetSearchTermOnSelect' | 'highlightOnHover'>, UseComponentIconsProps {
|
||||||
/**
|
/**
|
||||||
* The element or component this component should render as.
|
* The element or component this component should render as.
|
||||||
* @defaultValue 'div'
|
* @defaultValue 'div'
|
||||||
@@ -175,7 +175,7 @@ export interface InputMenuSlots<
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts" generic="T extends ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false">
|
<script setup lang="ts" generic="T extends ArrayOrNested<InputMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false">
|
||||||
import { computed, ref, toRef, onMounted, toRaw, nextTick } from 'vue'
|
import { computed, ref, toRef, onMounted, toRaw } from 'vue'
|
||||||
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits, useFilter } from 'reka-ui'
|
import { ComboboxRoot, ComboboxArrow, ComboboxAnchor, ComboboxInput, ComboboxTrigger, ComboboxPortal, ComboboxContent, ComboboxViewport, ComboboxEmpty, ComboboxGroup, ComboboxLabel, ComboboxSeparator, ComboboxItem, ComboboxItemIndicator, TagsInputRoot, TagsInputItem, TagsInputItemText, TagsInputItemDelete, TagsInputInput, useForwardPropsEmits, useFilter } from 'reka-ui'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import { isEqual } from 'ohash/utils'
|
import { isEqual } from 'ohash/utils'
|
||||||
@@ -196,7 +196,9 @@ const props = withDefaults(defineProps<InputMenuProps<T, VK, M>>(), {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
autofocusDelay: 0,
|
autofocusDelay: 0,
|
||||||
portal: true,
|
portal: true,
|
||||||
labelKey: 'label' as never
|
labelKey: 'label' as never,
|
||||||
|
resetSearchTermOnBlur: true,
|
||||||
|
resetSearchTermOnSelect: true
|
||||||
})
|
})
|
||||||
const emits = defineEmits<InputMenuEmits<T, VK, M>>()
|
const emits = defineEmits<InputMenuEmits<T, VK, M>>()
|
||||||
const slots = defineSlots<InputMenuSlots<T, VK, M>>()
|
const slots = defineSlots<InputMenuSlots<T, VK, M>>()
|
||||||
@@ -207,7 +209,7 @@ const { t } = useLocale()
|
|||||||
const appConfig = useAppConfig()
|
const appConfig = useAppConfig()
|
||||||
const { contains } = useFilter({ sensitivity: 'base' })
|
const { contains } = useFilter({ sensitivity: 'base' })
|
||||||
|
|
||||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'required', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover', 'ignoreFilter'), emits)
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'required', 'multiple', 'resetSearchTermOnBlur', 'resetSearchTermOnSelect', 'highlightOnHover', 'ignoreFilter'), emits)
|
||||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
||||||
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
||||||
|
|
||||||
@@ -311,6 +313,10 @@ function onUpdate(value: any) {
|
|||||||
emits('change', event)
|
emits('change', event)
|
||||||
emitFormChange()
|
emitFormChange()
|
||||||
emitFormInput()
|
emitFormInput()
|
||||||
|
|
||||||
|
if (props.resetSearchTermOnSelect) {
|
||||||
|
searchTerm.value = ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBlur(event: FocusEvent) {
|
function onBlur(event: FocusEvent) {
|
||||||
@@ -324,18 +330,29 @@ function onFocus(event: FocusEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onUpdateOpen(value: boolean) {
|
function onUpdateOpen(value: boolean) {
|
||||||
|
let timeoutId
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
const event = new FocusEvent('blur')
|
const event = new FocusEvent('blur')
|
||||||
|
|
||||||
emits('blur', event)
|
emits('blur', event)
|
||||||
emitFormBlur()
|
emitFormBlur()
|
||||||
|
|
||||||
|
// Since we use `displayValue` prop inside ComboboxInput we should reset searchTerm manually
|
||||||
|
// https://reka-ui.com/docs/components/combobox#api-reference
|
||||||
|
if (props.resetSearchTermOnBlur) {
|
||||||
|
const STATE_ANIMATION_DELAY_MS = 100
|
||||||
|
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
searchTerm.value = ''
|
||||||
|
}, STATE_ANIMATION_DELAY_MS)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const event = new FocusEvent('focus')
|
const event = new FocusEvent('focus')
|
||||||
emits('focus', event)
|
emits('focus', event)
|
||||||
|
emitFormFocus()
|
||||||
|
clearTimeout(timeoutId)
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick(() => {
|
|
||||||
searchTerm.value = ''
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRemoveTag(event: any) {
|
function onRemoveTag(event: any) {
|
||||||
@@ -414,7 +431,7 @@ defineExpose({
|
|||||||
</TagsInputItemDelete>
|
</TagsInputItemDelete>
|
||||||
</TagsInputItem>
|
</TagsInputItem>
|
||||||
|
|
||||||
<ComboboxInput as-child @update:model-value="searchTerm = $event">
|
<ComboboxInput v-model="searchTerm" as-child>
|
||||||
<TagsInputInput
|
<TagsInputInput
|
||||||
ref="inputRef"
|
ref="inputRef"
|
||||||
v-bind="{ ...$attrs, ...ariaAttrs }"
|
v-bind="{ ...$attrs, ...ariaAttrs }"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export type SelectMenuItem = _SelectMenuItem | AcceptableValue | boolean
|
|||||||
|
|
||||||
type SelectMenuVariants = VariantProps<typeof selectMenu>
|
type SelectMenuVariants = VariantProps<typeof selectMenu>
|
||||||
|
|
||||||
export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = ArrayOrNested<SelectMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'highlightOnHover'>, UseComponentIconsProps {
|
export interface SelectMenuProps<T extends ArrayOrNested<SelectMenuItem> = ArrayOrNested<SelectMenuItem>, VK extends GetItemKeys<T> | undefined = undefined, M extends boolean = false> extends Pick<ComboboxRootProps<T>, 'open' | 'defaultOpen' | 'disabled' | 'name' | 'resetSearchTermOnBlur' | 'resetSearchTermOnSelect' | 'highlightOnHover'>, UseComponentIconsProps {
|
||||||
id?: string
|
id?: string
|
||||||
/** The placeholder text when the select is empty. */
|
/** The placeholder text when the select is empty. */
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
@@ -188,7 +188,8 @@ const props = withDefaults(defineProps<SelectMenuProps<T, VK, M>>(), {
|
|||||||
portal: true,
|
portal: true,
|
||||||
searchInput: true,
|
searchInput: true,
|
||||||
labelKey: 'label' as never,
|
labelKey: 'label' as never,
|
||||||
resetSearchTermOnBlur: true
|
resetSearchTermOnBlur: true,
|
||||||
|
resetSearchTermOnSelect: true
|
||||||
})
|
})
|
||||||
const emits = defineEmits<SelectMenuEmits<T, VK, M>>()
|
const emits = defineEmits<SelectMenuEmits<T, VK, M>>()
|
||||||
const slots = defineSlots<SelectMenuSlots<T, VK, M>>()
|
const slots = defineSlots<SelectMenuSlots<T, VK, M>>()
|
||||||
@@ -199,7 +200,7 @@ const { t } = useLocale()
|
|||||||
const appConfig = useAppConfig()
|
const appConfig = useAppConfig()
|
||||||
const { contains } = useFilter({ sensitivity: 'base' })
|
const { contains } = useFilter({ sensitivity: 'base' })
|
||||||
|
|
||||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'required', 'multiple', 'resetSearchTermOnBlur', 'highlightOnHover'), emits)
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'modelValue', 'defaultValue', 'open', 'defaultOpen', 'required', 'multiple', 'resetSearchTermOnBlur', 'resetSearchTermOnSelect', 'highlightOnHover'), emits)
|
||||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }) as ComboboxContentProps)
|
||||||
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
const arrowProps = toRef(() => props.arrow as ComboboxArrowProps)
|
||||||
const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t('selectMenu.search'), variant: 'none' }) as InputProps)
|
const searchInputProps = toRef(() => defu(props.searchInput, { placeholder: t('selectMenu.search'), variant: 'none' }) as InputProps)
|
||||||
@@ -293,6 +294,10 @@ function onUpdate(value: any) {
|
|||||||
emits('change', event)
|
emits('change', event)
|
||||||
emitFormChange()
|
emitFormChange()
|
||||||
emitFormInput()
|
emitFormInput()
|
||||||
|
|
||||||
|
if (props.resetSearchTermOnSelect) {
|
||||||
|
searchTerm.value = ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUpdateOpen(value: boolean) {
|
function onUpdateOpen(value: boolean) {
|
||||||
|
|||||||
Reference in New Issue
Block a user