diff --git a/packages/pluggableWidgets/datagrid-dropdown-filter-web/CHANGELOG.md b/packages/pluggableWidgets/datagrid-dropdown-filter-web/CHANGELOG.md index 1113929297..dfb37af188 100644 --- a/packages/pluggableWidgets/datagrid-dropdown-filter-web/CHANGELOG.md +++ b/packages/pluggableWidgets/datagrid-dropdown-filter-web/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Fixed + +- We fixed an issue with option filtering not working correctly with IME input methods. + ## [3.10.0] - 2026-05-06 ### Fixed diff --git a/packages/shared/widget-plugin-dropdown-filter/src/containers/EnumFilterContainer.tsx b/packages/shared/widget-plugin-dropdown-filter/src/containers/EnumFilterContainer.tsx index 6d7b4408e0..a0892e8304 100644 --- a/packages/shared/widget-plugin-dropdown-filter/src/containers/EnumFilterContainer.tsx +++ b/packages/shared/widget-plugin-dropdown-filter/src/containers/EnumFilterContainer.tsx @@ -1,10 +1,10 @@ +import { ActionValue, EditableValue } from "mendix"; +import { observer } from "mobx-react-lite"; +import { CSSProperties, ReactElement, useEffect } from "react"; import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider"; import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/main"; import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst"; import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup"; -import { ActionValue, EditableValue } from "mendix"; -import { observer } from "mobx-react-lite"; -import { CSSProperties, ReactElement, useEffect } from "react"; import { EnumComboboxController } from "../controllers/EnumComboboxController"; import { EnumSelectController } from "../controllers/EnumSelectController"; import { EnumTagPickerController } from "../controllers/EnumTagPickerController"; @@ -91,6 +91,7 @@ const ComboboxWidget = observer(function ComboboxWidget(props: EnumFilterContain onClear={ctrl2.handleClear} onFocus={ctrl2.handleFocus} onBlur={ctrl2.handleBlur} + onChange={ctrl2.handleChange} empty={ctrl2.isEmpty} className={props.className} style={props.styles} @@ -112,6 +113,7 @@ const TagPickerWidget = observer(function TagPickerWidget(props: EnumFilterConta useComboboxProps={ctrl3.useComboboxProps} onClear={ctrl3.handleClear} onBlur={ctrl3.handleBlur} + onChange={ctrl3.handleChange} inputPlaceholder={ctrl3.inputPlaceholder} emptyCaption={ctrl3.emptyCaption} ariaLabel={props.ariaLabel} diff --git a/packages/shared/widget-plugin-dropdown-filter/src/containers/RefFilterContainer.tsx b/packages/shared/widget-plugin-dropdown-filter/src/containers/RefFilterContainer.tsx index 63af5fcd6d..efcefa2a8b 100644 --- a/packages/shared/widget-plugin-dropdown-filter/src/containers/RefFilterContainer.tsx +++ b/packages/shared/widget-plugin-dropdown-filter/src/containers/RefFilterContainer.tsx @@ -1,11 +1,11 @@ +import { ActionValue, EditableValue } from "mendix"; +import { observer } from "mobx-react-lite"; +import { CSSProperties, ReactElement, useEffect } from "react"; import { useOnScrollBottom } from "@mendix/widget-plugin-hooks/useOnScrollBottom"; import { GateProvider } from "@mendix/widget-plugin-mobx-kit/GateProvider"; import { DerivedPropsGate } from "@mendix/widget-plugin-mobx-kit/main"; import { useConst } from "@mendix/widget-plugin-mobx-kit/react/useConst"; import { useSetup } from "@mendix/widget-plugin-mobx-kit/react/useSetup"; -import { ActionValue, EditableValue } from "mendix"; -import { observer } from "mobx-react-lite"; -import { CSSProperties, ReactElement, useEffect } from "react"; import { RefComboboxController } from "../controllers/RefComboboxController"; import { RefSelectController } from "../controllers/RefSelectController"; import { RefTagPickerController } from "../controllers/RefTagPickerController"; @@ -94,6 +94,7 @@ const ComboboxWidget = observer(function ComboboxWidget(props: RefFilterContaine onClear={ctrl2.handleClear} onFocus={ctrl2.handleFocus} onBlur={ctrl2.handleBlur} + onChange={ctrl2.handleChange} onMenuScroll={handleMenuScroll} empty={ctrl2.isEmpty} className={props.className} @@ -118,6 +119,7 @@ const TagPickerWidget = observer(function TagPickerWidget(props: RefFilterContai onClear={ctrl3.handleClear} onBlur={ctrl3.handleBlur} onFocus={ctrl3.handleFocus} + onChange={ctrl3.handleChange} onMenuScroll={handleMenuScroll} inputPlaceholder={ctrl3.inputPlaceholder} emptyCaption={ctrl3.emptyCaption} diff --git a/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/ComboboxControllerMixin.ts b/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/ComboboxControllerMixin.ts index c108223be4..ae7c6c4adc 100644 --- a/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/ComboboxControllerMixin.ts +++ b/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/ComboboxControllerMixin.ts @@ -1,7 +1,7 @@ -import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch"; import { useCombobox, UseComboboxProps } from "downshift"; import { action, autorun, computed, makeObservable, observable, reaction } from "mobx"; -import { FocusEvent } from "react"; +import { ChangeEvent, FocusEvent } from "react"; +import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch"; import { SearchStore } from "../../stores/SearchStore"; import { OptionWithState } from "../../typings/OptionWithState"; import { GConstructor } from "../../typings/type-utils"; @@ -43,7 +43,8 @@ export function ComboboxControllerMixin(Base: TBas isEmpty: computed, options: computed, handleBlur: action, - handleClear: action + handleClear: action, + handleChange: action }); } @@ -134,6 +135,11 @@ export function ComboboxControllerMixin(Base: TBas this.filterStore.clear(); }; + handleChange = (event: ChangeEvent): void => { + this.setTouched(true); + this.setInputValue(event.target.value); + }; + useComboboxProps = (): UseComboboxProps => { const props: UseComboboxProps = { items: this.filterStore.options, @@ -141,19 +147,14 @@ export function ComboboxControllerMixin(Base: TBas itemToString: item => item?.caption ?? "", inputValue: this.inputValue, defaultHighlightedIndex: this.selectedIndex, - onInputValueChange: changes => { - // Blur is handled by handleBlur; + onStateChange: changes => { if (changes.type === useCombobox.stateChangeTypes.InputBlur) { + // Blur is handled by handleBlur; return; } if (changes.type === useCombobox.stateChangeTypes.InputKeyDownEscape) { this.handleClear(); - return; - } - if (changes.type === useCombobox.stateChangeTypes.InputChange) { - this.setTouched(true); } - this.setInputValue(changes.inputValue); }, onSelectedItemChange: ({ selectedItem, type }) => { if ( diff --git a/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/TagPickerControllerMixin.ts b/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/TagPickerControllerMixin.ts index c644ead731..713a4723ec 100644 --- a/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/TagPickerControllerMixin.ts +++ b/packages/shared/widget-plugin-dropdown-filter/src/controllers/mixins/TagPickerControllerMixin.ts @@ -1,6 +1,7 @@ -import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch"; import { useCombobox, UseComboboxProps, useMultipleSelection, UseMultipleSelectionProps } from "downshift"; import { action, autorun, computed, makeObservable, observable } from "mobx"; +import { ChangeEvent } from "react"; +import { disposeBatch } from "@mendix/widget-plugin-mobx-kit/disposeBatch"; import { SearchStore } from "../../stores/SearchStore"; import { OptionWithState } from "../../typings/OptionWithState"; import { GConstructor } from "../../typings/type-utils"; @@ -43,6 +44,7 @@ export function TagPickerControllerMixin(Base: TBa selectedOptions: computed, handleBlur: action, handleClear: action, + handleChange: action, isEmpty: computed, options: computed }); @@ -106,6 +108,11 @@ export function TagPickerControllerMixin(Base: TBa this.filterStore.clear(); }; + handleChange = (event: ChangeEvent): void => { + this.setTouched(true); + this.setInputValue(event.target.value); + }; + useComboboxProps = (): UseComboboxProps => { const props: UseComboboxProps = { items: this.options, @@ -113,15 +120,14 @@ export function TagPickerControllerMixin(Base: TBa itemToString: item => item?.caption ?? "", inputValue: this.inputValue, defaultHighlightedIndex: this.selectedIndex, - onInputValueChange: changes => { - // Blur is handled by handleBlur; + onStateChange: changes => { if (changes.type === useCombobox.stateChangeTypes.InputBlur) { + // Blur is handled by handleBlur; return; } - if (changes.type === useCombobox.stateChangeTypes.InputChange) { - this.setTouched(true); + if (changes.type === useCombobox.stateChangeTypes.InputKeyDownEscape) { + this.handleClear(); } - this.setInputValue(changes.inputValue); }, onSelectedItemChange: ({ selectedItem, type }) => { if ( diff --git a/packages/shared/widget-plugin-dropdown-filter/src/controls/combobox/Combobox.tsx b/packages/shared/widget-plugin-dropdown-filter/src/controls/combobox/Combobox.tsx index 1095a89501..d0b6b2af5e 100644 --- a/packages/shared/widget-plugin-dropdown-filter/src/controls/combobox/Combobox.tsx +++ b/packages/shared/widget-plugin-dropdown-filter/src/controls/combobox/Combobox.tsx @@ -1,7 +1,7 @@ import cn from "classnames"; import { useCombobox, UseComboboxProps } from "downshift"; import { observer } from "mobx-react-lite"; -import { CSSProperties, FocusEventHandler, UIEventHandler, useRef } from "react"; +import { ChangeEventHandler, CSSProperties, FocusEventHandler, UIEventHandler, useRef } from "react"; import { OptionWithState } from "../../typings/OptionWithState"; import { ClearButton } from "../base/ClearButton"; import { OptionsWrapper } from "../base/OptionsWrapper"; @@ -20,6 +20,7 @@ interface ComboboxProps { onClear: () => void; onBlur: FocusEventHandler; onFocus: FocusEventHandler; + onChange: ChangeEventHandler; onMenuScroll?: UIEventHandler; } @@ -48,6 +49,7 @@ export const Combobox = observer(function Combobox(props: ComboboxProps) { ref: inputRef, onBlur: props.onBlur, onFocus: props.onFocus, + onChange: props.onChange, placeholder: props.empty ? (isOpen ? props.inputPlaceholder : props.emptyCaption) : undefined })} /> diff --git a/packages/shared/widget-plugin-dropdown-filter/src/controls/tag-picker/TagPicker.tsx b/packages/shared/widget-plugin-dropdown-filter/src/controls/tag-picker/TagPicker.tsx index 94315d8868..1332dee090 100644 --- a/packages/shared/widget-plugin-dropdown-filter/src/controls/tag-picker/TagPicker.tsx +++ b/packages/shared/widget-plugin-dropdown-filter/src/controls/tag-picker/TagPicker.tsx @@ -1,7 +1,15 @@ import cn from "classnames"; import { useCombobox, UseComboboxProps, useMultipleSelection, UseMultipleSelectionProps } from "downshift"; import { observer } from "mobx-react-lite"; -import { CSSProperties, FocusEventHandler, ReactElement, UIEventHandler, useId, useRef } from "react"; +import { + ChangeEventHandler, + CSSProperties, + FocusEventHandler, + ReactElement, + UIEventHandler, + useId, + useRef +} from "react"; import { OptionWithState } from "../../typings/OptionWithState"; import { ClearButton } from "../base/ClearButton"; import { OptionsWrapper } from "../base/OptionsWrapper"; @@ -24,6 +32,7 @@ interface TagPickerProps { onClear: () => void; onBlur: () => void; onFocus?: FocusEventHandler; + onChange: ChangeEventHandler; onMenuScroll?: UIEventHandler; } @@ -102,6 +111,7 @@ export const TagPicker = observer(function TagPicker(props: TagPickerProps): Rea "aria-label": inputLabel || "filter", onBlur: props.onBlur, onFocus: props.onFocus, + onChange: props.onChange, placeholder: props.empty ? (isOpen ? props.inputPlaceholder : props.emptyCaption) : undefined, ...getDropdownProps(), "aria-describedby": props.empty ? undefined : `${helperText1} ${inputContainerId}`