diff --git a/src/runtime/components/forms/InputMenu.vue b/src/runtime/components/forms/InputMenu.vue
index 5ce1e764..2264b503 100644
--- a/src/runtime/components/forms/InputMenu.vue
+++ b/src/runtime/components/forms/InputMenu.vue
@@ -48,7 +48,7 @@
v-slot="{ active, selected, disabled: optionDisabled }"
:key="index"
as="template"
- :value="valueAttribute ? option[valueAttribute] : option"
+ :value="valueAttribute ? accessor(option, valueAttribute) : option"
:disabled="option.disabled"
>
@@ -104,6 +104,7 @@ import {
import { computedAsync, useDebounceFn } from '@vueuse/core'
import { defu } from 'defu'
import { twMerge, twJoin } from 'tailwind-merge'
+import { isEqual } from 'ohash'
import UIcon from '../elements/Icon.vue'
import UAvatar from '../elements/Avatar.vue'
import { useUI } from '../../composables/useUI'
@@ -308,8 +309,28 @@ export default defineComponent({
return
}
+ function getValue(value: any) {
+ if (props.valueAttribute) {
+ return accessor(value, props.valueAttribute)
+ }
+
+ return value
+ }
+
+ function compareValues(value1: any, value2: any) {
+ if (props.by && typeof value1 === 'object' && typeof value2 === 'object') {
+ return isEqual(value1[props.by], value2[props.by])
+ }
+ return isEqual(value1, value2)
+ }
+
if (props.valueAttribute) {
- const option = options.value.find(option => option[props.valueAttribute] === props.modelValue)
+ const option = options.value.find((option) => {
+ const optionValue = getValue(option)
+
+ return compareValues(optionValue, props.modelValue)
+ })
+
return option ? accessor(option, props.optionAttribute) : null
} else {
return ['string', 'number'].includes(typeof props.modelValue) ? props.modelValue : accessor(props.modelValue as Record, props.optionAttribute)
diff --git a/src/runtime/components/forms/SelectMenu.vue b/src/runtime/components/forms/SelectMenu.vue
index 273f1bd7..eac8cbc3 100644
--- a/src/runtime/components/forms/SelectMenu.vue
+++ b/src/runtime/components/forms/SelectMenu.vue
@@ -71,7 +71,7 @@
v-slot="{ active, selected: optionSelected, disabled: optionDisabled }"
:key="index"
as="template"
- :value="valueAttribute ? option[valueAttribute] : option"
+ :value="valueAttribute ? accessor(option, valueAttribute) : option"
:disabled="option.disabled"
>
@@ -140,6 +140,7 @@ import {
import { computedAsync, useDebounceFn } from '@vueuse/core'
import { defu } from 'defu'
import { twMerge, twJoin } from 'tailwind-merge'
+import { isEqual } from 'ohash'
import UIcon from '../elements/Icon.vue'
import UAvatar from '../elements/Avatar.vue'
import { useUI } from '../../composables/useUI'
@@ -364,39 +365,53 @@ export default defineComponent({
})
const selected = computed(() => {
+ function compareValues(value1: any, value2: any) {
+ if (props.by && typeof value1 === 'object' && typeof value2 === 'object') {
+ return isEqual(value1[props.by], value2[props.by])
+ }
+ return isEqual(value1, value2)
+ }
+
+ function getValue(value: any) {
+ if (props.valueAttribute) {
+ return accessor(value, props.valueAttribute)
+ }
+
+ return value
+ }
+
if (props.multiple) {
- if (!Array.isArray(props.modelValue) || !props.modelValue.length) {
+ const modelValue = props.modelValue
+ if (!Array.isArray(modelValue) || !modelValue.length) {
return []
}
- if (props.valueAttribute) {
- return options.value.filter(option => (props.modelValue as any[]).includes(option[props.valueAttribute]))
- }
- return options.value.filter(option => (props.modelValue as any[]).includes(option))
+ return options.value.filter((option) => {
+ const optionValue = getValue(option)
+ return modelValue.some(value => compareValues(value, optionValue))
+ })
}
- if (props.valueAttribute) {
- return options.value.find(option => option[props.valueAttribute] === props.modelValue)
- }
- return options.value.find(option => option === props.modelValue)
+ return options.value.find((option) => {
+ const optionValue = getValue(option)
+ return compareValues(optionValue, toRaw(props.modelValue))
+ }) ?? props.modelValue
})
const label = computed(() => {
- if (props.multiple) {
- if (Array.isArray(props.modelValue) && props.modelValue.length) {
- return `${selected.value.length} selected`
- } else {
- return null
- }
- } else if (props.modelValue !== undefined && props.modelValue !== null) {
- if (props.valueAttribute) {
- return accessor(selected.value, props.optionAttribute) ?? null
- } else {
- return ['string', 'number'].includes(typeof props.modelValue) ? props.modelValue : accessor(props.modelValue as Record, props.optionAttribute)
- }
+ if (!selected.value) return null
+
+ if (props.valueAttribute) {
+ return accessor(selected.value as Record, props.optionAttribute)
}
- return null
+ if (Array.isArray(props.modelValue) && props.modelValue.length) {
+ return `${props.modelValue.length} selected`
+ } else if (['string', 'number'].includes(typeof props.modelValue)) {
+ return props.modelValue
+ }
+
+ return accessor(props.modelValue as Record, props.optionAttribute)
})
const selectClass = computed(() => {