Files
gunshiz 6d0feb11ca
CI / Verify (push) Successful in 1m45s
CI / Build immutable images and deploy (push) Successful in 2m26s
feat : update
2026-10-07 19:01:45 +07:00

56 lines
2.1 KiB
TypeScript

"use client";
import { useRef, useState, type ComponentProps } from "react";
import { XIcon } from "lucide-react";
import { Input } from "@/components/ui/input";
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "@/components/ui/input-group";
export function ClearableInput({ className, ...props }: ComponentProps<typeof Input>) {
const editableText = ["text", "search", "email", "url", "tel"].includes(props.type ?? "text");
if (!editableText) return <Input className={className} {...props} />;
return <InputGroup className={className}><ClearableInputGroupInput {...props} /></InputGroup>;
}
export function ClearableInputGroupInput({ ref, onChange, onValueChange, ...props }: ComponentProps<typeof Input>) {
const inputRef = useRef<HTMLInputElement | null>(null);
const [uncontrolledValue, setUncontrolledValue] = useState(props.defaultValue ?? "");
const value = props.value ?? uncontrolledValue;
return (
<>
<InputGroupInput
{...props}
ref={(node) => {
inputRef.current = node;
if (typeof ref === "function") return ref(node);
if (ref) ref.current = node;
}}
onChange={(event) => {
setUncontrolledValue(event.target.value);
onValueChange?.(event.target.value);
onChange?.(event);
}}
/>
{String(value).length > 0 && !props.disabled && !props.readOnly ? (
<InputGroupAddon align="inline-end">
<InputGroupButton
size="icon-xs"
aria-label={`ล้าง${props["aria-label"] ?? props.placeholder ?? "ข้อความ"}`}
onClick={() => {
const input = inputRef.current;
if (!input) return;
// Use the native setter so React receives the same change as typing.
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set?.call(input, "");
input.dispatchEvent(new Event("input", { bubbles: true }));
input.focus();
}}
>
<XIcon />
</InputGroupButton>
</InputGroupAddon>
) : null}
</>
);
}