Files
frontend/apps/wr/app/map/searchBar/SearchInputText.tsx
T
2025-08-06 17:06:24 +09:00

123 lines
3.3 KiB
TypeScript

// SearchInputText.tsx
"use client";
import { Input } from "@common/components/ui";
import { useEffect, useRef, useState } from "react";
interface SearchInputTextProps {
initValue?: string;
setValue: (val: string) => void;
setRtnData: (val: { fnm: string; fid: string }) => void;
searchList: { fnm: string; fid: string }[];
onEnter?: () => void;
className?: string;
}
export default function SearchInputText({
initValue,
setValue,
setRtnData,
searchList,
onEnter,
className,
}: SearchInputTextProps) {
const [showResults, setShowResults] = useState(false);
const [text, setText] = useState(initValue ?? "");
const [highlightIndex, setHighlightIndex] = useState(-1);
const wrapperRef = useRef(null);
useEffect(() => {
setText(initValue ?? "");
}, [initValue]);
useEffect(() => {
if (searchList.length > 0) {
setShowResults(true);
} else {
setShowResults(false);
}
setHighlightIndex(-1);
}, [searchList]);
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (
wrapperRef.current &&
!(wrapperRef.current as any).contains(event.target)
) {
setShowResults(false);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [wrapperRef]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setText(e.target.value);
setValue(e.target.value);
setHighlightIndex(-1);
};
const handleSelect = (item: { fnm: string; fid: string }) => {
setText(item.fnm);
setValue(item.fnm);
setRtnData(item);
setShowResults(false);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
if (highlightIndex >= 0 && highlightIndex < searchList.length) {
const selected = searchList[highlightIndex];
if (selected) handleSelect(selected);
} else if (onEnter) {
onEnter();
}
} else if (e.key === "ArrowDown") {
e.preventDefault();
setHighlightIndex((prev) =>
prev < searchList.length - 1 ? prev + 1 : prev
);
} else if (e.key === "ArrowUp") {
e.preventDefault();
setHighlightIndex((prev) => (prev > 0 ? prev - 1 : -1));
}
};
return (
<div className="relative" ref={wrapperRef}>
<Input
value={text}
onChange={handleChange}
onKeyDown={handleKeyDown}
placeholder="시설명을 입력하세요"
className={
className + " rounded-lg border px-2 py-1 text-sm h-[29.5px]"
}
/>
{showResults && (
<div className="absolute z-10 mt-1 max-h-200 w-full overflow-auto rounded border bg-white shadow">
{searchList.length > 0 ? (
searchList.map((item, index) => (
<div
key={index}
className={`cursor-pointer px-3 py-1 hover:bg-gray-100 ${
highlightIndex === index ? "bg-blue-100" : ""
}`}
onClick={() => handleSelect(item)}
>
{item.fnm}
</div>
))
) : (
<div className="px-3 py-2 text-sm text-gray-500">
검색 결과가 없습니다.
</div>
)}
</div>
)}
</div>
);
}