271 lines
24 KiB
Markdown
271 lines
24 KiB
Markdown
# HM Custom Implementation Inventory
|
||
|
||
> 조사 기준일: 2026-10-06. 실제 코드(`packages/ui/src`) 기준의 현황 기록이며 확정 규격이 아니다. 구현은 바꾸지 않았다.
|
||
> 신규 구현은 [AI/Component 구현 원칙](shadcn-기반-구현-원칙.md)과 [Navigation Single Mode Policy](navigation-single-mode.md)의 2026-10-07 확정 정책을 따른다. 아래 조사 이력은 운영 예제나 정책 예외를 허용하는 근거가 아니다.
|
||
> Select의 `UNDER_REVIEW`는 2026-10-06 조사 당시 설계 평가이며 현재 작업 진행 상태를 뜻하지 않는다. 현재 API·동작은 `docs/components/select.md`와 실제 구현·대표 Story를 따른다.
|
||
|
||
> **현재 탐색 기준 (2026-10-08 개발 저장소)**: UI 구현 TSX 44개, 공개 Component 모듈 44개(222 named export), Component Story 파일/그룹 44개, Component 문서 45개(`field.md`는 독립 구현이 아닌 소비 가이드)다. Pattern은 소스 디렉터리/공개 모듈 8개(62 named export), Story 파일/그룹 6개, Pattern 문서 7개다. 확정 배포 기준 `HMDesignTest.zip`에는 Component 구성은 동일하고 Pattern 모듈 7개(50 named export)가 포함되며 Dashboard Status 모듈은 없다. 파일·심볼·그룹은 서로 다른 집계 단위다. 현재 경로 연결은 [Component / Pattern Reference Index](component-pattern-reference.md)를 따른다. 아래 표와 분석은 2026-10-06 당시의 분류 기록이다.
|
||
|
||
## 0. 한 줄 요약
|
||
|
||
shadcn/Radix를 그대로 쓰지 않고 **실제로 API·State·Behavior·Structure가 추가된 Component는 44개 중 15개**다. 나머지 29개는 shadcn 구조를 유지하고 CSS/Token만 얹었다. Pattern 7종은 모두 기존 Component의 조합이다.
|
||
|
||
| 질문 | 답 |
|
||
|---|---|
|
||
| 꼭 필요한가? | Component 기준 15개 중 `REQUIRED` 13, `CAN_SIMPLIFY` 1(Textarea), `UNDER_REVIEW` 1(Select). 항목 단위로는 `CAN_SIMPLIFY` 3건, `LEGACY` 1건(Button alias) (§4, §11, §12) |
|
||
| Public API에 영향을 주는가? | 12건이 consumer에게 노출된다 (§8). 내부 전용은 6건 (§7) |
|
||
| shadcn 업데이트 시 관리해야 하는가? | **Tabs(HIGH)** 우선, 이어서 Button·Select(MEDIUM). 나머지는 LOW |
|
||
|
||
> 위 숫자는 아래 표의 합이다. 표를 고치면 이 요약도 함께 고친다.
|
||
|
||
## 1. 목적
|
||
|
||
- shadcn 업데이트·재생성 시 "무엇을 손으로 지켜야 하는가"를 한 문서에서 확인한다.
|
||
- HM 스타일이 들어갔다는 이유만으로 Custom으로 부르지 않는다. Behavior / Structure를 유지하고 CSS/Token만 바꾼 것은 `HM_THEME`다.
|
||
- 이 문서는 가시화·분류·유지보수 기준만 다룬다. 제거·단순화 판단은 별도 작업이다.
|
||
- Visual 값(height, radius, color 등)은 각 `docs/components/<name>.md`, `docs/patterns/<name>.md`가 담당하므로 여기에 나열하지 않는다.
|
||
|
||
## 2. 분류 기준
|
||
|
||
| 분류 | 정의 |
|
||
|---|---|
|
||
| `SHADCN_BASE` | shadcn/Radix 구조·API 그대로. `.tsx`에 HM 전용 코드가 없고 Theme CSS도 얇은 Token 매핑 수준 |
|
||
| `HM_THEME` | Behavior / Structure는 shadcn/Radix 그대로, Visual만 HM CSS / Token. 독립 Custom 아님 |
|
||
| `HM_CUSTOM` | shadcn에 없는 Public API, 상태/behavior, Radix 동작 확장, 추가 Context/state, helper logic, 구조 확장 중 하나 이상 |
|
||
| `HM_COMPOSITION` | 기존 HM/shadcn Component를 조합한 Pattern |
|
||
| `STORY_ONLY` | 검증용 Story, StateBoard 등. Production Custom 아님 |
|
||
|
||
조사 한계(반드시 읽을 것):
|
||
|
||
- 현재 저장소는 Git으로 관리한다. 2026-10-06 조사는 shadcn 원본 사본과의 Git diff를 수행하지 않았다. 따라서 당시 분류는 "shadcn 원본과의 diff"가 아니라 **현재 코드와 코드 주석을 읽고 shadcn v4(Radix) 구조에 대한 지식과 대조**해 판정했다. 경계 항목은 `shadcn add`로 원본을 받아 diff하면 확정할 수 있다.
|
||
- `SHADCN_BASE`와 `HM_THEME`의 경계는 휴리스틱이다: `.tsx`가 shadcn 그대로이면서 `packages/ui/src/theme/<name>.css`가 약 70줄 이하이면 `SHADCN_BASE`, 그보다 크면 `HM_THEME`. 둘 다 "Custom 아님"이므로 유지보수 판단에는 영향이 없다.
|
||
- Story는 전수 검토하지 않고 공용 helper와 파일 구성만 확인했다.
|
||
|
||
## 3. 전체 요약
|
||
|
||
| Category | Count | 비고 |
|
||
|---|---:|---|
|
||
| Component 총계 | 44 | `packages/ui/src/components/ui/` |
|
||
| `SHADCN_BASE` | 16 | §5 |
|
||
| `HM_THEME` | 13 | §5 |
|
||
| `HM_CUSTOM` | 15 | §4 (Public 12건 + Internal 6건이 이 15개에 걸쳐 있음) |
|
||
| `HM_COMPOSITION` | 7 | Pattern (§6, Component 44개와 별도) |
|
||
| `STORY_ONLY` | 4 묶음 | §9 |
|
||
|
||
## 4. Components — HM_CUSTOM
|
||
|
||
한 Component 안에 Visual(HM_THEME)과 구조 Custom이 함께 있을 수 있다. 아래는 구조·API·상태 부분만 적었다. 평가: `REQUIRED` 현재 필요 / `CAN_SIMPLIFY` shadcn 방식으로 단순화 가능 / `LEGACY` 필요성 불명확 / `UNDER_REVIEW` 작업 중·미결정.
|
||
|
||
| Component | Base | Custom 종류 | Scope | 평가 | Risk |
|
||
|---|---|---|---|---|---|
|
||
| Button | shadcn + Radix Slot + CVA | API, Structure | Public | REQUIRED (+ alias는 LEGACY) | MEDIUM |
|
||
| Input | shadcn | API | Public | REQUIRED | LOW |
|
||
| Textarea | shadcn | API | Public | CAN_SIMPLIFY | LOW |
|
||
| Card | shadcn | API | Public | REQUIRED | LOW |
|
||
| Select | Radix Select | API, State, Structure | Public + Internal | UNDER_REVIEW | MEDIUM |
|
||
| Tabs | Radix Tabs | API, State, Behavior, Structure | Public + Internal | REQUIRED | HIGH |
|
||
| Dialog | Radix Dialog | API(Structure), Behavior | Public + Internal | REQUIRED | LOW |
|
||
| Sheet | Radix Dialog | API(Structure), Behavior | Public + Internal | REQUIRED | LOW |
|
||
| Drawer | vaul | API(Structure), Behavior | Public + Internal | REQUIRED | LOW |
|
||
| Alert Dialog | Radix Alert Dialog | API | Public | REQUIRED | LOW |
|
||
| Combobox | Popover + Command (cmdk) | API, State, Composition | Public | REQUIRED | LOW |
|
||
| Date Picker | Popover + Calendar (react-day-picker) | API, State, Behavior | Public + Internal | REQUIRED | LOW |
|
||
| Popover | Radix Popover | Behavior | Internal | REQUIRED | LOW |
|
||
| Collapsible | Radix Collapsible | Behavior | Internal | REQUIRED | LOW |
|
||
| Slider | Radix Slider | Behavior | Internal | REQUIRED | LOW |
|
||
|
||
### 4.1 항목별 기록
|
||
|
||
**Button** — `button.tsx`, `theme/button.css`
|
||
- 추가: `variant`를 역할(`primary|secondary|modify|destructive|cancel`)로 교체, `appearance`(`brand|solid|outline`) 추가, `data-variant/data-appearance/data-size`. `default`·`outline`은 shadcn 호환 alias로 `primary`/`primary+outline`에 매핑, `ghost`·`link`는 shadcn 기본 유지.
|
||
- 이유: ui_viz 역할/처리(treatment) 2축 규격. `<Button />`만으로 HM 디자인 적용.
|
||
- Public API 영향: 있음(`variant` 값 집합, `appearance`). 기존 shadcn `variant="default|outline"` 코드는 alias로 동작.
|
||
- 구조 주의: `data-slot="button"`을 `{...props}` **뒤에** 둔다. 앞에 두면 `<XTrigger asChild><Button/></XTrigger>`가 trigger의 `data-slot`으로 덮어써 HM 스타일이 사라진다(§7 I3).
|
||
- 대체 가능한 shadcn 방식: shadcn `variant` 값에 HM 역할을 추가하는 방식은 가능하나 `appearance` 2축은 표현 불가.
|
||
- 리스크 사유: `buttonVariants` CVA 정의를 통째로 다시 썼다. shadcn이 `buttonVariants`를 바꾸면 수동 병합이 필요하다. 코드에 `dark:` 잔재 2곳(§11).
|
||
- 유지 필요성: REQUIRED. 단, `default`/`outline` alias는 LEGACY(호환 목적이며 소비처가 정리되면 제거 후보).
|
||
|
||
**Input** — `input.tsx`
|
||
- 추가: `size="small|medium|large"`(기본 large). 네이티브 `size`(문자 폭) 속성은 `Omit`으로 가려져 **사용 불가**.
|
||
- Public API 영향: 있음, 네이티브 속성 가림. 대체: `className` 높이 지정(2축 상태 규칙은 불가). 유지 REQUIRED. Risk LOW.
|
||
|
||
**Textarea** — `textarea.tsx`
|
||
- 추가: `resize="vertical|none|both"`(기본 vertical)를 `data-resize`로 노출. readonly→none은 CSS에서 처리.
|
||
- 대체: `className="resize-none"` 등. 기본 정책을 컴포넌트가 갖게 하려는 목적이라 단순화 가능. CAN_SIMPLIFY, Risk LOW.
|
||
|
||
**Card** — `card.tsx`
|
||
- 추가: `surface="surface|content"`(`data-surface`). `size="sm"`은 shadcn 기존 API.
|
||
- 유지 REQUIRED(ui_viz Content Card 면 구분). Risk LOW.
|
||
|
||
**Select** — `select.tsx`, `theme/select.css` (size 계약 구현됨; 구조 선택은 아래 UNDER_REVIEW)
|
||
- 추가(조사 시점 코드):
|
||
- `SelectTrigger`의 `size="medium|large"`(shadcn `sm|default` 대체), `data-size`.
|
||
- `SelectSizeContext` + `Select` Root를 Provider로 감싸 `useState`로 size 보관, Trigger가 `useLayoutEffect`로 등록. Portal 안의 `SelectContent`가 `data-size`를 읽는다. 즉 **Root가 shadcn처럼 순수 `SelectPrimitive.Root`가 아니라 Provider 래퍼**다.
|
||
- 아이콘을 Radix 기본 대신 18×18 SVG로 교체, `SelectItem`의 check indicator 제거(선택 표시는 배경 면), `SelectContent` 기본값 `position="popper"`, `sideOffset=-1`(border 1px 공유 seam).
|
||
- long text ellipsis와 seam(`--hm-select-seam-color`)은 CSS 처리(`select.css`).
|
||
- Public API 영향: `size` prop(Public). Context·`setSize`는 노출되지 않는 Internal.
|
||
- 대체 가능한 shadcn 방식: shadcn은 Content가 `size`를 몰라도 되게 Trigger 쪽만 `data-size`를 둔다. Content까지 size 연동이 필요한 이유가 Portal 때문이므로 대안은 (a) Content에도 `size` prop을 직접 전달, (b) CSS만으로 처리, (c) 현 Context 유지. **어느 쪽이 맞는지 결정되지 않았다.**
|
||
- 유지 필요성: UNDER_REVIEW. Risk MEDIUM(Root 래퍼 + 렌더 후 `useLayoutEffect`로 state를 갱신하는 구조라, 첫 렌더에서 Content가 기본 `large`로 보일 수 있는 타이밍 의존이 있음).
|
||
- 이 항목은 Final Spec이 아니다.
|
||
|
||
**Tabs** — `tabs.tsx`, `theme/tabs.css`
|
||
- 추가:
|
||
- `TabsList`에 `fill`(동일 폭·초록 선택 border·곡선 연결)과 `panelSurface="surface|content"` prop.
|
||
- `TabsList`가 Radix List를 `<div data-slot="tabs-frame">`로 **한 겹 감싼다**(DOM 구조 변경).
|
||
- 넘침 감지(`ResizeObserver`, `MutationObserver`, scroll 리스너, `document.fonts.ready`), 이전/다음 이동 버튼(`aria-label` 한국어 고정), 선택 탭 가시 유지(`keepSelectedVisible`), `prefers-reduced-motion` 분기, `useId`로 List id 생성, 외부 `ref` 병합.
|
||
- 연결 곡선은 `tabs.css`의 `::before/::after` + `radial-gradient`(HM 고유 구조 CSS).
|
||
- Public API 영향: `fill`, `panelSurface`(Public). 나머지는 Internal.
|
||
- 대체: shadcn Tabs는 위 기능이 전혀 없다. 넘침 버튼 없이 가로 스크롤만 허용하는 단순화는 가능하나 ui_viz D-090 규격을 포기해야 한다.
|
||
- 유지 REQUIRED. **Risk HIGH**: 원본 `TabsList` 구조를 크게 바꿨고 Observer 기반 로직과 한국어 문구가 컴포넌트 안에 있다.
|
||
- 2026-10-06: 대표 형태를 Primary(`fill` + `panelSurface="content"`)·Secondary(`fill` + `panelSurface="surface"`) 두 가지로 정리했다. Story 노출만 줄였고 코드·API·CSS branch는 그대로라 **Custom complexity 변화 없음**. non-fill branch는 REMOVE_CANDIDATE(사용자 확정 대기).
|
||
- 2026-10-08 추가 개선 E 승인: 당시 `fill=false`, `panelSurface="surface"` 기본값을 현재 `fill=true`, `panelSurface="content"`(Primary)로 변경했다. Props 이름·타입·기존 CSS 디자인 값·선택자·Observer 동작은 유지하므로 **Custom complexity 변화 없음**. Legacy non-fill은 `fill={false}`로 유지하고 OLD_TEST_ONLY / REMOVE_CANDIDATE 삭제 대기 이력도 보존한다. 외부 기본 렌더링·명시적 Props 조합·CSS Override 영향은 [Tabs 문서 §15](../components/tabs.md#15-외부-소비자-영향--호환성-2026-10-08)를 따른다. 외부 소비자 전체 호환성은 미검증이다.
|
||
|
||
**Dialog / Sheet / Drawer** — `dialog.tsx`, `sheet.tsx`, `drawer.tsx`
|
||
- 추가(Public): `DialogBody`, `SheetBody`, `DrawerBody` — 스크롤 소유 영역(Header/Footer 고정, Body만 스크롤). shadcn에는 없는 구조 API.
|
||
- 추가(Internal): `*Close`가 `asChild`일 때 `data-slot`을 넘기지 않는 규칙(§7 I3).
|
||
- Drawer 추가: `autoFocus` 기본값을 `true`로(vaul 기본은 `false`라 modal에서 포커스가 trigger에 남음). 소비자가 `autoFocus={false}`로 되돌릴 수 있다 → Public 동작 차이.
|
||
- `showCloseButton`, `side`는 shadcn 기존 API(Custom 아님). Radius·shadow 등은 HM_THEME.
|
||
- 대체: Body는 `className`이 붙은 `div`로 대체 가능하나 `data-slot` 기반 CSS 선택이 사라진다. REQUIRED, Risk LOW.
|
||
|
||
**Alert Dialog** — `alert-dialog.tsx`
|
||
- 추가: `AlertDialogAction`/`AlertDialogCancel`이 `variant|appearance|size`를 받고 `Button asChild`로 합성. 기본값 Action=`primary/solid`, Cancel=`cancel/solid`. shadcn도 Button 스타일을 입히지만 `appearance`는 HM 전용.
|
||
- REQUIRED, Risk LOW.
|
||
|
||
**Combobox** — `combobox.tsx`
|
||
- shadcn에는 파일이 아닌 recipe(Popover+Command)만 있고 HM은 이를 **`options` 기반 컴포넌트**로 만들었다. Public: `options`(value/label/disabled), `value/defaultValue/onValueChange`, `placeholder/searchPlaceholder/emptyText`, `size="medium|large"`. State: `open`, 비제어용 `inner`(제어/비제어 분기 직접 구현). 한국어 기본 문구 포함.
|
||
- 대체: Popover+Command를 소비자가 직접 조합(shadcn 방식). REQUIRED(서비스 공통 필요), Risk LOW(원본 파일이 없어 업스트림 충돌 없음).
|
||
- 내부: `PopoverContent`에 인라인 `--hm-popover-padding/width` 주입 → CAN_SIMPLIFY(§11).
|
||
|
||
**Date Picker** — `date-picker.tsx`
|
||
- 같은 성격. Public: `value/defaultValue/onValueChange`, `placeholder`, `size`, `format`, `calendarProps`(Calendar 옵션 일부). 제어/비제어 상태 직접 구현. Behavior: `onOpenAutoFocus`에서 Calendar의 tab stop 날짜로 포커스 이동(Internal). 한국어 기본 포맷.
|
||
- 대체: Popover+Calendar 직접 조합. REQUIRED, Risk LOW.
|
||
|
||
**Popover / Collapsible** — `popover.tsx`, `collapsible.tsx`
|
||
- `PopoverClose`, `CollapsibleTrigger`의 `asChild` data-slot 규칙만 추가(§7 I3). Risk LOW.
|
||
|
||
**Slider** — `slider.tsx`
|
||
- 추가: `aria-label`을 Root가 아니라 **각 Thumb**에 전달(Range는 `"라벨 1/2"`). `role="slider"`가 Thumb에 있기 때문. Internal. shadcn 원본에는 없음. REQUIRED(접근성), Risk LOW.
|
||
|
||
## 5. Components — HM_THEME / SHADCN_BASE
|
||
|
||
`.tsx`에 HM 구조·API·State 추가가 없는 Component. 시각 값은 각 Component 문서가 관리한다.
|
||
|
||
**SHADCN_BASE (16)**: Accordion, Alert, Aspect Ratio, Avatar, Badge, Breadcrumb, Checkbox, Hover Card, Label, Progress, Radio Group, Scroll Area, Separator, Skeleton, Switch, Tooltip
|
||
|
||
**HM_THEME (13)**: Calendar, Carousel, Command, Context Menu, Dropdown Menu, Menubar, Navigation Menu, Pagination, Resizable, Sonner, Table, Toggle, Toggle Group
|
||
|
||
참고(Custom으로 보지 않은 이유):
|
||
|
||
- Alert·Badge: 사용 가능한 `variant`를 HM Theme에 있는 의미로 **줄였다**(Alert=default/destructive, Badge=4종). API 축소이며 추가가 아니다.
|
||
- Calendar: 기본 `locale`을 한국어(`ko`)로 두었다. shadcn도 `Chevron` 컴포넌트를 교체한다. 기본값 하나의 차이라 THEME로 둔다.
|
||
- Command: shadcn의 `CommandDialog`가 **없다**(의도적 제외, 코드 주석 명시). 기능 제거이며 추가 Custom 아님.
|
||
- Toggle Group: shadcn 그대로 Context를 쓰며 `spacing`을 CSS 변수(`--hm-toggle-group-gap`)로 넘기는 한 줄이 추가됐다.
|
||
- Carousel: shadcn 원본 로직(Context, Embla, 키보드)이 그대로다.
|
||
- Tooltip: 원본처럼 `Tooltip`이 자체 `TooltipProvider`를 가진다(shadcn v4).
|
||
|
||
## 6. Patterns — HM_COMPOSITION
|
||
|
||
`packages/ui/src/patterns/`. 모두 기존 HM Component의 조합이며 별도 primitive가 아니다. 전부 shadcn에 없는 **Public API**다(Pattern 이름 자체).
|
||
|
||
| Pattern | Composition | Custom Logic | Public API |
|
||
|---|---|---|---|
|
||
| GNB | Navigation Menu, Dropdown Menu, Avatar, Sheet, Button | 있음: `GNBMobileMenu`(open state, Context, Sheet 합성), `GNBMobileLink`가 `preventDefault`된 클릭에도 Sheet를 닫음, `GNBUser` 기본 `aria-label` | `GNB`(`sticky`), `GNBBrand`, `GNBNav`, `GNBUtilities`, `GNBUser`, `GNBMobileMenu`, `GNBMobileLink`, `GNBMobileGroup` |
|
||
| LNB | Collapsible, Slot | 없음(`LNBGroup`은 Collapsible 합성) | `LNB`, `LNBBrand`, `LNBNav`, `LNBItem`, `LNBGroup`, `LNBProfile` |
|
||
| Dashboard Layout | 현재는 Dashboard 내부 Header/Menu/Sidebar 조합만 허용 | 없음(레이아웃) | `DashboardLayout`(`header`, `sidebar`), `DashboardMain`, `DashboardContent` |
|
||
| Page Header | Breadcrumb·Button을 child로 받음 | 없음 | `PageHeader`, `PageHeaderContent/Title/Description/Actions` |
|
||
| Loading Screen | 없음(자체 요소) | 24개 막대 렌더, CSS 애니메이션·reduced-motion, `role="status"` | `LoadingScreen`(`fullscreen`) |
|
||
| Filter Bar | Input, Select·Combobox·Date Picker·Button을 child로 받음 | 있음: `FilterBarSearch`(검색 아이콘 + Input + 지우기 버튼, `aria-label` 기본값) | `FilterBar`, `FilterBarSearch`, `FilterBarActions` |
|
||
| Data Table | Table, Checkbox, Dropdown Menu, Pagination, Select, Skeleton, Button + TanStack Table v9 | 있음: 기능(feature) 등록, `useDataTable`, `dataTableSelectColumn`, `DataTableColumnHeader`(정렬 순환·`aria-sort`), `DataTableViewOptions`, `DataTablePagination`(`pageRange`), loading/empty 상태 | `DataTable`, `useDataTable`, `dataTableSelectColumn`, `DataTableColumnHeader`, `DataTableViewOptions`, `DataTablePagination` |
|
||
|
||
CSS 자체가 구조를 구현하는 항목(HM 고유): GNB 아래쪽 concave join과 current 항목 연결 곡선(`gnb.css`), LNB와 콘텐츠 join(`lnb.css`, `--hm-lnb-join`), Loading Screen 막대 애니메이션(`loading-screen.css`). 각 Navigation Mode는 독립 레이아웃을 소유하며 Dashboard에 외부 GNB/LNB를 넣지 않는다.
|
||
|
||
과거 조사에서는 GNB+LNB 동시 조립과 Brand ownership을 기록했으나 현재 단일 Navigation 정책으로 대체되었다. 혼합 Story는 기술 검증 목적의 `verification` 태그와 **VERIFICATION ONLY** 표시가 있을 때만 유지할 수 있으며 운영 Reference로 사용하지 않는다(`docs/patterns/gnb.md`, `lnb.md`).
|
||
|
||
## 7. Internal Custom
|
||
|
||
consumer에게 노출되지 않는 내부 구현. 6건.
|
||
|
||
| # | 항목 | 위치 | 평가 | Risk |
|
||
|---|---|---|---|---|
|
||
| I1 | Select size Context + `useLayoutEffect` 등록 (**작업 중일 수 있음**) | `select.tsx` | UNDER_REVIEW | MEDIUM |
|
||
| I2 | Tabs 넘침 측정(Observer·scroll·state) 과 이동 버튼 | `tabs.tsx` | REQUIRED | HIGH |
|
||
| I3 | `asChild` 시 `data-slot`을 child에 남기는 규칙(Dialog/Sheet/Drawer/Popover/Collapsible의 Close·Trigger, Button의 `data-slot` 후순위 배치) | 여러 파일 | REQUIRED | LOW |
|
||
| I4 | Slider thumb별 `aria-label` 전달 | `slider.tsx` | REQUIRED | LOW |
|
||
| I5 | Date Picker `onOpenAutoFocus` 날짜 포커스 | `date-picker.tsx` | REQUIRED | LOW |
|
||
| I6 | Combobox·Date Picker의 `PopoverContent` 인라인 `--hm-popover-*` 변수 | `combobox.tsx`, `date-picker.tsx` | CAN_SIMPLIFY | LOW |
|
||
|
||
## 8. Public API Custom
|
||
|
||
shadcn 원본에 없는 consumer-facing 확장. Component 12건 + Pattern 전체(§6).
|
||
|
||
| # | Component | HM API | shadcn 원본 | Risk |
|
||
|---|---|---|---|---|
|
||
| P1 | Button | `variant`(역할 5종+alias), `appearance` | `variant` 값이 다름 | MEDIUM |
|
||
| P2 | Input | `size="small|medium|large"` | 네이티브 `size` 가림 | LOW |
|
||
| P3 | Textarea | `resize` | 없음 | LOW |
|
||
| P4 | Card | `surface` | 없음(`size`는 있음) | LOW |
|
||
| P5 | SelectTrigger | `size="medium|large"` (**작업 중일 수 있음**) | `sm|default` | MEDIUM |
|
||
| P6 | TabsList | `fill`, `panelSurface` (+ 프레임 DOM) | 없음 | HIGH |
|
||
| P7 | Dialog | `DialogBody` | 없음 | LOW |
|
||
| P8 | Sheet | `SheetBody` | 없음 | LOW |
|
||
| P9 | Drawer | `DrawerBody`, `autoFocus` 기본 `true` | 없음 / vaul 기본 `false` | LOW |
|
||
| P10 | AlertDialogAction / Cancel | `appearance` (`variant`·`size` 포함) | `appearance` 없음 | LOW |
|
||
| P11 | Combobox | `options` 등 전체 API | 파일 없음(recipe) | LOW |
|
||
| P12 | Date Picker | `format`, `calendarProps` 등 전체 API | 파일 없음(recipe) | LOW |
|
||
|
||
## 9. Storybook-only Custom (`STORY_ONLY`)
|
||
|
||
Production Custom 목록에 포함하지 않는다. 4묶음.
|
||
|
||
| 묶음 | 위치 | 내용 |
|
||
|---|---|---|
|
||
| StateBoard helper | `src/components/story-board.tsx` | `BoardState`(`note`, `noteAfter`, `wide`), `StateBoard`. 39개 Story 파일이 사용 |
|
||
| 고정 상태·검증 Story | `src/components/*.stories.tsx`, `src/patterns/*.stories.tsx` | `States`, `StandardStates`, `ListSizeComparison` 등 비교·검증용 export. 전수 검토하지 않았음 |
|
||
| 샘플 데이터 | `src/patterns/sample-users.ts` | Data Table Story용 |
|
||
| Demo / CENTER Story | `src/hm-theme.css`, `src/theme/preview.ts`, `src/center/*` | Demo 스타일, preview 설정, `center-graphic` 전용 Story(UI 규격과 분리) |
|
||
|
||
## 10. External Library Base
|
||
|
||
| Library | 사용처 | 구분 |
|
||
|---|---|---|
|
||
| `radix-ui` | 대부분의 primitive | Base. Custom은 §4 |
|
||
| `class-variance-authority` | Button, Badge, Alert, Toggle | shadcn 구조. Button만 CVA 정의를 HM 값으로 교체 |
|
||
| `cmdk` | Command, Combobox | Library Base + HM Theme (Combobox는 HM_CUSTOM 합성) |
|
||
| `vaul` | Drawer | Library Base + HM Custom(`DrawerBody`, `autoFocus` 기본값) |
|
||
| `embla-carousel-react` | Carousel | Library Base + HM Theme (shadcn 로직 그대로) |
|
||
| `react-resizable-panels` | Resizable | Library Base + HM Theme |
|
||
| `react-day-picker` | Calendar, Date Picker | Library Base + HM Theme (Date Picker는 HM_CUSTOM 합성) |
|
||
| `sonner` | Sonner(Toast) | Library Base + HM Theme |
|
||
| `@tanstack/react-table` v9 | Data Table | Library Base + HM Composition (v9 feature 등록 방식) |
|
||
| `lucide-react` | 아이콘 전반 | shadcn 기본 |
|
||
|
||
## 11. CAN_SIMPLIFY 후보
|
||
|
||
평가만 한다. 변경은 하지 않았다.
|
||
|
||
| 항목 | 단순화 방향 | 비고 |
|
||
|---|---|---|
|
||
| Textarea `resize` (P3) | `className`(`resize-none` 등)로 대체 가능 | 기본 정책을 컴포넌트에 두려는 의도라면 유지 |
|
||
| Combobox·Date Picker 인라인 `--hm-popover-*` (I6) | CSS 선택자·`data-slot`으로 이동 | |
|
||
| `dark:` 잔재 | 현재 `button.tsx` 2개 행에만 남아 있고 `select.tsx`에는 없다. 기존 upstream `dark:` 분기는 보존할 수 있으며 새 HM Dark 분기는 추가하지 않는다 | HM_CUSTOM이 아니라 shadcn 원본 잔재. 정리 후보 |
|
||
|
||
## 12. UNDER_REVIEW / LEGACY
|
||
|
||
| 항목 | 상태 | 비고 |
|
||
|---|---|---|
|
||
| Select `size` Context (P5 + I1) | UNDER_REVIEW | 조사 당시 미결 설계 평가. 대안은 §4.1 Select 참조. 현재 작업 중이라는 뜻이 아니며 현재 API는 Select 문서·코드를 따른다 |
|
||
| Button `default`/`outline` alias (P1) | LEGACY | shadcn 호환용. 소비처 사용 여부 미확인 |
|
||
|
||
## 13. 유지 원칙
|
||
|
||
1. HM_THEME·SHADCN_BASE는 CSS/Token만 바꾼다. `.tsx`에 구조·상태를 추가하려면 `shadcn-기반-구현-원칙.md` §6의 Custom 허용 조건과 기록 요건을 확인하고 이 문서에 행을 추가한다.
|
||
2. shadcn 재생성·업데이트 시 우선 확인 순서: **Tabs → Button → Select → 나머지 Body/Close 규칙(I3)**. 이 파일들은 덮어쓰지 않고 수동 병합한다.
|
||
3. `data-slot`을 child에 남기는 규칙(I3)은 새 `asChild` 지원 컴포넌트에도 같은 방식으로 적용한다.
|
||
4. 새 Pattern은 §6 표에 "Composition / Custom Logic / Public API"를 한 행으로 기록한다.
|
||
5. 이 문서의 수치는 조사 시점(2026-10-06) 기준이다. Select 설계 평가가 변경되면 §4·§7·§8·§12를 함께 갱신한다.
|
||
|
||
## 2026-10-06 Theme infrastructure
|
||
|
||
Default/External 동일 Runtime 계약, 패키지 theme API, Semantic/팔레트 연결과 Accent derived 공통화는 HM_THEME / Theme infrastructure다. Component DOM/props/state/Portal/breakpoint를 바꾸지 않았으므로 위 HM_CUSTOM Inventory 수를 늘리지 않는다. 상세: [Runtime Theme](runtime-theme.md).
|
||
|