# Component API Naming Conventions

`@orioncactuscorp/ui`는 컴포넌트의 시각적 선택지를 `variant`,
`appearance`, `size`로 일관되게 표현합니다. 이 규칙은 처음 사용하는
컴포넌트에서도 prop의 역할을 예측할 수 있게 하는 공개 API 계약입니다.

## 유틸과 React API 네이밍

- `ocMotion`, `ocGesture`, `ocFocus`는 관련 시스템 정책이나 동작을 묶는 도메인 진입점입니다. 모든 함수에 namespace를 추가하는 규칙은 아닙니다.
- React 훅은 `usePrefersReducedMotion`처럼 `use*`, 조합 함수는 `mergeRefs`처럼 동작명, 실행 객체 생성은 `createFlingAnimator`처럼 `create*`를 사용합니다.
- `ocGesture`는 저항·감속·속도 계산, `ocMotion`은 모션 정책 해석을 담당합니다. 입력 이벤트와 컴포넌트 owner 정책은 호출부에 둡니다.

## 역할은 계약, 시각 값은 기본값

prop 이름과 TypeScript에 선언된 선택지는 버전 관리되는 계약입니다. 반면 각
선택지가 사용하는 색, 간격, 크기 같은 구체적인 시각 값은 디자인 시스템의
기본값입니다. 지원되는 token, component contract 변수, selector 계약을 통해
consumer가 조정할 수 있으며, 디자인 시스템 정책에 따라 변경될 수 있습니다.

지원되는 선택지의 정확한 목록은 각 컴포넌트의 TypeScript 선언을 기준으로
확인하세요. 모든 컴포넌트가 아래 축을 전부 제공하지는 않습니다.

## `variant`: 하나의 시각·표현 축

컴포넌트에 열거형 시각 또는 표현 축이 하나라면 `variant`를 사용합니다.
`variant`가 나타내는 구체적인 역할은 컴포넌트에 따라 의미·색, 강조 강도,
형태, surface 표현, layout 표현, slot content 종류 등이 될 수 있습니다.

상태, 간격, 동작처럼 독립된 개념은 `variant`에 합치지 않고 별도 prop으로
표현합니다.

## `appearance` + `variant`: 독립된 두 축

형태 또는 surface와 의미 또는 색을 각각 선택해야 하는 컴포넌트는 두 축을
분리합니다.

- `appearance`: 형태 또는 surface 처리
- `variant`: 의미 또는 색 의도

`Button`이 대표적인 예입니다. `appearance`는 `solid | outlined`, `variant`는
`default | primary | secondary | assistive`를 제공합니다.

```tsx
<Button appearance='solid' variant='primary'>
  저장
</Button>

<Button appearance='outlined' variant='assistive'>
  도움말
</Button>
```

이 분리는 형태와 의미를 하나의 조합 이름으로 합치지 않고 각 역할을 독립적으로
읽고 선택할 수 있게 합니다.

## TextInput 형태와 Field 라벨 배치

`TextInput`과 `TextArea`는 `variant='outlined | underlined'`로 입력 영역의 형태를 선택합니다.
기본값은 기존 사방 테두리형인 `outlined`입니다. 라벨 배치는 독립된 계약이므로
`Field`의 `labelPlacement='outside | floating'`으로 선택하며 기본값은 `floating`이며, 지원되는 underlined 입력에만 적용됩니다. `labelPlacement="outside"`를 명시하면 외부 라벨을 유지합니다.

여러 줄 입력에는 `TextArea variant='underlined' minRows={2} maxRows={5}`를 사용합니다.
밑줄형에서도 줄바꿈, 자동 높이 조절, supporting content를 유지합니다. `TextArea`도 밑줄형이면 floating 라벨이 기본입니다. 빈 라벨은 첫 줄에 정렬되며, 여러 줄 입력으로 높이가 늘어나도 올라간 라벨은 상단에 고정됩니다.

```tsx
<Field labelPlacement='floating'>
  <FieldLabel>생년월일 6자리</FieldLabel>
  <FieldControl>
    <TextInput variant='underlined' inputMode='numeric' maxLength={6} />
  </FieldControl>
  <FieldMessage>생년월일을 6자리로 입력하세요.</FieldMessage>
</Field>
```

floating은 세로 Field의 직접 자식 FieldLabel과 FieldControl, 그 안의 직접 자식
underlined TextInput 또는 TextArea 조합에서 지원합니다. 지원 타입은 text/email/password/search/tel/url입니다.
가로 Field, outlined 입력, 날짜·숫자 입력, 다른 컨트롤은 기존 외부 라벨 배치를 유지합니다.
숫자 문자열은 `type='text'`와 `inputMode='numeric'`를 조합하세요.

라벨은 비어 있을 때 입력 위치에 머물고, 값이 있으면 위로 이동하며 0.75배로 축소됩니다.
placeholder가 없으면 포커스만으로 이동하지 않습니다. placeholder가 있으면 빈 입력도 포커스 시 라벨이 올라가고 안내가 fade로 나타납니다. 빈 상태에서 blur하면 안내를 숨기고 라벨을 내립니다. 값이 있으면 blur 후에도 작은 라벨을 유지합니다.
floating 라벨은 medium 굵기입니다. 모든 FieldLabel은 기본 `label-alternative`, 입력 영역에 포커스가 있을 때 primary, invalid일 때 오류 색상을 공통으로 사용합니다. invalid 색상은 포커스보다 우선하며, 값이 있어도 포커스가 없으면 기본 색상입니다. 밑줄형의 stroke 끝은 max radius로 둥글게 표시합니다.
placeholder는 실제 input에 전달하며, 생략한 경우에만 내부 빈 값 판별용 공백을 사용합니다. 추가 설명은 FieldMessage에 작성하세요.
라벨은 한 줄로 표시하고 긴 내용은 말줄임 처리하며, 전체 내용은 접근성 이름으로 유지합니다.
reduced-motion에서는 이동·축소 전환을 제거하고 색상 피드백을 유지합니다.

## `size`: 표준 크기 순서의 부분집합

named size의 표준 순서는 다음과 같습니다.

```text
xsmall < small < medium < large
```

각 컴포넌트는 실제로 지원하는 크기만 부분집합으로 제공합니다. 예를 들어 어떤
컴포넌트가 `small | medium`만 제공하더라도 사용하지 않는 `xsmall`이나 `large`를
대칭성을 위해 추가하지 않습니다. TypeScript union의 선언 순서는 별도 계약이
아니며, 크기 비교에는 위 순서를 사용합니다.

### Named size 밖의 예외

named preset이 아니라 외부 문맥이나 직접 지정한 치수로 크기를 정해야 할 때만
다음과 같은 값을 허용합니다.

- `inherit`: owner의 typography·크기를 상속
- `custom`: component CSS가 치수를 결정
- 숫자 또는 자유 형식 값: primitive나 icon-sized control에 직접 치수를 전달

`TextButton`은 owner 안에서 자연스럽게 조합할 수 있도록 `size='inherit'`을
제공합니다. 색을 상속하는 `variant='inherit'`은 size가 아닌 variant 축의
선택지입니다.

```tsx
<TextButton variant='inherit' size='inherit'>
  자세히 보기
</TextButton>
```

새 named size가 필요할 때 `tiny`, `mini` 같은 별도 척도를 만들지 않습니다.
직접·custom·상속 크기가 필요한 경우에는 해당 예외의 목적을 컴포넌트 API에
문서화합니다.

`Badge`의 작은 preset도 `size='xsmall'`을 사용하므로 모든 named size가 이
표준 순서를 따릅니다.

`Badge`의 `variant='default'`는 소비자 커스터마이즈의 기준이 되는 canonical
기본 표현이며 `label-strong` 배경과 `background-normal-normal` 라벨 색을 사용합니다.
기존 `variant='normal'`은 `label-alternative` 라벨과 `fill-normal` 배경을 사용하는
레거시 표현으로 유지됩니다. 신규 코드는 `default`를 사용하세요.

`ProgressIndicator`는 선의 block size를 `small | medium | large`로 제공합니다.
기본 `small`은 모바일과 navigation chrome에 사용하고, `medium`과 `large`는
태블릿·데스크톱의 독립적인 작업 진행 표시에 사용합니다.

## InputGroup

`variant`는 `outlined | underlined` 외형 축입니다. `labelPlacement`는 독립적인 `outside | floating` 배치 축입니다. 기본 요청값은 floating이며, Field와 동일하게 outlined는 outside로 표시하고 underlined에만 floating을 적용합니다. `required`, `readOnly`, `disabled`, `invalid`는 그룹 소유 상태입니다. 네이티브 입력 속성은 `InputGroupInput`에 전달합니다.
