@hjmds/design-contracts 1.18.0 → 1.20.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 (251) hide show
  1. package/dist/action-session.d.ts +16 -0
  2. package/dist/action-session.d.ts.map +1 -1
  3. package/dist/action-session.js +18 -0
  4. package/dist/action-session.js.map +1 -1
  5. package/dist/behaviors.d.ts +8 -6
  6. package/dist/behaviors.d.ts.map +1 -1
  7. package/dist/behaviors.js +4 -3
  8. package/dist/behaviors.js.map +1 -1
  9. package/dist/bottom-navigation.d.ts +14 -0
  10. package/dist/bottom-navigation.d.ts.map +1 -1
  11. package/dist/bottom-navigation.js +21 -0
  12. package/dist/bottom-navigation.js.map +1 -1
  13. package/dist/carousel.d.ts +3 -0
  14. package/dist/carousel.d.ts.map +1 -1
  15. package/dist/carousel.js.map +1 -1
  16. package/dist/catalog.d.ts +61 -0
  17. package/dist/catalog.d.ts.map +1 -1
  18. package/dist/component-recipes.d.ts +67 -0
  19. package/dist/component-recipes.d.ts.map +1 -1
  20. package/dist/component-recipes.js +27 -1
  21. package/dist/component-recipes.js.map +1 -1
  22. package/dist/field-group.d.ts +14 -0
  23. package/dist/field-group.d.ts.map +1 -1
  24. package/dist/field-group.js +9 -0
  25. package/dist/field-group.js.map +1 -1
  26. package/dist/form.d.ts.map +1 -1
  27. package/dist/form.js +10 -3
  28. package/dist/form.js.map +1 -1
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/screen-patterns.d.ts +4 -0
  33. package/dist/screen-patterns.d.ts.map +1 -1
  34. package/dist/screen-patterns.js +12 -3
  35. package/dist/screen-patterns.js.map +1 -1
  36. package/dist/semantic-colors.d.ts +9 -0
  37. package/dist/semantic-colors.d.ts.map +1 -1
  38. package/dist/semantic-colors.js +5 -0
  39. package/dist/semantic-colors.js.map +1 -1
  40. package/dist/toast.d.ts +10 -1
  41. package/dist/toast.d.ts.map +1 -1
  42. package/dist/toast.js +43 -2
  43. package/dist/toast.js.map +1 -1
  44. package/dist/version.d.ts +1 -1
  45. package/dist/version.js +1 -1
  46. package/dist/version.js.map +1 -1
  47. package/docs/action-session.md +2 -0
  48. package/docs/asset.md +7 -0
  49. package/docs/bottom-navigation.md +22 -0
  50. package/docs/brand-boundary.md +3 -3
  51. package/docs/collection-rail.md +4 -0
  52. package/docs/compound-controls.md +8 -3
  53. package/docs/consumer-policy.md +39 -120
  54. package/docs/generated/component-maturity.md +1 -1
  55. package/docs/generated/renderer-evidence.json +3 -3
  56. package/docs/generated/renderer-evidence.md +1 -1
  57. package/docs/generated/showcase-manifest.json +1 -1
  58. package/docs/gravity-letters.md +2 -0
  59. package/docs/grid-reveal.md +2 -0
  60. package/docs/layout.md +2 -2
  61. package/docs/load-more.md +5 -0
  62. package/docs/migration-native-legacy-removal.md +30 -17
  63. package/docs/optional-adapters.md +4 -0
  64. package/docs/screen-patterns.md +23 -1
  65. package/docs/toast.md +41 -2
  66. package/docs/usage/README.md +248 -245
  67. package/docs/usage/SELECTION.md +43 -0
  68. package/docs/usage/STANDARD.md +22 -10
  69. package/docs/usage/components/accordion.md +5 -3
  70. package/docs/usage/components/agreement.md +6 -9
  71. package/docs/usage/components/alert-dialog.md +12 -6
  72. package/docs/usage/components/asset.md +10 -4
  73. package/docs/usage/components/auth-provider-button.md +2 -2
  74. package/docs/usage/components/avatar.md +8 -6
  75. package/docs/usage/components/badge.md +4 -4
  76. package/docs/usage/components/bottom-cta.md +4 -4
  77. package/docs/usage/components/bottom-info.md +2 -2
  78. package/docs/usage/components/bottom-navigation.md +30 -6
  79. package/docs/usage/components/button.md +2 -2
  80. package/docs/usage/components/card.md +1 -1
  81. package/docs/usage/components/carousel.md +12 -4
  82. package/docs/usage/components/chat-message.md +6 -2
  83. package/docs/usage/components/chat-screen.md +5 -5
  84. package/docs/usage/components/checkbox-group.md +1 -1
  85. package/docs/usage/components/checkbox.md +2 -2
  86. package/docs/usage/components/chip.md +2 -2
  87. package/docs/usage/components/code-block.md +3 -4
  88. package/docs/usage/components/collapsible.md +6 -4
  89. package/docs/usage/components/combobox.md +2 -2
  90. package/docs/usage/components/command-palette.md +1 -1
  91. package/docs/usage/components/comment-thread-screen.md +7 -4
  92. package/docs/usage/components/container.md +1 -1
  93. package/docs/usage/components/content-transition.md +2 -2
  94. package/docs/usage/components/context-menu.md +2 -2
  95. package/docs/usage/components/counter-badge.md +3 -3
  96. package/docs/usage/components/data-table.md +1 -1
  97. package/docs/usage/components/date-picker.md +4 -4
  98. package/docs/usage/components/description-list.md +3 -3
  99. package/docs/usage/components/design-system-provider.md +2 -2
  100. package/docs/usage/components/dialog.md +14 -3
  101. package/docs/usage/components/divider.md +2 -2
  102. package/docs/usage/components/editor-screen.md +5 -3
  103. package/docs/usage/components/effect-surface.md +1 -1
  104. package/docs/usage/components/empty-state.md +6 -6
  105. package/docs/usage/components/field.md +5 -3
  106. package/docs/usage/components/file-picker.md +6 -3
  107. package/docs/usage/components/form.md +1 -1
  108. package/docs/usage/components/heading.md +3 -3
  109. package/docs/usage/components/icon-button.md +3 -3
  110. package/docs/usage/components/icon.md +1 -1
  111. package/docs/usage/components/image.md +5 -4
  112. package/docs/usage/components/keyboard-dock.md +1 -1
  113. package/docs/usage/components/layout.md +1 -1
  114. package/docs/usage/components/link.md +2 -2
  115. package/docs/usage/components/list-detail-screen.md +6 -6
  116. package/docs/usage/components/list-row.md +13 -4
  117. package/docs/usage/components/list.md +5 -4
  118. package/docs/usage/components/masonry.md +2 -1
  119. package/docs/usage/components/media-selection-screen.md +11 -5
  120. package/docs/usage/components/mentions.md +2 -2
  121. package/docs/usage/components/menu.md +3 -2
  122. package/docs/usage/components/menubar.md +2 -2
  123. package/docs/usage/components/message-composer.md +3 -3
  124. package/docs/usage/components/moderation-screen.md +3 -2
  125. package/docs/usage/components/notice.md +2 -2
  126. package/docs/usage/components/notification-inbox-screen.md +1 -1
  127. package/docs/usage/components/notification-item.md +2 -2
  128. package/docs/usage/components/number-field.md +3 -3
  129. package/docs/usage/components/otp-field.md +1 -1
  130. package/docs/usage/components/overview-screen.md +1 -1
  131. package/docs/usage/components/permission-screen.md +1 -1
  132. package/docs/usage/components/photo-source-sheet.md +1 -1
  133. package/docs/usage/components/popover.md +2 -2
  134. package/docs/usage/components/profile-screen.md +1 -1
  135. package/docs/usage/components/progress.md +2 -2
  136. package/docs/usage/components/qr-code.md +2 -2
  137. package/docs/usage/components/radio-group.md +1 -2
  138. package/docs/usage/components/radio.md +1 -2
  139. package/docs/usage/components/result.md +1 -1
  140. package/docs/usage/components/saved-items-screen.md +4 -2
  141. package/docs/usage/components/screen-layout.md +4 -3
  142. package/docs/usage/components/search-field.md +1 -1
  143. package/docs/usage/components/search-screen.md +4 -4
  144. package/docs/usage/components/section.md +3 -3
  145. package/docs/usage/components/segmented-control.md +4 -4
  146. package/docs/usage/components/select.md +2 -3
  147. package/docs/usage/components/settings-screen.md +11 -49
  148. package/docs/usage/components/sheet.md +10 -5
  149. package/docs/usage/components/sidebar.md +1 -1
  150. package/docs/usage/components/skeleton.md +1 -1
  151. package/docs/usage/components/skip-nav.md +1 -1
  152. package/docs/usage/components/slider.md +2 -2
  153. package/docs/usage/components/spinner.md +2 -2
  154. package/docs/usage/components/splitter.md +1 -1
  155. package/docs/usage/components/statistic.md +5 -4
  156. package/docs/usage/components/steps.md +2 -2
  157. package/docs/usage/components/surface.md +2 -3
  158. package/docs/usage/components/switch.md +1 -1
  159. package/docs/usage/components/tabs.md +4 -4
  160. package/docs/usage/components/tag.md +2 -2
  161. package/docs/usage/components/tags-input.md +4 -4
  162. package/docs/usage/components/text-area.md +2 -3
  163. package/docs/usage/components/text.md +85 -4
  164. package/docs/usage/components/timeline.md +2 -2
  165. package/docs/usage/components/toast.md +17 -7
  166. package/docs/usage/components/toggle-group.md +3 -3
  167. package/docs/usage/components/tooltip.md +1 -1
  168. package/docs/usage/components/top-bar.md +5 -4
  169. package/docs/usage/components/top.md +3 -3
  170. package/docs/usage/components/transfer-list.md +5 -4
  171. package/docs/usage/components/upload-item.md +3 -3
  172. package/docs/usage/components/virtual-list.md +1 -0
  173. package/docs/usage/compositions/action-feedback.md +42 -6
  174. package/docs/usage/compositions/action-recovery-optimistic.md +6 -1
  175. package/docs/usage/compositions/action-recovery-save.md +19 -23
  176. package/docs/usage/compositions/action-recovery-undo.md +6 -1
  177. package/docs/usage/compositions/activity-status.md +11 -5
  178. package/docs/usage/compositions/collection-detail.md +2 -0
  179. package/docs/usage/compositions/command-records.md +15 -5
  180. package/docs/usage/compositions/common-message.md +4 -2
  181. package/docs/usage/compositions/common-notification.md +5 -3
  182. package/docs/usage/compositions/compound-controls.md +13 -5
  183. package/docs/usage/compositions/content-transition-comparison.md +2 -2
  184. package/docs/usage/compositions/date-entry.md +10 -5
  185. package/docs/usage/compositions/date-time-selection.md +3 -3
  186. package/docs/usage/compositions/design-profile-comparison.md +7 -5
  187. package/docs/usage/compositions/disclosure.md +1 -1
  188. package/docs/usage/compositions/document-resource.md +10 -3
  189. package/docs/usage/compositions/expo-interactions.md +3 -2
  190. package/docs/usage/compositions/family-drawer.md +9 -4
  191. package/docs/usage/compositions/field-group.md +7 -1
  192. package/docs/usage/compositions/floating-action-button.md +18 -18
  193. package/docs/usage/compositions/illustrated-outcome.md +3 -2
  194. package/docs/usage/compositions/input-sheet.md +6 -2
  195. package/docs/usage/compositions/interaction-adapters.md +1 -1
  196. package/docs/usage/compositions/interaction-flow-apply.md +6 -3
  197. package/docs/usage/compositions/interaction-flow-draft.md +5 -2
  198. package/docs/usage/compositions/interaction-flow-search.md +5 -2
  199. package/docs/usage/compositions/live-list.md +7 -5
  200. package/docs/usage/compositions/navigation-bar-collection.md +8 -7
  201. package/docs/usage/compositions/optional-adapters.md +1 -1
  202. package/docs/usage/compositions/origin-dialog.md +5 -5
  203. package/docs/usage/compositions/paper-surface.md +1 -1
  204. package/docs/usage/compositions/photo-source.md +1 -1
  205. package/docs/usage/compositions/purpose-input-comment.md +5 -3
  206. package/docs/usage/compositions/purpose-input-message.md +5 -3
  207. package/docs/usage/compositions/reference-first.md +63 -42
  208. package/docs/usage/compositions/reference-review.md +60 -50
  209. package/docs/usage/compositions/reference-settings.md +60 -50
  210. package/docs/usage/compositions/selection-scope.md +48 -35
  211. package/docs/usage/compositions/stea-order-progress.md +1 -0
  212. package/docs/usage/compositions/stea-otp-verify.md +5 -3
  213. package/docs/usage/compositions/stea-pixel-empty.md +3 -3
  214. package/docs/usage/compositions/time-selection.md +6 -5
  215. package/docs/usage/compositions/upload-recovery.md +10 -1
  216. package/docs/usage/compositions/video-dialog.md +10 -3
  217. package/docs/usage/compositions/web-additions.md +5 -5
  218. package/docs/usage/compositions/web-navigation.md +1 -1
  219. package/docs/usage/screens/common-chat.md +21 -8
  220. package/docs/usage/screens/common-comments.md +13 -1
  221. package/docs/usage/screens/common-inbox.md +19 -6
  222. package/docs/usage/screens/common-login.md +19 -7
  223. package/docs/usage/screens/common-profile.md +22 -9
  224. package/docs/usage/screens/common-saved.md +16 -2
  225. package/docs/usage/screens/common-search.md +24 -4
  226. package/docs/usage/screens/common-settings.md +22 -50
  227. package/docs/usage/screens/common-shell.md +14 -2
  228. package/docs/usage/screens/dashboard.md +52 -109
  229. package/docs/usage/screens/discovery-gallery.md +57 -148
  230. package/docs/usage/screens/flow-collection.md +38 -9
  231. package/docs/usage/screens/flow-editor.md +25 -7
  232. package/docs/usage/screens/flow-media.md +23 -7
  233. package/docs/usage/screens/flow-moderation.md +15 -2
  234. package/docs/usage/screens/flow-onboarding.md +3 -3
  235. package/docs/usage/screens/flow-permission.md +17 -3
  236. package/docs/usage/screens/landing.md +37 -20
  237. package/docs/usage/screens/mockup-studio.md +22 -7
  238. package/docs/usage/screens/notification-settings.md +18 -4
  239. package/docs/usage/screens/product-bento.md +18 -9
  240. package/docs/usage/screens/reference-comparison.md +29 -10
  241. package/docs/usage/tokens/color.md +6 -3
  242. package/docs/usage/tokens/elevation-opacity.md +4 -2
  243. package/docs/usage/tokens/font-roles.md +2 -2
  244. package/docs/usage/tokens/layers.md +3 -3
  245. package/docs/usage/tokens/motion.md +2 -2
  246. package/docs/usage/tokens/radius.md +4 -2
  247. package/docs/usage/tokens/spacing.md +3 -3
  248. package/docs/usage/tokens/theme-studio.md +2 -2
  249. package/docs/usage/tokens/typography-studio.md +14 -8
  250. package/docs/usage/tokens/typography.md +15 -5
  251. package/package.json +1 -1
@@ -95,7 +95,7 @@ import { Notice } from "@hjmds/react-native/feedback";
95
95
  ## 꼭 지킬 것
96
96
 
97
97
  - 제목·설명·행동 문구는 i18n 키로 넣는다. 아이콘은 제품 소유 자산이고 색은 tone이 정한다.
98
- - 배치는 `layoutStyle`로만 한다. 색·padding·radius를 `style`/`className`으로 덮지 않는다. Native `style`은 deprecated(개발 모드 경고, 다음 major 제거)다.
98
+ - 배치는 `layoutStyle`로만 한다. 색·padding·radius를 `style`/`className`으로 덮지 않는다. Native `style`은 제거된 속성이다.
99
99
  - 같은 화면에 같은 내용의 Notice와 Toast를 동시에 띄우지 않는다.
100
100
 
101
101
  ## 플랫폼 차이
@@ -105,7 +105,7 @@ import { Notice } from "@hjmds/react-native/feedback";
105
105
  | 발표 | 항상 live region. `danger`는 `role="alert"`+assertive, 나머지는 `role="status"`+polite | `announcement`: `none`(기본) · `polite` · `assertive`. 지정해야 발표한다 |
106
106
  | title/description 타입 | `ReactNode` | `string` |
107
107
  | 아이콘 렌더 함수 | 없음 | `renderIcon` |
108
- | 배치 | `className`, `layoutStyle`(HTML `style`도 받음) | `layoutStyle`(`style`은 deprecated) |
108
+ | 배치 | `className`, `layoutStyle`(HTML `style`도 받음) | `layoutStyle`(`style`은 제거된 속성) |
109
109
 
110
110
  ## 함정
111
111
 
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-06
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
  - 스토리북: `배포/화면/소통/알림함`
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-06
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
  - 스토리북: `배포/구성/정보 표시/알림 항목`, `배포/화면/소통/알림함`
@@ -95,4 +95,4 @@ import { NotificationItem } from "@hjmds/react-native/screens";
95
95
  | 상태·시각 줄 | 설명 아래 caption `Text` | `description`과 줄바꿈(`\n`)으로 합친 한 문자열 |
96
96
  | 이동 | `href`, `onClick` | `onPress` |
97
97
  | 추가 슬롯 | `className`, `layoutStyle` | `titleMetadata`, `trailingAction`, `trailingText`, `layoutStyle` |
98
- | 제목 굵기 조정 | `Text emphasis` | 렌더러 비공개 입력(`hjmTitleEmphasis`)으로 안 읽음 700(`fontWeight.bold`)·읽음 400(`fontWeight.regular`). deprecated `ListRow.titleStyle`을 쓰지 않으므로 HJM이 `titleStyle` 경고를 내지 않는다. `NotificationItemProps`에는 `titleStyle`이 없다(미게시(1.12.1 이후)) |
98
+ | 제목 굵기 조정 | `Text emphasis` | 렌더러 비공개 입력(`hjmTitleEmphasis`)으로 안 읽음 700(`fontWeight.bold`)·읽음 400(`fontWeight.regular`). 제거된 `ListRow.titleStyle`을 사용하지 않는다. `NotificationItemProps`에는 `titleStyle`이 없다(1.13.0 변경) |
@@ -120,7 +120,7 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
120
120
  - 단위·통화·소수 자릿수 표시는 만들지 않는다. 보조기기용 문구가 필요하면 `getValueText`로 제품이 포맷한다.
121
121
  - 제어형과 비제어형을 렌더 사이에 바꾸지 않는다(`value`를 넣었다 뺐다 하면 던진다).
122
122
  - `min ≥ max`, `step ≤ 0`, 범위 밖 `value`는 던진다. DurationField도 범위 밖·정수 아닌 초를 던진다.
123
- - 색·높이를 덮지 않는다. 배치는 `layoutStyle`로 한다. Native `inputStyle`·`containerStyle`은 deprecated(개발 모드 경고, 다음 major 제거) — 높이·글꼴은 `size`, 배치는 `layoutStyle`.
123
+ - 색·높이를 덮지 않는다. 배치는 `layoutStyle`로 한다. Native `inputStyle`·`containerStyle`은 제거된 속성 — 높이·글꼴은 `size`, 배치는 `layoutStyle`.
124
124
 
125
125
  ## 플랫폼 차이
126
126
 
@@ -129,5 +129,5 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
129
129
  | 역할 | `spinbutton`, `type="text"` | 입력 + 증감 button, accessibility action |
130
130
  | label·description·error 타입 | `ReactNode` | `string` |
131
131
  | 추가 이름 | 없음 | `accessibilityLabel`, `accessibilityHint` |
132
- | 클래스·스타일 | `className`, `inputClassName`, `layoutStyle`(필드 전체). `style`은 안쪽 input | `layoutStyle`(필드 전체). `inputStyle`·`containerStyle`은 deprecated |
133
- | DurationField 배치 | `className`, `layoutStyle`(fieldset) | `layoutStyle`(미게시(1.12.1 이후), 1.12.1은 감싸는 View) |
132
+ | 클래스·스타일 | `className`, `inputClassName`, `layoutStyle`(필드 전체). `style`은 안쪽 input | `layoutStyle`(필드 전체). `inputStyle`·`containerStyle`은 제거된 속성 |
133
+ | DurationField 배치 | `className`, `layoutStyle`(fieldset) | `layoutStyle`(1.13.0 변경, 1.12.1은 감싸는 View) |
@@ -97,5 +97,5 @@ import { OtpField } from "@hjmds/react-native/otp-field";
97
97
  | 항목 | Web | Native |
98
98
  | --- | --- | --- |
99
99
  | 이름 | `label` | `label` 또는 `accessibilityLabel`만 |
100
- | 칸 스타일 통로 | 없음 | `slotStyle`, `slotTextStyle`은 deprecated(개발 모드 경고, 다음 major 제거). 외형은 `size`·`presentation` |
100
+ | 칸 스타일 통로 | 없음 | `slotStyle`, `slotTextStyle`은 제거된 속성. 외형은 `size`·`presentation` |
101
101
  | busy 표현 | read-only + `aria-busy` | `editable={false}` + `accessibilityState.busy` |
@@ -12,7 +12,7 @@
12
12
 
13
13
  같은 데이터와 기능을 유지하면서 테마별 행·카드·격자와 도구 배치를 선택하는 목록 화면에 쓴다.
14
14
 
15
- 기본 공개 API는 npm 1.15.0에 있다. 후속 글자 역할·종이 줄 간격·토큰 소비 개선의 main 구현은 별도 미게시이며, 이 적용 버전으로 후속 개선까지 게시됐다고 해석하지 않는다.
15
+ 기본 공개 API는 npm 1.15.0에 있다. 글자 역할·종이 줄 간격·토큰 소비 개선은 1.16.0 변경이다. 실제 설치 버전과 기기 검증은 별도로 확인한다.
16
16
 
17
17
  ## 쓰지 않을 때
18
18
 
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-06
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
  - 스토리북: `배포/화면/소개/권한 안내`
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-06
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
  - 스토리북: `배포/구성/선택과 필터/사진 촬영과 앨범 선택`
@@ -63,7 +63,7 @@ Native 예는 없다(renderer 없음).
63
63
  | `dismissPolicy`(부분 지정) | `{ dismissible?, outsideDismiss?, escapeDismiss?, focusOutDismiss? }`(`boolean`) | 모두 `true` | |
64
64
  | `open` · `defaultOpen` | `boolean` | 비제어 `false` | 제어하면 `onOpenChange` 필수 |
65
65
  | `onOpenChange` | `(open: boolean, details: { reason }) => void` | — | `reason`: `trigger` · `close-action` · `outside-pointer` · `outside-focus` · `escape` · `programmatic` |
66
- | `motionOrigin` | `TransitionRect` | — | 미게시: 열기 직전 viewport 좌표. 위치 확정 뒤 공간 전환하며 기존 비모달 초점·닫기 정책 유지 |
66
+ | `motionOrigin` | `TransitionRect` | — | 1.14.0 추가: 열기 직전 viewport 좌표. 위치 확정 뒤 공간 전환하며 기존 비모달 초점·닫기 정책 유지 |
67
67
  | `initialFocusRef` | `RefObject<HTMLElement \| null>` | 첫 포커스 가능 요소 | 열릴 때 처음 포커스 |
68
68
  | `portalContainer` | `HTMLElement` | `document.body` | 표면을 붙일 곳 |
69
69
  | `className` | 문자열 | — | `layoutStyle`은 받지 않는다(아래 함정) |
@@ -113,7 +113,7 @@ Native 예는 없다(renderer 없음).
113
113
  - 초안은 Popover 위의 제품 상태에 둔다. 종료 후 portal이 제거되므로 내부 비제어 입력에만 두면 사라진다.
114
114
  - 공간 전환 실험은 [버튼에서 이어지는 편집](../compositions/origin-dialog.md)의 Web 전용 변형이다.
115
115
 
116
- 미게시(1.14.0 이후): 가장 가까운 프로필의 `shadow.floating`을 열린 portal에도 상속한다. 프로필이 없으면 기존 recipe 그림자를 유지한다. 초안과 비모달 초점/닫기 계약은 그대로이며 Native는 기존 Sheet 경로를 쓴다.
116
+ 1.15.0 변경: 가장 가까운 프로필의 `shadow.floating`을 열린 portal에도 상속한다. 프로필이 없으면 기존 recipe 그림자를 유지한다. 초안과 비모달 초점/닫기 계약은 그대로이며 Native는 기존 Sheet 경로를 쓴다.
117
117
 
118
118
  [Motion 세 편집 예제 검토](../../../../../docs/qa/2026-10-07-motion-reference-page-review.md)에서
119
119
  aria-modal 표시와 실제 초점 경계가 다르고, 닫기 후 defaultValue 편집이 초기화되는 것을 확인했다.
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-06
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
  - 스토리북: `배포/화면/계정/프로필`
@@ -104,7 +104,7 @@ linear circular (Web) circular (Native)
104
104
  `max ≤ 0`, 범위 밖 `value`는 던진다.
105
105
  - 이름은 지역화한 `label`로 준다. Native는 보이는 label 없이 `accessibilityLabel`만 줄 수도 있다(`ScrollProgress`는 `label` 필수).
106
106
  - 색은 `tone`, 두께는 `size`로만 바꾸고 배치는 `layoutStyle`로 한다. Native의 `style`·`labelStyle`·`valueStyle`·`trackStyle`·`indicatorStyle`은
107
- deprecated(개발 모드 경고, 다음 major 제거)다.
107
+ 제거된 속성이다.
108
108
  - `ScrollProgress`는 window에 자동으로 붙지 않는다. Web은 스크롤 host를, Native는 측정값을 반드시 넘긴다.
109
109
  - 작업 완료율에는 `ScrollProgress`가 아니라 `Progress`를 쓴다.
110
110
 
@@ -125,7 +125,7 @@ linear circular (Web) circular (Native)
125
125
 
126
126
  2026-10-07 레퍼런스 조사에서 끝까지 스크롤한 마지막 행도 블러에 가려지는 문제를 확인했다.
127
127
  새 `resolveScrollEdges`는 같은 `ScrollMetrics`에서 논리적 이전/다음 콘텐츠 존재 여부를 계산한다.
128
- 아직 미게시이며 `/scroll-progress` subpath에서 제공한다. 블러 renderer 자체를 제공한다는 뜻은 아니다.
128
+ 1.14.0부터 `/scroll-progress` subpath에서 제공한다. 블러 renderer 자체를 제공한다는 뜻은 아니다.
129
129
 
130
130
  ```ts
131
131
  import { resolveScrollEdges } from "@hjmds/design-contracts/scroll-progress";
@@ -76,7 +76,7 @@ import { spacing } from "@hjmds/design-contracts/foundations";
76
76
  | `fallback` | `ReactNode` | 필수 | QR 아래에 그려지는 대체 행동(`null`·`false`면 `TypeError`) |
77
77
  | `size` | 숫자(px) | `192` | 실제 크기는 모듈 수의 정수배로 내림된다. 모듈당 2px 미만이면 `TypeError` |
78
78
  | `level` | `L` · `M` · `Q` · `H` | `M` | 오류 정정 수준 |
79
- | `layoutStyle` | 배치 전용 style 객체 | — | 루트 배치만(Native는 미게시(1.12.1 이후)) |
79
+ | `layoutStyle` | 배치 전용 style 객체 | — | 루트 배치만(Native는 1.13.0 변경) |
80
80
 
81
81
  콜백은 없다. `style`·`className`은 두 renderer 모두 없다. 1.12.1 Native는 `layoutStyle`이 없어 감싸는 레이아웃에서 배치한다.
82
82
 
@@ -117,6 +117,6 @@ import { spacing } from "@hjmds/design-contracts/foundations";
117
117
  | --- | --- | --- |
118
118
  | 그리기 | 인라인 `<svg role="img">` | `react-native-svg`, 감싼 `View`가 `accessibilityRole="image"` |
119
119
  | 필요한 peer | `qrcode-generator` | `qrcode-generator`, `react-native-svg` |
120
- | 배치 | `layoutStyle` | `layoutStyle`(미게시(1.12.1 이후), 1.12.1은 감싸는 View) |
120
+ | 배치 | `layoutStyle` | `layoutStyle`(1.13.0 변경, 1.12.1은 감싸는 View) |
121
121
 
122
122
  - 2026-10-06 독립 재구현에서 QRCode 바깥 Stack의 gap으로 내부 QR–fallback 간격을 바꿀 수 없음을 확인해 슬롯 안 여백 예제로 수정했다.
@@ -108,8 +108,7 @@ card(vertical) grouped(vertical)
108
108
  `value`/`defaultValue`가 items에 없으면 `RangeError`를 던진다. 서버 목록은 정리한 뒤 넘긴다.
109
109
  - 옛 Native `options` prop은 1.11에서 제거됐다. 넘기면 `TypeError`다([이관표](../../migration-native-legacy-removal.md)).
110
110
  - 오류 문구는 `error`로 넘긴다. 그룹 아래에 별도 Text로 직접 그리지 않는다.
111
- - 배치는 `layoutStyle`로 한다. Native의 `style`과 slot style(`controlStyle`·`indicatorStyle`·`labelStyle` 등)은 deprecated
112
- (개발 모드 경고, 다음 major 제거)다([소비 정책 §3.1](../../consumer-policy.md)). 외형은 `presentation`·`size`·`renderIndicator`로 바꾼다.
111
+ - 배치는 `layoutStyle`로 한다. Native의 `style`과 slot style(`controlStyle`·`indicatorStyle`·`labelStyle` 등)은 제거된 속성이다([소비 정책 §3.1](../../consumer-policy.md)). 외형은 `presentation`·`size`·`renderIndicator`로 바꾼다.
113
112
 
114
113
  ## 플랫폼 차이
115
114
 
@@ -88,8 +88,7 @@ import { Radio } from "@hjmds/react-native/inputs";
88
88
  - 묶음의 접근성 이름(fieldset/radiogroup)은 Radio가 만들지 않는다. 단독 Radio 여러 개로 묶음을
89
89
  흉내 내지 말고 RadioGroup을 쓴다.
90
90
  - 선택 표시는 indicator(dot)가 맡는다. 색만으로 선택을 알리도록 바꾸지 않는다.
91
- - 배치는 `layoutStyle`로 한다. Native의 `style`·`controlStyle`·`labelStyle` 등 slot style은 deprecated(개발 모드 경고,
92
- 다음 major 제거)다. 색·글자·radius·높이를 덮지 않는다([소비 정책 §3.1](../../consumer-policy.md)).
91
+ - 배치는 `layoutStyle`로 한다. Native의 `style`·`controlStyle`·`labelStyle` 등 slot style은 제거된 속성이다. 색·글자·radius·높이를 덮지 않는다([소비 정책 §3.1](../../consumer-policy.md)).
93
92
 
94
93
  ## 플랫폼 차이
95
94
 
@@ -113,4 +113,4 @@ import { Result } from "@hjmds/react-native/feedback";
113
113
  | 아이콘 | `icon`(ReactNode) | `renderIcon({ status, color, backgroundColor })` |
114
114
  | 제목 heading 수준 | `headingLevel` | `accessibilityRole="header"` 고정 |
115
115
  | 실패 알림 | `role="alert"`(그 외 `status`) | assertive live region, iOS는 `announceForAccessibility` |
116
- | 바깥 배치 | `className`, `layoutStyle`(HTML `style`도 받음) | `layoutStyle`(`style`은 deprecated — 개발 모드 경고, 다음 major 제거) |
116
+ | 바깥 배치 | `className`, `layoutStyle`(HTML `style`도 받음) | `layoutStyle`(`style`은 제거된 속성) |
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
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
  - 스토리북: `배포/화면/콘텐츠/저장한 항목`
@@ -87,7 +87,7 @@ import { SavedItemsScreen } from "@hjmds/react-native/saved-items";
87
87
  | actions · leading | ScreenLayout 상속 | 없음 | 홈에서는 제품 `actions` 대신 컬렉션 만들기 버튼이 그 자리를 쓰고 제품 `leading`은 유지된다. 컬렉션·상세에서는 `leading`이 뒤로 버튼이 되고 제품 `actions`가 보인다 |
88
88
  | renderThumbnail · renderDetail | `(item) => ReactNode`, 필수 | — | 사진·상세 슬롯, API·자산은 제품 소유 |
89
89
  | state · notice | ScreenLayout 상속 | ready · 없음 | 조회 상태, 저장 해제/복구 안내 |
90
- | layoutStyle | `HjmCompositionStyleProp` | 없음 | Web·Native 모두 목록·상세를 담는 ListDetailScreen 바깥 틀에 적용한다(컬렉션·격자·상세 전환과 상관없이 같은 루트). 미게시(1.12.1 이후) |
90
+ | layoutStyle | `HjmCompositionStyleProp` | 없음 | Web·Native 모두 목록·상세를 담는 ListDetailScreen 바깥 틀에 적용한다(컬렉션·격자·상세 전환과 상관없이 같은 루트). 1.13.0 변경 |
91
91
  | className(Web) | `string` | 없음 | 안쪽 목록 ScreenLayout에 붙는다 |
92
92
 
93
93
  ## 배치
@@ -126,3 +126,5 @@ Native collection cover의 모서리는 Provider의 `tokens.radius.md`다. 저
126
126
 
127
127
  - 비공개 안내는 권한 구현이 아니다. 서버에서 소유자 접근을 검사한다.
128
128
  - HTML/WebView나 Instagram 자산을 복사하는 구현이 아니다. 제품 사진·테마·문구를 슬롯으로 전달한다.
129
+
130
+ 미게시(1.18.0 이후): 선택한 컬렉션의 항목이 0개면 별도 Text 행 대신 ListDetailScreen의 empty 상태를 사용해 남은 본문 중앙에 안내한다. 명시한 loading/error/restricted가 우선하고 컬렉션 개요는 ready를 유지한다. 커버는 그룹별로 한 번 계산하며 기존 items 순서의 첫 네 항목을 사용한다.
@@ -3,8 +3,8 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
7
- - 검토일: 2026-10-07
6
+ - 적용: 1.17.1
7
+ - 검토일: 2026-10-13
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,7 +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
+ | `presentation` | `"dashboard"` · `"editorial"` · `"landscape"` | 가장 가까운 profile.screens.overview / 없으면 기존 골격 | [디자인 프로필](../../design-profile.md)의 제공 범위를 따른다. 명시값이 프로필을 이긴다. 헤더 배치·읽기 폭만 바꾸고 상태·입력·행동 슬롯은 유지한다 |
83
83
  | `as` (Web) | `"main"` · `"section"` | `"main"` | 제품 셸에 이미 `<main>`이 있으면 `section` |
84
84
  | `layoutStyle` | `HjmCompositionStyleProp` | 없음 | 화면 루트 배치 전용(예: 분할 화면의 `flex`·`width`). ScreenLayout 위에 만든 화면은 모두 이 prop을 루트까지 넘긴다 |
85
85
  | `className` (Web) | `string` | 없음 | 식별·배치 보조. 색·여백을 덮지 않는다 |
@@ -98,6 +98,7 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
98
98
  ## 꼭 지킬 것
99
99
 
100
100
  - Web의 화면 스크롤 본문은 Tab으로 진입할 수 있다. `scroll="content"`의 정상 본문은 자식이 키보드 스크롤을 소유하지만, 오류·빈 상태 등 대체 안내는 화면 스크롤로 바뀌며 Tab 진입도 함께 복원된다.
101
+ - Web에서 본문에 초점을 가진 입력·재시도 버튼이 상태 전환으로 제거되면 같은 본문으로 초점을 복구한다. `scroll="content"`의 본문은 이 복구만을 위한 `tabIndex=-1`을 가지며 일반 Tab 순서에는 추가되지 않는다. 사용자가 다른 컨트롤이나 바깥 영역으로 초점을 옮긴 경우에는 이동시키지 않는다. 2026-10-13 재시도·권한 제한 전환에서 초점이 body로 유실된 경로를 수정했다.
101
102
  - 가상화 목록(FlatList, VirtualList)을 넣으면 `scroll="content"`로 둔다. 스크롤을 이중으로 중첩하지 않는다.
102
103
  - 새로고침 실패·저장 오류는 `state`를 바꾸지 말고 `ready` + `notice`로 알린다. `loading`으로 바꾸면 본문이
103
104
  unmount되어 입력 초안이 사라진다.
@@ -117,7 +117,7 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
117
117
  | --- | --- | --- |
118
118
  | 진행 상태 prop | `loading`(+`renderLoadingIndicator`) | `busy`(+`renderBusyIndicator`, `busyLabel` 필수) |
119
119
  | 검색 아이콘 | `renderSearchIcon`, 또는 `leading` | `renderLeading`, 또는 `leading` |
120
- | 진행 중 입력 | 입력 가능(`aria-busy`) | 입력 가능(`accessibilityState.busy`). 2026-10-06까지 Native는 `busy`인 동안 입력을 무시했다(1.12.1 이후 미게시) |
120
+ | 진행 중 입력 | 입력 가능(`aria-busy`) | 입력 가능(`accessibilityState.busy`). 2026-10-06까지 Native는 `busy`인 동안 입력을 무시했다(1.13.0 변경) |
121
121
  | 입력 요소 | `<input type="search">`, 원시 `onChange`도 전달 | `TextInput` |
122
122
  | 배치 | `layoutStyle`·`fieldClassName`(필드 틀), `style`은 안쪽 input | `layoutStyle` |
123
123
 
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-06
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screens.tsx`·`src/screen-flows.tsx`; 기존 개별 지침을 새 규격으로 통합. `onSubmit`·`filtersOverflow`는 2026-10-06 사용자 요청("검색과 필터 있는 앱 서비스 따라해")의 검색 화면 개편에서 추가. 같은 날 사용자 위임 결정(권장안)으로 미리보기에만 있던 두 단계 검색 로직(`committedQuery`·`recentQueries`·`suggestedQueries`·`suggestions`·`resultSummary`·`appliedFilters`·`filterSheet`)과 `queryLabelVisibility`를, utilverse 적용 조사로 `searching`·`searchingLabel`을 추가([계약 결정 표](../../screen-patterns.md#searchscreen-두-단계-검색)). 1.13.0 utilverse 적용에서 드러난 결함으로 `hostGutter`와 확정 시 키보드 닫기(Web 결과 영역 포커스)를 추가(1.13.1 patch). 예제 스토리는 2026-10-06 사용자 승인으로 스토리북 배포([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). 스토리북 배포는 API 게시가 아니다(`적용` 참고)
9
9
  - 스토리북: `배포/화면/검색/검색 결과와 필터`
@@ -144,9 +144,9 @@ import { SearchScreen } from "@hjmds/react-native/screen-flows";
144
144
  | `onSearch` | `(query: string, context: { signal: AbortSignal }) => void` | 필수 | `debounceMs` 뒤 호출. 값이 바뀌면 이전 타이머를 지우고 이전 신호를 abort한다 |
145
145
  | `queryClearLabel` | `string` | `queryField`가 없으면 필수 | 기본 입력의 지우기 버튼 이름. 비어 있으면 `TypeError` |
146
146
  | `queryField` | `ReactNode` | 없음 | 기본 `SearchField` 대신 그릴 입력. 지우기 동작을 직접 제공한다 |
147
- | `debounceMs` | `number` | `300` | 0 미만은 0 |
147
+ | `debounceMs` | `number` | `searchScreenRecipe.debounceMs` (`300`) | 유한값을 받으며 0 미만은 0. `NaN`·±`Infinity`는 `RangeError`. 두 renderer가 `resolveSearchDebounceMs`를 공유한다 |
148
148
  | `filters` | `ReactNode` | 없음 | 검색 입력 아래, 상단에 고정. 두 단계 검색에서는 결과 단계에만, 검색어 때문인 0건에는 숨긴다 |
149
- | `onSubmit` | `(query: string) => void` | 없음 | 확정 신호. 모든 확정에서 키보드를 닫는다(Native `Keyboard.dismiss()`, Web은 고른 항목이면 결과 영역으로 포커스, 미게시(1.13.1 이후)) — 아래 플랫폼 차이. 기본 입력의 Web Enter(`enterKeyHint="search"`, IME 조합 중 Enter는 무시)·Native 키보드 검색 키(`returnKeyType="search"`, `onSubmitEditing`)와 SearchScreen이 그린 확정 행·제안·최근·추천 검색어가 모두 여기로 온다. 앞뒤 공백을 지운 값이고 공백만이면 부르지 않는다. 고른 값이 입력과 다르면 먼저 `onQueryChange`. 대기 중인 `onSearch` debounce는 그대로 둔다. `queryField`를 주면 그 입력의 키는 연결하지 않는다 |
149
+ | `onSubmit` | `(query: string) => void` | 없음 | 확정 신호. 모든 확정에서 키보드를 닫는다(Native `Keyboard.dismiss()`, Web은 고른 항목이면 결과 영역으로 포커스, 1.13.1 변경) — 아래 플랫폼 차이. 기본 입력의 Web Enter(`enterKeyHint="search"`, IME 조합 중 Enter는 무시)·Native 키보드 검색 키(`returnKeyType="search"`, `onSubmitEditing`)와 SearchScreen이 그린 확정 행·제안·최근·추천 검색어가 모두 여기로 온다. 앞뒤 공백을 지운 값이고 공백만이면 부르지 않는다. 고른 값이 입력과 다르면 먼저 `onQueryChange`. 대기 중인 `onSearch` debounce는 그대로 둔다. `queryField`를 주면 그 입력의 키는 연결하지 않는다 |
150
150
  | `committedQuery` | `string` | 없음 | 결과를 보여 줄 확정 검색어. 주면 두 단계 검색(`onSubmit` 필수, 타입). 단계: 검색어 공백 = 검색 전, 확정값과 다름 = 입력 중, 같음 = 결과(앞뒤 공백 무시). `children`은 결과 단계에만 그린다 |
151
151
  | `queryLabelVisibility` | `visible` · `hidden` | `visible` | `hidden`이면 보이는 label 없이 `queryLabel`을 접근성 이름(Web `aria-label`, Native `accessibilityLabel`)과 placeholder로 쓴다 |
152
152
  | `searching` · `searchingLabel` | `boolean` · `string` | 없음 | 기본 입력의 진행 표시(Web `loading`, Native `busy`+`busyLabel`). 함께 주거나 함께 생략(타입). 켜져 있으면 `searchingLabel`을 낭독한다 |
@@ -158,7 +158,7 @@ import { SearchScreen } from "@hjmds/react-native/screen-flows";
158
158
  | `appliedFilters` | `{ items: { key, label }[], removeLabel(label), onRemove(key), clearAllLabel, onClearAll(), removeIcon? }` | 없음 | 결과 머리 아래 × 칩 + `모두 해제`. 개수는 trigger 이름과 0건 원인 판정에도 쓴다 |
159
159
  | `filterSheet` | `{ open, onOpenChange(open), title, value, onApply(next), count(draft): number \| null, reset(draft), isDefault(draft), renderContent(draft, setDraft), labels: { close, reset, apply(count) }, size?, trigger? }` | 없음 | 열 때 `value`를 초안으로 복사, 닫히면 초안을 버림, 주 행동에서만 `onApply`. `count = 0`이면 주 행동 비활성, `isDefault`면 초기화 비활성. `trigger`를 주면 칩 줄 맨 앞에 `label(적용 개수)` Chip |
160
160
  | `filtersOverflow` | `wrap` · `scroll` | `wrap` | `scroll`이면 `filters`를 한 줄 가로 스크롤 영역에 넣고 화면 좌우 여백(`spacing.md` 16, `contentInset="none"`이면 0)에 `hostGutter`를 더한 만큼 가장자리까지 넓힌다. 첫 칩은 검색 입력과 같은 시작선에 놓인다 |
161
- | `hostGutter` | `none` · `compact` · `regular` · `spacious` | `none` | 미게시(1.13.1 이후). 이 화면을 감싼 host가 이미 준 좌우 여백 이름(`containerRecipe.gutters`: 0 · `spacing.md` 16 · `spacing.lg` 20 · `spacing.xl` 24). Container 안이면 그 `gutter`, Sheet 본문 안이면 `regular`(`sheetRecipe.content.paddingHorizontal`과 같은 `spacing.lg`). `scroll` 줄만 이 값을 쓴다 |
161
+ | `hostGutter` | `none` · `compact` · `regular` · `spacious` | `none` | 1.13.1 변경. 이 화면을 감싼 host가 이미 준 좌우 여백 이름(`containerRecipe.gutters`: 0 · `spacing.md` 16 · `spacing.lg` 20 · `spacing.xl` 24). Container 안이면 그 `gutter`, Sheet 본문 안이면 `regular`(`sheetRecipe.content.paddingHorizontal`과 같은 `spacing.lg`). `scroll` 줄만 이 값을 쓴다 |
162
162
  | `recentSearches` | `ReactNode` | 없음 | `query`가 공백일 때만 본문 맨 위에 보인다 |
163
163
  | `children` | `ReactNode` | 필수 | 결과 |
164
164
  | 나머지 | `ScreenLayout`과 같음(`children`·`footer` 제외) | — | `notice`는 필터 아래에 붙는다 |
@@ -78,7 +78,7 @@ import { Section } from "@hjmds/react-native/primitives";
78
78
  | 항목 | 값 | 근거 |
79
79
  | --- | --- | --- |
80
80
  | 크기 | 자체 배경·테두리·여백이 없다. 폭은 부모를 따른다 | `.hjm-section` |
81
- | 글자 | 제목 `title` 18/26 bold, 설명 `caption` 11/16(두 플랫폼). 2026-10-06까지 Web은 둘 다 본문 14를 물려받았다(1.12.1 이후 미게시) | `sectionRecipe.title`·`description`, `.hjm-section__title`·`__description` |
81
+ | 글자 | 제목 `title` 18/26 bold, 설명 `caption` 11/16(두 플랫폼). 2026-10-06까지 Web은 둘 다 본문 14를 물려받았다(1.13.0 변경) | `sectionRecipe.title`·`description`, `.hjm-section__title`·`__description` |
82
82
  | 간격 | 머리와 본문 사이 `spacing.xs` 8, 글자 묶음과 행동 사이 `spacing.sm` 12, 제목과 설명 사이 `spacing.xxs` 4. Section끼리의 간격은 Section이 주지 않는다. 감싸는 [Stack](stack.md)이나 `layoutStyle`로 `layout.sectionGap`(`spacing.xl` 24)을 둔다 | `sectionRecipe.gap`·`headerGap`·`copyGap`, `layout.sectionGap` |
83
83
  | 순서·정렬 | 머리 행동은 끝(LTR 오른쪽)에 하나, 글자 묶음과 세로 가운데 정렬. 보통 [Link](link.md) 또는 `tone="link"` [Button](button.md) | `.hjm-section__header`, Native `Section` |
84
84
  | 고정·스크롤 | 고정되지 않는다. 화면 본문 스크롤 안에 둔다 | — |
@@ -98,7 +98,7 @@ import { Section } from "@hjmds/react-native/primitives";
98
98
 
99
99
  - 제목·설명은 i18n 문구로 넣는다. Native는 `string`만 받는다.
100
100
  - 배치는 `layoutStyle`로 한다. Native slot 배치는 `headerStyle`·`copyStyle`·`actionStyle`·`contentStyle`(모두 배치 전용 타입)이다.
101
- Native `style`은 deprecated(개발 모드 경고, 다음 major 제거)다.
101
+ Native `style`은 제거된 속성이다.
102
102
  - 머리 행동은 하나로 둔다. 여러 행동은 본문 안이나 [Menu](menu.md)로 옮긴다.
103
103
 
104
104
  ## 플랫폼 차이
@@ -108,4 +108,4 @@ import { Section } from "@hjmds/react-native/primitives";
108
108
  | `title`·`description` 타입 | `ReactNode` | `string` |
109
109
  | heading 수준 | `headingLevel` | 없음(header role 고정) |
110
110
  | 루트 | `<section>` | `View` |
111
- | 배치 | `className`, `layoutStyle`(HTML `style`도 받음) | `layoutStyle`, slot `*Style`(`style`은 deprecated) |
111
+ | 배치 | `className`, `layoutStyle`(HTML `style`도 받음) | `layoutStyle`, slot `*Style`(`style`은 제거된 속성) |
@@ -66,7 +66,7 @@ import { SegmentedControl } from "@hjmds/react-native/inputs";
66
66
  | prop | 값 | 기본값 | 설명 |
67
67
  | --- | --- | --- | --- |
68
68
  | `items` | Web `readonly { value: string; label: ReactNode; disabled? }[]` · Native `readonly { value: Value; label: string; disabled?; leading?; renderLeading? }[]` | 필수 | 값이 비거나 중복이면 던진다 |
69
- | `presentation` | `connected` · `pills` | `connected` | 연결된 보기 전환 / 독립된 카테고리 필터. `pills`는 미게시(1.12.1 이후) |
69
+ | `presentation` | `connected` · `pills` | `connected` | 연결된 보기 전환 / 독립된 카테고리 필터. `pills`는 1.13.0 변경 |
70
70
  | `size` | `small` · `medium` | `medium` | 항목 최소 높이 36(+hitSlop 4) · 44 |
71
71
  | `value` · `defaultValue` | 항목 값 | 첫 번째 활성 항목 | 선택 해제 상태는 없다 |
72
72
  | `onValueChange` | Web `(value: string) => void` · Native `(value: Value) => void` | — | 다른 항목을 고를 때. `null`은 오지 않는다 |
@@ -74,7 +74,7 @@ import { SegmentedControl } from "@hjmds/react-native/inputs";
74
74
  | `disabled` | `boolean` | `false` | 전체 비활성(Web은 fieldset 속성) |
75
75
  | `layoutStyle` | 배치 전용 style 객체 | — | 바깥 배치 |
76
76
 
77
- `connected`는 글자 크기 160% 이상(`stackAtFontScale`)에서 항목을 세로로 쌓는다. `pills`는 쌓지 않는다(`pills.largeTextLayout` `wrap`, 미게시(1.13.1 이후)).
77
+ `connected`는 글자 크기 160% 이상(`stackAtFontScale`)에서 항목을 세로로 쌓는다. `pills`는 쌓지 않는다(`pills.largeTextLayout` `wrap`, 1.13.1 변경).
78
78
 
79
79
  ## 배치
80
80
 
@@ -103,7 +103,7 @@ import { SegmentedControl } from "@hjmds/react-native/inputs";
103
103
  `value`가 비활성 항목이어도 `RangeError`다.
104
104
  - 옛 Native `options` prop은 제거됐다. 넘기면 `TypeError`다([이관표](../../migration-native-legacy-removal.md)).
105
105
  - 연결형의 선택 표시는 focus 색 테두리(ring), `pills`는 본문색 채움과 반전 글자다. 제품에서 선택 배경을 직접 덮지 않는다. 배치는 `layoutStyle`로 하고, Native `style`은
106
- deprecated(개발 모드 경고, 다음 major 제거)다.
106
+ 제거된 속성이다.
107
107
 
108
108
  ## 플랫폼 차이
109
109
 
@@ -134,7 +134,7 @@ import { SegmentedControl } from "@hjmds/react/selection";
134
134
  items={categories} value={category} onValueChange={setCategory} />
135
135
  ```
136
136
 
137
- Native는 `@hjmds/react-native/inputs`에서 같은 prop을 사용한다. `presentation`은 게시 버전 1.12.1에 없다(미게시, 1.12.1 이후). 게시·소비 앱 반영 전에는 연결형을 쓴다.
137
+ Native는 `@hjmds/react-native/inputs`에서 같은 prop을 사용한다. `presentation`은 1.13.0 추가 API다. 연결형과 pills는 같은 단일 선택 계약을 따른다.
138
138
  스토리는 `버튼형 선택`의 `알약 모양`·`비활성`·`알약 모양 · 큰 글자`다. 2026-10-06 사용자 승인으로 실험 `입력/카테고리 필터` 항목을 배포하면서 별도 공개 API가 아니라 이 표현이라 그 스토리로 합쳤다([승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정)). Storybook 배포는 npm 게시가 아니다.
139
139
 
140
140
  ## 함정
@@ -107,7 +107,7 @@ import { NativeSelect } from "@hjmds/react/forms";
107
107
  | 항목 | 값 | 근거 |
108
108
  | --- | --- | --- |
109
109
  | 크기 | 트리거 최소 높이 `medium` 44 · `large` 52, 폼 열 폭을 채운다(Web `inline-size: 100%`). 선택지 행 `comfortable` 56 · `compact` 44. Web 목록 최대 폭 420(`min(26.25rem, 100vw − 2×spacing.md)`)·최대 높이 360. Native sheet 최대 높이 75% | `fieldFrameContract.minHeight`, `control.buttonHeight.large`, `selectRecipe.density`·`popover`, `.hjm-select__listbox`, Native `forms.tsx` |
110
- | 간격 | 트리거 좌우 `medium` `spacing.md` 16 · `large` `spacing.lg` 20(recipe), 안쪽 요소 사이 `spacing.sm` 12. 라벨·설명·오류와 `spacing.xs` 8. Web 목록은 트리거에서 8 떨어지고 안쪽 여백 `spacing.xs` 8(`selectRecipe.popover.padding`; 2026-10-06까지 4, 1.12.1 이후 미게시), 화면 가장자리에서 8(`selectRecipe.popover.collisionPadding`). Native sheet 안쪽 `spacing.md` 16, 머리와 목록 사이 `spacing.sm` 12 | `selectRecipe.sizes`·`value.gap`, `formSupportContract.gap`, `selectRecipe.popover`(sideOffset 8, collisionPadding 8, padding 8), Native `forms.tsx` |
110
+ | 간격 | 트리거 좌우 `medium` `spacing.md` 16 · `large` `spacing.lg` 20(recipe), 안쪽 요소 사이 `spacing.sm` 12. 라벨·설명·오류와 `spacing.xs` 8. Web 목록은 트리거에서 8 떨어지고 안쪽 여백 `spacing.xs` 8(`selectRecipe.popover.padding`; 2026-10-06까지 4, 1.13.0 변경), 화면 가장자리에서 8(`selectRecipe.popover.collisionPadding`). Native sheet 안쪽 `spacing.md` 16, 머리와 목록 사이 `spacing.sm` 12 | `selectRecipe.sizes`·`value.gap`, `formSupportContract.gap`, `selectRecipe.popover`(sideOffset 8, collisionPadding 8, padding 8), Native `forms.tsx` |
111
111
  | 순서·정렬 | 트리거: 앞 아이콘 → 값(넘치면 말줄임) → 펼침 표시. Web 목록은 트리거 아래·트리거와 같은 폭, 공간이 없으면 위로 뒤집힌다. Native sheet 머리는 제목 + 끝쪽 닫기 ×(44). 확인 버튼은 없고 항목을 누르면 선택하고 닫힌다 | `.hjm-select__trigger`, `select.tsx`(`matchAnchorWidth`), `CollectionSheetHeader` |
112
112
  | 고정·스크롤 | Web 목록은 `position: fixed` popover(z-index `layer.dropdown` 400), 넘치면 목록 안에서 스크롤. Native는 화면 아래에서 올라오는 modal sheet로 목록만 스크롤되고, 아래 여백에 안전 영역(`safeArea.bottom`)을 더한다. 배경(scrim)을 누르면 닫힌다 | `.hjm-select__listbox`, Native `Select`(Modal·ScrollView) |
113
113
  | 좁은 폭·큰 글자 | 트리거 높이는 최소값이라 큰 글자에서 늘어나고 값은 한 줄 말줄임이다. Web 목록 폭은 화면 폭 − 32를 넘지 않는다 | `.hjm-select__value`, `.hjm-select__listbox` |
@@ -135,8 +135,7 @@ Web popover Native sheet
135
135
  - 옛 Native `options`·`value`·`onValueChange`는 1.11에서 제거됐다. `items`/`selectedKey`/`onSelectionChange`를 쓴다.
136
136
  - Native 선택 후 화면 이동·다른 modal 열기는 `onSelectionAfterDismiss`에서 한다. sheet가 닫히기 전에
137
137
  다음 modal을 띄우지 않는다.
138
- - 배치는 `layoutStyle`로 한다. Web `className`·`style`은 트리거 버튼에 붙는다. Native `style`은 deprecated(개발 모드 경고,
139
- 다음 major 제거)다.
138
+ - 배치는 `layoutStyle`로 한다. Web `className`·`style`은 트리거 버튼에 붙는다. Native `style`은 제거된 속성이다.
140
139
 
141
140
  ## 플랫폼 차이
142
141
 
@@ -34,55 +34,17 @@
34
34
 
35
35
  ## 최소 사용 예
36
36
 
37
- ```tsx
38
- // Web — Switch는 /selection, ListRow는 /display, 행 이동은 onClick(또는 href)
39
- import { SettingsScreen } from "@hjmds/react/screens";
40
- import { Switch } from "@hjmds/react/selection";
41
- import { ListRow } from "@hjmds/react/display";
42
-
43
- <SettingsScreen
44
- title={t("settings.title")}
45
- sections={[
46
- { id: "notifications", title: t("settings.notifications"), children: (
47
- <Switch
48
- presentation="row"
49
- label={t("settings.push.label")}
50
- description={t("settings.push.description")}
51
- checked={pushEnabled}
52
- onCheckedChange={setPushEnabled}
53
- />
54
- ) },
55
- { id: "account", title: t("settings.account"), children: (
56
- <ListRow title={t("settings.language")} description={currentLanguageName} onClick={openLanguageSheet} />
57
- ) },
58
- ]}
59
- />
60
- ```
61
-
62
- ```tsx
63
- // Native — Switch는 /inputs, ListRow는 /data-display, 행 이동은 onPress
64
- import { SettingsScreen } from "@hjmds/react-native/screens";
65
- import { Switch } from "@hjmds/react-native/inputs";
66
- import { ListRow } from "@hjmds/react-native/data-display";
67
-
68
- <SettingsScreen
69
- title={t("settings.title")}
70
- sections={[
71
- { id: "notifications", title: t("settings.notifications"), children: (
72
- <Switch
73
- presentation="row"
74
- label={t("settings.push.label")}
75
- description={t("settings.push.description")}
76
- checked={pushEnabled}
77
- onCheckedChange={setPushEnabled}
78
- />
79
- ) },
80
- { id: "account", title: t("settings.account"), children: (
81
- <ListRow title={t("settings.language")} description={currentLanguageName} onPress={openLanguageSheet} />
82
- ) },
83
- ]}
84
- />
85
- ```
37
+ 문서와 Storybook은 같은 실행 예제를 참조한다. 제품 데이터·문구·저장·라우팅은 제품에서 연결하고,
38
+ 아래 preview의 메모리 상태를 서버 저장으로 취급하지 않는다. 예제는 읽기용이며 제품에서 showcase를 import하지 않는다.
39
+
40
+ <!-- usage-example: Web ../../../../../showcase/web/src/patterns/settings-page-preview.tsx -->
41
+ - [Web 실행 예제](../../../../../showcase/web/src/patterns/settings-page-preview.tsx): 공개 SettingsScreen·행·Sheet 조합과 로컬 설정 상태.
42
+ <!-- usage-example: Native ../../../../../showcase/native/src/settings-page-preview.tsx -->
43
+ - [Native 실행 예제](../../../../../showcase/native/src/settings-page-preview.tsx): 같은 흐름의 Native 공개 API와 이벤트 연결.
44
+
45
+ 설치 패키지에서 소스 링크를 열 수 없다면 [Web 원본](https://github.com/jim1286/hjm-design-system/blob/v1.17.1/showcase/web/src/patterns/settings-page-preview.tsx)과
46
+ [Native 원본](https://github.com/jim1286/hjm-design-system/blob/v1.17.1/showcase/native/src/settings-page-preview.tsx)을 참고한다.
47
+ 고정 버전 예제와 현재 checkout의 후속 변경은 구분하며 설치된 타입을 기준으로 사용한다.
86
48
 
87
49
  ## 축과 기본값
88
50
 
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-07
7
+ - 검토일: 2026-10-13
8
8
  - 근거: [Sheet 입력 화면과 가용 영역](../../sheet.md), [optional adapters](../../optional-adapters.md)(Native 제스처 확장), `src/component-recipes.ts`(`sheetRecipe`), `src/sheet.ts`(`sheetBehaviorDefaults`)
9
9
  - 스토리북: `배포/컴포넌트/오버레이/시트`
10
10
 
@@ -50,12 +50,17 @@ import { TextField } from "@hjmds/react/forms";
50
50
  import { Sheet } from "@hjmds/react/overlays";
51
51
 
52
52
  <Sheet open={open} onOpenChange={(next) => setOpen(next)}
53
+ returnFocusRef={openButtonRef}
53
54
  title={t("profile.edit.title")} closeLabel={t("common.close")}
54
55
  footer={<Button onClick={save} loading={saving}>{t("common.save")}</Button>}>
55
56
  <TextField label={t("profile.name")} value={name} onValueChange={setName} />
56
57
  </Sheet>
57
58
  ```
58
59
 
60
+ Web의 외부 열기 버튼과 `returnFocusRef`에 같은 `useRef<HTMLButtonElement>(null)`을 연결한다.
61
+ 버튼 클릭 시 초점을 주지 않는 macOS WebKit에서도 닫은 뒤 호출 위치로 돌아오기 위해서다.
62
+ `trigger` 슬롯을 쓰면 내부에서 연결한다([Dialog 초점 복귀](dialog.md#최소-사용-예)).
63
+
59
64
  ```tsx
60
65
  // Native — 입력 폼은 keyboardAvoidance + scrollable
61
66
  import { Button } from "@hjmds/react-native/actions";
@@ -86,7 +91,7 @@ import { Sheet } from "@hjmds/react-native/overlays";
86
91
  | `detents`(Web) · `activeDetent` · `onDetentChange` | `readonly ("medium" \| "large" \| "full")[]` · `(detent) => void` | — | 사용자가 높이를 바꿀 단계. `detentLabels: { expand, collapse }` 필수 |
87
92
  | `keyboardAvoidance` · `scrollable`(Native) | `boolean` | `false` | 입력 폼은 둘 다 켠다 |
88
93
  | `safeAreaInsets`(Native) | `Partial<Insets>` | provider inset | — |
89
- | `contentStyle`(Native) | 배치 key만 | — | 배치 밖 key(색·높이 등)는 deprecated(개발 모드 경고), 다음 major에서 배치 전용 타입으로 좁힌다 |
94
+ | `contentStyle`(Native) | 배치 key만 | — | `HjmCompositionStyleProp` 배치 전용 타입. 색·padding·높이 등 시각 key는 받지 않는다 |
90
95
 
91
96
  ### 디자인 프로필 상속
92
97
 
@@ -108,7 +113,7 @@ import { Sheet } from "@hjmds/react-native/overlays";
108
113
  | 크기 | 하단 시트 높이: `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` |
109
114
  | 간격 | 두 플랫폼 같은 값: 좌우 `content.paddingHorizontal`(`spacing.lg` 20), 위·아래 `content.paddingTop/Bottom`(`spacing.sm` 12, 하단 시트는 아래 safe area를 더함), 머리·본문·footer 사이 `body.gap`(`spacing.md` 16), footer 위 `footer.paddingTop`(`spacing.sm` 12), 제목–닫기 `header.gap`(`spacing.sm` 12), footer 버튼 사이 `footer.gap`(`spacing.sm` 12) | `.hjm-sheet__*`, `sheetRecipe.content`·`body`·`footer` |
110
115
  | 순서·정렬 | 머리(제목·설명 + 닫기) → 본문 → `footer`. 머리 최소 높이 44(`control.minTouchTarget`), 닫기는 끝 쪽에서 제목 세로 중앙. Web footer는 오른쪽 정렬 가로 줄 [보조][주]. Native footer는 세로 열이라 꽉 찬 폭 버튼을 주 행동 먼저 둔다. Web에서 `detents`를 주면 위 가운데 36×4 손잡이 버튼(터치 최소 폭 44 · 높이 `spacing.lg` 20). Native 기본 Sheet는 손잡이가 없다 | `sheetRecipe.header`·`handle`, `.hjm-sheet__footer`, `.hjm-sheet__handle` |
111
- | 고정·스크롤 | 본문만 스크롤, 머리·`footer` 고정(Native는 `scrollable`일 때 ScrollView). 고정 높이(`medium`·`large`·`full`, 옆 시트)에서는 본문이 머리·footer를 뺀 남은 높이를 차지하고 `footer`는 시트 아래에 붙는다. 그래서 본문의 `flex: 1` 자식(SearchScreen, 목록 화면)이 그 높이를 채운다(Web `.hjm-sheet__body` `flex: 1 1 auto`, Native 본문 `flexGrow: 1`·`minHeight: 0`, 미게시(1.13.1 이후)). `auto`는 내용 높이 그대로다. 저장·확인은 `footer`에. 아래 안전 영역은 시트가 자기 여백에 더한다(`spacing.sm` 12 + 아래 inset, Web은 `env(safe-area-inset-bottom)`). 위 inset은 시트가 올라갈 높이를 줄인다. 제품이 inset을 다시 더하지 않는다 | `.hjm-sheet__body`, `sheetRecipe.safeArea`, Native `Sheet` |
116
+ | 고정·스크롤 | 본문만 스크롤, 머리·`footer` 고정(Native는 `scrollable`일 때 ScrollView). 고정 높이(`medium`·`large`·`full`, 옆 시트)에서는 본문이 머리·footer를 뺀 남은 높이를 차지하고 `footer`는 시트 아래에 붙는다. 그래서 본문의 `flex: 1` 자식(SearchScreen, 목록 화면)이 그 높이를 채운다(Web `.hjm-sheet__body` `flex: 1 1 auto`, Native 본문 `flexGrow: 1`·`minHeight: 0`, 1.13.1 변경). `auto`는 내용 높이 그대로다. 저장·확인은 `footer`에. 아래 안전 영역은 시트가 자기 여백에 더한다(`spacing.sm` 12 + 아래 inset, Web은 `env(safe-area-inset-bottom)`). 위 inset은 시트가 올라갈 높이를 줄인다. 제품이 inset을 다시 더하지 않는다 | `.hjm-sheet__body`, `sheetRecipe.safeArea`, Native `Sheet` |
112
117
  | 좁은 폭·큰 글자 | 폭 < 640이면 하단 시트가 화면 폭을 채운다. Web footer는 줄을 바꾼다. 큰 글자로 내용이 길어지면 `auto`는 최대 90%에서 멈추고 본문이 스크롤된다(`full`은 위 safe area까지) | `.hjm-sheet[data-placement="bottom"]`, `maxHeightRatio` |
113
118
 
114
119
  ```text
@@ -136,7 +141,7 @@ import { Sheet } from "@hjmds/react-native/overlays";
136
141
  - 닫힌 뒤 다른 modal을 열거나 화면 이동은 `onDismissComplete`에서 한다. 두 modal을 동시에 띄우지 않는다.
137
142
  - 문구(`title`, `closeLabel`, 본문)는 i18n 키로 넣는다. 제목 정렬을 위해 `as unknown as string` 캐스트나
138
143
  `.hjm-sheet__header` CSS 덮어쓰기를 하지 않는다.
139
- - Native `contentStyle`은 배치 key만 쓴다. 높이는 `size`로 정한다(`contentStyle={{ height }}` 금지, 배치 밖 key는 deprecated).
144
+ - Native `contentStyle`은 배치 key만 쓴다. 높이는 `size`로 정한다(`contentStyle={{ height }}` 금지, 배치 밖 key는 지원하지 않음).
140
145
  - Web Sheet는 `layoutStyle`을 받지 않는다(Web `layoutStyle` 제외 15개 중 하나). 표면 위치·크기는 `placement`·`size`가 정한다.
141
146
 
142
147
  ## 플랫폼 차이
@@ -162,7 +167,7 @@ import { Sheet } from "@hjmds/react-native/overlays";
162
167
 
163
168
  ## 함정
164
169
 
165
- - 미게시(1.12.1 이후) 변경: 1.12.1까지 `size="full"`(Web `detents`의 `full` 포함)은 0.9 상한에 걸려 90%에서 멈췄다. 1.12.1을 쓰는 앱에서 화면 전체가 필요하면 화면 전환을 쓴다.
170
+ - `size="full"`(Web `detents`의 `full` 포함)은 위 안전 영역을 뺀 전체 높이를 사용한다. 0.9 상한은 `auto`에만 적용된다(1.13.0 변경).
166
171
  - 1.13.0 이하 Native 고정 높이 Sheet는 본문이 내용 높이라서 `flex: 1` 자식이 0pt가 됐다. 시트 안 SearchScreen이 검색 입력만 그리고
167
172
  필터 줄·목록이 사라졌다(2026-10-06 utilverse 채팅 도구 선택, iPhone 17 Pro · iOS 26.5). 제품은 창 높이 `flexBasis`로 우회했다.
168
173
  1.13.1부터는 그 우회 없이 채워진다. 1.13.0 이하에서도 footer는 본문 바로 아래에 있었고, 1.13.1부터 고정 높이 시트에서는 시트 아래에 붙는다.
@@ -110,4 +110,4 @@ Native: 없음. 폰은 BottomNavigation, 태블릿 split view는 navigator가
110
110
 
111
111
  2026-10-07 소비 감사에서 Web 항목의 숫자 recipe 모서리가 프로필을 우회했다. 기존 `radius.md` 역할을 가까운 Provider의 CSS 변수로 읽고 변수 없는 독립 사용은 recipe 12를 유지한다. 레일 폭·링크·현재 위치·접기·초점과 Web 전용 범위는 바꾸지 않는다.
112
112
 
113
- 프로필 연결은 1.15.0 이후 미게시 변경이며, 기본 배포 계약과 실제 Native 기기 검증은 구분한다.
113
+ 프로필 연결은 1.16.0 변경이며, 기본 배포 계약과 실제 Native 기기 검증은 구분한다.
@@ -90,7 +90,7 @@ import { Skeleton } from "@hjmds/react-native/feedback";
90
90
 
91
91
  - 실제 콘텐츠와 같은 자리·비슷한 크기로 둔다. 로딩이 끝나면 Skeleton을 내용으로 **바꾼다**(겹쳐 두지 않는다).
92
92
  - 색·테두리는 recipe와 테마가 정한다. 배치는 `layoutStyle`로 하고 `style`/`className`으로 회색 배경을 덮지 않는다.
93
- Native `style`은 deprecated(개발 모드 경고, 다음 major 제거)다.
93
+ Native `style`은 제거된 속성이다.
94
94
  - Web Skeleton은 `aria-hidden`이다. 로딩 사실을 알려야 하면 영역 단위로 한 번 알린다
95
95
  (예: 감싼 영역의 `aria-busy`, 또는 Spinner 하나). Skeleton마다 라벨을 붙이지 않는다.
96
96
  - Web은 `HjmProvider` 안에서 렌더한다. 원 지름·펄스 값을 provider가 내보내는 `--hjm-skeleton-*` 변수로 읽는다.
@@ -79,4 +79,4 @@ Native: 없음.
79
79
 
80
80
  2026-10-07 소비 감사에서 Web 링크의 숫자 recipe 모서리가 프로필을 우회했다. 기존 `radius.md` 역할을 가까운 Provider의 CSS 변수로 읽고 변수 없는 독립 사용은 recipe 12를 유지한다. 숨김·고정 위치·표시·본문 초점 이동과 Web 전용 범위는 바꾸지 않는다.
81
81
 
82
- 프로필 연결은 1.15.0 이후 미게시 변경이며, 기본 배포 계약과 실제 Native 기기 검증은 구분한다.
82
+ 프로필 연결은 1.16.0 변경이며, 기본 배포 계약과 실제 Native 기기 검증은 구분한다.
@@ -104,7 +104,7 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
104
104
  - `label`·`getValueText`·(Native) `incrementLabel`/`decrementLabel`은 i18n 문구로 준다. 단위·형식은 제품 소유다.
105
105
  - 사용자 입력만 step으로 snap된다. 제품이 준 `value`가 범위 안이면 step 밖이어도 그대로 그린다.
106
106
  - 색·트랙 두께·thumb 크기는 HJM 소유다. 배치는 `layoutStyle`로 한다. Web `style`/`className`/`inputClassName`은 배치용으로만 쓰고,
107
- Native `containerStyle`/`controlStyle`은 deprecated(개발 모드 경고, 다음 major 제거)다.
107
+ Native `containerStyle`/`controlStyle`은 제거된 속성이다.
108
108
 
109
109
  ## 플랫폼 차이
110
110
 
@@ -113,7 +113,7 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
113
113
  | 접근성 | `input type="range"`, `aria-valuetext` | role `adjustable`, `accessibilityValue` |
114
114
  | 키 조작 | 방향키·Home/End·PageUp/PageDown(step×10) | `increment`/`decrement` action만(페이지 이동 없음) |
115
115
  | 필수 추가 문구 | 없음 | `incrementLabel`, `decrementLabel` |
116
- | 스타일 슬롯 | `layoutStyle`, `style`(루트), `className`, `inputClassName` | `layoutStyle`. `containerStyle`·`controlStyle`은 deprecated(`style` prop 없음) |
116
+ | 스타일 슬롯 | `layoutStyle`, `style`(루트), `className`, `inputClassName` | `layoutStyle`. `containerStyle`·`controlStyle`은 제거된 속성(`style` prop 없음) |
117
117
  | 의존성 | 없음 | 없음(PanResponder 사용) |
118
118
 
119
119
  ## 함정
@@ -53,7 +53,7 @@ import { Spinner } from "@hjmds/react-native/feedback";
53
53
  | `tone`(Web) | `brand` · `neutral` · `inverse` | `brand` | — |
54
54
  | `size`(Native) | `small` · `large` | `small` | 플랫폼 `ActivityIndicator`를 테마 `contentBrand` 색으로 그린다. `tone`은 없다 |
55
55
  | `layoutStyle` | `HjmCompositionStyleProp`(margin·width·flex 계열·`alignSelf`) | — | 루트 배치. Web·Native 모두 |
56
- | `style`(Native) | `StyleProp<ViewStyle>` | — | deprecated — `layoutStyle` 또는 `size`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
56
+ | `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle` 또는 `size`. 현재 공개 props에서 제거되었다 |
57
57
 
58
58
  ## 배치
59
59
 
@@ -83,4 +83,4 @@ import { Spinner } from "@hjmds/react-native/feedback";
83
83
  | 크기 | 3단계 | `small`·`large` 2단계 |
84
84
  | tone | 있음 | 없음(항상 brand 색) |
85
85
  | reduced motion | 회전 멈춤(CSS) | 별도 처리 없음(`ActivityIndicator` 그대로) |
86
- | `style` | HTML 속성(`layoutStyle`과 합쳐지고 `layoutStyle`이 이김) | deprecated |
86
+ | `style` | HTML 속성(`layoutStyle`과 합쳐지고 `layoutStyle`이 이김) | 제거된 속성 |