@hjmds/design-contracts 1.14.0 → 1.15.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 (110) hide show
  1. package/dist/design-profile-layout.d.ts +11 -0
  2. package/dist/design-profile-layout.d.ts.map +1 -0
  3. package/dist/design-profile-layout.js +18 -0
  4. package/dist/design-profile-layout.js.map +1 -0
  5. package/dist/design-profile.d.ts +89 -0
  6. package/dist/design-profile.d.ts.map +1 -0
  7. package/dist/design-profile.js +262 -0
  8. package/dist/design-profile.js.map +1 -0
  9. package/dist/design-system-provider.d.ts +6 -0
  10. package/dist/design-system-provider.d.ts.map +1 -1
  11. package/dist/design-system-provider.js +4 -2
  12. package/dist/design-system-provider.js.map +1 -1
  13. package/dist/gooey-navigation.d.ts +19 -1
  14. package/dist/gooey-navigation.d.ts.map +1 -1
  15. package/dist/gooey-navigation.js +37 -2
  16. package/dist/gooey-navigation.js.map +1 -1
  17. package/dist/palette-contrast.d.ts +6 -0
  18. package/dist/palette-contrast.d.ts.map +1 -1
  19. package/dist/palette-contrast.js +17 -0
  20. package/dist/palette-contrast.js.map +1 -1
  21. package/dist/screen-patterns.d.ts +16 -1
  22. package/dist/screen-patterns.d.ts.map +1 -1
  23. package/dist/screen-patterns.js +4 -0
  24. package/dist/screen-patterns.js.map +1 -1
  25. package/dist/toast-liquid.d.ts +3 -1
  26. package/dist/toast-liquid.d.ts.map +1 -1
  27. package/dist/toast-liquid.js +6 -2
  28. package/dist/toast-liquid.js.map +1 -1
  29. package/dist/version.d.ts +1 -1
  30. package/dist/version.js +1 -1
  31. package/dist/version.js.map +1 -1
  32. package/docs/asset.md +7 -0
  33. package/docs/brand-boundary.md +14 -5
  34. package/docs/code-block.md +12 -1
  35. package/docs/collapsible.md +6 -0
  36. package/docs/design-profile.md +263 -0
  37. package/docs/design-system-provider.md +7 -0
  38. package/docs/dialog.md +5 -1
  39. package/docs/generated/component-maturity.md +1 -1
  40. package/docs/generated/renderer-evidence.json +3 -3
  41. package/docs/generated/renderer-evidence.md +1 -1
  42. package/docs/generated/showcase-manifest.json +1 -1
  43. package/docs/gooey-navigation.md +37 -6
  44. package/docs/heading.md +15 -0
  45. package/docs/theming.md +18 -5
  46. package/docs/usage/README.md +5 -0
  47. package/docs/usage/components/activity-heatmap.md +3 -1
  48. package/docs/usage/components/agreement.md +2 -0
  49. package/docs/usage/components/alert-dialog.md +9 -0
  50. package/docs/usage/components/asset.md +9 -2
  51. package/docs/usage/components/badge.md +3 -1
  52. package/docs/usage/components/bottom-cta.md +3 -1
  53. package/docs/usage/components/bottom-navigation.md +5 -1
  54. package/docs/usage/components/button.md +7 -1
  55. package/docs/usage/components/calendar.md +3 -1
  56. package/docs/usage/components/card.md +19 -2
  57. package/docs/usage/components/carousel.md +5 -0
  58. package/docs/usage/components/code-block.md +14 -2
  59. package/docs/usage/components/collapsible.md +10 -2
  60. package/docs/usage/components/combobox.md +12 -1
  61. package/docs/usage/components/command-palette.md +11 -6
  62. package/docs/usage/components/content-transition.md +1 -1
  63. package/docs/usage/components/context-menu.md +7 -1
  64. package/docs/usage/components/date-picker.md +3 -1
  65. package/docs/usage/components/design-system-provider.md +7 -5
  66. package/docs/usage/components/dialog.md +53 -1
  67. package/docs/usage/components/field.md +3 -1
  68. package/docs/usage/components/form.md +7 -2
  69. package/docs/usage/components/heading.md +7 -1
  70. package/docs/usage/components/image.md +2 -0
  71. package/docs/usage/components/list-row.md +2 -0
  72. package/docs/usage/components/list.md +2 -0
  73. package/docs/usage/components/load-more.md +3 -1
  74. package/docs/usage/components/mentions.md +3 -1
  75. package/docs/usage/components/menu.md +3 -1
  76. package/docs/usage/components/menubar.md +7 -1
  77. package/docs/usage/components/message-composer.md +11 -5
  78. package/docs/usage/components/notice.md +9 -0
  79. package/docs/usage/components/number-field.md +3 -1
  80. package/docs/usage/components/onboarding-screen.md +16 -9
  81. package/docs/usage/components/overview-screen.md +73 -0
  82. package/docs/usage/components/password-field.md +5 -1
  83. package/docs/usage/components/popover.md +7 -0
  84. package/docs/usage/components/saved-items-screen.md +3 -1
  85. package/docs/usage/components/screen-layout.md +9 -1
  86. package/docs/usage/components/search-field.md +3 -1
  87. package/docs/usage/components/select.md +9 -0
  88. package/docs/usage/components/sheet.md +14 -1
  89. package/docs/usage/components/skeleton.md +9 -0
  90. package/docs/usage/components/slider.md +3 -1
  91. package/docs/usage/components/statistic.md +3 -1
  92. package/docs/usage/components/surface.md +8 -1
  93. package/docs/usage/components/tabs.md +11 -2
  94. package/docs/usage/components/tag.md +3 -1
  95. package/docs/usage/components/tags-input.md +6 -1
  96. package/docs/usage/components/text-area.md +3 -1
  97. package/docs/usage/components/text-transition.md +8 -2
  98. package/docs/usage/components/text.md +3 -1
  99. package/docs/usage/components/toast.md +18 -1
  100. package/docs/usage/components/top-bar.md +3 -1
  101. package/docs/usage/compositions/command-records.md +106 -0
  102. package/docs/usage/compositions/content-transition-comparison.md +108 -0
  103. package/docs/usage/compositions/date-time-selection.md +110 -0
  104. package/docs/usage/compositions/design-profile-comparison.md +114 -0
  105. package/docs/usage/tokens/color.md +9 -2
  106. package/docs/usage/tokens/elevation-opacity.md +8 -1
  107. package/docs/usage/tokens/motion.md +10 -1
  108. package/docs/usage/tokens/radius.md +8 -1
  109. package/docs/usage/tokens/typography.md +15 -1
  110. package/package.json +13 -1
@@ -91,6 +91,8 @@ import { ImageViewer } from "@hjmds/react-native/image-viewer";
91
91
 
92
92
  ## 배치
93
93
 
94
+ Native 이미지 프레임은 `imageRecipe.radius` 역할을 Provider의 `tokens.radius`에서 읽는다. intrinsic 치수·대체 상태·접근성 구분은 유지한다.
95
+
94
96
  | 항목 | 값 | 근거 |
95
97
  | --- | --- | --- |
96
98
  | 크기 | 자리는 `width`·`height` 비율로 미리 잡는다(Web `aspect-ratio`, Native `aspectRatio`). 로드 전후로 높이가 바뀌지 않는다. 모서리는 `radius.md` 12로 잘린다(`imageRecipe.radius`) | `design-contracts/src/image.ts`(`imageRecipe`), `design-contracts/src/foundations.ts`(`radius`), `react/src/supplemental-display.tsx`(Image) |
@@ -77,6 +77,8 @@ import { Avatar, ListRow } from "@hjmds/react-native/data-display";
77
77
 
78
78
  ## 배치
79
79
 
80
+ Native 원형 leading의 `full`은 Provider token에서 읽지만 고정 원형 역할을 유지한다. square leading은 모서리를 부여하지 않는다.
81
+
80
82
  | 항목 | 값 | 근거 |
81
83
  | --- | --- | --- |
82
84
  | 크기 | 폭은 부모를 가득 채운다(Web `inline-size: 100%`). leading 프레임은 40×40(`leadingSize`), `circle`이면 `radius.full`. trailing 아이콘은 `glyph.sm` 20. 최소 높이는 아래 density 표 | `design-contracts/src/component-recipes.ts`(`listRowRecipe`), `design-contracts/src/foundations.ts`(`layout.rowHeight`) |
@@ -86,6 +86,8 @@ import { Text } from "@hjmds/react-native/primitives";
86
86
 
87
87
  ## 배치
88
88
 
89
+ Native `grouped` 프레임은 Provider의 `tokens.radius.lg`를 읽는다. plain 목록과 separator 의미는 변하지 않는다.
90
+
89
91
  | 항목 | 값 | 근거 |
90
92
  | --- | --- | --- |
91
93
  | 크기 | 화면 본문 폭을 채우는 세로 묶음이다. `grouped`는 배경 `--hjm-color-bg`와 모서리 `radius.lg` 16으로 한 덩어리가 된다 | `design-contracts/src/foundations.ts`(`radius`), `react/src/styles.css`(`.hjm-list`) |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [LoadMore](../../load-more.md), `src/component-recipes.ts`(`loadMoreRecipe`), `src/load-more.ts`(상태·controller)
9
9
  - 스토리북: `배포/컴포넌트/탐색/더 보기`
10
10
 
@@ -76,6 +76,8 @@ const loadMore = useRef<LoadMoreHandle>(null);
76
76
 
77
77
  ## 배치
78
78
 
79
+ Native trigger 모서리는 Provider token에서 `loadMoreRecipe.trigger.radius`를 읽는다. requestKey·중복 요청 방지와 요청 상태는 그대로다.
80
+
79
81
  | 항목 | 값 | 근거 |
80
82
  | --- | --- | --- |
81
83
  | 크기 | 더 보기·다시 시도 버튼은 최소 높이 `control.minTouchTarget` 44, 좌우 안쪽 `spacing.md` 16, radius `radius.md` 12의 텍스트 버튼. 끝 문구는 `caption` | `loadMoreRecipe.trigger`, `.hjm-load-more__trigger` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Mentions](../../mentions.md), 트리거 판정 `src/mentions.ts`
9
9
  - 스토리북: `배포/컴포넌트/입력/사용자 언급`
10
10
 
@@ -74,6 +74,8 @@ import { Mentions } from "@hjmds/react-native/mentions";
74
74
 
75
75
  ## 배치
76
76
 
77
+ Native 후보 목록의 모서리는 `comboboxRecipe.popover.radius` 역할을 Provider의 `tokens.radius`에서 해석한다. 프로필 교체가 입력·caret·후보 선택을 초기화하지 않는다.
78
+
77
79
  | 항목 | 값 | 근거 |
78
80
  | --- | --- | --- |
79
81
  | 크기 | 후보 한 줄 최소 높이 44(`control.minTouchTarget`). Web 목록 최대 높이 `14rem`, 입력 폭에 맞춤 | `.hjm-mentions__option`·`__list`, Native `minHeight: 44` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Dropdown 판정](../../dropdown.md), [Popover 경계](../../popover.md), `src/component-recipes.ts`(`menuRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/탐색/메뉴`
10
10
 
@@ -84,6 +84,8 @@ import { Menu } from "@hjmds/react-native/navigation";
84
84
 
85
85
  ## 배치
86
86
 
87
+ Native popover와 항목 모서리는 Provider token에서 recipe 역할을 해석한다. 선택·열림·dismiss와 action 순서는 프로필 교체로 초기화하지 않는다.
88
+
87
89
  | 항목 | 값 | 근거 |
88
90
  | --- | --- | --- |
89
91
  | 크기 | 항목 높이 `comfortable` 56(`layout.rowHeight.singleLine`) · `compact` 44(`control.minTouchTarget`). Web 표면 폭 `13.75rem`~`min(24rem, 90vw)`, 높이 최대 `100dvh − 2 × spacing.md`. Native 표면 폭 100%·최대 520, 높이 최대 75% | `menuRecipe.density`, `.hjm-menu__content`, `react-native/src/navigation.tsx` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Menubar](../../menubar.md), `src/menubar.ts`(`menubarRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/탐색/메뉴 막대`
10
10
 
@@ -91,3 +91,9 @@ Native 예는 없다(renderer 없음).
91
91
  - 항목 `textValue`는 계약 타입상 필수다. 지역화한 문구를 그대로 넣는다.
92
92
  - 메뉴 구성과 단축키 문구는 제품 소유다. 단축키 자체의 키 바인딩은 Menubar가 등록하지 않으므로 제품이 따로 연결한다.
93
93
  - `className`·`layoutStyle`은 배치에만 쓴다. 색·높이를 덮지 않는다.
94
+
95
+ 2026-10-07 Web 전체 회귀 중 키보드로 옮긴 항목이 첫 항목으로 돌아가는 문제를 재현했다.
96
+ 미게시(1.14.0 이후) 수정은 패널의 늦은 mouseenter가 키보드 선택을 덮지 않고 실제 마우스 이동에
97
+ 맞춰 활성 항목을 바꾼다. 메뉴 막대 라벨의 hover 전환·클릭·비활성 건너뛰기는 유지한다.
98
+ 고정 지연이나 키보드 검사 재시도로 가리는 대신 입력 의도를 구분했다.
99
+ [검증 기록](../../../../../docs/qa/2026-10-07-command-records.md).
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 미게시(1.12.1 이후)
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
9
9
  - 스토리북: `배포/구성/입력과 작성/메시지 작성`, `배포/구성/입력과 작성/댓글 작성`, `배포/화면/소통/채팅`
10
10
 
@@ -74,7 +74,11 @@ import { Image } from "react-native";
74
74
  | prop | 값 | 기본값 | 설명 |
75
75
  | --- | --- | --- | --- |
76
76
  | `value` | `string` | 필수 | 완전 제어형. HJM은 초안을 지우지 않는다 |
77
- | `label` | `string` | 필수 | placeholder 겸 접근성 이름 |
77
+ | `label` | `string` | 필수 | 접근성 이름; placeholder 생략 시 같은 문구 |
78
+ | `placeholder` | `string` | `label` | 짧은 시각 안내와 전체 접근성 이름을 분리 |
79
+ | `description` · `error` · `invalid` | `string` · `string` · `boolean` | 없음 | TextArea의 안내·오류 연결. Web describedby/invalid, Native hint/오류 표면 |
80
+ | `onBlur` | `() => void` | 없음 | host의 입력 중 상태 해제 |
81
+ | `submitMode` | `"newline"` · `"send"` | `"newline"` | Web Enter 전송은 Shift/IME/229 보호. Native send는 submit, newline은 기존 줄바꿈 |
78
82
  | `sendLabel` | `string` | 필수 | 전송 버튼 문구·접근성 이름 |
79
83
  | `onValueChange` | `(value: string) => void` | 필수 | 입력 변경 |
80
84
  | `onSend` | `(value: string) => void` | 필수 | 현재 문자열만 넘긴다 |
@@ -89,7 +93,7 @@ import { Image } from "react-native";
89
93
  | `sendIcon` | `ReactNode` | 없음 | 주면 아이콘 모드: 빈 입력에서는 입력창 안에 `attachmentAction`, 내용이 있거나 `pending`이면 전송 아이콘. 없으면 입력창 옆 텍스트 `Button` |
90
94
  | `sendPresentation` | `"inline"` · `"circle"` | `"inline"` | `circle`은 primary 원형 `IconButton size="small"`(댓글·DM 레퍼런스). `sendIcon`이 있을 때만 의미가 있다 |
91
95
  | `attachmentAction` | `{ label, icon, onPress(), disabled? }` | 없음 | 첨부 버튼(ghost `IconButton`) |
92
- | `attachments` | `readonly { id, removeLabel, preview }[]` | `[]` | 첨부 미리보기. 있으면 `onRemoveAttachment` 필수 |
96
+ | `attachments` | `readonly { id, removeLabel, preview, disabled? }[]` | `[]` | 첨부 미리보기. 있으면 `onRemoveAttachment` 필수 |
93
97
  | `onRemoveAttachment` | `(id: string) => void` | 없음 | 첨부 제거 |
94
98
  | Web `layoutStyle` | `HjmCompositionStyleProp` | 없음 | 작성창 루트 배치(margin·width·flex 등). 미게시(1.12.1 이후) |
95
99
 
@@ -107,11 +111,13 @@ import { Image } from "react-native";
107
111
 
108
112
  ## 꼭 지킬 것
109
113
 
110
- - 문구(`label`은 placeholder 겸 접근성 이름, `sendLabel`, `removeLabel`, `cancelLabel`)는 모두 i18n 키로 넣는다.
114
+ - 문구(`label`은 접근성 이름; placeholder 생략 시 같은 문구, `sendLabel`, `removeLabel`, `cancelLabel`)는 모두 i18n 키로 넣는다.
111
115
  - `onSend(value)`는 현재 문자열만 넘긴다. 첨부 목록은 제품 상태에서 읽고, **서버 성공 뒤에만** 제품이 글·첨부·답장 대상을 지운다.
112
116
  - 첨부 `id`는 비어 있지 않고 유일해야 하며 `removeLabel`이 필요하다. 첨부가 있으면 `onRemoveAttachment`가 필수다. 어기면 던진다.
113
117
  - 사진 권한·선택기·업로드·개수 제한은 제품 소유다. 출처 선택 UI는 [PhotoSourceSheet](photo-source-sheet.md)를 쓴다.
114
- - Enter는 줄바꿈이다(IME 조합 보호). Enter 전송을 덧붙이지 않는다.
118
+ - Enter는 기본 줄바꿈이다. 데스크톱 채팅만 `submitMode="send"`로 선택할 수 있고 Shift+Enter·IME 조합·Safari keyCode 229는 전송하지 않는다. Native는 별도로 선택하지 않으면 줄바꿈을 유지한다.
119
+ - 2026-10-07 번뚝 채택에서 기존 blur/IME/검증 연결이 누락되어 이 공개 축을 추가했다. 제품이 내부 TextArea를 따로 조립하는 대안 대신 기존 MessageComposer 엔진을 확장한다.
120
+ - 로컬 준비 사진은 `attachments`로 표시하며 UploadItem의 서버 업로드 완료로 가장하지 않는다. 준비 중 해당 항목의 `disabled`와 attachmentAction.disabled를 연결해 편집 가능한 본문과 사진 제거를 분리한다. 서버 성공 전 초안을 지우지 않는다.
115
121
  - Web 배치는 `layoutStyle`로 한다. Native는 스타일 통로가 없어 감싸는 레이아웃에서 배치한다.
116
122
 
117
123
  ## 플랫폼 차이
@@ -73,6 +73,15 @@ import { Notice } from "@hjmds/react-native/feedback";
73
73
  | `announcement`(Native) | `none` · `polite` · `assertive` | `none` | 새로 나타나는 상태만 발표한다(아래 플랫폼 차이) |
74
74
  | `layoutStyle` | 배치 전용 style 객체 | — | 바깥 여백·폭만 |
75
75
 
76
+ ### 디자인 프로필 상속
77
+
78
+ 2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
79
+ 모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
80
+ 읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
81
+ 프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
82
+ 플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
83
+
84
+
76
85
  ## 배치
77
86
 
78
87
  | 항목 | 값 | 근거 |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [NumberField](../../number-field.md), [DurationField](../../compound-controls.md#durationfield), `src/number-field.ts`(`numberFieldRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/입력/숫자 입력`, `배포/컴포넌트/입력/소요 시간 입력`
10
10
 
@@ -104,6 +104,8 @@ const decreaseKey = { hours: "timer.decrease.hours", minutes: "timer.decrease.mi
104
104
 
105
105
  ## 배치
106
106
 
107
+ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
108
+
107
109
  | 항목 | 값 | 근거 |
108
110
  | --- | --- | --- |
109
111
  | 크기 | 높이 `medium` 44(`fieldFrameContract.minHeight`) · `large` 52(`control.buttonHeight.large`). 증감 버튼 각 44×44(`control.minTouchTarget`) | `numberFieldRecipe.sizes`, `.hjm-number-field__stepper` |
@@ -3,11 +3,16 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
7
- - 검토일: 2026-10-06
6
+ - 적용: 1.14.0
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
9
9
  - 스토리북: `배포/화면/소개/온보딩`
10
10
 
11
+ 2026-10-07 Motion의 단계 카드 검토에서 새 상태 엔진을 추가하기 전에 npm 1.14.0의
12
+ 양 renderer `screen-flows.d.ts`·`screen-flows.js`·exports를 확인했다. 기존 `layoutStyle`과
13
+ 마지막 `complete` 행동이 이미 게시돼 있어 오래된 미게시 표기를 바로잡는다. 현재 개발 중인
14
+ 디자인 프로필 확장의 게시 여부와는 별개다([조사 근거](../../../../../docs/qa/2026-10-07-motion-reference-page-review.md)).
15
+
11
16
  ## 언제 쓰나
12
17
 
13
18
  첫 실행 소개·초기 설정처럼 **몇 단계를 차례로 넘기는 화면**에 쓴다. 현재 단계의 제목·설명·본문,
@@ -79,18 +84,19 @@ import { OnboardingScreen } from "@hjmds/react-native/screen-flows";
79
84
  | `index`, `onIndexChange` | 현재 단계(0부터, 제어형). 범위를 벗어나면 던진다 |
80
85
  | `nextLabel`, `backLabel` | 다음·이전 문구. 첫 단계에는 이전이 없다 |
81
86
  | `complete` | 마지막 단계의 주 행동 `{ label, onAction, disabled?, pending? }` |
82
- | `skip` | 선택. 상단 actions 자리에 보조 버튼으로 놓인다 |
87
+ | `skip` | 선택. Web은 헤더 actions, Native는 본문 진행 문구 다음에 보조 버튼으로 놓인다 |
83
88
  | `progressLabel(current, total)` | 1부터 센 현재 단계와 전체 수로 진행 문구를 만든다 |
89
+ | `layoutStyle` | 선택. ScreenLayout 루트의 공개 배치 슬롯 |
84
90
 
85
91
  ## 배치
86
92
 
87
93
  | 항목 | 값 | 근거 |
88
94
  | --- | --- | --- |
89
- | 크기 | 한 단계의 ScreenLayout 폭(최대 720); 다음·완료·이전은 `Button` 기본 크기 | `OnboardingScreen` |
90
- | 간격 | 화면 padding `spacing.md` 16(진행 문구 notice는 좌우만); footer 다음/완료–이전 `spacing.sm` 12; 단계 본문 안 간격은 `content`(제품) 소유 | Web·Native `OnboardingScreen` `Stack gap="sm"` |
91
- | 순서·정렬 | 헤더(단계 제목·설명 → 건너뛰기 ghost) → 진행 문구(caption) → 단계 `content` → footer(다음 또는 완료 primary → 이전 ghost, 첫 단계는 이전 없음) | 렌더 순서 |
92
- | 고정·스크롤 | 헤더·진행 문구·footer 고정, 단계 본문 화면 스크롤 | `ScreenLayout` |
93
- | 좁은 폭·큰 글자 | 제목 열 최소 폭 120 × 글자 배율, 모자라면 건너뛰기가 다음 줄로 내려간다; footer 버튼은 세로로 쌓인다 | `screenPatternRecipe.headerMinWidth` |
95
+ | 크기 | ScreenLayout의 기본 최대 폭 720; 다음·완료·이전은 `Button` 기본 크기 | `screenPatternRecipe.maxWidth` |
96
+ | 간격 | 기본 화면 padding `spacing.md` 16; footer 다음/완료–이전 `spacing.sm` 12; Native 본문 제목·설명·진행·건너뛰기·content 사이 `spacing.md` 16. 단계 content 내부 간격은 제품 소유 | ScreenLayout·양 renderer OnboardingScreen |
97
+ | 순서·정렬 | Web: 헤더(제목·설명 → 건너뛰기) → 진행 문구 → content. Native: 본문(제목 → 설명 → 진행 문구 → 건너뛰기 → content). 둘 다 footer는 다음 또는 완료 → 이전, 첫 단계는 이전 없음 | 실제 렌더 순서 |
98
+ | 고정·스크롤 | Web은 헤더·진행 문구·footer가 본문 스크롤 밖. Native는 제목·설명·진행·건너뛰기·content가 함께 스크롤하고 footer만 고정 | Native의 빈 header·기본 scroll="screen" |
99
+ | 좁은 폭·큰 글자 | Web 헤더 제목 열은 최소 폭 120 × 글자 배율이며 actions가 줄바꿈한다. Native는 본문 세로 Stack을 사용한다. 둘 다 footer 버튼은 세로로 쌓인다 | ScreenLayout·OnboardingScreen |
94
100
 
95
101
  ## 꼭 지킬 것
96
102
 
@@ -103,4 +109,5 @@ import { OnboardingScreen } from "@hjmds/react-native/screen-flows";
103
109
 
104
110
  | 항목 | Web | Native |
105
111
  | --- | --- | --- |
106
- | 배치 prop | `layoutStyle`(ScreenLayout 루트, 미게시(1.12.1 이후)) | `layoutStyle`(ScreenLayout 루트, 미게시(1.12.1 이후)) |
112
+ | 배치 prop | `layoutStyle`(ScreenLayout 루트, 1.14.0 게시 확인) | `layoutStyle`(ScreenLayout 루트, 1.14.0 게시 확인) |
113
+ | 단계 안내 | 헤더와 notice | 스크롤 본문. 큰 글자에서 안내가 고정 영역을 모두 차지하지 않도록 기존 본문을 사용한다 |
@@ -0,0 +1,73 @@
1
+ # OverviewScreen
2
+
3
+ - 단계: 컴포넌트
4
+ - 상태: 실험
5
+ - 지원: Web · Native
6
+ - 적용: 미게시(1.14.0 이후)
7
+ - 검토일: 2026-10-07
8
+ - 근거: [디자인 프로필](../../design-profile.md), 양 renderer `src/design-profile.tsx`; 기존 ScreenLayout·Grid·Collapsible의 상태 엔진을 재사용한다.
9
+ - 스토리북: `실험/컴포넌트/레이아웃/목록 화면 골격`
10
+
11
+ ## 언제 쓰나
12
+
13
+ 같은 데이터와 기능을 유지하면서 테마별 행·카드·격자와 도구 배치를 선택하는 목록 화면에 쓴다.
14
+
15
+ ## 쓰지 않을 때
16
+
17
+ | 상황 | 대신 쓸 것 |
18
+ | --- | --- |
19
+ | 설정·검색·알림 | [SettingsScreen](settings-screen.md), [SearchScreen](search-screen.md), [NotificationInboxScreen](notification-inbox-screen.md) |
20
+ | 앱 전체 navigation | [Layout](layout.md) |
21
+ | 임의 마케팅 페이지 | 제품의 페이지 구조 |
22
+
23
+ ## 공개 이름과 import
24
+
25
+ | 이름 | 역할 | Web | Native |
26
+ | --- | --- | --- | --- |
27
+ | `OverviewScreen` | 프로필 기반 목록 화면, supplemental | `@hjmds/react/design-profile` | `@hjmds/react-native/design-profile` |
28
+
29
+ root barrel에 넣지 않는다. Native 질감은 기존 optional `react-native-svg` host가 필요하다. 프로필 레지스트리는 renderer core에 번들하지 않는다.
30
+
31
+ ## 최소 사용 예
32
+
33
+ ```tsx
34
+ // Web
35
+ import { HjmProvider } from "@hjmds/react/provider";
36
+ import { OverviewScreen } from "@hjmds/react/design-profile";
37
+ import { defineHjmDesignProfile } from "@hjmds/design-contracts/design-profile";
38
+ const design = defineHjmDesignProfile({ extends: "forest", id: "app-forest" });
39
+ <HjmProvider designProfile={design}>
40
+ <OverviewScreen title={t("records.title")} toolbarLabel={t("records.tools")}
41
+ toolbar={<RecordTools />} items={records.map(record => ({ id: record.id, children: <RecordSummary record={record} /> }))}
42
+ footer={<SaveAction />} />
43
+ </HjmProvider>
44
+ ```
45
+
46
+ ```tsx
47
+ // Native
48
+ import { HjmNativeProvider } from "@hjmds/react-native/provider";
49
+ import { OverviewScreen } from "@hjmds/react-native/design-profile";
50
+ <HjmNativeProvider designProfile={design}>
51
+ <OverviewScreen title={t("records.title")} toolbarLabel={t("records.tools")}
52
+ toolbar={<RecordTools />} items={records.map(record => ({ id: record.id, children: <RecordSummary record={record} /> }))}
53
+ footer={<SaveAction />} />
54
+ </HjmNativeProvider>
55
+ ```
56
+
57
+ ## 배치
58
+
59
+ 헤더 → notice → 도구 → 목록 → footer. 뒤로는 leading, 화면 도구는 actions, 주 행동은 footer다. 하나의 화면에 경쟁하는 주 행동을 추가하지 않는다.
60
+
61
+ | 항목 | 값 | 근거 |
62
+ | --- | --- | --- |
63
+ | 크기 | editorial은 `layout.readingMaxWidth` 720, dashboard·landscape는 `layout.contentMaxWidth` 1200, host가 높이를 제공한다 | `resolveDesignProfileScreen`, ScreenLayout |
64
+ | 간격 | 도구–목록 `spacing.xl` 24, rows `spacing.sm` 12, cards/grid `spacing.lg` 20, 카드 내부 rows `spacing.md` 16 / 나머지 `spacing.xl` 24 | OverviewScreen·공유 collection resolver |
65
+ | 순서·정렬 | 헤더 → notice → 도구 → 목록 → footer. leading은 뒤로, actions는 화면 도구, footer는 주 행동 | ScreenLayout 슬롯 |
66
+ | 고정·스크롤 | 헤더·notice·footer 고정, 본문 스크롤. 가상 목록은 별도 ScreenLayout + `scroll="content"` | ScreenLayout 상태·스크롤 엔진 |
67
+ | 좁은 폭·큰 글자 | rows 1/1/1, cards 1/2/2, grid 1/2/3(compact/medium/expanded). 최소 열 폭 240이며 실제 컨테이너·글자 배율로 열 수를 줄인다 | `resolveDesignProfileCollection`·Grid |
68
+
69
+ `collection`, `toolbarPresentation`, `presentation` 명시값이 프로필을 이긴다. 작은 화면의 열 수는 늘리지 않는다. virtual list는 이 정적 items 목록 대신 기존 ScreenLayout의 `scroll="content"`와 제품 list를 쓴다.
70
+
71
+ ## 꼭 지킬 것
72
+
73
+ ScreenLayout의 ready/loading/empty/error와 stateAction을 그대로 사용한다. 초기 조회 오류만 본문을 교체하고 저장 실패는 notice로 알린다. stable id가 중복되거나 비어 있으면 거부한다. 도구를 닫으면 입력 상태는 유지하되 접근성·포커스 대상에서 제외한다. 제품이 서버 확정·재시도·동시 저장 방지를 소유한다. 프로필은 같은 아이템의 입력 subtree를 갈아 끼우지 않는다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [PasswordField](../../password-field.md), `src/password-field.ts`(`passwordFieldRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/입력/비밀번호 입력`
10
10
 
@@ -101,6 +101,10 @@ const passwordRef = useRef<TextInput>(null);
101
101
 
102
102
  ## 배치
103
103
 
104
+ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
105
+
106
+ Native `large`는 프로필의 `typography.bodyLarge`를 읽고 그 줄 높이로 프레임도 늘린다. recipe의 최소 높이가 큰 글자 프레임을 덮지 않으며 controlled textScale은 한 번만 적용한다.
107
+
104
108
  | 항목 | 값 | 근거 |
105
109
  | --- | --- | --- |
106
110
  | 크기 | 높이 `medium` 44(`fieldFrameContract.minHeight`) · `large` 52(`control.buttonHeight.large`). 토글 44×44 원형(`control.minTouchTarget`) | `passwordFieldRecipe.sizes`, `.hjm-password-field__toggle` |
@@ -112,3 +112,10 @@ Native 예는 없다(renderer 없음).
112
112
  공간 전환을 생략하고 기존 표현을 쓴다. 닫혔을 때는 즉시 inert/aria-hidden으로 입력에서 제외한다.
113
113
  - 초안은 Popover 위의 제품 상태에 둔다. 종료 후 portal이 제거되므로 내부 비제어 입력에만 두면 사라진다.
114
114
  - 공간 전환 실험은 [버튼에서 이어지는 편집](../compositions/origin-dialog.md)의 Web 전용 변형이다.
115
+
116
+ 미게시(1.14.0 이후): 가장 가까운 프로필의 `shadow.floating`을 열린 portal에도 상속한다. 프로필이 없으면 기존 recipe 그림자를 유지한다. 초안과 비모달 초점/닫기 계약은 그대로이며 Native는 기존 Sheet 경로를 쓴다.
117
+
118
+ [Motion 세 편집 예제 검토](../../../../../docs/qa/2026-10-07-motion-reference-page-review.md)에서
119
+ aria-modal 표시와 실제 초점 경계가 다르고, 닫기 후 defaultValue 편집이 초기화되는 것을 확인했다.
120
+ MorphingPopover 원본 엔진으로 교체하지 않는다. 공개 `motionOrigin`은 이어지는 표현만 맡고,
121
+ 제목/field label·nonmodal 의미·초점 복귀는 Popover, 저장 전 초안·실패/재시도는 제품이 소유한다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 미게시(1.12.1 이후)
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [반복 화면 계약](../../screen-patterns.md); 저장한 항목을 Instagram의 컬렉션 탐색 방식으로 바꾸라는 사용자 요청. 기존 ListDetailScreen·Grid를 합성하며 별도 저장 엔진은 만들지 않는다. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
9
9
  - 스토리북: `배포/화면/콘텐츠/저장한 항목`
10
10
 
@@ -92,6 +92,8 @@ import { SavedItemsScreen } from "@hjmds/react-native/saved-items";
92
92
 
93
93
  ## 배치
94
94
 
95
+ Native collection cover의 모서리는 Provider의 `tokens.radius.md`다. 저장 항목·컬렉션·선택·탐색 계약은 바꾸지 않는다.
96
+
95
97
  | 항목 | 값 | 근거 |
96
98
  | --- | --- | --- |
97
99
  | 크기 | host의 남은 높이 100%, ScreenLayout 폭(최대 720); 컬렉션 표지·게시물 썸네일 1:1, 표지 radius `radius.md` | `ListDetailScreen`, Web `.hjm-saved-*`, Native `saved-items.tsx` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 미게시(1.12.1 이후)
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
9
9
  - 스토리북: `배포/화면/화면 틀과 도구/화면 골격과 상태`
10
10
 
@@ -79,6 +79,7 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
79
79
  | `stateAction` | `ReactNode` | 없음 | 상태 안내 아래 행동(재시도 등) |
80
80
  | `scroll` | `"screen"` · `"content"` | `"screen"` | `content`는 본문 자식(가상화 목록)이 스크롤을 소유한다. 상태 교체 중에는 `screen`으로 돌아간다 |
81
81
  | `contentInset` | `"default"` · `"none"` | `"default"` | `none`은 헤더·notice·본문·footer padding을 0으로(Native는 footer 위 테두리도 뺀다) |
82
+ | `presentation` | `"dashboard"` · `"editorial"` · `"landscape"` | 가장 가까운 profile.screens.overview / 없으면 기존 골격 | 미게시 실험. 명시값이 프로필을 이긴다. 헤더 배치·읽기 폭만 바꾸고 상태·입력·행동 슬롯은 유지한다 |
82
83
  | `as` (Web) | `"main"` · `"section"` | `"main"` | 제품 셸에 이미 `<main>`이 있으면 `section` |
83
84
  | `layoutStyle` | `HjmCompositionStyleProp` | 없음 | 화면 루트 배치 전용(예: 분할 화면의 `flex`·`width`). ScreenLayout 위에 만든 화면은 모두 이 prop을 루트까지 넘긴다 |
84
85
  | `className` (Web) | `string` | 없음 | 식별·배치 보조. 색·여백을 덮지 않는다 |
@@ -117,3 +118,10 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
117
118
  ## 함정
118
119
 
119
120
  - 이미 `<main>`이 있는 제품 셸 안에서는 `as="section"`을 준다. 중첩 main이 생긴다.
121
+
122
+ ### 디자인 프로필의 화면 표현
123
+
124
+ `presentation` 명시값, 가장 가까운 프로필의 screens.overview, 기존 화면 골격 순으로 선택한다.
125
+ dashboard는 가로 헤더/1200 목록 폭, editorial은 세로 헤더/720 읽기 폭, landscape는 중앙 세로 헤더/1200 폭이다.
126
+ 폭은 foundations의 contentMaxWidth/readingMaxWidth다. 프로필을 지정하지 않으면 기존 recipe 배치를 유지한다.
127
+ 같은 header/body/notice/footer 및 상태 엔진을 유지하며 입력 subtree를 테마별로 교체하지 않는다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: `src/component-recipes.ts`(`searchFieldRecipe`). 별도 계약 문서는 없다
9
9
  - 스토리북: `배포/컴포넌트/입력/검색 입력`
10
10
 
@@ -78,6 +78,8 @@ import { SearchField } from "@hjmds/react-native/inputs";
78
78
 
79
79
  ## 배치
80
80
 
81
+ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
82
+
81
83
  | 항목 | 값 | 근거 |
82
84
  | --- | --- | --- |
83
85
  | 크기 | 최소 높이 `medium` 44 · `large` 52. 지우기 버튼 `medium` 지름 36 + hitSlop 4, `large` 44(Web은 36 원에 `::after` 4px로 터치 44를 만든다) | `searchFieldRecipe.sizes`, `control.minTouchTarget`, `control.buttonHeight.large`, `.hjm-search-field__clear` |
@@ -93,6 +93,15 @@ import { NativeSelect } from "@hjmds/react/forms";
93
93
  | `options`(NativeSelect) | `readonly { value: string; label: string; disabled? }[]` | 필수 | 브라우저 `<select>` 대안 |
94
94
  | `onValueChange`(NativeSelect) | `(value: string) => void` | — | 원시 `onChange`도 받는다 |
95
95
 
96
+ ### 디자인 프로필 상속
97
+
98
+ 2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
99
+ 모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
100
+ 읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
101
+ 프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
102
+ 플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
103
+
104
+
96
105
  ## 배치
97
106
 
98
107
  | 항목 | 값 | 근거 |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Sheet 입력 화면과 가용 영역](../../sheet.md), [optional adapters](../../optional-adapters.md)(Native 제스처 확장), `src/component-recipes.ts`(`sheetRecipe`), `src/sheet.ts`(`sheetBehaviorDefaults`)
9
9
  - 스토리북: `배포/컴포넌트/오버레이/시트`
10
10
 
@@ -88,8 +88,21 @@ import { Sheet } from "@hjmds/react-native/overlays";
88
88
  | `safeAreaInsets`(Native) | `Partial<Insets>` | provider inset | — |
89
89
  | `contentStyle`(Native) | 배치 key만 | — | 배치 밖 key(색·높이 등)는 deprecated(개발 모드 경고), 다음 major에서 배치 전용 타입으로 좁힌다 |
90
90
 
91
+ ### 디자인 프로필 상속
92
+
93
+ 2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
94
+ 모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
95
+ 읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
96
+ 프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
97
+ 플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
98
+
99
+
91
100
  ## 배치
92
101
 
102
+ 선택형 Native `GestureSheetInput`의 실제 keyboard-tracking host에도 제품 `tokens.fontFamily.ui`가 이어진다. optional library·폰트 설치와 실제 기기 검증은 제품이 맡는다.
103
+
104
+ 선택형 GestureSheetInput은 Provider typography와 field recipe radius 역할을 읽고 textScale을 한 번 적용한다. optional keyboard-tracking host는 그대로다.
105
+
93
106
  | 항목 | 값 | 근거 |
94
107
  | --- | --- | --- |
95
108
  | 크기 | 하단 시트 높이: `auto` 내용 높이(최대 화면 높이 × `maxHeightRatio` 0.9), `medium` 60%, `large` 85%, `full` 위 safe area 안 전체 높이(0.9 상한 없음). Web 하단 시트 최대 폭 640. 위 두 모서리만 `radius.xl` 24. 옆 시트(`start`·`end`): Web 폭 `min(28rem, 100%)`·높이 화면 − 32, Native 폭 88%(최대 420)·화면 높이 | `sheetRecipe.sizes`·`content`·`web`, `.hjm-sheet`, Native `Sheet` |
@@ -67,6 +67,15 @@ import { Skeleton } from "@hjmds/react-native/feedback";
67
67
 
68
68
  콜백 prop은 없다.
69
69
 
70
+ ### 디자인 프로필 상속
71
+
72
+ 2026-10-07 테마 소비 경로 점검에서 고정 foundation/recipe 값이 남은 곳을 보완했다.
73
+ 모서리의 recipe 역할은 유지하고 값은 가장 가까운 Provider의 `designProfile.tokens.radius`를
74
+ 읽는다. Dialog/AlertDialog/Sheet/일반 Toast의 그림자는 `tokens.shadow.floating`을 읽으며
75
+ 프로필 없는 소비자의 기본값은 유지한다. 상태·초안·선택·Modal teardown은 이 축의 소유가 아니다.
76
+ 플랫폼 근사와 미검증 범위는 [프로필 계약](../../design-profile.md#오버레이선택-입력의-프로필-연결-보완)을 따른다.
77
+
78
+
70
79
  ## 배치
71
80
 
72
81
  | 항목 | 값 | 근거 |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Slider](../../slider.md), `src/slider.ts`(`sliderRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/입력/슬라이더`, `배포/컴포넌트/입력/별점`
10
10
 
@@ -81,6 +81,8 @@ import { Slider } from "@hjmds/react-native/slider";
81
81
 
82
82
  ## 배치
83
83
 
84
+ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
85
+
84
86
  | 항목 | 값 | 근거 |
85
87
  | --- | --- | --- |
86
88
  | 크기 | 가로 폭을 채운다. 트랙 줄은 터치 높이 `control.minTouchTarget` 44 안에 두께 4 트랙과 지름 20 thumb을 세로 중앙에 그린다 | `sliderRecipe.sizes.medium`, `.hjm-slider__control` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Statistic](../../statistic.md), [optional adapters](../../optional-adapters.md), `src/component-recipes.ts`(`statisticRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/데이터 표시/수치 표시`, `배포/컴포넌트/데이터 표시/움직이는 수치`
10
10
 
@@ -88,6 +88,8 @@ import { Statistic } from "@hjmds/react-native/data-display";
88
88
 
89
89
  ## 배치
90
90
 
91
+ Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Provider token에서 해석한다. 수치·locale·낭독 문구는 제품 데이터 그대로다.
92
+
91
93
  | 항목 | 값 | 근거 |
92
94
  | --- | --- | --- |
93
95
  | 크기 | `presentation="surface"`의 안쪽 여백: `comfortable` `spacing.md` 16 · `compact` `spacing.sm` 12(두 플랫폼). 테두리 `stroke.default` 1, radius `md` 12 | `statisticRecipe.density`·`presentations`, `styles.css` `.hjm-statistic[data-presentation="surface"]` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: `src/base-recipes.ts`(`surfaceRecipe`·`surfaceDefaults`·`surfaceGeometry`)
9
9
  - 스토리북: `배포/컴포넌트/레이아웃/배경 영역`
10
10
 
@@ -62,6 +62,13 @@ import { Surface } from "@hjmds/react-native/primitives";
62
62
  | `as`(Web) | `div` · `section` · `article` | `div` | — |
63
63
  | `layoutStyle` | `HjmCompositionStyleProp` | — | Surface 자신의 바깥 여백·폭·flex·`alignSelf`. Web·Native 모두 |
64
64
 
65
+ ### 프로필 표면 질감(미게시)
66
+
67
+ 선택한 `designProfile.material.surface`를 자동으로 읽는다. glass는 지원하는 Web에서 실제 배경 흐림,
68
+ clay는 안쪽 그림자를 사용한다. Native는 루트 Provider의 선택형 `surfaceEffects` host와 inset capability를
69
+ 한 번 등록한다. 사용할 수 없거나 투명도 줄이기 설정이면 불투명 표면을 유지한다. 효과와 입력은 서로 다른
70
+ subtree라 질감을 바꾸거나 host가 실패해도 본문/초안은 유지한다. [범위·등록·대비 계약](../../design-profile.md#surfacecard의-유리클레이-질감)을 따른다.
71
+
65
72
  ## 배치
66
73
 
67
74
  | 항목 | 값 | 근거 |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Gooey navigation](../../gooey-navigation.md), `src/component-recipes.ts`(`tabsRecipe`), `src/behaviors.ts`(`tabsBehaviorDefaults`)
9
9
  - 스토리북: `배포/컴포넌트/탐색/탭`, `배포/컴포넌트/탐색/선택 표시가 이어지는 탭`
10
10
 
@@ -77,7 +77,7 @@ import { Tabs } from "@hjmds/react-native/navigation";
77
77
  | `overflow` | `scroll` · `clip` | `scroll` | — |
78
78
  | `orientation` | `horizontal` · `vertical` | `horizontal` | — |
79
79
  | `loop` | `boolean` | `true` | — |
80
- | `appearance` | `standard` · `gooey` | `standard` | `gooey`는 가로일 때만 선택 표시가 늘어나며 이동, 세로는 standard 유지 |
80
+ | `appearance` | `standard` · `slide` · `gooey` | 미지정 시 프로필의 selectionMotion; 없으면 `standard` | 미게시(1.14.0 이후): `slide`는 2점 표시선 이동, `gooey`는 6점 표시선 늘어남. 명시 값 우선, 세로는 standard 유지 |
81
81
  | `renderPanels` | `boolean` | `true` | `false`면 패널을 그리지 않는다. 패널을 라우터·스크롤 상태와 함께 따로 둘 때 `TabPanel`에 `tabsId`(Tabs의 `id`와 같게)·`activeValue`·`value`를 넘긴다 |
82
82
  | `children`(Native) | `(selectedValue: Value) => ReactNode` | — | 항목 `panel` 대신 선택 값으로 패널을 그린다 |
83
83
  | `TabPanel` | `{ tabsId, activeValue, children, mode?: "keyed", value, mountPolicy? }` 또는 `{ mode: "dynamic" }`, Native는 `label` 필수 | — | — |
@@ -129,6 +129,15 @@ import { Tabs } from "@hjmds/react-native/navigation";
129
129
 
130
130
  ## 함정
131
131
 
132
+ - 2026-10-07 [Animated Tabs 대조](../../../../../docs/plans/aceternity-interaction-adoption-2026-10-07.md)에서
133
+ 선택 표시의 이동과 겹친 패널의 이동을 구분했다. 현재 `appearance="gooey"`는 표시선만 늘어나며,
134
+ 패널을 겹쳐 복제하거나 순서를 바꾸지 않는다. 미게시(1.14.0 이후) 후속 구현에서
135
+ `appearance`를 생략하면 `designProfile.interactions.selectionMotion="slide"`가 일반 이동선으로
136
+ 연결된다. 명시 `standard`는 이동을 끄고 명시 `gooey`만 늘어남을 고른다. `slide`와 `gooey`를
137
+ 같은 의미로 간주하지 않는다. 전환 표현이 필요하면 [ContentTransition](content-transition.md)의
138
+ 단일 콘텐츠 전환과 Tabs의 `mountPolicy`·`panelMode`를 함께 검토한다. 프로필이 탭·패널 수명을
139
+ 자동 결정하거나 active 패널의 unmount 후 로컬 초안을 보존한다고 안내하지 않는다.
140
+
132
141
  - Native `Tabs`는 예전 `options` prop을 받으면 `TypeError`("options was removed")를 던진다. `items`로 옮긴다.
133
142
  - 외부 `TabPanel`을 쓸 때 Tabs에 `id`를 주지 않으면 Web은 생성 id를 써서 `tabsId`를 맞출 수 없다.
134
143
  `id`를 명시하고 같은 값을 `TabPanel tabsId`에 넘긴다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [Tag contract](../../tag.md), `src/tag.ts`(`tagRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/데이터 표시/태그`
10
10
 
@@ -59,6 +59,8 @@ import { Tag } from "@hjmds/react-native/data-display";
59
59
 
60
60
  ## 배치
61
61
 
62
+ Native의 모서리는 Provider의 `tokens.radius.sm`이다. metadata 의미와 tone은 변하지 않는다.
63
+
62
64
  | 항목 | 값 | 근거 |
63
65
  | --- | --- | --- |
64
66
  | 크기 | 최소 높이 20, 테두리 1, radius `sm` 8. 누르는 대상이 아니므로 44 터치 영역을 두지 않는다 | `tagRecipe.size`, `styles.css` `.hjm-tag`, `react-native/src/data-display.tsx` |
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-06
7
+ - 검토일: 2026-10-07
8
8
  - 근거: [TagsInput](../../tags-input.md), `src/tags-input.ts`(`tagsInputRecipe`)
9
9
  - 스토리북: `배포/컴포넌트/입력/태그 입력`
10
10
 
@@ -84,6 +84,11 @@ import { TagsInput } from "@hjmds/react-native/tags-input";
84
84
 
85
85
  ## 배치
86
86
 
87
+ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력 host에 연결한다. 기본 UI stack은 OS 서체를 유지하고, 제품이 지정한 첫 named font의 등록·글리프 확인은 제품이 맡는다.
88
+ Native 입력칸은 `tokens.typography.body`의 글자·줄 높이도 읽는다. Provider가 textScale을 제어하면 한 번만 확대하고 시스템의 추가 확대를 끈다. 태그/편집 초안은 테마 전환 때 유지한다.
89
+
90
+ Native 입력 프레임의 `md` 모서리는 Provider의 `tokens.radius.md`를 읽는다. pill 태그와 고정 삭제 glyph는 그대로이며 프로필 교체는 입력 중인 초안·태그를 유지한다.
91
+
87
92
  | 항목 | 값 | 근거 |
88
93
  | --- | --- | --- |
89
94
  | 크기 | 입력 틀 최소 높이 44(필드 틀과 같음), 모서리 `radius.md` 12. 입력 칸 최소 Web `8ch`, Native 80. 태그 칩 높이 28, 삭제 버튼 터치 영역 44(`control.minTouchTarget`). 후보 행 최소 높이 44(두 플랫폼, Native는 미게시(1.12.1 이후). 1.12.1 Native는 28) | `tagsInputRecipe`, `.hjm-tags-input__frame`·`__remove::after`·`__suggestion` |