"use client"; import { useState, type FormEvent } from "react"; import { cx } from "../../utils"; import { FoxSelectText } from "../fox-select-text"; import type { FoxSelectItem } from "../fox-select"; export interface FoxListSearchProps { /** 앞쪽 셀렉트에 넣을 검색 대상. 비우면 셀렉트 자체가 나오지 않는다. */ fields?: FoxSelectItem[]; /** 선택된 검색 대상(제어). */ field?: string; onFieldChange?: (field: string) => void; /** 입력값(제어). 주지 않으면 컴포넌트가 스스로 들고 있다. */ keyword?: string; onKeywordChange?: (keyword: string) => void; /** 돋보기를 누르거나 Enter를 쳤을 때. 현재 검색어와 대상을 함께 넘긴다. */ onSearch?: (keyword: string, field?: string) => void; placeholder?: string; /** 글자가 없으므로 이 값이 검색 버튼의 접근성 이름이 된다. */ label?: string; disabled?: boolean; hidden?: boolean; className?: string; } /** * @fox 목록 검색 상자 — 시안: 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) list-toolbar의 search * * 마크업 계약 (React 밖 소비자용): * * * `FoxInput`을 쓰지 않는다 — 시안은 입력칸 **앞쪽**에 검색 대상 셀렉트가 들어가는데 FoxInput에 * 그 슬롯이 없다. 크기·radius·테두리는 시안이 지정한 값이 FoxInput md와 같지만, 좌우 여백만 * `form/padding/sm`으로 더 좁다(안에 셀렉트와 버튼이 들어가기 때문이다). * * `
`이라 Enter가 그대로 제출이 된다 — 키 이벤트를 따로 듣지 않는다. * * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"` * (또는 개별 파티셜)로 한 번 불러와야 한다. */ export function FoxListSearch({ fields, field, onFieldChange, keyword, onKeywordChange, onSearch, placeholder = "검색어를 입력하세요.", label = "검색", disabled = false, hidden = false, className, }: FoxListSearchProps) { const [innerKeyword, setInnerKeyword] = useState(keyword ?? ""); const controlled = keyword !== undefined; const value = controlled ? keyword : innerKeyword; if (hidden) { return null; } function handleChange(next: string) { if (!controlled) { setInnerKeyword(next); } onKeywordChange?.(next); } function handleSubmit(event: FormEvent) { event.preventDefault(); onSearch?.(value, field); } return (
{fields && fields.length > 0 && ( )} handleChange(event.target.value)} /> {/* 시안의 이 버튼은 btn-ico 인스턴스가 아니라 로컬 프레임(32×32)이라 FoxIconButton의 크기 체계(24·28·40·56)와 맞지 않는다. 그래서 직접 그린다. */}