Skip to content

Commit 46754e6

Browse files
authored
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
1 parent 208c6fd commit 46754e6

File tree

6 files changed

+63
-6
lines changed

6 files changed

+63
-6
lines changed

packages/@headlessui-react/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Fix regression where `displayValue` crashes ([#2087](https://github.com/tailwindlabs/headlessui/pull/2087))
1113

1214
## [1.7.5] - 2022-12-08
1315

packages/@headlessui-react/src/components/combobox/combobox.test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,30 @@ describe('Rendering', () => {
412412
})
413413
)
414414
})
415+
416+
it(
417+
'should not crash when a defaultValue is not given',
418+
suppressConsoleLogs(async () => {
419+
let data = [
420+
{ id: 1, name: 'alice', label: 'Alice' },
421+
{ id: 2, name: 'bob', label: 'Bob' },
422+
{ id: 3, name: 'charlie', label: 'Charlie' },
423+
]
424+
425+
render(
426+
<Combobox name="assignee" by="id">
427+
<Combobox.Input displayValue={(value: { name: string }) => value.name} />
428+
<Combobox.Options>
429+
{data.map((person) => (
430+
<Combobox.Option key={person.id} value={person}>
431+
{person.label}
432+
</Combobox.Option>
433+
))}
434+
</Combobox.Options>
435+
</Combobox>
436+
)
437+
})
438+
)
415439
})
416440

417441
describe('Combobox.Input', () => {

packages/@headlessui-react/src/components/combobox/combobox.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ let Input = forwardRefWithAs(function Input<
705705
// you don't have to use this at all, a more common UI is a "tag" based UI, which you can render
706706
// yourself using the selected option(s).
707707
let currentValue = useMemo(() => {
708-
if (typeof displayValue === 'function') {
708+
if (typeof displayValue === 'function' && data.value !== undefined) {
709709
return displayValue(data.value as unknown as TType) ?? ''
710710
} else if (typeof data.value === 'string') {
711711
return data.value
@@ -909,7 +909,9 @@ let Input = forwardRefWithAs(function Input<
909909
'aria-labelledby': labelledby,
910910
defaultValue:
911911
props.defaultValue ??
912-
displayValue?.(data.defaultValue as unknown as TType) ??
912+
(data.defaultValue !== undefined
913+
? displayValue?.(data.defaultValue as unknown as TType)
914+
: null) ??
913915
data.defaultValue,
914916
disabled: data.disabled,
915917
onCompositionStart: handleCompositionStart,

packages/@headlessui-vue/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Fix regression where `displayValue` crashes ([#2087](https://github.com/tailwindlabs/headlessui/pull/2087))
1113

1214
## [1.7.5] - 2022-12-08
1315

packages/@headlessui-vue/src/components/combobox/combobox.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,31 @@ describe('Rendering', () => {
465465
})
466466
)
467467
})
468+
469+
it(
470+
'should not crash when a defaultValue is not given',
471+
suppressConsoleLogs(async () => {
472+
let data = [
473+
{ id: 1, name: 'alice', label: 'Alice' },
474+
{ id: 2, name: 'bob', label: 'Bob' },
475+
{ id: 3, name: 'charlie', label: 'Charlie' },
476+
]
477+
478+
renderTemplate({
479+
template: html`
480+
<Combobox name="assignee" by="id">
481+
<ComboboxInput :displayValue="(value) => value.name" />
482+
<ComboboxOptions>
483+
<ComboboxOption v-for="person in data" :key="person.id" :value="person">
484+
{{ person.label }}
485+
</ComboboxOption>
486+
<ComboboxOptions>
487+
</Combobox>
488+
`,
489+
setup: () => ({ data }),
490+
})
491+
})
492+
)
468493
})
469494

470495
describe('ComboboxInput', () => {

packages/@headlessui-vue/src/components/combobox/combobox.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ export let ComboboxInput = defineComponent({
676676
let value = api.value.value
677677
if (!dom(api.inputRef)) return ''
678678

679-
if (typeof props.displayValue !== 'undefined') {
679+
if (typeof props.displayValue !== 'undefined' && value !== undefined) {
680680
return props.displayValue(value as unknown) ?? ''
681681
} else if (typeof value === 'string') {
682682
return value
@@ -874,7 +874,9 @@ export let ComboboxInput = defineComponent({
874874
let defaultValue = computed(() => {
875875
return (
876876
props.defaultValue ??
877-
props.displayValue?.(api.defaultValue.value) ??
877+
(api.defaultValue.value !== undefined
878+
? props.displayValue?.(api.defaultValue.value)
879+
: null) ??
878880
api.defaultValue.value ??
879881
''
880882
)

0 commit comments

Comments
 (0)