From 46754e637c98034a1fe13ae8e2ba451d6bb2ba09 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 12 Dec 2022 16:43:57 +0100 Subject: [PATCH] Fix regression where `displayValue` crashes (#2087) * fix regression where `displayValue` crashes It regressed in the sense that it now uses `displayValue` for the `defaultValue` as well, but if nothing is passed it would crash. Right now, it makes sure to only run the displayValue value on the actual value and the actual default value if they are not undefined. Note: if your displayValue is implemented like `(value) => value.name`, and your `value` is passed as `null`, it will still crash (as expected) because then you are in charge of rendering something else than null. If we would "fix" this, then no value can be rendered instead of `null`. Fixes: #2084 * update changelog --- packages/@headlessui-react/CHANGELOG.md | 4 ++- .../src/components/combobox/combobox.test.tsx | 24 ++++++++++++++++++ .../src/components/combobox/combobox.tsx | 6 +++-- packages/@headlessui-vue/CHANGELOG.md | 4 ++- .../src/components/combobox/combobox.test.ts | 25 +++++++++++++++++++ .../src/components/combobox/combobox.ts | 6 +++-- 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index d103ab9..456689f 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Fix regression where `displayValue` crashes ([#2087](https://github.com/tailwindlabs/headlessui/pull/2087)) ## [1.7.5] - 2022-12-08 diff --git a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx index e3be24c..9c5561d 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.test.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.test.tsx @@ -412,6 +412,30 @@ describe('Rendering', () => { }) ) }) + + it( + 'should not crash when a defaultValue is not given', + suppressConsoleLogs(async () => { + let data = [ + { id: 1, name: 'alice', label: 'Alice' }, + { id: 2, name: 'bob', label: 'Bob' }, + { id: 3, name: 'charlie', label: 'Charlie' }, + ] + + render( + + value.name} /> + + {data.map((person) => ( + + {person.label} + + ))} + + + ) + }) + ) }) describe('Combobox.Input', () => { diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 594b956..ba84793 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -705,7 +705,7 @@ let Input = forwardRefWithAs(function Input< // you don't have to use this at all, a more common UI is a "tag" based UI, which you can render // yourself using the selected option(s). let currentValue = useMemo(() => { - if (typeof displayValue === 'function') { + if (typeof displayValue === 'function' && data.value !== undefined) { return displayValue(data.value as unknown as TType) ?? '' } else if (typeof data.value === 'string') { return data.value @@ -909,7 +909,9 @@ let Input = forwardRefWithAs(function Input< 'aria-labelledby': labelledby, defaultValue: props.defaultValue ?? - displayValue?.(data.defaultValue as unknown as TType) ?? + (data.defaultValue !== undefined + ? displayValue?.(data.defaultValue as unknown as TType) + : null) ?? data.defaultValue, disabled: data.disabled, onCompositionStart: handleCompositionStart, diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md index 405297c..ecd9068 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 + +- Fix regression where `displayValue` crashes ([#2087](https://github.com/tailwindlabs/headlessui/pull/2087)) ## [1.7.5] - 2022-12-08 diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts index 4c60888..1af8cdc 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.test.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.test.ts @@ -465,6 +465,31 @@ describe('Rendering', () => { }) ) }) + + it( + 'should not crash when a defaultValue is not given', + suppressConsoleLogs(async () => { + let data = [ + { id: 1, name: 'alice', label: 'Alice' }, + { id: 2, name: 'bob', label: 'Bob' }, + { id: 3, name: 'charlie', label: 'Charlie' }, + ] + + renderTemplate({ + template: html` + + + + + {{ person.label }} + + + + `, + setup: () => ({ data }), + }) + }) + ) }) describe('ComboboxInput', () => { diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index b7c8d17..ac9cc2f 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -676,7 +676,7 @@ export let ComboboxInput = defineComponent({ let value = api.value.value if (!dom(api.inputRef)) return '' - if (typeof props.displayValue !== 'undefined') { + if (typeof props.displayValue !== 'undefined' && value !== undefined) { return props.displayValue(value as unknown) ?? '' } else if (typeof value === 'string') { return value @@ -874,7 +874,9 @@ export let ComboboxInput = defineComponent({ let defaultValue = computed(() => { return ( props.defaultValue ?? - props.displayValue?.(api.defaultValue.value) ?? + (api.defaultValue.value !== undefined + ? props.displayValue?.(api.defaultValue.value) + : null) ?? api.defaultValue.value ?? '' )