diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 188704c0ce..137fcb8494 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix `className` hydration for `` ([#2390](https://github.com/tailwindlabs/headlessui/pull/2390)) - Improve `Combobox` types to improve false positives ([#2411](https://github.com/tailwindlabs/headlessui/pull/2411)) - Merge `className` correctly when it’s a function ([#2412](https://github.com/tailwindlabs/headlessui/pull/2412)) +- Correctly handle IME composition in `` ([#2426](https://github.com/tailwindlabs/headlessui/pull/2426)) ### Added diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 60b922f5aa..d7a508ea14 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -821,12 +821,19 @@ function InputFn< ) let isComposing = useRef(false) + let composedChangeEvent = useRef | null>(null) let handleCompositionStart = useEvent(() => { isComposing.current = true }) let handleCompositionEnd = useEvent(() => { - setTimeout(() => { + d.nextFrame(() => { isComposing.current = false + + if (composedChangeEvent.current) { + actions.openCombobox() + onChange?.(composedChangeEvent.current) + composedChangeEvent.current = null + } }) }) @@ -953,6 +960,10 @@ function InputFn< }) let handleChange = useEvent((event: React.ChangeEvent) => { + if (isComposing.current) { + composedChangeEvent.current = event + return + } actions.openCombobox() onChange?.(event) }) diff --git a/packages/@headlessui-vue/CHANGELOG.md b/packages/@headlessui-vue/CHANGELOG.md index 0873634280..cf688f3e32 100644 --- a/packages/@headlessui-vue/CHANGELOG.md +++ b/packages/@headlessui-vue/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `FocusTrap` event listeners once document has loaded ([#2389](https://github.com/tailwindlabs/headlessui/pull/2389)) - Don't scroll-lock `` when wrapping transition isn't showing ([#2422](https://github.com/tailwindlabs/headlessui/pull/2422)) - Ensure DOM `ref` is properly handled in the `RadioGroup` component ([#2424](https://github.com/tailwindlabs/headlessui/pull/2424)) +- Correctly handle IME composition in `` ([#2426](https://github.com/tailwindlabs/headlessui/pull/2426)) ### Added diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index b5ec3e7cbf..c0f26aa4ec 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -37,6 +37,7 @@ import { objectToFormEntries } from '../../utils/form' import { useControllable } from '../../hooks/use-controllable' import { useTrackedPointer } from '../../hooks/use-tracked-pointer' import { isMobile } from '../../utils/platform' +import { disposables } from '../../utils/disposables' function defaultComparator(a: T, z: T): boolean { return a === z @@ -763,12 +764,19 @@ export let ComboboxInput = defineComponent({ }) let isComposing = ref(false) + let composedChangeEvent = ref<(Event & { target: HTMLInputElement }) | null>(null) function handleCompositionstart() { isComposing.value = true } function handleCompositionend() { - setTimeout(() => { + disposables().nextFrame(() => { isComposing.value = false + + if (composedChangeEvent.value) { + api.openCombobox() + emit('change', composedChangeEvent.value) + composedChangeEvent.value = null + } }) } @@ -891,6 +899,10 @@ export let ComboboxInput = defineComponent({ } function handleInput(event: Event & { target: HTMLInputElement }) { + if (isComposing.value) { + composedChangeEvent.value = event + return + } api.openCombobox() emit('change', event) }