Skip to Content

Lookup

기존에 존재하는 내부 또는 외부 데이터를 선택하기 위해 사용하는 입력 요소


개요

Lookup은 팝업을 통해 데이터를 조회하고 선택할 수 있는 입력 컴포넌트입니다. Foundation Lookup을 FormItem으로 감싸 레이블, 설명, 에러 메시지를 통합 제공합니다.

주요 특징

  • 기본 상태: 데이터 선택을 위한 입력 요소 제공
  • 필수값 표시: Label 좌측에 * 표시
  • 포커스 상태: 포커스 시 시각적으로 구분되는 스타일
  • 읽기 전용 상태: 읽기 전용(readOnly) 시각적 구분
  • 오류 상태 표시: error prop으로 에러 메시지와 스타일 자동 적용
  • 레이블 제공: label, labelWidth, orientation으로 레이블 배치
  • 디자인 토큰: 테마 커스터마이징 지원

Sizes


사용 예시

기본 상태

기존에 존재하는 내부 또는 외부 데이터를 선택하기 위해 사용하는 입력 요소를 제공합니다.

필수값 표시

필수 입력 항목은 Label 좌측에 *(Asterisk)를 표시합니다.

포커스 상태

포커스 시 시각적으로 구분되는 스타일을 제공합니다.

읽기 전용 상태

읽기 전용(readOnly) 상태를 시각적으로 구분합니다. 클릭해도 팝업이 열리지 않습니다.

오류 상태 표시

오류 발생 시 error prop으로 에러 메시지를 표시하고, 오류 스타일이 자동 적용됩니다.

레이블 제공

레이블(Label)을 제공하며, orientation으로 배치 방향을 설정합니다.

데이터 조회 팝업에서 사용자를 선택합니다

프로젝트팀 구현 항목: 아래 기능은 프로젝트 요구사항에 맞춰 직접 구현합니다.

  • 팝업 호출: Lookup 버튼 클릭 시 데이터 조회 팝업 화면 표시
  • 선택 결과 반영: 팝업에서 데이터 선택 시 팝업 닫힘 및 선택 데이터 반영
  • Select/Cancel/Clear 버튼: 팝업 내 선택, 취소, 초기화 버튼 제공
  • 단일 행 선택: 데이터(Row) 클릭 시 단일 항목만 선택
  • 입력 방식 제한: 팝업에서만 값 선택 가능
  • 데이터 소스 연동: 내부/외부 API 데이터 조회
  • 입력 가능 제어: 읽기 전용 상태에서 선택 및 변경 제한

API Reference

Props

PropTypeDefaultDescription
size"xs" | "sm" | "md" | "lg" | "xl""md"크기
valueT | null-선택된 값
displayValuestring-표시할 텍스트
placeholderstring"선택하세요"플레이스홀더 텍스트
disabledbooleanfalse비활성화 여부
readOnlybooleanfalse읽기 전용 여부
widthstring | number-너비
modalOptionsLookupModalOptions-팝업 모달 옵션
labelstring-필드 레이블
labelWidthnumber-레이블 너비
labelAlign"start" | "center" | "end"-레이블 가로 정렬
labelVerticalAlign"start" | "center" | "end"-레이블 세로 정렬
requiredbooleanfalse필수 여부 (Label에 * 표시)
orientation"horizontal" | "vertical""horizontal"레이블-필드 배치 방향
descriptionstring-설명 텍스트
errorstring-에러 메시지
classNamestring-래퍼에 적용할 추가 CSS 클래스
renderContent(props: LookupRenderProps<T>) => ReactNode필수팝업 콘텐츠 렌더 함수

Events

EventTypeDescription
onValueChange(value: T | null) => void값 변경 시 호출

LookupModalOptions

PropTypeDefaultDescription
titleReactNode-팝업 타이틀
descriptionReactNode-팝업 설명
classNamestring-팝업 추가 CSS 클래스
type"center" | "bottomsheet" | "fullscreen" | "sidepanel"-팝업 유형
dimboolean-배경 딤 처리 여부
allowInteractionboolean-딤 상태에서 뒤쪽 조작 허용
resizableboolean-팝업 리사이즈 가능 여부
showCloseButtonboolean-닫기 버튼 표시 여부
draggableboolean-팝업 드래그 가능 여부
footerAlign"left" | "center" | "right"-푸터 정렬
dedupeKeystring-동일 lookup 중복 방지용 식별자 (자세한 내용은 아래 참고)

미지정 시 DialogProvider의 전역 config 기본값이 적용됩니다.

LookupRenderProps

PropTypeDescription
select(value: T) => void값 선택 (팝업 닫힘)
cancel() => void선택 취소 (팝업 닫힘)
clear() => void값 초기화 (팝업 닫힘)

기본 사용법

import { Lookup } from "@vortex/ui-icignal" <Lookup label="사용자" labelWidth={100} required value={selectedUser} displayValue={selectedUser?.name} onValueChange={setSelectedUser} placeholder="사용자 선택" modalOptions={{ title: "사용자 조회" }} renderContent={({ select, cancel, clear }) => ( <div> {users.map((user) => ( <div key={user.id} onClick={() => select(user)}>{user.name}</div> ))} </div> )} />

모달 옵션 활용

<Lookup label="사용자" labelWidth={100} value={selectedUser} displayValue={selectedUser?.name} onValueChange={setSelectedUser} placeholder="사용자 선택" modalOptions={{ title: "사용자 조회", dim: false, allowInteraction: true, resizable: true, type: "center", }} renderContent={({ select, cancel, clear }) => ( <div> {users.map((user) => ( <div key={user.id} onClick={() => select(user)}>{user.name}</div> ))} </div> )} />

중복 모달 방지 (dedupeKey)

Lookup 컴포넌트는 내부에서 인스턴스별 자동 dedupeKey 를 부여하여 같은 인스턴스에서 빠른 더블클릭으로 모달이 두 번 열리지 않도록 자동 차단합니다. (사용자가 별도 설정을 하지 않아도 동작합니다.)

다음과 같은 경우에는 호출자가 명시적으로 modalOptions.dedupeKey 를 지정해야 cross-instance 중복까지 차단할 수 있습니다.

  • 여러 트리거(다른 인스턴스 / 외부 버튼 / 단축키 등)에서 의미상 같은 lookup을 호출하는 경우
  • useDialog().lookup(...) 을 직접 호출하는 경우
  • dim: false, allowInteraction: true 로 배경 조작이 허용된 상태

modalOptions.dedupeKey (또는 useDialog().lookup({ dedupeKey })) 를 지정하면 동일 key 의 lookup이 이미 열려있을 때 새 모달을 띄우지 않고 즉시 Promise<null> 로 resolve 합니다. 사용자가 명시한 dedupeKey 가 있으면 자동 인스턴스 키 대신 명시값이 사용됩니다. 이미 열린 lookup은 그대로 유지되며, 자체 select/cancel 로만 닫힙니다.

<Lookup label="사용자" labelWidth={100} value={selectedUser} displayValue={selectedUser?.name} onValueChange={setSelectedUser} placeholder="사용자 선택" modalOptions={{ title: "사용자 조회", dim: false, allowInteraction: true, dedupeKey: "user-pick", }} renderContent={({ select, cancel }) => (...)} />

또는 store 를 직접 호출하는 경우:

const user = await useDialog.getState().lookup<User>({ dedupeKey: "user-pick", title: "사용자 조회", content: ({ select, cancel }) => (...), }) // user === null 인 경우: cancel 되었거나, 이미 동일 dedupeKey 의 lookup 이 열려있어 dedupe 로 차단된 호출

dedupeKey 미지정 호출은 기존과 동일하게 매번 별개 모달이 열립니다.

반환값 동작

케이스store PromiseLookup 컴포넌트의 onValueChange
select(value)valueonValueChange(value)
clear() (Lookup만)내부 CLEAR_SYMBOL 처리onValueChange(null)
cancel()null(호출 안 됨)
dedupeKey 로 차단됨null(호출 안 됨)

주의: dedupeKey 로 차단된 호출은 cancel 과 동일하게 null 로 resolve 됩니다. 호출자는 두 경우를 구분할 수 없습니다. 구분이 필요하면 호출 전에 외부 플래그/ref 로 in-flight 여부를 직접 확인하세요. clear 는 store 의 LookupHandlers 에는 존재하지 않으며, Lookup 컴포넌트가 CLEAR_SYMBOLselect 하는 wrapper 트릭으로 제공합니다.


접근성

키보드 네비게이션

  • Tab: Lookup 필드에 포커스 이동
  • Enter/Click: 조회 팝업 열기

권장 사항

  • label을 제공하여 입력 필드 목적 전달
  • ✅ 에러 시 error prop으로 구체적 안내
  • displayValue로 선택된 값을 명확히 표시
  • ❌ readOnly 상태에서 팝업 호출 방지
  • ❌ placeholder만으로 레이블 대체 지양

관련 컴포넌트

Last updated on