diff --git a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx index a4df3818a9..54c679482f 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx @@ -460,6 +460,46 @@ describe('Rendering', () => { }) ) + it( + 'selecting an option puts the display value into Combobox.Input when displayValue is provided (when value is undefined)', + suppressConsoleLogs(async () => { + function Example() { + let [value, setValue] = useState(undefined) + + return ( + + str?.toUpperCase() ?? ''} + /> + Trigger + + Option A + Option B + Option C + + + ) + } + + render() + + // Focus the input + await focus(getComboboxInput()) + + // Type in it + await type(word('A'), getComboboxInput()) + + // Stop typing (and clear the input) + await press(Keys.Escape, getComboboxInput()) + + // Focus the body (so the input loses focus) + await focus(document.body) + + expect(getComboboxInput()).toHaveValue('') + }) + ) + it( 'conditionally rendering the input should allow changing the display value', suppressConsoleLogs(async () => { diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md index 1cab876079..17a84b8414 100644 --- a/packages/@headlessui-vue/CHANGELOG.md +++ b/packages/@headlessui-vue/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Call `displayValue` with a v-model of `ref(undefined)` on `ComboboxInput` ([#1865](https://github.com/tailwindlabs/headlessui/pull/1865)) ## [1.7.2] - 2022-09-15 diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts index a7c7b21b30..0bbf63e00e 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts @@ -493,6 +493,43 @@ describe('Rendering', () => { }) ) + // This really is a bug in Vue but we have a workaround for it + it( + 'selecting an option puts the display value into Combobox.Input when displayValue is provided (when v-model is undefined)', + suppressConsoleLogs(async () => { + let Example = defineComponent({ + template: html` + + + Trigger + + Option A + Option B + Option C + + + `, + setup: () => ({ value: ref(undefined) }), + }) + + renderTemplate(Example) + + // Focus the input + await focus(getComboboxInput()) + + // Type in it + await type(word('A'), getComboboxInput()) + + // Stop typing (and clear the input) + await press(Keys.Escape, getComboboxInput()) + + // Focus the body (so the input loses focus) + await focus(document.body) + + expect(getComboboxInput()).toHaveValue('') + }) + ) + it('conditionally rendering the input should allow changing the display value', async () => { let Example = defineComponent({ template: html` diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index 157255ae4a..d287ac7cbd 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -629,11 +629,20 @@ export let ComboboxInput = defineComponent({ } } + // Workaround Vue bug where watching [ref(undefined)] is not fired immediately even when value is true + const __fixVueImmediateWatchBug__ = ref('') + onMounted(() => { - watch([api.value], () => (currentValue.value = getCurrentValue()), { - flush: 'sync', - immediate: true, - }) + watch( + [api.value, __fixVueImmediateWatchBug__], + () => { + currentValue.value = getCurrentValue() + }, + { + flush: 'sync', + immediate: true, + } + ) watch( [currentValue, api.comboboxState],