Skip to content

Commit f76320a

Browse files
committed
fix: fix issue with dropdown filter for IME inputs
this uses recommended workaround from https://github.com/downshift-js/downshift/tree/master/src/hooks/useCombobox#inputvalue
1 parent 5846367 commit f76320a

7 files changed

Lines changed: 51 additions & 24 deletions

File tree

packages/pluggableWidgets/datagrid-dropdown-filter-web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- We fixed an issue with option filtering not working correctly with IME input methods.
12+
913
## [3.10.0] - 2026-05-06
1014

1115
### Fixed

packages/shared/widget-plugin-dropdown-filter/src/containers/EnumFilterContainer.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import { ActionValue, EditableValue } from "mendix";
2+
import { observer } from "mobx-react-lite";
3+
import { CSSProperties, ReactElement, useEffect } from "react";
14
import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider";
25
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/main";
36
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
47
import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup";
5-
import { ActionValue, EditableValue } from "mendix";
6-
import { observer } from "mobx-react-lite";
7-
import { CSSProperties, ReactElement, useEffect } from "react";
88
import { EnumComboboxController } from "../controllers/EnumComboboxController";
99
import { EnumSelectController } from "../controllers/EnumSelectController";
1010
import { EnumTagPickerController } from "../controllers/EnumTagPickerController";
@@ -91,6 +91,7 @@ const ComboboxWidget = observer(function ComboboxWidget(props: EnumFilterContain
9191
onClear={ctrl2.handleClear}
9292
onFocus={ctrl2.handleFocus}
9393
onBlur={ctrl2.handleBlur}
94+
onChange={ctrl2.handleChange}
9495
empty={ctrl2.isEmpty}
9596
className={props.className}
9697
style={props.styles}
@@ -112,6 +113,7 @@ const TagPickerWidget = observer(function TagPickerWidget(props: EnumFilterConta
112113
useComboboxProps={ctrl3.useComboboxProps}
113114
onClear={ctrl3.handleClear}
114115
onBlur={ctrl3.handleBlur}
116+
onChange={ctrl3.handleChange}
115117
inputPlaceholder={ctrl3.inputPlaceholder}
116118
emptyCaption={ctrl3.emptyCaption}
117119
ariaLabel={props.ariaLabel}

packages/shared/widget-plugin-dropdown-filter/src/containers/RefFilterContainer.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
import { ActionValue, EditableValue } from "mendix";
2+
import { observer } from "mobx-react-lite";
3+
import { CSSProperties, ReactElement, useEffect } from "react";
14
import { useOnScrollBottom } from "@mendix/widget-plugin-hooks/useOnScrollBottom";
25
import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider";
36
import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/main";
47
import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst";
58
import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup";
6-
import { ActionValue, EditableValue } from "mendix";
7-
import { observer } from "mobx-react-lite";
8-
import { CSSProperties, ReactElement, useEffect } from "react";
99
import { RefComboboxController } from "../controllers/RefComboboxController";
1010
import { RefSelectController } from "../controllers/RefSelectController";
1111
import { RefTagPickerController } from "../controllers/RefTagPickerController";
@@ -94,6 +94,7 @@ const ComboboxWidget = observer(function ComboboxWidget(props: RefFilterContaine
9494
onClear={ctrl2.handleClear}
9595
onFocus={ctrl2.handleFocus}
9696
onBlur={ctrl2.handleBlur}
97+
onChange={ctrl2.handleChange}
9798
onMenuScroll={handleMenuScroll}
9899
empty={ctrl2.isEmpty}
99100
className={props.className}
@@ -118,6 +119,7 @@ const TagPickerWidget = observer(function TagPickerWidget(props: RefFilterContai
118119
onClear={ctrl3.handleClear}
119120
onBlur={ctrl3.handleBlur}
120121
onFocus={ctrl3.handleFocus}
122+
onChange={ctrl3.handleChange}
121123
onMenuScroll={handleMenuScroll}
122124
inputPlaceholder={ctrl3.inputPlaceholder}
123125
emptyCaption={ctrl3.emptyCaption}

packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/ComboboxControllerMixin.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
21
import { useCombobox, UseComboboxProps } from "downshift";
32
import { action, autorun, computed, makeObservable, observable, reaction } from "mobx";
4-
import { FocusEvent } from "react";
3+
import { ChangeEvent, FocusEvent } from "react";
4+
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
55
import { SearchStore } from "../../stores/SearchStore";
66
import { OptionWithState } from "../../typings/OptionWithState";
77
import { GConstructor } from "../../typings/type-utils";
@@ -43,7 +43,8 @@ export function ComboboxControllerMixin<TBase extends BaseController>(Base: TBas
4343
isEmpty: computed,
4444
options: computed,
4545
handleBlur: action,
46-
handleClear: action
46+
handleClear: action,
47+
handleChange: action
4748
});
4849
}
4950

@@ -134,26 +135,26 @@ export function ComboboxControllerMixin<TBase extends BaseController>(Base: TBas
134135
this.filterStore.clear();
135136
};
136137

138+
handleChange = (event: ChangeEvent<HTMLInputElement>): void => {
139+
this.setTouched(true);
140+
this.setInputValue(event.target.value);
141+
};
142+
137143
useComboboxProps = (): UseComboboxProps<OptionWithState> => {
138144
const props: UseComboboxProps<OptionWithState> = {
139145
items: this.filterStore.options,
140146
itemToKey: item => item?.value,
141147
itemToString: item => item?.caption ?? "",
142148
inputValue: this.inputValue,
143149
defaultHighlightedIndex: this.selectedIndex,
144-
onInputValueChange: changes => {
145-
// Blur is handled by handleBlur;
150+
onStateChange: changes => {
146151
if (changes.type === useCombobox.stateChangeTypes.InputBlur) {
152+
// Blur is handled by handleBlur;
147153
return;
148154
}
149155
if (changes.type === useCombobox.stateChangeTypes.InputKeyDownEscape) {
150156
this.handleClear();
151-
return;
152-
}
153-
if (changes.type === useCombobox.stateChangeTypes.InputChange) {
154-
this.setTouched(true);
155157
}
156-
this.setInputValue(changes.inputValue);
157158
},
158159
onSelectedItemChange: ({ selectedItem, type }) => {
159160
if (

packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/TagPickerControllerMixin.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
21
import { useCombobox, UseComboboxProps, useMultipleSelection, UseMultipleSelectionProps } from "downshift";
32
import { action, autorun, computed, makeObservable, observable } from "mobx";
3+
import { ChangeEvent } from "react";
4+
import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch";
45
import { SearchStore } from "../../stores/SearchStore";
56
import { OptionWithState } from "../../typings/OptionWithState";
67
import { GConstructor } from "../../typings/type-utils";
@@ -43,6 +44,7 @@ export function TagPickerControllerMixin<TBase extends BaseController>(Base: TBa
4344
selectedOptions: computed,
4445
handleBlur: action,
4546
handleClear: action,
47+
handleChange: action,
4648
isEmpty: computed,
4749
options: computed
4850
});
@@ -106,22 +108,26 @@ export function TagPickerControllerMixin<TBase extends BaseController>(Base: TBa
106108
this.filterStore.clear();
107109
};
108110

111+
handleChange = (event: ChangeEvent<HTMLInputElement>): void => {
112+
this.setTouched(true);
113+
this.setInputValue(event.target.value);
114+
};
115+
109116
useComboboxProps = (): UseComboboxProps<OptionWithState> => {
110117
const props: UseComboboxProps<OptionWithState> = {
111118
items: this.options,
112119
itemToKey: item => item?.value,
113120
itemToString: item => item?.caption ?? "",
114121
inputValue: this.inputValue,
115122
defaultHighlightedIndex: this.selectedIndex,
116-
onInputValueChange: changes => {
117-
// Blur is handled by handleBlur;
123+
onStateChange: changes => {
118124
if (changes.type === useCombobox.stateChangeTypes.InputBlur) {
125+
// Blur is handled by handleBlur;
119126
return;
120127
}
121-
if (changes.type === useCombobox.stateChangeTypes.InputChange) {
122-
this.setTouched(true);
128+
if (changes.type === useCombobox.stateChangeTypes.InputKeyDownEscape) {
129+
this.handleClear();
123130
}
124-
this.setInputValue(changes.inputValue);
125131
},
126132
onSelectedItemChange: ({ selectedItem, type }) => {
127133
if (

packages/shared/widget-plugin-dropdown-filter/src/controls/combobox/Combobox.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import cn from "classnames";
22
import { useCombobox, UseComboboxProps } from "downshift";
33
import { observer } from "mobx-react-lite";
4-
import { CSSProperties, FocusEventHandler, UIEventHandler, useRef } from "react";
4+
import { ChangeEventHandler, CSSProperties, FocusEventHandler, UIEventHandler, useRef } from "react";
55
import { OptionWithState } from "../../typings/OptionWithState";
66
import { ClearButton } from "../base/ClearButton";
77
import { OptionsWrapper } from "../base/OptionsWrapper";
@@ -20,6 +20,7 @@ interface ComboboxProps {
2020
onClear: () => void;
2121
onBlur: FocusEventHandler<HTMLInputElement>;
2222
onFocus: FocusEventHandler<HTMLInputElement>;
23+
onChange: ChangeEventHandler<HTMLInputElement>;
2324
onMenuScroll?: UIEventHandler<HTMLUListElement>;
2425
}
2526

@@ -48,6 +49,7 @@ export const Combobox = observer(function Combobox(props: ComboboxProps) {
4849
ref: inputRef,
4950
onBlur: props.onBlur,
5051
onFocus: props.onFocus,
52+
onChange: props.onChange,
5153
placeholder: props.empty ? (isOpen ? props.inputPlaceholder : props.emptyCaption) : undefined
5254
})}
5355
/>

packages/shared/widget-plugin-dropdown-filter/src/controls/tag-picker/TagPicker.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import cn from "classnames";
22
import { useCombobox, UseComboboxProps, useMultipleSelection, UseMultipleSelectionProps } from "downshift";
33
import { observer } from "mobx-react-lite";
4-
import { CSSProperties, FocusEventHandler, ReactElement, UIEventHandler, useId, useRef } from "react";
4+
import {
5+
ChangeEventHandler,
6+
CSSProperties,
7+
FocusEventHandler,
8+
ReactElement,
9+
UIEventHandler,
10+
useId,
11+
useRef
12+
} from "react";
513
import { OptionWithState } from "../../typings/OptionWithState";
614
import { ClearButton } from "../base/ClearButton";
715
import { OptionsWrapper } from "../base/OptionsWrapper";
@@ -24,6 +32,7 @@ interface TagPickerProps {
2432
onClear: () => void;
2533
onBlur: () => void;
2634
onFocus?: FocusEventHandler<HTMLInputElement>;
35+
onChange: ChangeEventHandler<HTMLInputElement>;
2736
onMenuScroll?: UIEventHandler<HTMLUListElement>;
2837
}
2938

@@ -102,6 +111,7 @@ export const TagPicker = observer(function TagPicker(props: TagPickerProps): Rea
102111
"aria-label": inputLabel || "filter",
103112
onBlur: props.onBlur,
104113
onFocus: props.onFocus,
114+
onChange: props.onChange,
105115
placeholder: props.empty ? (isOpen ? props.inputPlaceholder : props.emptyCaption) : undefined,
106116
...getDropdownProps(),
107117
"aria-describedby": props.empty ? undefined : `${helperText1} ${inputContainerId}`

0 commit comments

Comments
 (0)