# 방문 기록 내비게이션

`useNavigationHistory<T>`는 한 UI 안의 방문 기록을 관리합니다. 브라우저 URL, 라우터, 폼 단계와 입력값은 관리하지 않습니다. `initialEntry`는 최초 마운트 시 한 번 읽고, 새 시작점은 `reset(value)`로 지정합니다.

```tsx
const history = useNavigationHistory({
  initialEntry: { screen: 'home', title: '홈', depth: 0 },
});
const targets = history.backEntries.map(entry => ({
  key: entry.key,
  label: entry.value.title,
}));

<HistoryNavigationButton
  direction='back'
  targets={targets}
  onNavigate={history.goTo}
  render={<Button>뒤로</Button>}
/>;
```

- `current`는 `{ key, value }`이고 같은 화면을 다시 방문해도 key가 다릅니다. title과 depth는 소비자 데이터이며 hook의 필수 형식이 아닙니다.
- `backEntries`·`forwardEntries`는 가까운 기록부터 제공합니다. `canGoBack`·`canGoForward`로 이동 가능 여부를 확인합니다.
- `push(value)`는 앞으로 기록을 제거하고 새 방문을 추가합니다. `replace(value)`는 현재 key와 다른 기록을 유지하며 현재 값만 교체합니다.
- `back()`·`forward()`는 범위를 벗어나지 않습니다. `goTo(key)`는 현재 기록 중 해당 key로 이동하고 알 수 없는 key는 무시합니다.
- `reset()`은 최초 값으로, `reset(value)`는 새 값으로 기록을 초기화합니다. `T`가 `undefined`를 허용하면 `reset(undefined)`는 명시적인 빈 값으로 초기화하고, `reset()`만 최초 값으로 돌아갑니다. 이전 key는 재사용하지 않습니다.
- 값은 불변 데이터로 다루세요. 화면 입력값 보존, 이동 허용 검증과 비동기 이동의 승인 여부는 소비자가 관리합니다.

## 버튼 조합

`HistoryNavigationButton`은 기본 아이콘 host에 방향별 접근성 이름을 제공하고 `render`로 버튼을 교체할 수 있습니다. 텍스트 버튼은 보이는 글자가 접근성 이름이 되며, custom icon-only render에는 `label` 또는 render의 `aria-label`을 지정하세요. 명시적인 `label`은 접근성 이름을 덮어쓰므로 보이는 글자를 포함해야 합니다. `render`는 native button과 ref·이벤트를 전달해야 합니다. 링크 이동은 라우터의 링크 계약으로 별도로 구현하세요.

- `targets`는 이 방향에서 실제로 이동 가능한 기록만 가까운 순서로 전달합니다. 버튼 클릭·Enter·Space는 첫 대상으로 이동합니다.
- `historyMenu`는 기본 `true`이며 기록 메뉴는 `small` 크기입니다. hold·오른쪽 클릭·Shift+F10으로 기록 메뉴를 열고, hold 후 release click이 한 단계 이동까지 실행하지 않습니다. 메뉴가 열린 동안 trigger를 다시 누르면 메뉴만 닫습니다.
- `historyMenu={false}`는 한 단계 이동만 제공합니다. 외부 라우터도 이 hook 없이 targets·onNavigate를 연결할 수 있습니다.
- `disabled`, render 버튼의 disabled, 빈 targets 중 하나라도 해당하면 이동을 막습니다. 소비자 onClick의 `preventDefault()`로 이동을 취소할 수 있습니다.
- 이벤트는 render와 wrapper 양쪽의 핸들러를 병합합니다. Base UI와 동일하게 wrapper 이벤트, render 이벤트, 내부 이동 순서로 실행합니다.
- ref, className, style, native button 속성은 전달합니다. `type`은 폼 제출을 방지하기 위해 `button`으로 고정하며, className은 병합하고 style의 같은 속성은 wrapper 값이 우선합니다.
- 방향은 탐색 기록을 설명합니다. 폼의 ‘다음 단계’나 계층의 ‘부모’와 같은 의미로 취급하지 마세요.

## 긴 제목과 접근성

목적지를 선택하기 전에 이름을 읽을 수 있도록 기록 메뉴는 원문을 줄바꿈하고 긴 목록은 스크롤합니다. 화면별 title을 Modal 제목과 메뉴 label에 재사용하되, JSX 제목에는 읽을 수 있는 별도 문자열 label을 지정하세요. 같은 title의 기록은 허용하며, 식별에 필요한 문맥은 소비자가 label에 추가합니다.

`ModalHeader titleOverflow='wrap'`은 긴 화면 제목에 권장합니다. 기존 기본값 `ellipsis`는 원문을 DOM에 유지하며 시각적으로만 자릅니다. 이 경우 보이는 원문 펼치기 버튼처럼 터치·키보드에서 사용할 수 있는 확인 경로를 제공하세요. Tooltip만으로 원문 접근을 해결하거나 history hold 위에 Tooltip hold를 중첩하지 마세요. Tooltip을 추가한다면 실제 overflow일 때만 제공하고 hover·focus, Escape 닫기, 읽는 동안 유지, 중복 낭독을 확인하세요.

Modal은 같은 상태에서 실제 계층 depth를 `navigationDepth`로 계산하세요. 방문 기록의 index를 depth로 사용하지 마세요. 화면 교체 후 포커스는 화면 owner가 새 제목 또는 적절한 대상으로 반드시 옮기고, 메뉴 닫힘의 포커스 복원과 충돌하지 않도록 합니다. 기록 초기화는 닫힘 전환 완료 후 또는 다시 열 때 수행하세요.

기존 Menu의 키보드 이동·Escape 계약과 Modal의 focus trap·닫기 정책을 유지합니다. hold는 지름길이고 모든 목적지는 일반 이동으로도 접근 가능해야 합니다.
