Skip to content

Commit 0bf325d

Browse files
authored
Ensure ComboboxInput syncs correctly (#1106)
* ensure ComboboxInput syncs correctly * update changelog
1 parent 639d8d2 commit 0bf325d

File tree

3 files changed

+39
-59
lines changed

3 files changed

+39
-59
lines changed

CHANGELOG.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3232

3333
### Added
3434

35-
- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047), [#1099](https://github.com/tailwindlabs/headlessui/pull/1099), [#1101](https://github.com/tailwindlabs/headlessui/pull/1101), - Bubble Escape event even if `Combobox.Options` is not rendered at all ()
36-
)
35+
- Add `Combobox` component ([#1047](https://github.com/tailwindlabs/headlessui/pull/1047), [#1099](https://github.com/tailwindlabs/headlessui/pull/1099), [#1101](https://github.com/tailwindlabs/headlessui/pull/1101), [#1104](https://github.com/tailwindlabs/headlessui/pull/1104), [#1106](https://github.com/tailwindlabs/headlessui/pull/1106))
3736

3837
## [@headlessui/react@v1.4.3] - 2022-01-14
3938

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

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import {
2+
computed,
23
defineComponent,
3-
ref,
4-
provide,
54
inject,
5+
nextTick,
66
onMounted,
77
onUnmounted,
8-
computed,
9-
nextTick,
10-
InjectionKey,
11-
Ref,
12-
ComputedRef,
13-
watchEffect,
8+
provide,
9+
ref,
1410
toRaw,
1511
watch,
12+
watchEffect,
13+
ComputedRef,
14+
InjectionKey,
1615
PropType,
16+
Ref,
1717
} from 'vue'
1818

1919
import { Features, render, omit } from '../../utils/render'
@@ -232,9 +232,7 @@ export let Combobox = defineComponent({
232232
api.closeCombobox()
233233
})
234234

235-
watchEffect(() => {
236-
api.syncInputValue()
237-
})
235+
watch([api.value, api.inputRef], () => api.syncInputValue(), { immediate: true })
238236

239237
// @ts-expect-error Types of property 'dataRef' are incompatible.
240238
provide(ComboboxContext, api)
@@ -525,7 +523,7 @@ export let ComboboxInput = defineComponent({
525523
tabIndex: 0,
526524
ref: api.inputRef,
527525
}
528-
let passThroughProps = props
526+
let passThroughProps = omit(props, ['displayValue'])
529527

530528
return render({
531529
props: { ...passThroughProps, ...propsWeControl },

packages/playground-vue/src/components/combobox/combobox-with-pure-tailwind.vue

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,18 @@ import {
1010
} from '@headlessui/vue'
1111
1212
let everybody = [
13-
'Wade Cooper',
14-
'Arlene Mccoy',
15-
'Devon Webb',
16-
'Tom Cook',
17-
'Tanya Fox',
18-
'Hellen Schmidt',
19-
'Caroline Schultz',
20-
'Mason Heaney',
21-
'Claudie Smitham',
22-
'Emil Schaefer',
13+
{ id: 1, name: 'Wade Cooper' },
14+
{ id: 2, name: 'Arlene Mccoy' },
15+
{ id: 3, name: 'Devon Webb' },
16+
{ id: 4, name: 'Tom Cook' },
17+
{ id: 5, name: 'Tanya Fox' },
18+
{ id: 6, name: 'Hellen Schmidt' },
19+
{ id: 7, name: 'Caroline Schultz' },
20+
{ id: 8, name: 'Mason Heaney' },
21+
{ id: 9, name: 'Claudie Smitham' },
22+
{ id: 10, name: 'Emil Schaefer' },
2323
]
2424
25-
/**
26-
* @template T
27-
* @param {Ref<T>} value
28-
* @param {number} delay
29-
*/
30-
function useDebounce(value, delay) {
31-
let debouncedValue = ref(value.value)
32-
let timer
33-
34-
return computed({
35-
get() {
36-
return debouncedValue.value
37-
},
38-
39-
set(newValue) {
40-
timer && clearTimeout(timer)
41-
timer = setTimeout(() => (debouncedValue.value = newValue), delay)
42-
},
43-
})
44-
}
45-
4625
export default defineComponent({
4726
components: {
4827
Combobox,
@@ -54,27 +33,30 @@ export default defineComponent({
5433
},
5534
setup() {
5635
let query = ref('')
57-
let activePerson = ref(everybody[2])
58-
59-
// Mimic delayed response from an API
60-
let actualQuery = useDebounce(
61-
query,
62-
0 /* Change to higher value like 100 for testing purposes */
63-
)
36+
let activePerson = ref(null) // everybody[Math.floor(Math.random() * everybody.length)]
37+
let filteredPeople = computed(() => {
38+
return query.value === ''
39+
? everybody
40+
: everybody.filter((person) => {
41+
return person.name.toLowerCase().includes(query.value.toLowerCase())
42+
})
43+
})
6444
6545
return {
6646
query,
6747
activePerson,
68-
everybody,
69-
actualQuery,
48+
filteredPeople,
7049
}
7150
},
7251
})
7352
</script>
53+
7454
<template>
7555
<div class="flex h-full w-screen justify-center bg-gray-50 p-12">
7656
<div class="mx-auto w-full max-w-xs">
77-
<div class="py-8 font-mono text-xs">Selected person: {{ activePerson }}</div>
57+
<div class="py-8 font-mono text-xs">
58+
Selected person: {{ activePerson?.name ?? 'Nobody yet' }}
59+
</div>
7860
<div class="space-y-1">
7961
<Combobox v-model="activePerson" as="div">
8062
<ComboboxLabel class="block text-sm font-medium leading-5 text-gray-700">
@@ -85,6 +67,7 @@ export default defineComponent({
8567
<span class="relative inline-flex flex-row overflow-hidden rounded-md border shadow-sm">
8668
<ComboboxInput
8769
@change="query = $event.target.value"
70+
:displayValue="(person) => person?.name ?? ''"
8871
class="border-none px-3 py-1 outline-none"
8972
/>
9073
<ComboboxButton
@@ -113,9 +96,9 @@ export default defineComponent({
11396
class="shadow-xs max-h-60 overflow-auto rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5"
11497
>
11598
<ComboboxOption
116-
v-for="name in everybody"
117-
:key="name"
118-
:value="name"
99+
v-for="person in filteredPeople"
100+
:key="person.id"
101+
:value="person"
119102
v-slot="{ active, selected }"
120103
>
121104
<div
@@ -125,7 +108,7 @@ export default defineComponent({
125108
]"
126109
>
127110
<span :class="['block truncate', selected ? 'font-semibold' : 'font-normal']">
128-
{{ name }}
111+
{{ person.name }}
129112
</span>
130113
<span
131114
v-if="selected"

0 commit comments

Comments
 (0)