Skip to content

Commit 900bf2c

Browse files
Refactor to use React state management instead of DOM manipulation
Co-authored-by: HenriqueLimas <2222191+HenriqueLimas@users.noreply.github.com>
1 parent 7d93094 commit 900bf2c

File tree

1 file changed

+44
-23
lines changed

1 file changed

+44
-23
lines changed

packages/ebayui-core-react/src/ebay-filter-input/filter-input.tsx

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import classnames from "classnames";
3-
import React, { FC, useRef } from "react";
3+
import React, { FC, useRef, useState } from "react";
44
import { EbayTextbox, EbayTextboxPrefixIcon, EbayTextboxPostfixIcon, type EbayTextboxProps } from "../ebay-textbox";
55
import { EbayIconSearch16 } from "../ebay-icon/icons/ebay-icon-search-16";
66
import { 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

Comments
 (0)