본문으로 건너뛰기

콤보박스

찾아서 고르는 칸입니다. 칸은 입력칸과 같은 파인 칸이고, 열린 목록은 선택 목록과 같은 뜸 판(층 60)입니다. 하나 · 여럿(칩) · 새 값 만들기 · 서버 검색을 한 부품이 맡습니다.

import
import { Combobox } from "@uyoolabs/ui/form";
쓰는 경우
고를 것이 많거나(20개 넘음) 서버에서 찾을 때 씁니다. 담당 · 참석자(여럿), 라벨(만들기), 알릴 채널(하나), 멤버 초대(빈 결과 → 이메일로 초대), 표 거르기 칩의 값 편집이 그렇습니다. 7~20개이고 찾을 일이 없으면 선택 목록(Select)입니다.
쓰지 않는 경우
자유 입력 칸 대신 쓰지 않습니다(목록에 없는 값을 넣지 못합니다. 새 값이 필요하면 creatable 을 켭니다). 하이라이트에 주 색(파랑)이나 굵기만 쓰지 않습니다(고른 항목의 600 과 헷갈립니다). 칩을 한 줄에 억지로 넣고 가로로 굴리지 않습니다(줄을 바꾸고, 떠나면 +N 으로 접습니다).
빈 결과
빈 결과에는 다음 할 일(초대 · 만들기 · 거르기 풀기)을 같이 둡니다. 무엇을 찾는지(멤버 · 라벨)는 labels.empty · labels.create 로 덮어 씁니다.
사람
아바타 + 이름 + 팀으로 보입니다. 같은 이름이 있으면 팀 · 이메일로 가립니다. 고를 수 없는 사람은 목록에서 빼지 않고 비활성 + 설명 줄로 이유를 적습니다.

하나 고르기

고른 값은 칸 안의 글자로 보입니다(앞에 아바타 · 아이콘). 키보드로 옮긴 항목은 파인 면 + 안쪽 링, 손을 올린 항목은 면만입니다.

고른 값: 김서연

여럿 — 칩

Enter 로 넣고 빼며 목록은 열려 있습니다. 빈 칸의 Backspace 는 마지막 칩을 먼저 고르고(링), 한 번 더 누르면 뺍니다.

한서윤서지우
한서윤서지우김서연이도현박지민최유나최도윤

만들기 · 빈 결과

결제

서버 검색

‘실패’ 를 치면 오류 줄과 다시 시도가 보입니다.

찾은 말 강조(Highlight)

거르기와 하이라이트가 같은 함수(match)에서 나와 거른 항목에는 늘 칠한 곳이 있습니다. 칠한 범위는 원문 위치라 NFD 한글 · 전각 글자 · 길이가 바뀌는 글자(İ)에서도 어긋나지 않습니다. 명령 팔레트 · 검색 결과 · 표 찾기가 같이 씁니다.

  • 환불 정책 v2 — 부분 환불 수수료
  • 새 대화 시작
  • 김서연 · 플랫폼팀
  • カナ入力の設定

키보드

APG Editable Combobox With List Autocomplete 입니다. 포커스는 늘 칸에 있고 활성 항목은 aria-activedescendant 로 가리킵니다. 항목은 Tab 정지점이 아닙니다.

자리키동작
칸↓열기 · 다음(끝에서 처음으로). 비활성 항목은 건너뜁니다
칸↑이전(처음에서 끝으로)
칸Alt + ↓활성 없이 엽니다
칸Enter활성 항목을 고릅니다. 한 · 일 조합 중이면 글자 확정만 합니다(isComposing 가드)
칸Esc닫습니다. 닫혀 있으면 검색 글자를 지웁니다. 조합 중이면 조합만 취소하고 목록은 그대로입니다
칸Tab고르지 않고 닫힙니다. 여럿이면 검색 글자를 비웁니다. 빈 결과의 다음 할 일이 있으면 그리로 갑니다
칸Home · End글자 커서입니다(목록이 아닙니다)
칸(여럿)Backspace빈 칸에서 마지막 칩을 먼저 고르고(링), 한 번 더 누르면 뺍니다
칸(여럿)←커서가 맨 앞이면 칩으로 갑니다. ← → 로 칩 사이, 끝에서 → 로 칸
칩Delete · Backspace그 칩을 뺍니다. 포커스는 다음 칩(없으면 칸)으로 갑니다

결과 수는 입력이 멈추고 500ms 뒤 한 번 읽힙니다(‘결과 5개’). 칩을 넣고 뺄 때는 ‘한서윤 넣음’ · ‘한서윤 뺌’ 이 읽히고, 오류 줄은 role=alert 입니다. 한국어 화면은 초성 검색(ㄱㅅㅇ → 김서연)이 기본이고 일본어 화면은 히라가나 · 가타카나를 같은 글자로 봅니다.

내장 문구

lang(ko · en · ja)으로 고르고 labels 로 일부를 바꿉니다(ADR 0011). 따옴표는 언어마다 다릅니다.

키koenja
open · clear목록 열기 · 모두 지우기Show options · Clear all一覧を開く · すべてクリア
removeChip(name){name} 빼기Remove {name}{name}を削除
more(n)+{n}+{n}+{n}
empty(q)‘{q}’에 맞는 항목이 없습니다.No results match ‘{q}’.「{q}」に一致する項目はありません。
noItems고를 항목이 없습니다.No options.選べる項目がありません。
create(q)‘{q}’ 만들기Create ‘{q}’「{q}」を作成
searching더 찾는 중Searching…検索中…
error · retry불러오지 못했습니다. · 다시 시도Couldn’t load results. · Try again読み込めませんでした。 · 再試行
results(n)결과 {n}개{n} results{n}件
added · removed{name} 넣음 · {name} 뺌Added {name} · Removed {name}{name}を追加 · {name}を削除
hint*이동 · 고르기 · 닫기 · 넣기 · 빼기 · 마지막 칩 · 칩으로to move · to select · to close · add/remove · last chip · to chips移動 · 選択 · 閉じる · 追加・削除 · 最後のチップ · チップへ

props

소스의 타입과 JSDoc 에서 생성한 표입니다. 컴포넌트를 고치면 pnpm gen 으로 다시 만듭니다.

Combobox

prop타입기본값설명
itemsreadonly T[]—고정 목록. 서버에서 찾으면 onSearch(둘 중 하나)
onSearch(query: string, signal: AbortSignal) => Promise<T[]>—서버 검색. 입력이 멈추고 200ms 뒤 부른다. 앞 요청은 signal 로 끊고, 늦게 온 앞 응답은 버린다(마지막 응답만). 결과는 거르지 않고 그대로 보이며 맞은 글자만 칠한다. 거절되면 목록 안 오류 줄 + 다시 시도
getLabel필수(item: T) => string—
getKey필수(item: T) => string—
renderItem(item: T, state: { query: string; selected: boolean; active: boolean }) => ReactNode—항목 그리기. 기본은 아이콘(getIcon) + 이름(하이라이트) + 설명
getDescription(item: T) => ReactNode—둘째 줄(팀 · 이메일). 비활성 이유도 여기에 쓴다. 항목의 접근성 이름에 이어 붙는다
getIcon(item: T) => ReactNode—이름 앞 아이콘 · 아바타. 항목 · 칩 · 하나 고른 값 앞에 함께 보인다(크기는 자리마다 CSS 가 맞춘다)
isDisabled(item: T) => boolean—
groupBy(item: T) => string—그룹 머리. 처음 나온 순서대로 묶는다
creatableboolean—친 글과 같은 이름이 없으면 마지막 줄에 ‘{query}’ 만들기
onCreate(query: string) => T | Promise<T>—만든 값이 곧 고른 값이 된다
emptyActionReactNode—빈 결과 아래 다음 할 일(‘이메일로 초대’). Tab 으로 닿는다
placeholderstring—
loadingboolean—끝 스피너 + 목록 끝 ‘더 찾는 중’(300ms 뒤에 보인다). onSearch 를 쓰면 스스로 켠다
errorstring | null—목록 안 오류 줄(role=alert) + ‘다시 시도’
onRetry() => void—다시 시도. 없으면 onSearch 를 다시 부른다
matchOptionsMatchOptions—거르기 · 하이라이트 정규화. 기본: 한국어면 초성 검색, 일본어면 가나 접기
defaultInputValuestring—처음 칸에 든 검색 글자(비제어)
namestring—폼 값. 고른 값의 getKey 를 hidden input 으로 낸다(여럿이면 같은 name 여러 개)
requiredboolean—
disabledboolean—
readOnlyboolean—평평한 칩 · 값만 보이고 끝 단추가 없다. 목록이 열리지 않는다
invalidboolean—오류 경계. aria-invalid 를 단다. 오류 문장은 Field 가 맡는다
openboolean—
defaultOpenboolean—
onOpenChange(open: boolean) => void—
hintsboolean—목록 바닥의 키 안내(기본 true)
lang"ko" | "en" | "ja"—
labelsPartial<ComboboxLabels>—
idstring—칸(input) id. Field 의 control props 를 펼치면 들어온다
aria-describedbystring—
aria-invalidboolean—
aria-requiredboolean—
aria-labelstring—
aria-labelledbystring—
classNamestring—
multiplefalse | true—
valueT | null | readonly T[]—
defaultValueT | null | readonly T[]—
onValueChange(value: T | null) => void | (value: T[]) => void—
collapseChipsboolean—포커스가 떠나면 두 줄을 넘는 칩을 +N 으로 접는다

Highlight

prop타입기본값설명
text필수string—원문
query필수string—친 글. 비었으면 원문 그대로
optionsMatchOptions—거르기와 같은 정규화 선택(가나 접기 · 공백 · 초성). 목록을 거른 옵션과 같은 것을 넘긴다