feat(form): Add clearable functionality to Select component

This commit introduces a new `clearable` prop to the `Select` component, allowing users to easily reset its value.

When the `clearable` prop is set to true, a clear button (an 'X' icon) is displayed when an option is selected. Clicking this button resets the select input to its initial placeholder state and triggers an optional `onClear` callback.

To support this, the component's internal state management was refactored to control the input's value.

Additionally, the `AdminListFilters` component has been updated to:
- Utilize the new clearable select for the status filter.
- Consolidate multiple search fields (email, username, full_name) into a single generic "search" input.
- Add explicit "Reset" and "Apply" buttons for better filter management.
This commit is contained in:
AmirReza Jamali
2025-10-13 12:26:56 +03:30
parent 5b73389d64
commit f84c21f829
8 changed files with 257 additions and 116 deletions
+38 -1
View File
@@ -22,6 +22,8 @@ type PropsType<T extends FieldValues> = {
register?: UseFormRegister<T>;
errors?: FieldErrors<T>;
required?: boolean;
clearable?: boolean;
onClear?: () => void;
} & (
| { placeholder?: string; defaultValue: string }
| { placeholder: string; defaultValue?: string }
@@ -42,13 +44,22 @@ export function Select<T extends FieldValues>({
onChange,
onBlur,
ref,
clearable = false,
onClear,
...props
}: PropsType<T>) {
const id = useId();
const [isOptionSelected, setIsOptionSelected] = useState(!!defaultValue);
const [value, setValue] = useState(defaultValue || "");
const error = errors && errors[name];
const handleClear = () => {
setValue("");
setIsOptionSelected(false);
onClear?.();
};
return (
<div className={cn("space-y-3", className)}>
<label
@@ -70,8 +81,9 @@ export function Select<T extends FieldValues>({
id={id}
name={name}
ref={ref}
defaultValue={defaultValue || ""}
value={value}
onChange={(e) => {
setValue(e.target.value);
setIsOptionSelected(!!e.target.value);
onChange?.(e);
}}
@@ -81,6 +93,7 @@ export function Select<T extends FieldValues>({
isOptionSelected && "text-dark dark:text-white",
error && "border-red focus:border-red dark:border-red",
prefixIcon && "pl-11.5",
clearable && value && "pr-20",
)}
>
{placeholder && (
@@ -96,6 +109,30 @@ export function Select<T extends FieldValues>({
))}
</select>
{clearable && value && (
<button
type="button"
onClick={handleClear}
className="absolute right-10 top-1/2 -translate-y-1/2 text-dark-5 hover:text-dark dark:text-dark-6 dark:hover:text-white"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 4L4 12M4 4L12 12"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</button>
)}
<ChevronUpIcon className="pointer-events-none absolute right-4 top-1/2 -translate-y-1/2 rotate-180" />
</div>