@hjmds/design-contracts 1.28.1 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/catalog.d.ts +486 -0
  2. package/dist/catalog.d.ts.map +1 -1
  3. package/dist/catalog.js +154 -105
  4. package/dist/catalog.js.map +1 -1
  5. package/dist/component-definitions.d.ts +21 -109
  6. package/dist/component-definitions.d.ts.map +1 -1
  7. package/dist/component-definitions.js +9 -109
  8. package/dist/component-definitions.js.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/screen-patterns.d.ts +58 -1
  14. package/dist/screen-patterns.d.ts.map +1 -1
  15. package/dist/screen-patterns.js +31 -0
  16. package/dist/screen-patterns.js.map +1 -1
  17. package/dist/showcase.d.ts.map +1 -1
  18. package/dist/showcase.js +7 -0
  19. package/dist/showcase.js.map +1 -1
  20. package/dist/version.d.ts +1 -1
  21. package/dist/version.js +1 -1
  22. package/dist/version.js.map +1 -1
  23. package/docs/architecture.md +18 -0
  24. package/docs/generated/component-maturity.md +29 -7
  25. package/docs/generated/renderer-evidence.json +4056 -1741
  26. package/docs/generated/renderer-evidence.md +237 -193
  27. package/docs/generated/showcase-manifest.json +1525 -6
  28. package/docs/screen-patterns.md +8 -1
  29. package/docs/stable-core.md +22 -0
  30. package/docs/usage/README.md +24 -24
  31. package/docs/usage/SELECTION.md +1 -1
  32. package/docs/usage/components/auth-screen-layout.md +1 -0
  33. package/docs/usage/components/dialog.md +1 -1
  34. package/docs/usage/components/editor-screen.md +1 -1
  35. package/docs/usage/components/field.md +1 -1
  36. package/docs/usage/components/icon-button.md +1 -0
  37. package/docs/usage/components/screen-layout.md +7 -3
  38. package/docs/usage/components/search-field.md +1 -1
  39. package/docs/usage/components/sheet.md +1 -1
  40. package/docs/usage/components/text-area.md +1 -1
  41. package/package.json +2 -1
@@ -5,7 +5,14 @@
5
5
  사용자가 로그인·설정·알림·채팅 화면을 미리 일반화해 개발 생산성을 높이도록 요청했다.
6
6
  기존 AuthScreenLayout, Section, ListRow, TopBar, Layout, EmptyState, action-session,
7
7
  NotificationBell과 두 renderer의 exports를 비교했다. 새 primitive catalog를 늘리는 대신
8
- `@hjmds/react/screens`, `@hjmds/react-native/screens`의 supplemental 화면 조합으로 제공한다.
8
+ `@hjmds/react/screens`, `@hjmds/react-native/screens`의 화면 조합으로 제공한다.
9
+
10
+ 2026-10-17 카탈로그 등록: 처음에는 동결된 catalog를 늘리지 않으려고 supplemental로 분류했으나, 소비 앱 검사기가 canonical id로만
11
+ 심볼을 해석해 여섯 제품의 미해석 finding 690건 중 606건(88%)이 이 화면 조합이었다(app-portfolio
12
+ `docs/design/STANDARD_SCOPE_REVIEW_2026-10.md` §1.2). 같은 날 동결이 종료돼([승격 기준](stable-promotion.md)) 22종을 canonical
13
+ 행으로 등록했다. 양 surface `beta`이며 renderer 증거의 누락 시나리오(`webScenarioGaps`·`nativeScenarioGaps`)와 Native
14
+ `OnboardingScreen` claim 부재(마운트 시 `ScrollView.scrollTo` 호출이 테스트 host에 없음)는 승격 부채다. 소비 앱은 `optionalBetaAdoptions`로
15
+ 채택을 기록한다.
9
16
 
10
17
  ## 현재 제품에서 확인한 반복과 차이
11
18
 
@@ -1,5 +1,27 @@
1
1
  # Stable Core
2
2
 
3
+ ## 2026-10-18 화면·구성 22종 승격
4
+
5
+ ScreenLayout, CompositionLayout, SettingsScreen, SearchScreen, EditorScreen, PermissionScreen,
6
+ OnboardingScreen, ModerationScreen, ChatScreen, NotificationInboxScreen, CommentThreadScreen,
7
+ ListDetailScreen, MediaSelectionScreen, ProfileScreen, ChatMessage, NotificationRow, NotificationItem,
8
+ CommentThreadRow, ProfileSummary, IconTile, MessageComposer, PhotoSourceSheet의 계약과 Web·Native
9
+ surface를 stable로 올렸다. 이름과 기존 id는 유지한다.
10
+
11
+ 인계된 default/evidence 통과 결과를 재사용하고, 이번 작업에서 해당 행의 환경 매트릭스를 실행했다.
12
+ 함께 확인한 Chart·ImageChoiceGroup을 포함해 Web 118건, Native 109건과 별도 Onboarding·Pagination·DataTable·Chart
13
+ 관련 Native 검사 20건이 통과했다. 최대 글자 조건은 사용자 지침에 따라 실행하지 않았다.
14
+ ScreenLayout의 포커스 가능한 본문 이름, ListRow 계열 fixture의 계약상 부모 여백, Native host API 모델과
15
+ DataTable RTL 들여쓰기·정렬을 바로잡았다. contracts component-references 13건과 Web preview 3건·Native registry 1건,
16
+ 세 패키지 build와 두 Showcase 타입 검사도 통과했다. 제품 수나 별도 승인 절차를 조건으로 추가하지 않았다.
17
+
18
+ 기기 QA·npm 게시·소비 앱 적용은 이번 결과가 아니다. Chart·ImageChoiceGroup과 Native Pagination·DataTable의
19
+ 기존 beta 상태는 이번 22종 승격 범위 밖이므로 유지했다.
20
+
21
+ 기존 별개 Storybook 정적 문제는 미해결이다: Web `showcase/web/src/patterns/CommonChat.stories.tsx` 및
22
+ Native `showcase/native/src/CommonChat.stories.tsx`의 Group 스토리 순서(S4), Web `showcase/web/src/patterns/ShortcutRecorder.stories.tsx`의
23
+ 플랫폼 전용 항목 차이 기록(S6). canonical 등록·S9 누락은 없으며 이 세 건을 전체 Storybook 검사 통과로 보고하지 않는다.
24
+
3
25
  ## 2026-09-30 선택형 상호작용 어댑터·Liquid Toast 승격
4
26
 
5
27
  `sortable`·`swipe-actions`·`content-transition`·`carousel-motion`·`celebration`(Web·Native)과 Native Liquid Toast를
@@ -6,7 +6,7 @@
6
6
  버튼 위치에서 시작해 구성·컴포넌트 지침으로 내려가고, 값은 토큰 지침에서 고른다.
7
7
  [선택 기준](SELECTION.md)으로 그대로 사용·공개 슬롯 확장·공통 API 보완·제품 고유 기능 연결을 고른다. 설치 버전의 지침을 본다: `node_modules/@hjmds/design-contracts/docs/usage/`.
8
8
  제공 기준은 확인한 기본 API 버전이며 최초 출시 버전이 아니다. 구성·화면은 각 API 지침의 제공 버전을 확인한다.
9
- API 안정성은 1.26.1의 생성 manifest에서 읽은 정규(canonical) API 기준이다. 동반·선택형 확장은 개별 계약을 확인한다.
9
+ API 안정성은 1.29.0의 생성 manifest에서 읽은 정규(canonical) API 기준이다. 동반·선택형 확장은 개별 계약을 확인한다.
10
10
  Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품 반영을 의미하지 않는다.
11
11
  `분류`는 Storybook 제목 `<배포|실험>/<단계>/<분류>/<항목>`의 셋째 마디이고, 토큰·구성·화면은 Storybook 메뉴와 같은 순서다.
12
12
 
@@ -43,7 +43,7 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
43
43
  | [AspectRatio](components/aspect-ratio.md) | 레이아웃 | 이미지·동영상·지도처럼 늦게 로드되는 매체의 자리를 미리 잡아 레이아웃 흔들림을 막을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
44
44
  | [Asset](components/asset.md) | 데이터 표시 | 아이콘·이미지·Lottie·비디오를 같은 크기·모서리 규칙의 액자에 넣을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
45
45
  | [AuthProviderButton](components/auth-provider-button.md) | 동작 | Google·Kakao·Naver·Apple 소셜 로그인 버튼에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
46
- | [AuthScreenLayout](components/auth-screen-layout.md) | 레이아웃 | 로그인·가입 진입 화면의 배치에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
46
+ | [AuthScreenLayout](components/auth-screen-layout.md) | 레이아웃 | 로그인·가입 진입 화면의 배치에 쓴다. | 1.12.1 (`safeAreaBottom`·링크 `target`/`rel`/`accessibilityHint` 1.28.1) | Web · Native | Web stable / Native stable | 배포 |
47
47
  | [Avatar](components/avatar.md) | 데이터 표시 | 사람·계정을 사진 또는 이니셜로 나타낼 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
48
48
  | [Badge](components/badge.md) | 데이터 표시 | 항목의 상태나 분류를 짧은 글자 하나로 붙일 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
49
49
  | [BezierEditor](components/bezier-editor.md) | 구성/직접 조작과 모션 | CSS `cubic-bezier` 이징 네 좌표를 슬라이더로 편집하고 곡선과 움직임 미리 보기를 함께 보여 줄 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
@@ -57,8 +57,8 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
57
57
  | [Carousel](components/carousel.md) | 데이터 표시 | 한 번에 카드 하나만 보이고 사용자가 순서대로 넘겨 보는 유한한 묶음에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
58
58
  | [Celebration](components/celebration.md) | 구성/직접 조작과 모션 | 목표 달성, 첫 완료처럼 드물게 일어나는 성공 순간에 한 번 터지는 색종이 효과에 쓴다. | 1.12.1 | Web · Native | 개별 API 계약 참조 | 배포 |
59
59
  | [Chart](components/chart.md) | 데이터 표시 | 수치의 흐름·비교·몫·모양·관계를 그림으로 읽게 할 때 쓴다. | 1.21.0 | Web · Native | Web beta / Native beta | 배포 |
60
- | [ChatMessage](components/chat-message.md) | 구성/정보 표시 | DM·대화 타임라인의 메시지 한 개에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
61
- | [ChatScreen](components/chat-screen.md) | 화면/소통 | DM·대화방처럼 헤더, 메시지 타임라인, 하단 작성창으로 이루어진 화면 한 장에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
60
+ | [ChatMessage](components/chat-message.md) | 구성/정보 표시 | DM·대화 타임라인의 메시지 한 개에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
61
+ | [ChatScreen](components/chat-screen.md) | 화면/소통 | DM·대화방처럼 헤더, 메시지 타임라인, 하단 작성창으로 이루어진 화면 한 장에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
62
62
  | [Checkbox](components/checkbox.md) | 입력 | 독립된 예/아니오 하나를 고르는 항목에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
63
63
  | [CheckboxGroup](components/checkbox-group.md) | 입력 | 한 질문에 대한 여러 선택지 중 0개 이상을 고르게 할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
64
64
  | [Chip](components/chip.md) | 입력 | 누를 수 있는 작은 pill이다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
@@ -68,9 +68,9 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
68
68
  | [ColorPicker](components/color-picker.md) | 입력 | 사용자가 콘텐츠 색(라벨 색, 태그 색, 테마 편집기의 사용자 값 등)을 sRGB HEX로 고르는 폼 입력에 쓴다. | 1.12.1 | Web | Web stable / Native unsupported | 배포 |
69
69
  | [Combobox](components/combobox.md) | 입력 | 주어진 목록에서 하나를 고르는데 목록이 길어 입력으로 좁혀야 할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
70
70
  | [CommandPalette](components/command-palette.md) | 오버레이 | ⌘K 스타일로 앱 전체의 **행동**을 검색해 실행하는 모달에 쓴다. | 1.12.1 | Web | Web stable / Native unsupported | 배포 |
71
- | [CommentThreadRow](components/comment-thread-row.md) | — | 가상화 목록(FlatList·가상 스크롤러)처럼 제품이 댓글 목록을 직접 그려야 할 때 댓글 한 행을 그린다. | 1.23.0 | Web · Native | 개별 API 계약 참조 | 실험 |
72
- | [CommentThreadScreen](components/comment-thread-screen.md) | 화면/소통 | 게시물·콘텐츠 아래의 댓글 화면 한 장에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
73
- | [CompositionLayout](components/composition-layout.md) | 화면/설정 | 카드·패널·화면 본문 안의 콘텐츠 묶음에 제목·배지·행동·안내·본문·하단 영역이 필요할 때 쓴다. | 1.23.0 | Web · Native | 개별 API 계약 참조 | 배포 |
71
+ | [CommentThreadRow](components/comment-thread-row.md) | — | 가상화 목록(FlatList·가상 스크롤러)처럼 제품이 댓글 목록을 직접 그려야 할 때 댓글 한 행을 그린다. | 1.23.0 | Web · Native | Web stable / Native stable | 실험 |
72
+ | [CommentThreadScreen](components/comment-thread-screen.md) | 화면/소통 | 게시물·콘텐츠 아래의 댓글 화면 한 장에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
73
+ | [CompositionLayout](components/composition-layout.md) | 화면/설정 | 카드·패널·화면 본문 안의 콘텐츠 묶음에 제목·배지·행동·안내·본문·하단 영역이 필요할 때 쓴다. | 1.23.0 | Web · Native | Web stable / Native stable | 배포 |
74
74
  | [Container](components/container.md) | 레이아웃 | 화면 본문의 최대 폭과 좌우(논리 방향) 여백을 맞출 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
75
75
  | [ContentTransition](components/content-transition.md) | 시각 효과 | 같은 자리의 내용이 상태에 따라 바뀔 때(필터 결과 패널, 단계별 본문) 새 내용이 짧게 나타나도록 감싼다. | 1.12.1 | Web · Native | 개별 API 계약 참조 | 배포 |
76
76
  | [ContextMenu](components/context-menu.md) | 탐색 | Web에서 제품이 소유한 영역(카드·목록 행·캔버스)의 우클릭·길게 누르기·Shift+F10에 명령 목록을 띄울 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native unsupported | 배포 |
@@ -85,7 +85,7 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
85
85
  | [DesignSystemProvider](components/design-system-provider.md) | 기반 기능 | 앱 루트에 한 번 둔다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
86
86
  | [Dialog](components/dialog.md) | 오버레이 | 화면 흐름을 잠시 멈추고 사용자의 주의가 필요한 **짧은 작업**에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
87
87
  | [Divider](components/divider.md) | 레이아웃 | 서로 다른 내용 묶음 사이에 얇은 구분선이 필요할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
88
- | [EditorScreen](components/editor-screen.md) | 화면/콘텐츠 | 글쓰기·프로필 수정처럼 한 화면 전체가 편집 흐름일 때 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
88
+ | [EditorScreen](components/editor-screen.md) | 화면/콘텐츠 | 글쓰기·프로필 수정처럼 한 화면 전체가 편집 흐름일 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
89
89
  | [EffectSurface](components/effect-surface.md) | 시각 효과 | 환영·온보딩·빈 히어로처럼 분위기를 주는 배경이 필요할 때 내용 뒤에 장식 레이어(mesh·glow·grain)를 깐다. | 1.12.1 | Web · Native | 개별 API 계약 참조 | 배포 |
90
90
  | [EmptyState](components/empty-state.md) | 상태와 알림 | 목록이 비었거나 검색 결과가 0건이라 **아직 없음**을 알릴 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
91
91
  | [EventAttendanceCard](components/event-attendance-card.md) | 구성/선택과 필터 | 행사·모임 카드에서 일정, 참석자 수, 참석자 목록을 보여 주고 참석 응답(참석·미정·불참 등)과 캘린더 추가를 실제 요청으로 처리할 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
@@ -101,7 +101,7 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
101
101
  | [HistogramExplorer](components/histogram-explorer.md) | 구성/정보 표시 | 실제 관측값 배열의 분포를 동폭 구간 막대로 보여 주고, 사용자가 구간 수를 바꿔 볼 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
102
102
  | [Icon](components/icon.md) | 글자와 아이콘 | HJM semantic 이름(`search`, `back`, `chevronEnd`, `notifications` 등 43개)으로 고르는 그림 기호에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
103
103
  | [IconButton](components/icon-button.md) | 동작 | 보이는 글자 없이 아이콘만으로 표시하는 행동에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
104
- | [IconTile](components/icon-tile.md) | — | 프로필·런처 격자의 아이콘 위/제목 아래 항목에 쓴다. | 1.26.0 | Web · Native | 개별 API 계약 참조 | 실험 |
104
+ | [IconTile](components/icon-tile.md) | — | 프로필·런처 격자의 아이콘 위/제목 아래 항목에 쓴다. | 1.26.0 | Web · Native | Web stable / Native stable | 실험 |
105
105
  | [Image](components/image.md) | 데이터 표시 | 원본 크기를 아는 사진·차트 이미지를 로드 전에 자리를 잡아 두고, 실패해도 의미를 잃지 않게 보여 줄 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
106
106
  | [ImageChoiceGroup](components/image-choice-group.md) | 화면/계정 | 아바타 얼굴, 프로필 사진, 모음에 넣을 사진처럼 **그림을 보고 고르는** 단일·다중 선택에 쓴다. | 미게시(1.26.1 이후) | Web · Native | Web beta / Native beta | 배포 |
107
107
  | [ImageComparison](components/image-comparison.md) | 데이터 표시 | 같은 좌표와 비율의 두 이미지를 겹쳐 변화량을 비교할 때 쓴다. | 1.14.0 | Web · Native | 개별 API 계약 참조 | 배포 |
@@ -115,34 +115,34 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
115
115
  | [Layout](components/layout.md) | 레이아웃 | 앱의 상시 골격(header · sidebar · main · footer)을 한 번 세울 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
116
116
  | [Link](components/link.md) | 동작 | 사용자가 복사하거나 새 탭으로 열 수 있는 **목적지**로 이동할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
117
117
  | [List](components/list.md) | 데이터 표시 | 이미 다 불러온, 개수가 많지 않은 행들을 이름 있는 목록 하나로 묶을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
118
- | [ListDetailScreen](components/list-detail-screen.md) | 화면/콘텐츠 | 목록 화면에서 한 항목의 상세를 같은 화면 안에서 열고, 뒤로 오면 목록의 입력·스크롤이 그대로 남아야 할 때 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
118
+ | [ListDetailScreen](components/list-detail-screen.md) | 화면/콘텐츠 | 목록 화면에서 한 항목의 상세를 같은 화면 안에서 열고, 뒤로 오면 목록의 입력·스크롤이 그대로 남아야 할 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
119
119
  | [ListRow](components/list-row.md) | 데이터 표시 | 목록의 한 줄에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
120
120
  | [LoadMore](components/load-more.md) | 탐색 | 이미 그린 항목을 그대로 둔 채 목록 끝에서 다음 페이지를 요청하는 footer에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
121
121
  | [Masonry](components/masonry.md) | 레이아웃 | 높이가 서로 다른 카드(사진 피드, 핀보드, 갤러리)를 여러 열에 빈틈없이 쌓을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
122
- | [MediaSelectionScreen](components/media-selection-screen.md) | 화면/콘텐츠 | 고른 사진·영상을 큰 썸네일 격자로 보여 주고, 각 항목의 업로드 상태·재시도·취소·순서 이동·삭제와 "추가"·"완료" 행동을 한 화면에 묶을 때 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
122
+ | [MediaSelectionScreen](components/media-selection-screen.md) | 화면/콘텐츠 | 고른 사진·영상을 큰 썸네일 격자로 보여 주고, 각 항목의 업로드 상태·재시도·취소·순서 이동·삭제와 "추가"·"완료" 행동을 한 화면에 묶을 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
123
123
  | [MediaTransport](components/media-transport.md) | 구성/직접 조작과 모션 | 제품의 실제 오디오·영상 엔진에 재생·일시 정지·유한 길이 탐색 제어를 붙일 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
124
124
  | [Mentions](components/mentions.md) | 입력 | 여러 줄 입력 중 `@`(사람)·`#`(해시태그) 같은 트리거를 치면 후보를 띄우고, 고른 후보를 트리거부터 커서까지 자리에 넣고 공백 하나를 붙이는 입력에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
125
125
  | [Menu](components/menu.md) | 탐색 | 트리거 버튼을 누르면 뜨는 **항목 목록**에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
126
126
  | [Menubar](components/menubar.md) | 탐색 | 데스크톱 Web 앱 상단에 항상 같은 자리에 있는 가로 메뉴 막대(파일·편집·보기)에 쓴다. | 1.12.1 | Web | Web stable / Native unsupported | 배포 |
127
- | [MessageComposer](components/message-composer.md) | 구성/입력과 작성 | 채팅·DM·댓글 입력창에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
128
- | [ModerationScreen](components/moderation-screen.md) | 화면/소통 | 게시물·댓글·사용자 **신고** 화면에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
127
+ | [MessageComposer](components/message-composer.md) | 구성/입력과 작성 | 채팅·DM·댓글 입력창에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
128
+ | [ModerationScreen](components/moderation-screen.md) | 화면/소통 | 게시물·댓글·사용자 **신고** 화면에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
129
129
  | [Notice](components/notice.md) | 상태와 알림 | 화면 흐름 안 **제자리에 남아 있는** 상태 알림에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
130
- | [NotificationInboxScreen](components/notification-inbox-screen.md) | 화면/소통 | 알림함 화면 전체 틀에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
131
- | [NotificationItem](components/notification-item.md) | 구성/정보 표시 | 알림함의 알림 한 행에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
132
- | [NotificationRow](components/notification-row.md) | — | 알림 목록에서 아바타, 유형 배지, 미리보기, 시간, 읽지 않음 표시, 선택적 썸네일을 나란히 배치한다. | 1.26.0 | Web · Native | 개별 API 계약 참조 | 실험 |
130
+ | [NotificationInboxScreen](components/notification-inbox-screen.md) | 화면/소통 | 알림함 화면 전체 틀에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
131
+ | [NotificationItem](components/notification-item.md) | 구성/정보 표시 | 알림함의 알림 한 행에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
132
+ | [NotificationRow](components/notification-row.md) | — | 알림 목록에서 아바타, 유형 배지, 미리보기, 시간, 읽지 않음 표시, 선택적 썸네일을 나란히 배치한다. | 1.26.0 | Web · Native | Web stable / Native stable | 실험 |
133
133
  | [NumberField](components/number-field.md) | 입력 | 범위가 정해진 **정확한 수 하나**를 입력받을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
134
- | [OnboardingScreen](components/onboarding-screen.md) | 화면/소개 | 첫 실행 소개·초기 설정처럼 **몇 단계를 차례로 넘기는 화면**에 쓴다. | 1.14.0 | Web · Native | 개별 API 계약 참조 | 배포 |
134
+ | [OnboardingScreen](components/onboarding-screen.md) | 화면/소개 | 첫 실행 소개·초기 설정처럼 **몇 단계를 차례로 넘기는 화면**에 쓴다. | 1.14.0 | Web · Native | Web stable / Native stable | 배포 |
135
135
  | [OtpField](components/otp-field.md) | 입력 | 문자·메일로 받은 **숫자 인증번호**를 칸 모양으로 입력받을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
136
136
  | [OverviewScreen](components/overview-screen.md) | 레이아웃 | 같은 데이터와 기능을 유지하면서 테마별 행·카드·격자와 도구 배치를 선택하는 목록 화면에 쓴다. | 1.15.0 | Web · Native | 개별 API 계약 참조 | 배포 |
137
137
  | [Pagination](components/pagination.md) | 탐색 | 총 개수(또는 총 페이지 수)가 정해진 결과 집합에서 사용자가 **임의의 페이지로 바로 이동**해야 할 때 Web·Native에서 쓴다. | 1.12.1 | Web · Native | Web stable / Native beta | 배포 |
138
138
  | [PasswordField](components/password-field.md) | 입력 | 비밀번호를 입력받고, 필요할 때만 값을 눈으로 확인하게 할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
139
139
  | [PasswordRulesField](components/password-rules-field.md) | 구성/입력과 작성 | 새 비밀번호 입력 아래에 제품이 정한 규칙의 충족 개수와 규칙별 상태를 함께 보여 줄 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
140
- | [PermissionScreen](components/permission-screen.md) | 화면/소개 | 카메라·위치·알림 같은 권한이 **왜 필요한지 설명하고 다음 행동을 고르게 하는** 화면에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
141
- | [PhotoSourceSheet](components/photo-source-sheet.md) | 구성/선택과 필터 | 사진 버튼 하나에서 **앨범에서 고르기 / 촬영하기**를 고르게 할 때 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
140
+ | [PermissionScreen](components/permission-screen.md) | 화면/소개 | 카메라·위치·알림 같은 권한이 **왜 필요한지 설명하고 다음 행동을 고르게 하는** 화면에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
141
+ | [PhotoSourceSheet](components/photo-source-sheet.md) | 구성/선택과 필터 | 사진 버튼 하나에서 **앨범에서 고르기 / 촬영하기**를 고르게 할 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
142
142
  | [Popover](components/popover.md) | 오버레이 | 트리거에 붙어 뜨는 비모달 표면 안에 **포커스를 받는 임의 콘텐츠**를 둘 때 쓴다. | 1.12.1 | Web | Web stable / Native unsupported | 배포 |
143
143
  | [PricingChoice](components/pricing-choice.md) | 구성/선택과 필터 | 요금제·결제 주기 중 하나를 고르고, 선택한 실제 가격과 혜택을 확인한 뒤 [계속]으로 제품 결제 흐름을 시작할 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
144
- | [ProfileScreen](components/profile-screen.md) | 화면/계정 | 내 프로필(또는 계정) 화면 틀에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
145
- | [ProfileSummary](components/profile-summary.md) | — | 프로필의 아바타·이름·배지·통계 수치·행동을 구성한다. | 1.26.0 | Web · Native | 개별 API 계약 참조 | 실험 |
144
+ | [ProfileScreen](components/profile-screen.md) | 화면/계정 | 내 프로필(또는 계정) 화면 틀에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
145
+ | [ProfileSummary](components/profile-summary.md) | — | 프로필의 아바타·이름·배지·통계 수치·행동을 구성한다. | 1.26.0 | Web · Native | Web stable / Native stable | 실험 |
146
146
  | [Progress](components/progress.md) | 상태와 알림 | 작업이 얼마나 진행됐는지 보여 줄 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
147
147
  | [ProgressiveBlur](components/progressive-blur.md) | 시각 효과 | 스크롤 영역의 바깥에 더 내용이 있음을 알리거나 장식 이미지 가장자리를 흐릴 때 쓴다. | 1.14.0 | Web · Native | 개별 API 계약 참조 | 배포 |
148
148
  | [QRCode](components/qr-code.md) | 데이터 표시 | 문자열(초대 링크, 연결 코드, 결제·체크인 URL)을 다른 기기의 카메라로 스캔하게 할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
@@ -154,14 +154,14 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
154
154
  | [ReplyMessage](components/reply-message.md) | 구성/입력과 작성 | 대화 타임라인의 메시지에 실제 메시지 id를 묶은 답장 동작을 붙일 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
155
155
  | [Result](components/result.md) | 상태와 알림 | 사용자 행동 뒤 흐름이 **끝난** 화면에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
156
156
  | [SavedItemsScreen](components/saved-items-screen.md) | 화면/콘텐츠 | 저장한 이미지·게시물을 컬렉션 표지 → 사진 격자 → 상세 순서로 탐색할 때 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
157
- | [ScreenLayout](components/screen-layout.md) | 화면/화면 틀과 도구 | 한 라우트 화면의 뼈대가 필요할 때 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
157
+ | [ScreenLayout](components/screen-layout.md) | 화면/화면 틀과 도구 | 한 라우트 화면의 뼈대가 필요할 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
158
158
  | [SearchField](components/search-field.md) | 입력 | 목록·화면 안에서 검색어를 입력받을 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
159
- | [SearchScreen](components/search-screen.md) | 화면/검색 | 검색어 입력, 필터, 최근 검색, 결과 목록을 갖춘 검색 화면 전체에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
159
+ | [SearchScreen](components/search-screen.md) | 화면/검색 | 검색어 입력, 필터, 최근 검색, 결과 목록을 갖춘 검색 화면 전체에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
160
160
  | [Section](components/section.md) | 레이아웃 | 화면 안의 내용 묶음에 제목·설명·머리 행동(“모두 보기”, “편집”)을 붙일 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
161
161
  | [SegmentedControl](components/segmented-control.md) | 입력 | 2~4개의 짧은 보기 중 **항상 하나가 선택된** 전환에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
162
162
  | [Select](components/select.md) | 입력 | 폼 한 칸에서 여러 선택지 중 하나를 고르게 할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
163
163
  | [SelectionActionBar](components/selection-action-bar.md) | 구성/선택과 필터 | 목록에서 여러 항목을 고른 뒤 보관·삭제 같은 같은 행동을 한 번에 실행하고, 방금 확정된 작업만 되돌릴 때 쓴다. | 1.21.0 | Web · Native | 개별 API 계약 참조 | 배포 |
164
- | [SettingsScreen](components/settings-screen.md) | 화면/설정 | 앱의 설정 화면 전체에 쓴다. | 1.17.1 | Web · Native | 개별 API 계약 참조 | 배포 |
164
+ | [SettingsScreen](components/settings-screen.md) | 화면/설정 | 앱의 설정 화면 전체에 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
165
165
  | [SharedTransitionElement](components/shared-transition-element.md) | 구성/직접 조작과 모션 | 목록의 카드(사진·썸네일)를 눌러 상세 화면으로 갈 때, 같은 요소가 두 화면 사이에서 확대·축소되어 이어지는 공유 요소 전환에 쓴다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
166
166
  | [SharedTransitionScreen](components/shared-transition-screen.md) | 구성/직접 조작과 모션 | `createHjmTransitionStack()`으로 만든 stack에서 공유 요소 전환을 쓸 때, **각 라우트 본문**을 감싼다. | 1.12.1 | Native | 개별 API 계약 참조 | 배포 |
167
167
  | [Sheet](components/sheet.md) | 오버레이 | 현재 화면 위에 모달로 띄우는 보조 작업 패널에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
@@ -46,7 +46,7 @@
46
46
  | 화면 나가기(뒤로·닫기·설정 나가기) | `ScreenLayout`(과 이를 쓰는 화면)의 `exit` — 헤더 시작 쪽 아이콘 버튼, 글자 없음 | 본문·하단의 "나가기" 글자 버튼, 화면마다 다른 화살표 |
47
47
  | 버튼 묶음 간격 | 세로로 쌓으면 `gap="xs"`(8), 가로로 나란하면 `gap="sm"`(12) — `actionGroupRecipe` | 세로 버튼 사이 12 이상 |
48
48
  | 간격 | `Stack`·`ScreenLayout`·recipe 간격 | 임의 `margin`·빈 `View` |
49
- | 화면 진입 시 입력 포커스 | `ScreenLayout`(과 이를 쓰는 화면)·`Sheet`·`Dialog`의 `initialFocus`, 주 입력 지정은 칸의 `initialFocusTarget`([진입 포커스](components/screen-layout.md#진입-포커스)) | 앱별 `autoFocus`·지연 `ref.focus()`, 대화·댓글 화면의 작성창 자동 포커스 |
49
+ | 화면 진입 시 입력 포커스 | `ScreenLayout`(과 이를 쓰는 화면)·`AuthScreenLayout`·`Sheet`·`Dialog`의 `initialFocus`, 주 입력 지정은 칸의 `initialFocusTarget`([진입 포커스](components/screen-layout.md#진입-포커스)) | 앱별 `autoFocus`·지연 `ref.focus()`·단계 전환·검색 열기 뒤 `ref.focus()`, 대화·댓글 화면의 작성창 자동 포커스 |
50
50
 
51
51
  리뷰 기준: 위 "쓰지 않을 것" 패턴이 보이면 예제 조립 문제인지 컴포넌트 recipe 문제인지 먼저 가리고, 원인 쪽(예제 또는 HJM 컴포넌트)을 고친다.
52
52
 
@@ -79,6 +79,7 @@ import { AuthScreenFooter, AuthScreenHero, AuthScreenLayout } from "@hjmds/react
79
79
  | `pendingLabel` | 문자열 | — | 주면 진행 상태다. 공백만 있으면 `TypeError`. 제거하면 원래 상태로 돌아온다 |
80
80
  | Web `as` | `main` · `section` | `main` | 최대 폭은 416이다 |
81
81
  | `layoutStyle` | margin·width·flex·`alignSelf` | — | 바깥 배치 전용(Web·Native 모두) |
82
+ | `initialFocus` | `first-input` · `none` | `none` | 1.28.2. [ScreenLayout 진입 포커스](screen-layout.md#진입-포커스)와 같은 규칙. 로그인은 제공자 버튼이 주 행동이라 기본 `none`, 가입 닉네임 단계처럼 입력이 주 행동인 `main`만 `first-input`. 닉네임 단계가 같은 화면에서 나중에 나타나면 그 칸에 `initialFocusTarget`을 준다 |
82
83
  | Native `testID` | `string` | — | 뿌리 `ScrollView` 식별 |
83
84
  | Native `safeAreaBottom` | 0 이상의 유한수 | `0` | 화면이 닿는 창 아래 가장자리의 safe area(`useSafeAreaInsets().bottom`, 이미 아래를 들인 host 안이면 0). 아래 여백이 `max(paddingBlock, inset)` — `regular` max(40, inset), `compact` max(20, inset) — 으로 한 번만 들어간다(ScreenLayout과 같은 규칙, 합산 없음). 키보드가 열리면 paddingBlock만. 음수·무한대는 `RangeError` |
84
85
  | `AuthScreenHero` `title` · `eyebrow` · `description` · `mark` · `headingLevel` | 문자열 · `ReactNode` · `1`~`3` | `headingLevel` 1 | 제목은 필수이고 빈 문자열이면 `TypeError`. 밀도는 바깥 `AuthScreenLayout`을 따른다 |
@@ -113,7 +113,7 @@ await handle.closed; // portal 제거·초점 복구 뒤. 다음 오버레이는
113
113
 
114
114
  | prop | 값 | 기본값 | 설명 |
115
115
  | --- | --- | --- | --- |
116
- | `initialFocus` | `single-input` · `first-input` · `none` | `single-input` | 1.28.1. 열린 뒤(Native: 표시·진입 애니메이션 뒤, Web: 포커스 이동 시점) 포커스할 텍스트 입력. 기본은 텍스트 입력이 **하나뿐일 때만** 그 칸(이름 바꾸기·메모 한 줄), 여럿이면 기존 규칙(Web 첫 포커스 가능 요소, Native 접근성 포커스) 그대로. `first-input`은 `initialFocusTarget` 칸, 없으면 첫 칸. `initialFocusRef`(Web)가 있으면 그쪽이 이긴다. 열 때마다 다시 고른다 |
116
+ | `initialFocus` | `single-input` · `first-input` · `none` | `single-input` | 1.28.1. 열린 뒤(Native: 표시·진입 애니메이션 뒤, Web: 포커스 이동 시점) 포커스할 텍스트 입력. 기본은 텍스트 입력이 **하나뿐일 때만** 그 칸(이름 바꾸기·메모 한 줄), 여럿이면 기존 규칙(Web 첫 포커스 가능 요소, Native 접근성 포커스) 그대로. `first-input`은 `initialFocusTarget` 칸, 없으면 첫 칸. `initialFocusRef`(Web)가 있으면 그쪽이 이긴다. 열 때마다 다시 고른다. 1.28.2: 열린 뒤 칸이 늦게 나타나도 조작 전이면 고르고, 단계형 내용은 각 단계 칸에 `initialFocusTarget`을 주면 단계가 바뀔 때 그 칸을 포커스한다(앱의 단계별 `ref.focus()` 대신). 위에 다른 오버레이가 열려 있는 동안은 고르지 않는다 |
117
117
  | `size` | `small` · `medium` · `large` | `medium` | Native recipe 최대 폭 320 · 420 · 640. Web 최대 폭 28rem · 36rem · 48rem(아래 배치 표) |
118
118
  | `dismissible` | `true` · `false` | `true` | `false`면 닫기 버튼과 바깥·Escape/back 닫기가 사라진다 |
119
119
  | `busy` | `true` · `false` | `false` | 비동기 작업 중에는 `open`을 유지하고 `busy`로 반복 행동과 닫기를 막는다 |
@@ -91,7 +91,7 @@ import { TextField } from "@hjmds/react-native/inputs";
91
91
 
92
92
  | prop | 값 | 기본값 | 설명 |
93
93
  | --- | --- | --- | --- |
94
- | `initialFocus` | `first-input` · `none` | `first-input` | 1.28.1. 작성·편집이 화면의 목적이라 진입 후 첫 입력(또는 `initialFocusTarget` 칸)에 한 번 포커스한다. 읽고 고칠 내용이 먼저인 편집은 `none` |
94
+ | `initialFocus` | `first-input` · `none` | `first-input` | 1.28.1. 작성·편집이 화면의 목적이라 진입 후 첫 입력(또는 `initialFocusTarget` 칸)에 한 번 포커스한다. 읽고 고칠 내용이 먼저인 편집은 `none`. 1.28.2: 단계형 작성(제목 → 본문)은 각 단계 칸에 `initialFocusTarget`을 주면 단계가 바뀔 때 그 칸을 포커스한다 |
95
95
  | `dirty` | `boolean` | 필수 | `true`에서 닫기를 누르면 `discard` 확인창을 띄우고, 확인하면 `cancel.onAction`을 부른다. `false`면 바로 부른다 |
96
96
  | `submit` | `ScreenFlowAction`(`{ label, onAction(), disabled?, pending? }`) | 필수 | `pending`이면 loading·비활성. 그동안 닫기 버튼도 비활성. 본문 `state`가 `ready`가 아니면 저장 비활성 |
97
97
  | `cancel` | `ScreenFlowAction` | 필수 | 헤더 시작 쪽 × 아이콘 닫기 버튼(`ScreenLayout` `exit` `close`). `label`은 보조기술 이름이다. 2026-10-17부터 글자 버튼 대신 아이콘 |
@@ -70,7 +70,7 @@ import { Field } from "@hjmds/react-native/forms";
70
70
 
71
71
  | prop | 값 | 기본값 | 설명 |
72
72
  | --- | --- | --- | --- |
73
- | `initialFocusTarget` | `boolean` | — | 1.28.1. 둘러싼 화면·시트가 진입 포커스를 켰을 때 `true`면 이 칸을 고르고, `false`면 절대 고르지 않는다. 생략하면 트리 순서대로 후보다. 비활성·읽기 전용 칸은 고르지 않는다. 앱별 `autoFocus`·지연 `ref.focus()` 대신 쓴다([진입 포커스](screen-layout.md#진입-포커스)). TextField·TextArea·SearchField·PasswordField 공통 |
73
+ | `initialFocusTarget` | `boolean` | — | 1.28.1. 둘러싼 화면·시트가 진입 포커스를 켰을 때 `true`면 이 칸을 고르고, `false`면 절대 고르지 않는다. 생략하면 트리 순서대로 후보다. 비활성·읽기 전용 칸은 고르지 않는다. 1.28.2부터 `true` 칸이 진입 뒤에 나타나면(검색 열기·단계 이동) 모드와 무관하게 그때 포커스한다. 앱별 `autoFocus`·지연 `ref.focus()` 대신 쓴다([진입 포커스](screen-layout.md#진입-포커스)). TextField·TextArea·SearchField·PasswordField 공통 |
74
74
  | `variant`(`TextField`) | `surface` · `inset` | `surface` | — |
75
75
  | `shape`(`TextField`) | `medium` · `large` · `full` | `medium` | — |
76
76
  | `align`(`TextField`) | `start` · `center` | `start` | `center`는 닉네임·코드처럼 짧은 한 값 |
@@ -39,6 +39,7 @@ Dialog·Sheet footer 행동, 목록 끝 "더 보기", 온보딩 다음·이전,
39
39
  | --- | --- | --- | --- |
40
40
  | `IconButton` | 기본 | `@hjmds/react`, `/actions` | `@hjmds/react-native`, `/actions`, `/bottom-cta` |
41
41
  | `NotificationBell` | 확장 — 미확인 수 배지 + 증가 시 한 번 흔들림 | `/notification-bell` | `/notification-bell` |
42
+ | `ClipboardIconButton` | 동반(복사) — 아이콘만 있는 복사 도구 행동. `value`, `labels: { idle; copied }`(두 상태의 접근성 이름), `onCopy?`, `onCopyError?`, `feedbackDuration?`(ms), `tone` 기본 `ghost` | `@hjmds/react`, `/clipboard` | — |
42
43
 
43
44
  `NotificationBell`은 granular subpath로만 import 된다. 추가 peer는 없다.
44
45
 
@@ -104,7 +104,7 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
104
104
 
105
105
  ## 진입 포커스
106
106
 
107
- 2026-10-18 사용자 요청("input이 있는 화면에 진입하면 포커스되도록, 웹앱 둘 다"). 앱마다 `autoFocus`·지연 `ref.focus()`를 붙이던 것을 화면 골격이 맡는다. 입력 칸(TextField·TextArea·SearchField·PasswordField, 작성창의 TextArea)은 가장 가까운 화면·시트 범위에 자신을 등록하고, 범위가 진입 뒤 한 칸을 고른다. 규칙의 정본은 contracts `resolveInitialFocusTarget`·`initialFocusDefaults`(`screen-patterns`)다.
107
+ 2026-10-18 사용자 요청("input이 있는 화면에 진입하면 포커스되도록, 웹앱 둘 다"). 앱마다 `autoFocus`·지연 `ref.focus()`를 붙이던 것을 화면 골격이 맡는다. 입력 칸(TextField·TextArea·SearchField·PasswordField, 작성창의 TextArea)은 가장 가까운 화면·시트 범위에 자신을 등록하고, 범위가 진입 뒤 한 칸을 고른다. 규칙의 정본은 contracts `resolveInitialFocusTarget`·`resolveEntryFocus`·`initialFocusDefaults`(`screen-patterns`)다.
108
108
 
109
109
  | 구성 | 기본값 | 이유 |
110
110
  | --- | --- | --- |
@@ -113,13 +113,17 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
113
113
  | `EditorScreen` | `first-input` | 작성·편집이 화면의 목적 |
114
114
  | `ChatScreen`·`CommentThreadScreen` | `none` | 입력은 읽기의 보조. 키보드가 기록을 가린다. 같은 prop으로 켤 수 있다 |
115
115
  | `Sheet`·`Dialog`·`AlertDialog` | `single-input` | 텍스트 입력이 하나뿐일 때만(이름 바꾸기 등). 여럿이면 기존 포커스 규칙 |
116
+ | `AuthScreenLayout` | `none` | 로그인 화면은 제공자 버튼이 주 행동. 가입 닉네임 단계만 `initialFocus="first-input"`(1.28.2) |
116
117
 
117
118
  - 고르는 순서: `initialFocusTarget` 칸 → 등록(트리) 순서 첫 칸. 비활성·읽기 전용 칸, `initialFocusTarget={false}` 칸은 고르지 않는다.
118
119
  - 시점: Native는 화면·시트 진입 전환이 끝난 뒤(`InteractionManager`, 시트는 표시 뒤) — 키보드 애니메이션이 전환과 겹치지 않는다. Web은 mount 직후, `preventScroll`.
119
- - 빼앗지 않는다: 사용자가 이미 입력 칸에 있으면 그대로 둔다(Native 포커스된 입력, Web 편집 가능한 요소). Web은 열린 모달(`aria-modal`) 밑의 화면 칸을 고르지 않는다.
120
+ - 빼앗지 않는다: 사용자가 이미 입력 칸에 있으면 그대로 둔다(Native 포커스된 입력, Web 편집 가능한 요소).
121
+ - 오버레이 아래(1.28.2, Web·Native): 위에 HJM `Dialog`·`AlertDialog`·`Sheet`가 열려 있으면 아래 화면·시트는 고르지 않는다. Web은 제품 자체 모달(`aria-modal`·`dialog[open]`)도 막는다. Native는 HJM 오버레이만 알 수 있으므로 화면을 덮는 모달은 HJM 오버레이로 만든다.
122
+ - 진입 창(1.28.2): 진입 뒤 아직 포커스하지 못한 범위는 사용자가 그 범위를 직접 조작(Native 터치·스크롤, Web 포인터·키·휠·터치)하기 전까지 열려 있다. 그 동안 ① 칸이 새로 나타나면(데이터 로드 뒤 드러나는 확인 칸) ② 진입 때 위에 있던 오버레이가 닫히면(첫 가입 약관 동의) 다시 고른다. 오버레이 안의 조작(동의 탭)은 아래 화면의 조작으로 세지 않는다. 오버레이가 닫힌 시점은 그 오버레이의 반환 포커스와 같은 시점(Native: 퇴장·dismiss 뒤, Web: 반환 포커스 뒤)이다.
123
+ - 나중에 드러나는 주 입력(1.28.2): 진입이 끝난 뒤 `initialFocusTarget`(`true`) 칸이 새로 mount되면 그 칸을 포커스한다. `initialFocus` 모드와 무관하다 — 검색 버튼으로 여는 검색 칸(`none` 화면), 단계형 시트·`EditorScreen`의 단계 칸(각 단계 칸에 `initialFocusTarget`)이 이 경우다. 다른 입력 칸에 초점이 있거나 위에 오버레이가 있으면 하지 않는다. 스스로 다시 mount되는 칸(가상화 목록 행)에는 주지 않는다.
120
124
  - 다시 진입: 화면은 mount당 한 번이다. 스택에서 돌아온 화면(이미 mount)은 다시 포커스하지 않는다 — 돌아온 맥락을 키보드가 가리고, HJM은 내비게이션 포커스 신호를 모른다. 시트·대화상자는 열 때마다 다시 고른다.
121
125
  - 모션 감소는 애니메이션에만 적용하고 포커스는 그대로 한다.
122
- - 제품은 `autoFocus`·`setTimeout(() => ref.focus())`를 쓰지 않고 `initialFocus`·`initialFocusTarget`으로 표현한다.
126
+ - 제품은 `autoFocus`·`setTimeout(() => ref.focus())`·단계 전환 뒤 `ref.focus()`를 쓰지 않고 `initialFocus`·`initialFocusTarget`으로 표현한다. 검증 실패 칸으로 옮기는 포커스(제출 오류)는 제품의 동작이라 그대로 둔다.
123
127
 
124
128
  ## 꼭 지킬 것
125
129
 
@@ -62,7 +62,7 @@ import { SearchField } from "@hjmds/react-native/inputs";
62
62
 
63
63
  | prop | 값 | 기본값 | 설명 |
64
64
  | --- | --- | --- | --- |
65
- | `initialFocusTarget` | `boolean` | — | 1.28.1. 둘러싼 화면·시트가 진입 포커스를 켰을 때 `true`면 이 칸을 고르고, `false`면 절대 고르지 않는다. 생략하면 트리 순서대로 후보다. 비활성·읽기 전용 칸은 고르지 않는다. 앱별 `autoFocus`·지연 `ref.focus()` 대신 쓴다([진입 포커스](screen-layout.md#진입-포커스)). TextField·TextArea·SearchField·PasswordField 공통 |
65
+ | `initialFocusTarget` | `boolean` | — | 1.28.1. 둘러싼 화면·시트가 진입 포커스를 켰을 때 `true`면 이 칸을 고르고, `false`면 절대 고르지 않는다. 생략하면 트리 순서대로 후보다. 비활성·읽기 전용 칸은 고르지 않는다. 1.28.2부터 `true` 칸이 진입 뒤에 나타나면(검색 열기·단계 이동) 모드와 무관하게 그때 포커스한다. 앱별 `autoFocus`·지연 `ref.focus()` 대신 쓴다([진입 포커스](screen-layout.md#진입-포커스)). TextField·TextArea·SearchField·PasswordField 공통 |
66
66
  | `size` | `medium` · `large` | `medium` | 최소 높이 44 · 52 |
67
67
  | `variant` | `surface` · `inset` | — | — |
68
68
  | `shape` | `medium` · `large` · `full` | `medium` | — |
@@ -78,7 +78,7 @@ import { Sheet } from "@hjmds/react-native/overlays";
78
78
 
79
79
  | prop | 값 | 기본값 | 설명 |
80
80
  | --- | --- | --- | --- |
81
- | `initialFocus` | `single-input` · `first-input` · `none` | `single-input` | 1.28.1. 열린 뒤(Native: 표시·진입 애니메이션 뒤, Web: 포커스 이동 시점) 포커스할 텍스트 입력. 기본은 텍스트 입력이 **하나뿐일 때만** 그 칸(이름 바꾸기·메모 한 줄), 여럿이면 기존 규칙(Web 첫 포커스 가능 요소, Native 접근성 포커스) 그대로. `first-input`은 `initialFocusTarget` 칸, 없으면 첫 칸. `initialFocusRef`(Web)가 있으면 그쪽이 이긴다. 열 때마다 다시 고른다 |
81
+ | `initialFocus` | `single-input` · `first-input` · `none` | `single-input` | 1.28.1. 열린 뒤(Native: 표시·진입 애니메이션 뒤, Web: 포커스 이동 시점) 포커스할 텍스트 입력. 기본은 텍스트 입력이 **하나뿐일 때만** 그 칸(이름 바꾸기·메모 한 줄), 여럿이면 기존 규칙(Web 첫 포커스 가능 요소, Native 접근성 포커스) 그대로. `first-input`은 `initialFocusTarget` 칸, 없으면 첫 칸. `initialFocusRef`(Web)가 있으면 그쪽이 이긴다. 열 때마다 다시 고른다. 1.28.2: 열린 뒤 칸이 늦게 나타나도 조작 전이면 고르고, 단계형 내용은 각 단계 칸에 `initialFocusTarget`을 주면 단계가 바뀔 때 그 칸을 포커스한다(앱의 단계별 `ref.focus()` 대신). 위에 다른 오버레이가 열려 있는 동안은 고르지 않는다 |
82
82
  | `placement` | `bottom` · `start` · `end` | `bottom` | 나오는 가장자리 |
83
83
  | `size` | `auto` · `medium`(60%) · `large`(85%) · `full`(100%) | `auto` | `auto`는 내용 높이. 비율은 화면 높이 기준(Web `dvh`), 두 플랫폼 모두 위 safe area(Native는 키보드도)를 뺀 남은 높이를 넘지 않는다. `maxHeightRatio` 0.9 상한은 `auto`에만 걸린다 |
84
84
  | `open` · `defaultOpen` | `boolean` | 비제어 `false` | Web은 제어하면 `onOpenChange` 필수, 비제어면 `trigger` 필수 |
@@ -62,7 +62,7 @@ import { TextArea } from "@hjmds/react-native/inputs";
62
62
 
63
63
  | prop | 값 | 기본값 | 설명 |
64
64
  | --- | --- | --- | --- |
65
- | `initialFocusTarget` | `boolean` | — | 1.28.1. 둘러싼 화면·시트가 진입 포커스를 켰을 때 `true`면 이 칸을 고르고, `false`면 절대 고르지 않는다. 생략하면 트리 순서대로 후보다. 비활성·읽기 전용 칸은 고르지 않는다. 앱별 `autoFocus`·지연 `ref.focus()` 대신 쓴다([진입 포커스](screen-layout.md#진입-포커스)). TextField·TextArea·SearchField·PasswordField 공통 |
65
+ | `initialFocusTarget` | `boolean` | — | 1.28.1. 둘러싼 화면·시트가 진입 포커스를 켰을 때 `true`면 이 칸을 고르고, `false`면 절대 고르지 않는다. 생략하면 트리 순서대로 후보다. 비활성·읽기 전용 칸은 고르지 않는다. 1.28.2부터 `true` 칸이 진입 뒤에 나타나면(검색 열기·단계 이동) 모드와 무관하게 그때 포커스한다. 앱별 `autoFocus`·지연 `ref.focus()` 대신 쓴다([진입 포커스](screen-layout.md#진입-포커스)). TextField·TextArea·SearchField·PasswordField 공통 |
66
66
  | `variant` | `surface` · `inset` | `surface` | — |
67
67
  | `shape` | `medium` · `large` · `full` | `medium` | — |
68
68
  | `align` | `start` · `center` | `start` | — |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hjmds/design-contracts",
3
- "version": "1.28.1",
3
+ "version": "1.30.0",
4
4
  "description": "Renderer-neutral design contracts, tokens, recipes, and behaviors shared by HJM products.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -801,6 +801,7 @@
801
801
  },
802
802
  "./conversation-row": {
803
803
  "types": "./dist/conversation-row.d.ts",
804
+ "react-native": "./dist/conversation-row.js",
804
805
  "import": "./dist/conversation-row.js",
805
806
  "default": "./dist/conversation-row.js"
806
807
  }