Files
HMDesign/docs/components/pagination.md

6.9 KiB
Raw Permalink Blame History

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: a props + 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-N href + 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의 --accent 45%는 유지한다. 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 시각.