{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "combobox",
  "title": "Combobox",
  "description": "shadcn/ui(new-york-v4) combobox의 유니버설(웹+네이티브 한 벌 소스) 포팅. 제거하고 완성된 popover(열림 상태·앵커 팝업) + command(필터·키보드 선택)를 조합해 재구성했다(엔진 재노출형 — 원본 export 16종을 그대로 유지).",
  "dependencies": [
    "@unikit-bridge/ui"
  ],
  "registryDependencies": [
    "command",
    "popover",
    "utils"
  ],
  "files": [
    {
      "path": "registry/ui/combobox.tsx",
      "content": "// Combobox — shadcn/ui（new-york-v4） combobox.tsx 유니버설 포팅 （사이클 40, T-1e）.\n// 원본: shadcn-ref/ui/combobox.tsx — @base-ui/react 헤드리스 엔진 기반이라 엔진을\n// 제거하고 완성된 popover（열림 상태앵커 팝업） + command（필터키보드 선택）를\n// 조합해 재구성했다（엔진 재노출형 — 원본 export 16종을 그대로 유지）.\n//\n// 포팅 판단（원본 대비 차이이유）:\n// - @base-ui/react 제거: Combobox 루트는 Popover（제어 open 미러링） 안에\n//   Command（카드 토큰 초기화）를 중첩해 렌더한다. Command를 루트에 두면\n//   CommandInput/CommandItem이 루트 어디에 있어도（팝업 밖 인라인Content\n//   내부） 필터와 화살표키엔터 탐색이 연결된다. 두 가지 구성 모두 지원:\n//   base-ui형 <ComboboxInput showTrigger/> 단독 입력창, 전통형\n//   <ComboboxTrigger><ComboboxValue/></ComboboxTrigger> + Content 내부 입력.\n// - 값 상태: 원본 Root의 value/onValueChange（단일）에 values/onValuesChange\n//   （다중）를 별도 prop으로 분리 — base-ui는 multiple 시 value에 배열이 실리는\n//   암묵 오버로드인데 유니버설 타이핑을 위해 명시 분리가 안전하다. multiple\n//   지정 시 항목 선택은 values 토글（팝업 유지）, 미지정 시 확정 후 팝업 닫기.\n//   지우기（Clear/×）의 \"값 없음\" 표현은 onValueChange（\"\"） 관례（radio-group의\n//   \"\" 기본값과 정합）를 쓴다. ComboboxValue도 빈 문자열을 미선택으로 판정해\n//   플레이스홀더를 렌더한다（value != null && value !== \"\"）.\n// - 선택값 표시: 팝업이 닫히면 브리지 Portal이 children을 언마운트해（webnative\n//   동일 계약） 항목이 사라지므로, 라벨 레지스트리는 항목 언마운트 시 삭제하지\n//   않는다（한 번 열린 목록의 value→label은 유지 — 목록이 동적으로 바뀌면 stale\n//   라벨이 남을 수 있는 근사）. 라벨을 못 찾으면 value 문자열 폴백, 정확 표시가\n//   필요하면 ComboboxValue의 children 함수로 매핑한다.\n// - ComboboxInput: input-group 미이식으로 원본 InputGroup 구조（인라인 애드온）를\n//   View + CommandInput + 애드온 행으로 재구성. showTrigger（▾ 토글, 기본 true）\n//   showClear（× 지우기, 기본 false）는 유지. 타이핑 중 자동 개방（base-ui 동작）은\n//   CommandInput이 필터 변경 훅을 노출하지 않아 미지원 — ▾ 트리거로 개방한다.\n// - ComboboxContent: 원본 side/sideOffset/align 기본값（bottom/6/start） 유지.\n//   alignOffsetanchor（앵커 폭 추종 CSS 변수 포함）은 AnchoredOverlay 계약\n//   밖이라 미지원 — 앵커 오버라이드는 popover의 PopoverAnchor를 children에\n//   넣는 조합으로, 팝업 폭은 w-72 고정（원본 w-（--anchor-width） 대체）.\n// - Chips 계열: 다중 선택 칩. ChipRemove는 원본 export 목록에 없어 내부 구현\n//   （× Pressable）하며 ComboboxChip의 showRemove로 노출한다.\n// - 아이콘: CheckIcon·ChevronDownIcon·XIcon — 브리지 lucide 아이콘 프리미티브\n//   （@unikit-bridge/ui/primitives）를 사용한다（dropdown-menu 관행）.\n// - 클래스 근사: 팝업 테두리는 원본（shadcn-ref/ui/combobox.tsx:119）의\n//   ring-1 ring-foreground/10에서 border border-border로 의도적 이탈 — 사유:\n//   select·dropdown·popover와 내부 형제 일관성,\n//   max-h-［calc（--spacing（96））］→web:max-h-96, h-［calc（--spacing（5.5））］→h-5,\n//   focus-within:ring-［3px］→web:focus-within:ring-3（비대괄호 계단 — 사이클 72\n//   원본 규격 정렬）, min-w-［］→\n//   표준 계단, 애니메이션CSS 변수 임의값dark:pointer-coarse: 토큰 제거,\n//   radix data-* 속성은 조건부 클래스로 전개.\n// - 접근성: 트리거 aria-expandedaria-controls와 카드 role=\"dialog\"는 소비하는\n//   PopoverTriggerPopoverContent가, listboxoptionaria-selected는 CommandList\n//   CommandItem이 제공한다. RN 한계（aria 2종 폐기role 무시）는 commandpopover\n//   머리 주석 그대로 승계.\nimport {\n  Children,\n  createContext,\n  forwardRef,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n  type ReactNode,\n} from \"react\";\nimport {\n  CheckIcon,\n  ChevronDownIcon,\n  Pressable,\n  Text,\n  View,\n  XIcon,\n  type BridgePressableRef,\n  type BridgeScrollViewRef,\n  type BridgeTextRef,\n  type BridgeTextInputRef,\n  type BridgeViewRef,\n  type PressableProps,\n  type TextProps,\n  type TextInputProps,\n  type ViewProps,\n} from \"@unikit-bridge/ui/primitives\";\n\nimport {\n  Command,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n  type CommandGroupProps,\n  type CommandListProps,\n} from \"./command\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"./popover\";\nimport type { OverlayAlign, OverlayPlacement } from \"../lib/overlay\";\nimport { cn } from \"@/lib/utils\";\n\n// ---------------------------------------------------------------------------\n// 내부 유틸\n// ---------------------------------------------------------------------------\n\n/** 자식 중 문자열/숫자를 내부 Text로 감싼다 — 네이티브 색 상속 불가 대응\n *  （dropdown-menu 관행과 동일, 요소 자식은 그대로 둔다） */\nfunction wrapTextChildren(children: ReactNode, textClassName: string) {\n  return Children.map(children, (child) =>\n    typeof child === \"string\" || typeof child === \"number\" ? (\n      <Text className={textClassName}>{child}</Text>\n    ) : (\n      child\n    ),\n  );\n}\n\n/** value 미지정 항목의 유도값/라벨 — 최상위 문자열 children 결합（command.tsx 관행） */\nfunction textValueOf(nodes: ReactNode): string {\n  return Children.toArray(nodes)\n    .filter((child): child is string => typeof child === \"string\")\n    .join(\" \")\n    .trim();\n}\n\n/** 웹 <button> 포커스 아웃라인 기본 처리(소비자 클래스 우선 보존) */\nconst TRIGGER_RESET_CLASSES = \"web:outline-none\";\n\n// ---------------------------------------------------------------------------\n// 상태 context — 열림（Popover 미러）값（단일/다중）라벨 레지스트리\n// ---------------------------------------------------------------------------\n\ntype ComboboxContextValue = {\n  multiple: boolean;\n  /** 단일 선택값（미선택 null） */\n  value: string | null;\n  /** 다중 선택값 목록 */\n  values: string[];\n  /** 항목 확정 — 단일은 값 교체+팝업 닫기, 다중은 토글+팝업 유지 */\n  commitItem: (value: string) => void;\n  /** 다중 목록에서 값 제거（칩 × 등） */\n  removeValue: (value: string) => void;\n  /** 선택 전부 지우기（ComboboxClear） */\n  clear: () => void;\n  open: boolean;\n  setOpen: (open: boolean) => void;\n  /** value→label 등록 — 언마운트 시 삭제하지 않는다（포팅 판단 참조） */\n  registerItem: (value: string, label: string) => void;\n  /** 등록된 라벨 맵（읽기 전용 관찰） */\n  labels: Map<string, string>;\n};\n\nconst ComboboxContext = createContext<ComboboxContextValue | null>(null);\n\nfunction useComboboxContext(component: string): ComboboxContextValue {\n  const ctx = useContext(ComboboxContext);\n  if (!ctx) {\n    throw new Error(`<${component}>는 <Combobox> 안에서 사용해야 합니다.`);\n  }\n  return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// 루트\n// ---------------------------------------------------------------------------\n\nexport type ComboboxProps = ViewProps & {\n  /** 단일 선택값（제어） */\n  value?: string;\n  defaultValue?: string;\n  onValueChange?: (value: string) => void;\n  /** 다중 선택값（제어） — multiple 조합 */\n  values?: string[];\n  defaultValues?: string[];\n  onValuesChange?: (values: string[]) => void;\n  /** 다중 선택 모드 — 항목 선택이 values 토글로 동작한다 */\n  multiple?: boolean;\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n};\n\nconst Combobox = forwardRef<BridgeViewRef, ComboboxProps>(\n  (\n    {\n      value,\n      defaultValue,\n      onValueChange,\n      values,\n      defaultValues,\n      onValuesChange,\n      multiple = false,\n      open,\n      defaultOpen,\n      onOpenChange,\n      className,\n      children,\n      ...props\n    },\n    ref,\n  ) => {\n    // 비제어 상태 — 제어（prop 지정）면 무시된다.\n    const [internalValue, setInternalValue] = useState<string | null>(\n      defaultValue ?? null,\n    );\n    const selectedValue = value !== undefined ? value : internalValue;\n    const [internalValues, setInternalValues] = useState<string[]>(\n      defaultValues ?? [],\n    );\n    const selectedValues = values !== undefined ? values : internalValues;\n    const [internalOpen, setInternalOpen] = useState(defaultOpen ?? false);\n    const isOpen = open ?? internalOpen;\n\n    const stateRef = useRef({\n      multiple,\n      value,\n      selectedValue,\n      onValueChange,\n      values,\n      selectedValues,\n      onValuesChange,\n      open,\n      isOpen,\n      onOpenChange,\n    });\n    stateRef.current = {\n      multiple,\n      value,\n      selectedValue,\n      onValueChange,\n      values,\n      selectedValues,\n      onValuesChange,\n      open,\n      isOpen,\n      onOpenChange,\n    };\n\n    // Popover에 제어로 전달해 열림을 미러링 — 항목 확정 시 여기서 닫는다.\n    const setOpen = useCallback((next: boolean) => {\n      const state = stateRef.current;\n      if (state.open === undefined) setInternalOpen(next);\n      if (next !== state.isOpen) state.onOpenChange?.(next);\n    }, []);\n\n    // 라벨 레지스트리 — 등록만 하고 해제하지 않는다（닫힘 상태 표시 유지）.\n    const labelRegistry = useRef(new Map<string, string>());\n    const [, setRegistryVersion] = useState(0);\n    const registerItem = useCallback((itemValue: string, label: string) => {\n      if (labelRegistry.current.get(itemValue) === label) return;\n      labelRegistry.current.set(itemValue, label);\n      setRegistryVersion((version) => version + 1);\n    }, []);\n\n    const commitItem = useCallback(\n      (itemValue: string) => {\n        const state = stateRef.current;\n        if (state.multiple) {\n          const next = state.selectedValues.includes(itemValue)\n            ? state.selectedValues.filter((entry) => entry !== itemValue)\n            : [...state.selectedValues, itemValue];\n          if (state.values === undefined) setInternalValues(next);\n          state.onValuesChange?.(next);\n          return; // 다중 선택은 팝업 유지\n        }\n        if (itemValue !== state.selectedValue) {\n          if (state.value === undefined) setInternalValue(itemValue);\n          state.onValueChange?.(itemValue);\n        }\n        setOpen(false);\n      },\n      [setOpen],\n    );\n\n    const removeValue = useCallback((itemValue: string) => {\n      const state = stateRef.current;\n      if (state.multiple) {\n        if (!state.selectedValues.includes(itemValue)) return;\n        const next = state.selectedValues.filter((entry) => entry !== itemValue);\n        if (state.values === undefined) setInternalValues(next);\n        state.onValuesChange?.(next);\n        return;\n      }\n      if (state.selectedValue !== itemValue) return;\n      if (state.value === undefined) setInternalValue(null);\n      state.onValueChange?.(\"\");\n    }, []);\n\n    const clear = useCallback(() => {\n      const state = stateRef.current;\n      if (state.multiple) {\n        if (state.selectedValues.length === 0) return;\n        if (state.values === undefined) setInternalValues([]);\n        state.onValuesChange?.([]);\n      } else {\n        if (state.selectedValue == null) return;\n        if (state.value === undefined) setInternalValue(null);\n        state.onValueChange?.(\"\");\n      }\n    }, []);\n\n    const contextValue = useMemo<ComboboxContextValue>(\n      () => ({\n        multiple,\n        value: selectedValue,\n        values: selectedValues,\n        commitItem,\n        removeValue,\n        clear,\n        open: isOpen,\n        setOpen,\n        registerItem,\n        labels: labelRegistry.current,\n      }),\n      [\n        multiple,\n        selectedValue,\n        selectedValues,\n        commitItem,\n        removeValue,\n        clear,\n        isOpen,\n        setOpen,\n        registerItem,\n      ],\n    );\n\n    return (\n      <ComboboxContext.Provider value={contextValue}>\n        <Popover open={isOpen} onOpenChange={setOpen}>\n          {/* Command 중첩 — 카드 토큰（bg-popoverroundedoverflow）은 인라인\n              입력...카드 이중 프레임을 만들지 않도록 초기화한다. 필터...키보드\n              탐색 컨텍스트는 그대로 제공된다. */}\n          <Command\n            ref={ref}\n            className={cn(\n              \"h-auto w-auto overflow-visible rounded-none bg-transparent\",\n              className,\n            )}\n            {...props}\n          >\n            {children}\n          </Command>\n        </Popover>\n      </ComboboxContext.Provider>\n    );\n  },\n);\nCombobox.displayName = \"Combobox\";\n\n// ---------------------------------------------------------------------------\n// 트리거 계열\n// ---------------------------------------------------------------------------\n\nexport type ComboboxTriggerProps = PressableProps;\n\nconst ComboboxTrigger = forwardRef<BridgePressableRef, ComboboxTriggerProps>(\n  ({ className, children, ...props }, ref) => (\n    <PopoverTrigger\n      ref={ref}\n      className={cn(\n        \"flex flex-row items-center gap-2\",\n        TRIGGER_RESET_CLASSES,\n        className,\n      )}\n      {...props}\n    >\n      {wrapTextChildren(children, \"font-sans text-sm text-foreground\")}\n      {/* 원본 트리거 아이콘: size-4 text-muted-foreground — opacity-50 없음 */}\n      <ChevronDownIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n    </PopoverTrigger>\n  ),\n);\nComboboxTrigger.displayName = \"ComboboxTrigger\";\n\nexport type ComboboxValueProps = Omit<ViewProps, \"children\"> & {\n  /** 미선택 시 표시（문자열 권장） */\n  placeholder?: ReactNode;\n  /** 문자열이면 선택 라벨 표시, 함수면 （label）을 받아 자유 렌더 — 라벨은\n   *  다중 선택 시 \", \" 결합, 못 찾으면 value 폴백, 미선택이면 null */\n  children?: ReactNode | ((label: string | null) => ReactNode);\n};\n\nconst ComboboxValue = forwardRef<BridgeViewRef, ComboboxValueProps>(\n  ({ className, placeholder, children, ...props }, ref) => {\n    const combobox = useComboboxContext(\"ComboboxValue\");\n    const selected = combobox.multiple\n      ? combobox.values\n      : combobox.value != null && combobox.value !== \"\"\n        ? [combobox.value]\n        : [];\n    const joined =\n      selected.length > 0\n        ? selected.map((v) => combobox.labels.get(v) ?? v).join(\", \")\n        : null;\n    const rendered =\n      typeof children === \"function\" ? children(joined) : joined;\n    return (\n      <View ref={ref} className={cn(\"flex-1 justify-center\", className)} {...props}>\n        {rendered != null ? (\n          wrapTextChildren(rendered, \"font-sans text-sm text-foreground\")\n        ) : (\n          <Text className=\"font-sans text-sm text-muted-foreground\">\n            {placeholder ?? \"\"}\n          </Text>\n        )}\n      </View>\n    );\n  },\n);\nComboboxValue.displayName = \"ComboboxValue\";\n\nexport type ComboboxClearProps = Omit<PressableProps, \"onPress\">;\n\nconst ComboboxClear = forwardRef<BridgePressableRef, ComboboxClearProps>(\n  ({ className, children, accessibilityLabel, ...props }, ref) => {\n    const combobox = useComboboxContext(\"ComboboxClear\");\n    return (\n      <Pressable\n        ref={ref}\n        accessibilityRole=\"button\"\n        accessibilityLabel={accessibilityLabel ?? \"선택 지우기\"}\n        className={cn(TRIGGER_RESET_CLASSES, className)}\n        onPress={() => combobox.clear()}\n        {...props}\n      >\n        {children ?? (\n          <XIcon className=\"size-3.5 text-muted-foreground\" />\n        )}\n      </Pressable>\n    );\n  },\n);\nComboboxClear.displayName = \"ComboboxClear\";\n\nexport type ComboboxInputProps = Omit<\n  TextInputProps,\n  \"value\" | \"defaultValue\" | \"onChangeText\"\n> & {\n  /** 인라인 ▾ 토글 표시（기본 true） */\n  showTrigger?: boolean;\n  /** 인라인 × 지우기 표시（기본 false） */\n  showClear?: boolean;\n  /** children은 래퍼 클래스로 해석된다（인라인 애드온 행 — 포팅 판단 참조） */\n  className?: string;\n  children?: ReactNode;\n};\n\nconst ComboboxInput = forwardRef<BridgeTextInputRef, ComboboxInputProps>(\n  (\n    {\n      className,\n      children,\n      disabled,\n      showTrigger = true,\n      showClear = false,\n      ...props\n    },\n    ref,\n  ) => (\n    // 원본 InputGroup（미이식） 구조를 검색 행으로 재구성 — 하단 보더는\n    // Content 내부 배치（전통형）에서 목록과 구분선을 이룬다.\n    <View\n      className={cn(\n        \"flex-none flex-row items-center border-b border-border h-9\",\n        className,\n      )}\n    >\n      <CommandInput\n        ref={ref}\n        disabled={disabled}\n        className=\"h-full flex-1 border-0 px-3\"\n        {...props}\n      />\n      {showClear ? (\n        <ComboboxClear disabled={disabled} className=\"mr-2\" />\n      ) : null}\n      {showTrigger ? (\n        <PopoverTrigger\n          accessibilityLabel=\"목록 열기\"\n          className={cn(\"mr-2\", TRIGGER_RESET_CLASSES)}\n        >\n          <ChevronDownIcon className=\"size-4 shrink-0 text-muted-foreground\" />\n        </PopoverTrigger>\n      ) : null}\n      {children}\n    </View>\n  ),\n);\nComboboxInput.displayName = \"ComboboxInput\";\n\n// ---------------------------------------------------------------------------\n// 팝업 계열\n// ---------------------------------------------------------------------------\n\nexport type ComboboxContentProps = ViewProps & {\n  /** 전개 방향（기본 bottom — 원본 기본값） */\n  side?: OverlayPlacement;\n  /** 앵커 변 기준 정렬（기본 start — 원본 기본값） */\n  align?: OverlayAlign;\n  /** 앵커와의 간격 px（기본 6 — 원본 기본값） */\n  sideOffset?: number;\n};\n\nconst ComboboxContent = forwardRef<BridgeViewRef, ComboboxContentProps>(\n  (\n    {\n      className,\n      side = \"bottom\",\n      align = \"start\",\n      sideOffset = 6,\n      children,\n      ...props\n    },\n    ref,\n  ) => (\n    // PopoverContent 기본 카드（w-72p-4border）를 원본 팝업 토큰으로 오버라이드.\n    // 테두리는 popover 기본 border border-border를 통과시킨다 — select·dropdown\n    // 과 형제 일관성（원본 ring 대비 의도적 이탈 — 머리 주석 참조）.\n    <PopoverContent\n      ref={ref}\n      side={side}\n      align={align}\n      sideOffset={sideOffset}\n      className={cn(\n        \"p-0 web:max-h-96 web:overflow-y-auto web:shadow-md\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </PopoverContent>\n  ),\n);\nComboboxContent.displayName = \"ComboboxContent\";\n\nexport type ComboboxListProps = CommandListProps;\n\nconst ComboboxList = forwardRef<BridgeScrollViewRef, ComboboxListProps>(\n  ({ className, ...props }, ref) => (\n    // 원본 List p-1스크롤 — CommandList（브리지 ScrollView, listbox role） 소비\n    <CommandList ref={ref} className={cn(\"p-1\", className)} {...props} />\n  ),\n);\nComboboxList.displayName = \"ComboboxList\";\n\nexport type ComboboxEmptyProps = ViewProps;\n\nconst ComboboxEmpty = forwardRef<BridgeViewRef, ComboboxEmptyProps>(\n  ({ className, ...props }, ref) => (\n    // 원본 py-2 — CommandEmpty 기본 py-6을 오버라이드\n    <CommandEmpty ref={ref} className={cn(\"py-2\", className)} {...props} />\n  ),\n);\nComboboxEmpty.displayName = \"ComboboxEmpty\";\n\nexport type ComboboxGroupProps = CommandGroupProps;\n\nconst ComboboxGroup = forwardRef<BridgeViewRef, ComboboxGroupProps>(\n  ({ className, ...props }, ref) => (\n    <CommandGroup\n      ref={ref}\n      className={cn(\"overflow-hidden p-1\", className)}\n      {...props}\n    />\n  ),\n);\nComboboxGroup.displayName = \"ComboboxGroup\";\n\nexport type ComboboxLabelProps = TextProps;\n\nconst ComboboxLabel = forwardRef<BridgeTextRef, ComboboxLabelProps>(\n  ({ className, ...props }, ref) => (\n    <Text\n      ref={ref}\n      className={cn(\n        \"px-2 py-1.5 font-sans text-xs text-muted-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n);\nComboboxLabel.displayName = \"ComboboxLabel\";\n\n/** API 호환용 투명 래퍼 — base-ui Collection의 그룹 묶음 역할을 View로 근사 */\nexport type ComboboxCollectionProps = ViewProps;\n\nconst ComboboxCollection = forwardRef<BridgeViewRef, ComboboxCollectionProps>(\n  ({ ...props }, ref) => <View ref={ref} {...props} />,\n);\nComboboxCollection.displayName = \"ComboboxCollection\";\n\nexport type ComboboxItemProps = PressableProps & {\n  /** 항목값 — 미지정 시 최상위 문자열 children에서 유도（command 관행） */\n  value?: string;\n  /** 필터 추가 검색어（cmdk keywords） */\n  keywords?: string[];\n  /** 선택 확정 콜백 — 터치 onPress와 웹 Enter가 호출 */\n  onSelect?: (value: string) => void;\n  children?: ReactNode;\n};\n\nconst ComboboxItem = forwardRef<BridgePressableRef, ComboboxItemProps>(\n  (\n    { value, keywords, disabled, onSelect, className, children, ...props },\n    ref,\n  ) => {\n    const combobox = useComboboxContext(\"ComboboxItem\");\n    const { registerItem } = combobox;\n    const resolvedValue = value ?? textValueOf(children);\n    const label = textValueOf(children) || resolvedValue;\n    const isSelected = combobox.multiple\n      ? combobox.values.includes(resolvedValue)\n      : combobox.value === resolvedValue;\n\n    // 라벨 등록（해제 없음 — 포팅 판단 참조）\n    useEffect(() => {\n      registerItem(resolvedValue, label);\n    }, [registerItem, resolvedValue, label]);\n\n    return (\n      <CommandItem\n        ref={ref}\n        value={resolvedValue}\n        keywords={keywords}\n        disabled={disabled}\n        onSelect={(selected) => {\n          combobox.commitItem(selected);\n          onSelect?.(selected);\n        }}\n        className={cn(\"pl-2 pr-8\", className)}\n        {...props}\n      >\n        {children}\n        {/* 표시자 — 원본 ItemIndicator + CheckIcon（원본 슬롯 size-4·아이콘 size-4） */}\n        <View\n          aria-hidden\n          className=\"absolute right-2 size-4 items-center justify-center\"\n        >\n          {isSelected ? (\n            <CheckIcon className=\"size-4 text-foreground\" />\n          ) : null}\n        </View>\n      </CommandItem>\n    );\n  },\n);\nComboboxItem.displayName = \"ComboboxItem\";\n\nexport type ComboboxSeparatorProps = ViewProps;\n\nconst ComboboxSeparator = forwardRef<BridgeViewRef, ComboboxSeparatorProps>(\n  ({ className, ...props }, ref) => (\n    <CommandSeparator\n      ref={ref}\n      className={cn(\"my-1\", className)}\n      {...props}\n    />\n  ),\n);\nComboboxSeparator.displayName = \"ComboboxSeparator\";\n\n// ---------------------------------------------------------------------------\n// 다중 선택 칩 계열\n// ---------------------------------------------------------------------------\n\nexport type ComboboxChipsProps = ViewProps;\n\nconst ComboboxChips = forwardRef<BridgeViewRef, ComboboxChipsProps>(\n  ({ className, ...props }, ref) => (\n    <View\n      ref={ref}\n      className={cn(\n        // 원본 px-2.5 py-1.5 shadow-xs（칩이 있을 때 px-1.5는 has- 셀렉터 미지원으로 고정）.\n        \"min-h-9 flex-row flex-wrap items-center gap-1.5 rounded-md border border-input px-2.5 py-1.5 web:focus-within:border-ring web:focus-within:ring-3 web:focus-within:ring-ring/50\",\n        className,\n      )}\n      {...props}\n    />\n  ),\n);\nComboboxChips.displayName = \"ComboboxChips\";\n\nexport type ComboboxChipProps = ViewProps & {\n  /** 이 칩이 나타내는 선택값 — × 제거에 쓰인다 */\n  value: string;\n  /** × 제거 버튼 표시（기본 true） */\n  showRemove?: boolean;\n};\n\nconst ComboboxChip = forwardRef<BridgeViewRef, ComboboxChipProps>(\n  ({ className, value, showRemove = true, children, ...props }, ref) => {\n    const combobox = useComboboxContext(\"ComboboxChip\");\n    return (\n      <View\n        ref={ref}\n        className={cn(\n          // 원본 h-［calc（--spacing（5.5））］（22px） → h-5 근사\n          \"h-5 flex-row items-center gap-1 rounded-sm bg-muted px-1.5\",\n          className,\n        )}\n        {...props}\n      >\n        {wrapTextChildren(\n          children,\n          \"font-sans text-xs font-medium text-foreground\",\n        )}\n        {showRemove ? (\n          <Pressable\n            accessibilityRole=\"button\"\n            accessibilityLabel=\"제거\"\n            // 원본 ChipRemove Button: -ml-1 opacity-50 hover:opacity-100.\n            className={cn(\n              TRIGGER_RESET_CLASSES,\n              \"-ml-1 opacity-50 web:hover:opacity-100\",\n            )}\n            onPress={() => combobox.removeValue(value)}\n          >\n            {/* 원본은 아이콘 크기 클래스가 없다 — 부모 icon-xs 버튼의\n                ［&_svg］:size-3 규칙이 자식 셀렉터라 미지원, 직접 size-3 명시（G3）. */}\n            <XIcon className=\"size-3 text-foreground\" />\n          </Pressable>\n        ) : null}\n      </View>\n    );\n  },\n);\nComboboxChip.displayName = \"ComboboxChip\";\n\nexport type ComboboxChipsInputProps = Omit<\n  TextInputProps,\n  \"value\" | \"defaultValue\" | \"onChangeText\"\n>;\n\nconst ComboboxChipsInput = forwardRef<\n  BridgeTextInputRef,\n  ComboboxChipsInputProps\n>(({ className, ...props }, ref) => (\n  // CommandInput 소비 — 칩 행 안 검색 입력. ⌕ 글리프 포함（검색 맥락）.\n  <CommandInput\n    ref={ref}\n    className={cn(\"h-8 min-w-16 flex-1 border-0 px-1\", className)}\n    {...props}\n  />\n));\nComboboxChipsInput.displayName = \"ComboboxChipsInput\";\n\n// ---------------------------------------------------------------------------\n// 앵커 훅\n// ---------------------------------------------------------------------------\n\n/**\n * 앵커 ref 팩토리 — 원본 useComboboxAnchor（HTMLElement）의 브리지 치환.\n * 소비: <View ref={anchor}> 요소를 <PopoverAnchor>로 감싸면 ComboboxContent의\n * 앵커가 트리거 대신 그 요소로 오버라이드된다（popover 조합）.\n */\nexport function useComboboxAnchor() {\n  return useRef<BridgeViewRef | null>(null);\n}\n\nexport {\n  Combobox,\n  ComboboxInput,\n  ComboboxContent,\n  ComboboxList,\n  ComboboxItem,\n  ComboboxGroup,\n  ComboboxLabel,\n  ComboboxCollection,\n  ComboboxEmpty,\n  ComboboxSeparator,\n  ComboboxChips,\n  ComboboxChip,\n  ComboboxChipsInput,\n  ComboboxTrigger,\n  ComboboxValue,\n};\n",
      "type": "registry:ui",
      "target": "components/ui/combobox.tsx"
    }
  ],
  "type": "registry:ui"
}
