6.9 KiB
Pagination
현재 HM 구현의 기준 문서. 공통 원칙은 docs/guidelines/프로젝트-지침.md(§6, §7), Token 구조 원칙은 테마-토큰-가이드.md를 따른다. 이 문서는 Pagination 고유의 API·Token·상태·결정만 기록한다.
1. 상태
| 항목 | 내용 |
|---|---|
| 구현 상태 | 구현 완료 (현재 HM 규격) |
| 기준일 | 2026-10-02 |
| 기반 | shadcn/ui Pagination (nav > ul > li > a, Radix 없음) |
| 대표 Story | Components/Navigation/Pagination → All (이름 "Pagination") |
| 보류 | 아래 §11 |
2. 적용 근거
- 참고 근거: 외부 ui_viz Reference (ZIP 미포함)의 기존 테스트 규격에는 Pagination이 컴포넌트 이름으로만 있고 규격은 없다. 참고할 수치가 없었다.
- 현재 HM 규격: 아래 §3~§4. 현재 HM Semantic 체계(fg-primary, action-primary, accent)로 새로 정했다.
- 구현 방식: shadcn Pagination 구조 유지. Presentational / navigation primitive로, page state와 href는 소비자가 관리한다. 링크는
a로 유지하고 Button으로 바꾸지 않는다. - Button과의 관계: shadcn은
buttonVariants를 입혀 Button처럼 그리지만, HM Button은data-slot="button"기반이라 이를 그대로 쓰면 HM 스타일이 적용되지 않고 Button token도 재사용하면 안 된다. 그래서PaginationLink는 독립 anchor 스타일(--hm-pagination-*)로 구현했다. - 보류: §11.
3. 기본 규격 (현재 HM 규격)
| 항목 | 값 |
|---|---|
| Page link | 34 × 34px(min-width 34), radius 4px(--hm-radius-control-md), 14 / 20 / 500, --hm-sem-fg-primary |
| Previous / Next | 높이 34px, padding 0 12px, 아이콘 16px, 라벨 hidden sm:block("Previous"/"Next", 모바일은 아이콘만) |
| 간격 | 목록 gap 4px |
| Current Page | 배경 --hm-sem-action-primary(Primary Green #123328), 글자 --hm-sem-on-action-primary(흰색), weight 700 |
| Ellipsis | 34 × 34 영역, 아이콘 16px, --hm-sem-fg-secondary |
4. 상태 규격
| 상태 | 값 |
|---|---|
| Hover | 배경 --accent 45%, 글자 --accent-foreground |
Focus (:focus-visible) |
ring 모양 0 0 0 3px ring 50% |
Current (isActive) |
aria-current="page", 위 Current 스타일(hover에도 Current로 보이도록 hover 배경 대신 유지) |
Disabled (aria-disabled="true") |
opacity: 0.6(이 컴포넌트 값, 전역 Disabled 규칙으로 승격 안 함), cursor: not-allowed, hover 면 없음, tabIndex -1, 클릭 취소(preventDefault) |
5. API
export: Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationPrevious, PaginationNext, PaginationEllipsis.
PaginationLink:aprops +isActive(현재 페이지),size"default" | "icon"(기본icon; shadcn은 Button size, HM은default/icon둘만). 출력data-slot="pagination-link",data-active,data-size.- disabled: 별도 prop 없이
aria-disabled를 쓴다.aria-disabled="true"이면 컴포넌트가tabIndex=-1로 두고 클릭(onClick 호출 포함)을 취소한다. anchor에는 native disabled가 없어 class만으로는 접근성이 보장되지 않기 때문에 보완했다. PaginationPrevious/PaginationNext: 기본aria-label("Go to previous/next page")과 라벨,children으로 교체 가능.- 새 상태 관리,
page/total같은 prop은 만들지 않았다.
6. Token
Component Mapping 위치: packages/ui/src/theme/pagination.css (--hm-pagination-*).
gap, height, min-width, padding-x, radius, font-size|line-height|font-weight, icon-size, text, hover-background, hover-text, active-background, active-text, active-font-weight, ellipsis-color, disabled-opacity. Semantic만 참조하고 --hm-button-* 등 다른 컴포넌트 Token을 쓰지 않는다. 신규 Primitive 없음.
7. shadcn에서 유지한 항목
nav role="navigation" aria-label="pagination", ul/li 구조, a 링크, isActive→aria-current="page", Previous/Next 아이콘과 aria-label, Ellipsis의 aria-hidden + sr-only, data-slot, cn(..., className).
8. HM에서 변경한 항목
buttonVariants합성을 제거하고 독립 anchor 스타일로 대체(위 §2).size를 shadcn의 Button size 전체에서default/icon으로 좁혔다.aria-disabled처리(tabIndex, 클릭 취소)를 추가했다.- 현재 페이지를 outline 대신 채움(primary)으로 표시.
9. Storybook
- 대표 Story
All("Pagination"): First page, Middle page, Last page, Long range with ellipsis(1 … 9 10 11 … 20)를 한 페이지에 둔다. 각 Specimen이 local state를 가지고 클릭 시 현재 페이지가 실제로 바뀐다(#page-Nhref +preventDefault). - verification:
First Page,Last Page,Long Range.
10. 사용자 확정 결정
- 2026-10-02: ui-viz는 참고 자료이며 최종 기준은 현재 HM 구현과 이 문서다(작업 지시). 개별 수치에 대한 별도 결정은 없다.
- 2026-10-06 (Pagination Current 원복): 직전 Active Semantic 작업에서 Current를
--hm-sem-state-active(Light 2)로 바꾼 변경을 취소하고 이전 값--hm-sem-action-primary/--hm-sem-on-action-primary(Primary Green#123328, 흰색)로 복원했다. Current + Hover도 Current 색을 유지한다. Hover의--accent45%는 유지한다. Focus·Disabled·API·구조 변경 없음.
11. 미확정 / 보류
- 수치(34px, 4px radius, 12px padding, 채움 current, Disabled opacity 0.6)는 현재 HM 규격이며 디자인 확정 시 재검토.
- page range(ellipsis 계산)는 소비자 책임이다(Story의
pageRange는 예시일 뿐 컴포넌트가 아님). - 언어: Previous/Next 기본 라벨은 shadcn 영어 그대로(
children으로 교체). - 좁은 화면 compact 표현은 shadcn의 라벨 숨김(
sm미만)만 유지. 별도 compact variant 없음. - 페이지 크기 선택, 결과 수 표시는 범위 밖.
12. 관련 파일
packages/ui/src/components/ui/pagination.tsx
packages/ui/src/theme/pagination.css
packages/ui/src/theme.css (import)
packages/ui/src/index.ts (export)
src/components/pagination.stories.tsx
13. 검증 상태
npm run typecheck,npm run build: 통과(2026-10-02).- 실제 interaction(Browser pane, JS click): page 4 클릭으로 current가 4로 변경, Next로 5, 첫 페이지의 Previous(
aria-disabled)와 마지막 페이지의 Next 클릭은 상태를 바꾸지 않음.aria-disabled링크는tabindex=-1, opacity 0.6, cursor not-allowed. Current는aria-current="page", 34×34, 배경rgb(18,51,40), 글자 white, weight 700. - 구조:
a요소, ellipsis 위치(1 … 9 10 11 … 20)와 First/Last 상태 확인. - Responsive: 390×844에서 Previous/Next 라벨이 숨겨져 아이콘만 남고, 20페이지 범위(
1 … 9 10 11 … 20)가 350px 한 줄에 들어가며 가로 overflow 없음. - 미확인: 실제 키보드 Tab/Enter 순서, pointer hover·focus ring 시각.