diff --git a/docs/components/content/examples/SelectMenuExampleCreatable.vue b/docs/components/content/examples/SelectMenuExampleCreatable.vue index 6d81079997..1a867d9c6f 100644 --- a/docs/components/content/examples/SelectMenuExampleCreatable.vue +++ b/docs/components/content/examples/SelectMenuExampleCreatable.vue @@ -23,6 +23,7 @@ const labels = computed({ // In a real app, you would make an API call to create the label const response = { + id: options.value.length + 1, name: label.name, color: generateColorFromString(label.name) } diff --git a/docs/components/content/examples/SelectMenuExampleCreatableAlways.vue b/docs/components/content/examples/SelectMenuExampleCreatableAlways.vue new file mode 100644 index 0000000000..df50b680f8 --- /dev/null +++ b/docs/components/content/examples/SelectMenuExampleCreatableAlways.vue @@ -0,0 +1,53 @@ + + + diff --git a/docs/content/3.forms/4.select-menu.md b/docs/content/3.forms/4.select-menu.md index 5c47db9f43..c31451b918 100644 --- a/docs/content/3.forms/4.select-menu.md +++ b/docs/content/3.forms/4.select-menu.md @@ -117,6 +117,8 @@ componentProps: By default, the search query will be kept after the menu is closed. To clear it on close, set the `clear-search-on-close` prop. +You can also configure this globally through the `ui.selectMenu.default.clearSearchOnClose` config. Defaults to `false`. + ::component-card --- baseProps: @@ -158,6 +160,20 @@ componentProps: --- :: +However, if you want to create options despite search query (apart from exact match), you can set the `show-create-option-when` prop to `'always'`. + +You can also configure this globally through the `ui.selectMenu.default.showCreateOptionWhen` config. Defaults to `empty`. + +Try to search for something that exists in the example below, but not an exact match. + +::component-example +--- +component: 'select-menu-example-creatable-always' +componentProps: + class: 'w-full lg:w-48' +--- +:: + ## Popper Use the `popper` prop to customize the popper instance. diff --git a/src/runtime/components/forms/SelectMenu.vue b/src/runtime/components/forms/SelectMenu.vue index dfc9dc967b..e87abcab96 100644 --- a/src/runtime/components/forms/SelectMenu.vue +++ b/src/runtime/components/forms/SelectMenu.vue @@ -98,11 +98,11 @@ - +
  • - - Create "{{ queryOption[optionAttribute] }}" + + Create "{{ createOption[optionAttribute] }}"
  • @@ -247,7 +247,7 @@ export default defineComponent({ }, clearSearchOnClose: { type: Boolean, - default: () => configMenu.default.clearOnClose + default: () => configMenu.default.clearSearchOnClose }, debounce: { type: Number, @@ -257,6 +257,10 @@ export default defineComponent({ type: Boolean, default: false }, + showCreateOptionWhen: { + type: String as PropType<'always' | 'empty'>, + default: () => configMenu.default.showCreateOptionWhen + }, placeholder: { type: String, default: null @@ -438,8 +442,21 @@ export default defineComponent({ }) }) - const queryOption = computed(() => { - return query.value === '' ? null : { [props.optionAttribute]: query.value } + const createOption = computed(() => { + if (query.value === '') { + return null + } + if (props.showCreateOptionWhen === 'empty' && filteredOptions.value.length) { + return null + } + if (props.showCreateOptionWhen === 'always') { + const existingOption = filteredOptions.value.find(option => ['string', 'number'].includes(typeof option) ? option === query.value : option[props.optionAttribute] === query.value) + if (existingOption) { + return null + } + } + + return ['string', 'number'].includes(typeof props.modelValue) ? query.value : { [props.optionAttribute]: query.value } }) function clearOnClose () { @@ -494,7 +511,7 @@ export default defineComponent({ trailingIconClass, trailingWrapperIconClass, filteredOptions, - queryOption, + createOption, query, onUpdate } diff --git a/src/runtime/ui.config/forms/selectMenu.ts b/src/runtime/ui.config/forms/selectMenu.ts index 9751d0091b..4add7aa878 100644 --- a/src/runtime/ui.config/forms/selectMenu.ts +++ b/src/runtime/ui.config/forms/selectMenu.ts @@ -22,7 +22,8 @@ export default { }, default: { selectedIcon: 'i-heroicons-check-20-solid', - clearOnClose: false + clearSearchOnClose: false, + showCreateOptionWhen: 'empty' }, arrow: { ...arrow,