From b85540a996c658b859a6c1d12daa8f16d26f962c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 12 Apr 2023 12:03:59 -0400 Subject: [PATCH 1/5] =?UTF-8?q?Don=E2=80=99t=20try=20to=20open=20combobox?= =?UTF-8?q?=20when=20composing=20characters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/@headlessui-react/src/components/combobox/combobox.tsx | 1 + packages/@headlessui-vue/src/components/combobox/combobox.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 60b922f5aa..199ae1722d 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -953,6 +953,7 @@ function InputFn< }) let handleChange = useEvent((event: React.ChangeEvent) => { + if (isComposing.current) return actions.openCombobox() onChange?.(event) }) diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index b5ec3e7cbf..bd81e5c35f 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -891,6 +891,7 @@ export let ComboboxInput = defineComponent({ } function handleInput(event: Event & { target: HTMLInputElement }) { + if (isComposing.value) return api.openCombobox() emit('change', event) } From 763a295344db4426cf05a77043b0c83cc02c288f Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 12 Apr 2023 12:13:23 -0400 Subject: [PATCH 2/5] wip --- .../src/components/combobox/combobox.tsx | 12 +++++++++++- .../src/components/combobox/combobox.ts | 12 +++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 199ae1722d..5283e77aa3 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(() => { isComposing.current = false + + if (composedChangeEvent.current) { + actions.openCombobox() + onChange?.(composedChangeEvent.current) + composedChangeEvent.current = null + } }) }) @@ -953,7 +960,10 @@ function InputFn< }) let handleChange = useEvent((event: React.ChangeEvent) => { - if (isComposing.current) return + if (isComposing.current) { + composedChangeEvent.current = event + return + } actions.openCombobox() onChange?.(event) }) diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index bd81e5c35f..598c3f16bc 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -763,12 +763,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(() => { isComposing.value = false + + if (composedChangeEvent.value) { + api.openCombobox() + emit('change', composedChangeEvent.value) + composedChangeEvent.value = null + } }) } @@ -891,7 +898,10 @@ export let ComboboxInput = defineComponent({ } function handleInput(event: Event & { target: HTMLInputElement }) { - if (isComposing.value) return + if (isComposing.value) { + composedChangeEvent.value = event + return + } api.openCombobox() emit('change', event) } From aac74435455835b40cb10015b919bfdbd94c30a4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 13 Apr 2023 10:58:56 -0400 Subject: [PATCH 3/5] Delay IME composition end until after keydown events --- packages/@headlessui-vue/src/components/combobox/combobox.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index 598c3f16bc..4e9f582ad1 100644 --- a/packages/@headlessui-vue/src/components/combobox/combobox.ts +++ b/packages/@headlessui-vue/src/components/combobox/combobox.ts @@ -776,7 +776,7 @@ export let ComboboxInput = defineComponent({ emit('change', composedChangeEvent.value) composedChangeEvent.value = null } - }) + }, 5) } function handleKeyDown(event: KeyboardEvent) { From e5fda276d286b457920c76d80e1e94198b065662 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 17 Apr 2023 10:11:30 -0400 Subject: [PATCH 4/5] Use `d.nextFrame` to handle `compositionend` event --- .../@headlessui-react/src/components/combobox/combobox.tsx | 2 +- packages/@headlessui-vue/src/components/combobox/combobox.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 5283e77aa3..d7a508ea14 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -826,7 +826,7 @@ function InputFn< isComposing.current = true }) let handleCompositionEnd = useEvent(() => { - setTimeout(() => { + d.nextFrame(() => { isComposing.current = false if (composedChangeEvent.current) { diff --git a/packages/@headlessui-vue/src/components/combobox/combobox.ts b/packages/@headlessui-vue/src/components/combobox/combobox.ts index 4e9f582ad1..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 @@ -768,7 +769,7 @@ export let ComboboxInput = defineComponent({ isComposing.value = true } function handleCompositionend() { - setTimeout(() => { + disposables().nextFrame(() => { isComposing.value = false if (composedChangeEvent.value) { @@ -776,7 +777,7 @@ export let ComboboxInput = defineComponent({ emit('change', composedChangeEvent.value) composedChangeEvent.value = null } - }, 5) + }) } function handleKeyDown(event: KeyboardEvent) { From 9d3f3c6d970b05c5ec84d253ce2a41c0e27b4b6d Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 17 Apr 2023 10:12:32 -0400 Subject: [PATCH 5/5] Update changelog --- packages/@headlessui-react/CHANGELOG.md | 1 + packages/@headlessui-vue/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) 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-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