11/* eslint-disable @typescript-eslint/no-explicit-any */
22import classnames from "classnames" ;
3- import React , { FC , useRef } from "react" ;
3+ import React , { FC , useRef , useState } from "react" ;
44import { EbayTextbox , EbayTextboxPrefixIcon , EbayTextboxPostfixIcon , type EbayTextboxProps } from "../ebay-textbox" ;
55import { EbayIconSearch16 } from "../ebay-icon/icons/ebay-icon-search-16" ;
66import { EbayIconClear16 } from "../ebay-icon/icons/ebay-icon-clear-16" ;
@@ -26,42 +26,61 @@ const EbayFilterInput: FC<EbayFilterInputProps> = ({
2626 onClear = ( ) => { } ,
2727 className,
2828 placeholder = "Filter" ,
29+ value : controlledValue ,
30+ defaultValue,
31+ onInputChange,
2932 ...rest
3033} ) => {
3134 const inputRef = useRef < HTMLInputElement > ( null ) ;
35+ const isControlled = controlledValue !== undefined ;
36+
37+ // Always manage internal state, even in controlled mode (for clear functionality)
38+ const [ internalValue , setInternalValue ] = useState ( defaultValue || "" ) ;
39+
40+ // Use controlled value if provided, otherwise use internal state
41+ const value = isControlled ? controlledValue : internalValue ;
3242
3343 // Map filter-input sizes to textbox sizes
3444 // filter-input "small" -> textbox "default", filter-input "large" -> textbox "large"
3545 const textboxSize : TextboxSize | undefined = inputSize && validSizes . includes ( inputSize )
3646 ? ( inputSize === "small" ? "default" : "large" )
3747 : undefined ;
3848
49+ const handleInputChange : EbayChangeEventHandler < HTMLInputElement , { value : string } > = ( event , { value : newValue } ) => {
50+ // Always update internal state for uncontrolled mode
51+ if ( ! isControlled ) {
52+ setInternalValue ( newValue ) ;
53+ }
54+
55+ // Call parent's onInputChange if provided
56+ if ( onInputChange ) {
57+ onInputChange ( event , { value : newValue } ) ;
58+ }
59+ } ;
60+
3961 const handleButtonClick = ( event : any ) => {
40- // Get the input element - either from ref or by finding it in the DOM
41- const inputElement = inputRef . current ||
42- ( event . target as HTMLElement ) . closest ( '.textbox' ) ?. querySelector ( 'input' ) as HTMLInputElement ;
62+ // Get the input element from the event target
63+ const inputElement = ( event . target as HTMLElement ) . closest ( '.textbox' ) ?. querySelector ( 'input' ) as HTMLInputElement ;
4364
44- if ( inputElement ) {
45- // Use React's property setter to update the value properly
46- const nativeInputValueSetter = Object . getOwnPropertyDescriptor ( window . HTMLInputElement . prototype , 'value' ) ?. set ;
47- if ( nativeInputValueSetter ) {
48- nativeInputValueSetter . call ( inputElement , '' ) ;
49-
50- // Dispatch input event to trigger React's onChange handlers
51- // This works for both controlled and uncontrolled components
52- const inputEvent = new Event ( 'input' , { bubbles : true } ) ;
53- inputElement . dispatchEvent ( inputEvent ) ;
54- }
55-
56- // Create synthetic event for the clear callback
57- const syntheticEvent = {
58- ...event ,
59- target : inputElement ,
60- currentTarget : inputElement ,
61- } as unknown as React . ChangeEvent < HTMLInputElement > ;
65+ // Create synthetic event for the clear action
66+ const syntheticEvent = {
67+ ...event ,
68+ target : inputElement || inputRef . current ,
69+ currentTarget : inputElement || inputRef . current ,
70+ } as unknown as React . ChangeEvent < HTMLInputElement > ;
6271
63- onClear ( syntheticEvent , { value : "" } ) ;
72+ // Update internal state for uncontrolled mode
73+ if ( ! isControlled ) {
74+ setInternalValue ( "" ) ;
6475 }
76+
77+ // Call onInputChange to notify parent of the change
78+ if ( onInputChange ) {
79+ onInputChange ( syntheticEvent , { value : "" } ) ;
80+ }
81+
82+ // Call onClear callback
83+ onClear ( syntheticEvent , { value : "" } ) ;
6584 } ;
6685
6786 const containerClassName = classnames (
@@ -75,6 +94,8 @@ const EbayFilterInput: FC<EbayFilterInputProps> = ({
7594 < EbayTextbox
7695 { ...rest }
7796 forwardedRef = { inputRef }
97+ value = { value }
98+ onInputChange = { handleInputChange }
7899 fluid
79100 type = "search"
80101 aria-controls = { a11yControlsId }
0 commit comments