@hjmds/design-contracts 1.17.2 → 1.19.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 (274) 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/activity-chip.d.ts +127 -0
  6. package/dist/activity-chip.d.ts.map +1 -0
  7. package/dist/activity-chip.js +65 -0
  8. package/dist/activity-chip.js.map +1 -0
  9. package/dist/base-recipes.d.ts +1 -1
  10. package/dist/base-recipes.d.ts.map +1 -1
  11. package/dist/base-recipes.js +2 -1
  12. package/dist/base-recipes.js.map +1 -1
  13. package/dist/behaviors.d.ts +9 -6
  14. package/dist/behaviors.d.ts.map +1 -1
  15. package/dist/behaviors.js +5 -3
  16. package/dist/behaviors.js.map +1 -1
  17. package/dist/bottom-navigation.d.ts +16 -0
  18. package/dist/bottom-navigation.d.ts.map +1 -1
  19. package/dist/bottom-navigation.js +18 -0
  20. package/dist/bottom-navigation.js.map +1 -1
  21. package/dist/card.d.ts +4 -0
  22. package/dist/card.d.ts.map +1 -1
  23. package/dist/card.js +4 -1
  24. package/dist/card.js.map +1 -1
  25. package/dist/carousel.d.ts +3 -0
  26. package/dist/carousel.d.ts.map +1 -1
  27. package/dist/carousel.js.map +1 -1
  28. package/dist/catalog.d.ts +80 -9
  29. package/dist/catalog.d.ts.map +1 -1
  30. package/dist/component-recipes.d.ts +74 -3
  31. package/dist/component-recipes.d.ts.map +1 -1
  32. package/dist/component-recipes.js +38 -6
  33. package/dist/component-recipes.js.map +1 -1
  34. package/dist/content-transition.d.ts +1 -1
  35. package/dist/content-transition.d.ts.map +1 -1
  36. package/dist/content-transition.js +2 -2
  37. package/dist/content-transition.js.map +1 -1
  38. package/dist/field-group.d.ts +14 -0
  39. package/dist/field-group.d.ts.map +1 -1
  40. package/dist/field-group.js +9 -0
  41. package/dist/field-group.js.map +1 -1
  42. package/dist/form.d.ts.map +1 -1
  43. package/dist/form.js +10 -3
  44. package/dist/form.js.map +1 -1
  45. package/dist/icon-button-recipe.d.ts +1 -5
  46. package/dist/icon-button-recipe.d.ts.map +1 -1
  47. package/dist/icon-button-recipe.js +2 -1
  48. package/dist/icon-button-recipe.js.map +1 -1
  49. package/dist/index.d.ts +3 -2
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +2 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/screen-patterns.d.ts +10 -0
  54. package/dist/screen-patterns.d.ts.map +1 -1
  55. package/dist/screen-patterns.js +17 -3
  56. package/dist/screen-patterns.js.map +1 -1
  57. package/dist/toast-liquid.d.ts +1 -1
  58. package/dist/toast-liquid.d.ts.map +1 -1
  59. package/dist/toast-liquid.js +3 -2
  60. package/dist/toast-liquid.js.map +1 -1
  61. package/dist/toast.d.ts +29 -2
  62. package/dist/toast.d.ts.map +1 -1
  63. package/dist/toast.js +59 -3
  64. package/dist/toast.js.map +1 -1
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.js +1 -1
  67. package/dist/version.js.map +1 -1
  68. package/docs/action-session.md +2 -0
  69. package/docs/activity-chip.md +34 -0
  70. package/docs/asset.md +7 -0
  71. package/docs/bottom-navigation.md +16 -1
  72. package/docs/brand-boundary.md +3 -3
  73. package/docs/collection-rail.md +4 -0
  74. package/docs/compound-controls.md +8 -3
  75. package/docs/consumer-policy.md +39 -120
  76. package/docs/generated/component-maturity.md +1 -1
  77. package/docs/generated/renderer-evidence.json +3 -3
  78. package/docs/generated/renderer-evidence.md +1 -1
  79. package/docs/generated/showcase-manifest.json +1 -1
  80. package/docs/gravity-letters.md +2 -0
  81. package/docs/grid-reveal.md +2 -0
  82. package/docs/layout.md +2 -2
  83. package/docs/load-more.md +5 -0
  84. package/docs/migration-native-legacy-removal.md +30 -17
  85. package/docs/optional-adapters.md +4 -0
  86. package/docs/screen-patterns.md +23 -1
  87. package/docs/toast.md +64 -2
  88. package/docs/usage/README.md +248 -243
  89. package/docs/usage/SELECTION.md +43 -0
  90. package/docs/usage/STANDARD.md +22 -10
  91. package/docs/usage/components/accordion.md +5 -3
  92. package/docs/usage/components/activity-chip.md +109 -0
  93. package/docs/usage/components/agreement.md +6 -9
  94. package/docs/usage/components/alert-dialog.md +12 -6
  95. package/docs/usage/components/asset.md +10 -4
  96. package/docs/usage/components/auth-provider-button.md +2 -2
  97. package/docs/usage/components/avatar.md +8 -6
  98. package/docs/usage/components/badge.md +4 -4
  99. package/docs/usage/components/bottom-cta.md +4 -4
  100. package/docs/usage/components/bottom-info.md +2 -2
  101. package/docs/usage/components/bottom-navigation.md +18 -6
  102. package/docs/usage/components/button.md +6 -3
  103. package/docs/usage/components/card.md +28 -7
  104. package/docs/usage/components/carousel.md +12 -4
  105. package/docs/usage/components/chat-message.md +10 -2
  106. package/docs/usage/components/chat-screen.md +5 -5
  107. package/docs/usage/components/checkbox-group.md +1 -1
  108. package/docs/usage/components/checkbox.md +2 -2
  109. package/docs/usage/components/chip.md +2 -2
  110. package/docs/usage/components/code-block.md +3 -4
  111. package/docs/usage/components/collapsible.md +6 -4
  112. package/docs/usage/components/combobox.md +2 -2
  113. package/docs/usage/components/command-palette.md +1 -1
  114. package/docs/usage/components/comment-thread-screen.md +7 -4
  115. package/docs/usage/components/container.md +1 -1
  116. package/docs/usage/components/content-transition.md +3 -2
  117. package/docs/usage/components/context-menu.md +2 -2
  118. package/docs/usage/components/counter-badge.md +3 -3
  119. package/docs/usage/components/data-table.md +1 -1
  120. package/docs/usage/components/date-picker.md +4 -4
  121. package/docs/usage/components/description-list.md +3 -3
  122. package/docs/usage/components/design-system-provider.md +2 -2
  123. package/docs/usage/components/dialog.md +14 -3
  124. package/docs/usage/components/divider.md +2 -2
  125. package/docs/usage/components/editor-screen.md +5 -3
  126. package/docs/usage/components/effect-surface.md +1 -1
  127. package/docs/usage/components/empty-state.md +6 -6
  128. package/docs/usage/components/field.md +5 -3
  129. package/docs/usage/components/file-picker.md +6 -3
  130. package/docs/usage/components/form.md +1 -1
  131. package/docs/usage/components/heading.md +3 -3
  132. package/docs/usage/components/icon-button.md +6 -3
  133. package/docs/usage/components/icon.md +1 -1
  134. package/docs/usage/components/image.md +5 -4
  135. package/docs/usage/components/keyboard-dock.md +1 -1
  136. package/docs/usage/components/layout.md +1 -1
  137. package/docs/usage/components/link.md +2 -2
  138. package/docs/usage/components/list-detail-screen.md +6 -6
  139. package/docs/usage/components/list-row.md +13 -4
  140. package/docs/usage/components/list.md +5 -4
  141. package/docs/usage/components/masonry.md +2 -1
  142. package/docs/usage/components/media-selection-screen.md +11 -5
  143. package/docs/usage/components/mentions.md +2 -2
  144. package/docs/usage/components/menu.md +3 -2
  145. package/docs/usage/components/menubar.md +2 -2
  146. package/docs/usage/components/message-composer.md +3 -3
  147. package/docs/usage/components/moderation-screen.md +3 -2
  148. package/docs/usage/components/notice.md +2 -2
  149. package/docs/usage/components/notification-inbox-screen.md +1 -1
  150. package/docs/usage/components/notification-item.md +2 -2
  151. package/docs/usage/components/number-field.md +3 -3
  152. package/docs/usage/components/otp-field.md +1 -1
  153. package/docs/usage/components/overview-screen.md +1 -1
  154. package/docs/usage/components/permission-screen.md +1 -1
  155. package/docs/usage/components/photo-source-sheet.md +1 -1
  156. package/docs/usage/components/popover.md +2 -2
  157. package/docs/usage/components/profile-screen.md +1 -1
  158. package/docs/usage/components/progress.md +2 -2
  159. package/docs/usage/components/qr-code.md +2 -2
  160. package/docs/usage/components/radio-group.md +1 -2
  161. package/docs/usage/components/radio.md +1 -2
  162. package/docs/usage/components/result.md +1 -1
  163. package/docs/usage/components/saved-items-screen.md +4 -2
  164. package/docs/usage/components/screen-layout.md +4 -3
  165. package/docs/usage/components/search-field.md +1 -1
  166. package/docs/usage/components/search-screen.md +4 -4
  167. package/docs/usage/components/section.md +3 -3
  168. package/docs/usage/components/segmented-control.md +4 -4
  169. package/docs/usage/components/select.md +2 -3
  170. package/docs/usage/components/settings-screen.md +18 -56
  171. package/docs/usage/components/sheet.md +10 -5
  172. package/docs/usage/components/sidebar.md +1 -1
  173. package/docs/usage/components/skeleton.md +1 -1
  174. package/docs/usage/components/skip-nav.md +1 -1
  175. package/docs/usage/components/slider.md +2 -2
  176. package/docs/usage/components/spinner.md +2 -2
  177. package/docs/usage/components/splitter.md +1 -1
  178. package/docs/usage/components/statistic.md +5 -4
  179. package/docs/usage/components/steps.md +2 -2
  180. package/docs/usage/components/surface.md +2 -3
  181. package/docs/usage/components/switch.md +1 -1
  182. package/docs/usage/components/tabs.md +4 -4
  183. package/docs/usage/components/tag.md +2 -2
  184. package/docs/usage/components/tags-input.md +4 -4
  185. package/docs/usage/components/text-area.md +5 -3
  186. package/docs/usage/components/text.md +85 -4
  187. package/docs/usage/components/timeline.md +2 -2
  188. package/docs/usage/components/toast.md +41 -13
  189. package/docs/usage/components/toggle-group.md +3 -3
  190. package/docs/usage/components/tooltip.md +1 -1
  191. package/docs/usage/components/top-bar.md +5 -4
  192. package/docs/usage/components/top.md +3 -3
  193. package/docs/usage/components/transfer-list.md +5 -4
  194. package/docs/usage/components/upload-item.md +3 -3
  195. package/docs/usage/components/virtual-list.md +1 -0
  196. package/docs/usage/compositions/action-feedback.md +42 -6
  197. package/docs/usage/compositions/action-recovery-optimistic.md +6 -1
  198. package/docs/usage/compositions/action-recovery-save.md +19 -23
  199. package/docs/usage/compositions/action-recovery-undo.md +6 -1
  200. package/docs/usage/compositions/activity-status.md +168 -0
  201. package/docs/usage/compositions/collection-detail.md +2 -0
  202. package/docs/usage/compositions/command-records.md +15 -5
  203. package/docs/usage/compositions/common-message.md +4 -2
  204. package/docs/usage/compositions/common-notification.md +5 -3
  205. package/docs/usage/compositions/compound-controls.md +13 -5
  206. package/docs/usage/compositions/content-transition-comparison.md +2 -2
  207. package/docs/usage/compositions/date-entry.md +10 -5
  208. package/docs/usage/compositions/date-time-selection.md +3 -3
  209. package/docs/usage/compositions/design-profile-comparison.md +7 -5
  210. package/docs/usage/compositions/disclosure.md +1 -1
  211. package/docs/usage/compositions/document-resource.md +10 -3
  212. package/docs/usage/compositions/expo-interactions.md +3 -2
  213. package/docs/usage/compositions/family-drawer.md +9 -4
  214. package/docs/usage/compositions/field-group.md +7 -1
  215. package/docs/usage/compositions/floating-action-button.md +18 -18
  216. package/docs/usage/compositions/illustrated-outcome.md +3 -2
  217. package/docs/usage/compositions/input-sheet.md +6 -2
  218. package/docs/usage/compositions/interaction-adapters.md +1 -1
  219. package/docs/usage/compositions/interaction-flow-apply.md +6 -3
  220. package/docs/usage/compositions/interaction-flow-draft.md +5 -2
  221. package/docs/usage/compositions/interaction-flow-search.md +5 -2
  222. package/docs/usage/compositions/live-list.md +7 -5
  223. package/docs/usage/compositions/navigation-bar-collection.md +8 -7
  224. package/docs/usage/compositions/optional-adapters.md +1 -1
  225. package/docs/usage/compositions/origin-dialog.md +5 -5
  226. package/docs/usage/compositions/paper-surface.md +1 -1
  227. package/docs/usage/compositions/photo-source.md +1 -1
  228. package/docs/usage/compositions/purpose-input-comment.md +5 -3
  229. package/docs/usage/compositions/purpose-input-message.md +5 -3
  230. package/docs/usage/compositions/reference-first.md +63 -42
  231. package/docs/usage/compositions/reference-review.md +60 -50
  232. package/docs/usage/compositions/reference-settings.md +60 -50
  233. package/docs/usage/compositions/selection-scope.md +48 -35
  234. package/docs/usage/compositions/stea-order-progress.md +1 -0
  235. package/docs/usage/compositions/stea-otp-verify.md +5 -3
  236. package/docs/usage/compositions/stea-pixel-empty.md +3 -3
  237. package/docs/usage/compositions/time-selection.md +6 -5
  238. package/docs/usage/compositions/upload-recovery.md +10 -1
  239. package/docs/usage/compositions/video-dialog.md +10 -3
  240. package/docs/usage/compositions/web-additions.md +5 -5
  241. package/docs/usage/compositions/web-navigation.md +1 -1
  242. package/docs/usage/screens/common-chat.md +21 -8
  243. package/docs/usage/screens/common-comments.md +13 -1
  244. package/docs/usage/screens/common-inbox.md +19 -6
  245. package/docs/usage/screens/common-login.md +19 -7
  246. package/docs/usage/screens/common-profile.md +22 -9
  247. package/docs/usage/screens/common-saved.md +16 -2
  248. package/docs/usage/screens/common-search.md +24 -4
  249. package/docs/usage/screens/common-settings.md +22 -50
  250. package/docs/usage/screens/common-shell.md +14 -2
  251. package/docs/usage/screens/dashboard.md +52 -109
  252. package/docs/usage/screens/discovery-gallery.md +57 -148
  253. package/docs/usage/screens/flow-collection.md +38 -9
  254. package/docs/usage/screens/flow-editor.md +25 -7
  255. package/docs/usage/screens/flow-media.md +23 -7
  256. package/docs/usage/screens/flow-moderation.md +15 -2
  257. package/docs/usage/screens/flow-onboarding.md +3 -3
  258. package/docs/usage/screens/flow-permission.md +17 -3
  259. package/docs/usage/screens/landing.md +37 -20
  260. package/docs/usage/screens/mockup-studio.md +22 -7
  261. package/docs/usage/screens/notification-settings.md +18 -4
  262. package/docs/usage/screens/product-bento.md +18 -9
  263. package/docs/usage/screens/reference-comparison.md +29 -10
  264. package/docs/usage/tokens/color.md +6 -3
  265. package/docs/usage/tokens/elevation-opacity.md +4 -2
  266. package/docs/usage/tokens/font-roles.md +2 -2
  267. package/docs/usage/tokens/layers.md +3 -3
  268. package/docs/usage/tokens/motion.md +2 -2
  269. package/docs/usage/tokens/radius.md +4 -2
  270. package/docs/usage/tokens/spacing.md +3 -3
  271. package/docs/usage/tokens/theme-studio.md +2 -2
  272. package/docs/usage/tokens/typography-studio.md +14 -8
  273. package/docs/usage/tokens/typography.md +15 -5
  274. package/package.json +7 -1
@@ -3,7 +3,7 @@
3
3
  - 단계: 컴포넌트
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
- - 적용: 미게시(1.12.1 이후)
6
+ - 적용: 1.17.1
7
7
  - 검토일: 2026-10-08
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
  - 스토리북: `배포/화면/설정/앱 설정`
@@ -11,7 +11,7 @@
11
11
  ## 언제 쓰나
12
12
 
13
13
  앱의 설정 화면 전체에 쓴다. 제목, 선택적 프로필 영역, id가 있는 섹션 목록을 받아
14
- [ScreenLayout](screen-layout.md) 안에 [Section](section.md)으로 쌓는다. 섹션 안의 행은
14
+ [ScreenLayout](screen-layout.md) 안에 그룹으로 쌓는다(Web은 의미 있는 Section, Native는 Stack과 header 역할). 섹션 안의 행은
15
15
  기존 ListRow·Switch·Select·Field를 그대로 넣는다.
16
16
 
17
17
  2026-09-23 소비 감사에서 제품마다 같은 설정 화면을 직접 조립하고 있었다. 제목·섹션 틀·구분선·
@@ -34,75 +34,37 @@
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
 
89
51
  | prop | 값 | 기본값 | 설명 |
90
52
  | --- | --- | --- | --- |
91
- | `sections` | `readonly { id: string; title: string; description?: string; children: ReactNode }[]` | 필수 | 각 항목을 Section 하나로 그린다. `id`는 안정적인 key |
53
+ | `sections` | `readonly { id: string; title: string; description?: string; children: ReactNode }[]` | 필수 | 각 항목을 설정 그룹 하나로 그린다. `id`는 안정적인 key |
92
54
  | `profile` | `ReactNode` | 없음 | 섹션 위 프로필 영역 |
93
55
  | 나머지 | `ScreenLayout`과 같음(`children`·`scroll` 제외) | — | `title` 필수, `state`·`stateAction`·`notice`·`footer`·`header`·`leading`·`actions`·`contentInset`. 화면 전체가 스크롤한다 |
94
56
 
95
- 두 플랫폼 모두 섹션 내용 위에 1px 구분선을 그리고 회색 카드 배경은 쓰지 않는다(2026-10-05 사용자 결정).
57
+ 두 플랫폼 모두 그룹 위의 별도 구분선과 카드 배경을 두지 않는다. 행 구분은 List·Switch의 계약을 따른다(2026-10-08 실제 설정 화면 재검토).
96
58
 
97
59
  ## 배치
98
60
 
99
61
  | 항목 | 값 | 근거 |
100
62
  | --- | --- | --- |
101
63
  | 크기 | ScreenLayout 폭(최대 720) 안에서 섹션을 세로로 쌓는다; 행 높이는 ListRow·Switch row 계약 | `ScreenLayout`, `Section` |
102
- | 간격 | 화면 padding `spacing.md` 16; `profile`·섹션 사이 `spacing.xl` 24; 섹션 제목–내용 `spacing.xs` 8, 제목–설명 `spacing.xxs` 4; 행 사이 간격은 없고 구분선 1 | Web·Native `SettingsScreen` `Stack gap="xl"`, `sectionRecipe` |
64
+ | 간격 | 화면 padding `spacing.md` 16; `profile`·섹션 사이 `spacing.md` 16; 그룹 제목–내용 `spacing.xs` 8; Native 설명도 같은 Stack 간격. 행 간격·구분은 행 계약 | Web·Native `SettingsScreen` `Stack gap="md"` |
103
65
  | 순서·정렬 | 헤더(제목) → `notice` → `profile` → `sections` 순서대로 → `footer` | 렌더 순서 |
104
66
  | 고정·스크롤 | 헤더·footer 고정, 본문 화면 스크롤(`scroll` 고정 `"screen"`); 저장 실패는 `notice` | `ScreenLayout` |
105
- | 좁은 폭·큰 글자 | 섹션 제목·행 문구는 줄바꿈되고 자르지 않는다; 제목 열 최소 폭 120 × 글자 배율 | `.hjm-section` `overflow-wrap: anywhere`, `headerMinWidth` |
67
+ | 좁은 폭·큰 글자 | 섹션 제목·행 문구는 줄바꿈되고 자르지 않는다 | Text와 각 행의 내용 기반 높이 |
106
68
 
107
69
  ## 꼭 지킬 것
108
70
 
@@ -120,7 +82,7 @@ import { ListRow } from "@hjmds/react-native/data-display";
120
82
 
121
83
  | 항목 | Web | Native |
122
84
  | --- | --- | --- |
123
- | 섹션 구분 | Section(`hjm-settings-section`) 내용 위 1px 구분선(CSS) | Section + 내용 위 1px 구분선(`View`) |
85
+ | 섹션 구분 | Section(`hjm-settings-section`), 별도 그룹 선 없음 | Stack + header 역할, 별도 그룹 선 없음 |
124
86
  | 조각 import | `Switch` `/selection`, `ListRow` `/display` | `Switch` `/inputs`, `ListRow` `/data-display` |
125
87
  | Switch 기본 `presentation` | `inline` | `row` |
126
88
  | 행 이동 이벤트 | ListRow `href`/`onClick` | ListRow `onPress` |
@@ -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`이 이김) | 제거된 속성 |
@@ -97,7 +97,7 @@ axis="horizontal"(기본)
97
97
 
98
98
  - 키보드는 pane 축 방향키만 쓴다(가로면 좌/우, 세로면 위/아래). 다른 방향키와 PageUp/PageDown은 pane 콘텐츠의 것이다.
99
99
  - 패널의 Tab 정지점은 넘침에 따라 생기고 사라진다(ResizeObserver·MutationObserver로 다시 잰다). 테스트에서 패널 `tabIndex`를 고정값으로 기대하지 않는다.
100
- 패널에는 접근성 이름이 없다(이름 prop은 breaking 변경이라 두지 않았다, `splitter.tsx` 주석). 미게시(1.12.1 이후) 변경이며 1.12.1까지는 패널이 포커스를 받지 않았다.
100
+ 패널에는 접근성 이름이 없다(이름 prop은 breaking 변경이라 두지 않았다, `splitter.tsx` 주석). 1.13.0 변경이며 1.12.1까지는 패널이 포커스를 받지 않았다.
101
101
  - RTL에서는 ArrowLeft가 increment다. 드래그 거리도 같은 기준으로 잰다.
102
102
  - primary pane 폭은 `value`가 아니라 `(value-min)/(max-min)` 비율로 그려진다. `value=min`이면 primary pane이 0%, `max`면 100%다.
103
103
  예를 들어 `min=15, max=60, value=30`은 33%로 그려진다. 원하는 실제 폭 범위에 맞춰 `min`/`max`를 정하고 화면에서 확인한다.
@@ -84,7 +84,7 @@ import { Statistic } from "@hjmds/react-native/data-display";
84
84
  | `renderValue`(Web) | `(value: string) => ReactNode` | — | 보이는 값만 바꾼다. 접근성 값은 descriptor 그대로 |
85
85
  | `availableWidth`(Native `StatisticGroup`) | `number` | 측정 폭 | 열 수 계산에 쓸 폭 |
86
86
  | `layoutStyle` | `HjmCompositionStyleProp` | — | 루트 배치. Web·Native 모두 |
87
- | Native `style`·`labelStyle`·`valueStyle`·`affixStyle`·`trendStyle`·`hintStyle`, 그룹 `style`·`itemStyle` | `StyleProp` | — | deprecated — `layoutStyle` 또는 `density`·`presentation`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
87
+ | Native `style`·`labelStyle`·`valueStyle`·`affixStyle`·`trendStyle`·`hintStyle`, 그룹 `style`·`itemStyle` | 지원하지 않음 | — | 제거된 속성 — `layoutStyle` 또는 `density`·`presentation`. 현재 공개 props에서 제거되었다 |
88
88
 
89
89
  ## 배치
90
90
 
@@ -93,7 +93,7 @@ Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Pr
93
93
  | 항목 | 값 | 근거 |
94
94
  | --- | --- | --- |
95
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"]` |
96
- | 글자 | 라벨 `label` 12 semibold(`compact` `caption` 11), 값 `heading` 24 heavy(`compact` `title` 18), prefix·suffix `body` 14 semibold 본문색, hint `caption`, 추세 `caption` bold(두 플랫폼). 2026-10-06까지 Web은 라벨 본문 14 medium, 값은 밀도와 관계없이 18, prefix·suffix는 흐린색이었다(1.12.1 이후 미게시) | `statisticRecipe.density`·`label`·`value`·`affix`·`hint`·`trend`, `.hjm-statistic__*` |
96
+ | 글자 | 라벨 `label` 12 semibold(`compact` `caption` 11), 값 `heading` 24 heavy(`compact` `title` 18), prefix·suffix `body` 14 semibold 본문색, hint `caption`, 추세 `caption` bold(두 플랫폼). 2026-10-06까지 Web은 라벨 본문 14 medium, 값은 밀도와 관계없이 18, prefix·suffix는 흐린색이었다(1.13.0 변경) | `statisticRecipe.density`·`label`·`value`·`affix`·`hint`·`trend`, `.hjm-statistic__*` |
97
97
  | 간격 | 그룹 간격 `statisticRecipe.group.gap` = `spacing.xs` 8. 지표 안 줄 간격(라벨·값·추세) `comfortable` `spacing.xs` 8 · `compact` `spacing.xxs` 4(두 플랫폼) | `styles.css` `.hjm-statistic`·`.hjm-statistic-group`, `statisticRecipe` |
98
98
  | 순서·정렬 | 화면 위쪽 요약 영역이나 카드 안에 둔다. 지표 여러 개는 [Grid](grid.md)를 직접 짜지 말고 `StatisticGroup`으로 묶는다 | — |
99
99
  | 고정·스크롤 | — | — |
@@ -106,7 +106,7 @@ Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Pr
106
106
  - `direction`과 `tone`은 따로 정한다. 증가가 나쁜 지표는 `up` + `danger`다([계약](../../statistic.md)).
107
107
  - 접근성 이름은 기본으로 `[contextLabel, label, 값, trend label, hint]`를 이어 만든다. 어순을 바꿔야 하면
108
108
  `composeAccessibilityLabel`을 쓴다. `StatisticGroup`은 group `label`을 각 항목의 `contextLabel`로 넘긴다.
109
- - 배치는 `layoutStyle`로만 한다. Native의 deprecated `style`·`*Style`·`itemStyle`로 recipe 색·굵기를 덮지 않는다.
109
+ - 배치는 `layoutStyle`로만 한다. Native에서 제거된 `style`·`*Style`·`itemStyle`로 recipe 색·굵기를 덮지 않는다.
110
110
 
111
111
  ## 플랫폼 차이
112
112
 
@@ -114,7 +114,7 @@ Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Pr
114
114
  | --- | --- | --- |
115
115
  | 값 렌더 교체 | `renderValue`(접근성 값은 descriptor 유지) | 없음 |
116
116
  | 그룹 폭 | CSS grid, 좁은 화면에서 1열 | `availableWidth` 또는 측정 폭, 최소 항목 폭 120×글자 배율로 열 수 감소 |
117
- | 슬롯 스타일 prop | 없음(`className`, 배치는 `layoutStyle`) | `style`·`*Style`, 그룹 `itemStyle`(모두 deprecated, 배치는 `layoutStyle`) |
117
+ | 슬롯 스타일 prop | 없음(`className`, 배치는 `layoutStyle`) | `style`·`*Style`, 그룹 `itemStyle`(모두 제거된 속성, 배치는 `layoutStyle`) |
118
118
  | `AnimatedStatistic` 모션 | 숫자 자리 단위 NumberFlow | 지표 전체 `rise` 전환 |
119
119
  | `renderTrendMark` color | `"currentColor"` | trend tone을 푼 색 문자열 |
120
120
 
@@ -122,6 +122,7 @@ Native 프레임의 모서리는 `statisticRecipe.presentations`의 역할을 Pr
122
122
 
123
123
  - Web `AnimatedStatistic`은 reduced motion, RTL, 라틴 숫자가 아닌 numbering system, `ar`·`fa`·`he`·`ur` locale,
124
124
  `scientific`·`engineering` 표기에서는 애니메이션 없이 `Intl` 결과 문자열만 그린다.
125
+ - Web은 탭이 숨겨지거나 숫자 호스트가 제거되면 진행 중 전환을 최종 값으로 완료한다. 화면 밖에서는 모션을 정지하고 새 값·접근 이름을 즉시 반영하며, 화면 안으로 돌아오면 다음 값부터 다시 전환한다. IntersectionObserver 미지원 환경은 정적으로 표시한다.
125
126
  - `AnimatedStatistic`의 `descriptor`에는 `value`를 넣지 않는다. 값은 `value` prop의 숫자로 받는다.
126
127
 
127
128
  ### 외부 숫자 효과 대조
@@ -75,7 +75,7 @@ import { Steps } from "@hjmds/react-native/steps";
75
75
  | `composeAccessibleName` | `(info: { position: number, total: number, label: string }) => string` | — (필수) | `position`은 1부터 |
76
76
  | `renderMark` | `(status: StepStatus, position: number) => ReactNode` | `✓`·`!`·번호 | 원 안 표시를 바꾼다 |
77
77
  | `layoutStyle` | `HjmCompositionStyleProp` | — | 루트 배치. Web·Native 모두 |
78
- | `style`(Native) | `StyleProp<ViewStyle>` | — | deprecated — `layoutStyle`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
78
+ | `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle`. 현재 공개 props에서 제거되었다 |
79
79
  | `StepPlayer` `progress`·`playing` | `number`(0~1)·`boolean` | — (필수) | 호스트 소유 |
80
80
  | `StepPlayer` `onPlayingChange`·`onReplay` | `(playing: boolean) => void`·`() => void` | — (필수) | 재생/일시정지·다시 보기 요청 |
81
81
  | `StepPlayer` `labels` | `{ play, pause, replay, progress }` | — (필수) | — |
@@ -105,6 +105,6 @@ import { Steps } from "@hjmds/react-native/steps";
105
105
  | 항목 | Web | Native |
106
106
  | --- | --- | --- |
107
107
  | 구조 | `<ol>`, 현재 단계 `aria-current="step"`, 상태 문구는 숨은 텍스트 | `accessibilityRole="summary"`, 단계마다 이름 + `accessibilityHint`에 상태 문구 |
108
- | 스타일 | `className`·`style`(HTML 속성), 배치는 `layoutStyle` | 배치는 `layoutStyle`(`style`은 deprecated) |
108
+ | 스타일 | `className`·`style`(HTML 속성), 배치는 `layoutStyle` | 배치는 `layoutStyle`(`style`은 제거된 속성) |
109
109
  | ref | `forwardRef`(`ol`) | 없음 |
110
110
  | import 경로 | root, `/navigation`, `/steps` | root, `/steps`(`/navigation` 없음) |
@@ -34,8 +34,7 @@
34
34
 
35
35
  공개 guide가 HJM profile context를 서버 module에서 평가해 실패한 사례(2026-10-07)를 보완했다.
36
36
  현재 main의 Web `/layout`은 client entry이므로 서버가 작성한 JSX children과 직렬화 가능한 props를
37
- Surface로 넘길 수 있다. 서버 page 전체를 client로 바꿀 필요는 없다. 이 보완은1.15.0 이후 미게시이므로
38
- 설치1.15.0에서는 제품의 작은 `"use client"` 재수출 경계를 유지한다. callback/ref 등 client 실행이
37
+ Surface로 넘길 수 있다. 서버 page 전체를 client로 바꿀 필요는 없다. 이 client entry는 1.16.0 변경이다. callback/ref 등 client 실행이
39
38
  필요한 props는 소비 Client Component에서 만든다. 루트 barrel/다른 entry를 서버에 직접 import해도
40
39
  된다는 보장은 아니다. [재현·검증](../../../../../docs/qa/2026-10-07-rsc-profile-boundary.md)을 따른다.
41
40
 
@@ -71,7 +70,7 @@ import { Surface } from "@hjmds/react-native/primitives";
71
70
  | `as`(Web) | `div` · `section` · `article` | `div` | — |
72
71
  | `layoutStyle` | `HjmCompositionStyleProp` | — | Surface 자신의 바깥 여백·폭·flex·`alignSelf`. Web·Native 모두 |
73
72
 
74
- ### 프로필 표면 질감(미게시)
73
+ ### 프로필 표면 질감(1.15.0 추가)
75
74
 
76
75
  선택한 `designProfile.material.surface`를 자동으로 읽는다. glass는 지원하는 Web에서 실제 배경 흐림,
77
76
  clay는 안쪽 그림자를 사용한다. Native는 루트 Provider의 선택형 `surfaceEffects` host와 inset capability를
@@ -69,7 +69,7 @@ import { Switch } from "@hjmds/react-native/inputs";
69
69
  | `description` | 문구 | — | 이름과 따로 연결한다(Web `aria-describedby`, Native `accessibilityHint` 기본값) |
70
70
  | `disabled` | `boolean` | `false` | — |
71
71
  | `layoutStyle` | `HjmCompositionStyleProp` | — | 루트(행) 배치. Web·Native 모두 |
72
- | `style`(Native) | `StyleProp<ViewStyle>` | — | deprecated — `layoutStyle` 또는 `size`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
72
+ | `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle` 또는 `size`. 현재 공개 props에서 제거되었다 |
73
73
 
74
74
  큰 글자(공통 large-text 기준)에서 `row`는 설명 아래로 track을 내린다.
75
75
 
@@ -77,12 +77,12 @@ 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` · `slide` · `gooey` | 미지정 시 프로필의 selectionMotion; 없으면 `standard` | 미게시(1.14.0 이후): `slide`는 2점 표시선 이동, `gooey`는 6점 표시선 늘어남. 명시 값 우선, 세로는 standard 유지 |
80
+ | `appearance` | `standard` · `slide` · `gooey` | 미지정 시 프로필의 selectionMotion; 없으면 `standard` | 1.15.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` 필수 | — | — |
84
84
  | `layoutStyle` | `HjmCompositionStyleProp` | — | Tabs·TabPanel 루트 배치. Web·Native 모두 |
85
- | Native `style`·`tabListStyle`, TabPanel `style` | `StyleProp<ViewStyle>` | — | deprecated — `layoutStyle` 또는 `size`·`layout`·`overflow`·`appearance`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
85
+ | Native `style`·`tabListStyle`, TabPanel `style` | 지원하지 않음 | — | 제거된 속성 — `layoutStyle` 또는 `size`·`layout`·`overflow`·`appearance`. 현재 공개 props에서 제거되었다 |
86
86
 
87
87
  ## 배치
88
88
 
@@ -112,7 +112,7 @@ import { Tabs } from "@hjmds/react-native/navigation";
112
112
  Web controlled `value`가 비활성·없는 항목이면 `RangeError`다.
113
113
  - 아이콘은 `renderLeading`으로 넣고 받은 `color`·`size`를 쓴다. 색을 직접 정하지 않는다.
114
114
  - 탭을 바꿔도 화면 이동(뒤로 가기 대상)이 아니다. 주소에 남겨야 하면 제품이 controlled 값으로 동기화한다.
115
- - 배치는 `layoutStyle`로 한다. Web 루트 `div` 속성(`className`·`style`)과 Native의 deprecated `style`·`tabListStyle`로
115
+ - 배치는 `layoutStyle`로 한다. Web 루트 `div` 속성(`className`·`style`)과 Native에서 제거된 `style`·`tabListStyle`로
116
116
  색·높이·인디케이터를 덮지 않는다.
117
117
 
118
118
  ## 플랫폼 차이
@@ -131,7 +131,7 @@ import { Tabs } from "@hjmds/react-native/navigation";
131
131
 
132
132
  - 2026-10-07 [Animated Tabs 대조](../../../../../docs/plans/aceternity-interaction-adoption-2026-10-07.md)에서
133
133
  선택 표시의 이동과 겹친 패널의 이동을 구분했다. 현재 `appearance="gooey"`는 표시선만 늘어나며,
134
- 패널을 겹쳐 복제하거나 순서를 바꾸지 않는다. 미게시(1.14.0 이후) 후속 구현에서
134
+ 패널을 겹쳐 복제하거나 순서를 바꾸지 않는다. 1.15.0 변경 후속 구현에서
135
135
  `appearance`를 생략하면 `designProfile.interactions.selectionMotion="slide"`가 일반 이동선으로
136
136
  연결된다. 명시 `standard`는 이동을 끄고 명시 `gooey`만 늘어남을 고른다. `slide`와 `gooey`를
137
137
  같은 의미로 간주하지 않는다. 전환 표현이 필요하면 [ContentTransition](content-transition.md)의
@@ -53,7 +53,7 @@ import { Tag } from "@hjmds/react-native/data-display";
53
53
  | `tone` | `neutral` · `info` · `success` · `attention` · `brand` | `neutral` | `warning`·`danger`는 없다(이유는 계약 문서) |
54
54
  | `layoutStyle` | `HjmCompositionStyleProp` | — | 바깥 여백·`alignSelf` 같은 배치. Web·Native 모두 |
55
55
  | `accessibilityLabel`(Native) | `string` | 라벨 | — |
56
- | `style`·`labelStyle`(Native) | `StyleProp` | — | deprecated — `layoutStyle` 또는 `tone`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
56
+ | `style`·`labelStyle`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle` 또는 `tone`. 현재 공개 props에서 제거되었다 |
57
57
 
58
58
  모양은 radius `sm` 사각형, 최소 높이 20(큰 글자에서 늘어남), caption 크기 semibold 글자다.
59
59
 
@@ -81,6 +81,6 @@ Native의 모서리는 Provider의 `tokens.radius.sm`이다. metadata 의미와
81
81
  | 항목 | Web | Native |
82
82
  | --- | --- | --- |
83
83
  | 접근 이름 | 보이는 글자 | 기본은 라벨, `accessibilityLabel`로 바꿀 수 있음 |
84
- | 추가 style prop | `className`·`style`(HTML 속성) | `style`·`labelStyle`(deprecated) |
84
+ | 추가 style prop | `className`·`style`(HTML 속성) | `style`·`labelStyle`(제거된 속성) |
85
85
  | ref | `forwardRef`(`span`) | 없음 |
86
86
  | import 경로 | `/display` | `/data-display` |
@@ -80,7 +80,7 @@ import { TagsInput } from "@hjmds/react-native/tags-input";
80
80
  | `suggestions` · `suggestionsLabel` | 제품이 거른 후보(`id`·`label`·`value?`·`disabled?`)와 목록 이름 | — | 거르려면 `onDraftChange`로 입력 중 문자를 받는다 |
81
81
  | `placeholder`·`description`·`disabled` | `string`·`string`·`boolean` | — | `disabled`는 라벨과 입력 틀을 `fieldRecipe.disabledOpacity`(0.6)로 흐리고 `description`은 그대로 둔다([Field](field.md)) |
82
82
  | `layoutStyle` | `HjmCompositionStyleProp` | — | 필드 전체 배치. Web·Native 모두 |
83
- | `style`(Native) | `StyleProp<ViewStyle>` | — | deprecated — `layoutStyle`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
83
+ | `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle`. 현재 공개 props에서 제거되었다 |
84
84
 
85
85
  ## 배치
86
86
 
@@ -91,7 +91,7 @@ Native 입력 프레임의 `md` 모서리는 Provider의 `tokens.radius.md`를
91
91
 
92
92
  | 항목 | 값 | 근거 |
93
93
  | --- | --- | --- |
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` |
94
+ | 크기 | 입력 틀 최소 높이 44(필드 틀과 같음), 모서리 `radius.md` 12. 입력 칸 최소 Web `8ch`, Native 80. 태그 칩 높이 28, 삭제 버튼 터치 영역 44(`control.minTouchTarget`). 후보 행 최소 높이 44(두 플랫폼, Native는 1.13.0 변경. 1.12.1 Native는 28) | `tagsInputRecipe`, `.hjm-tags-input__frame`·`__remove::after`·`__suggestion` |
95
95
  | 간격 | 라벨과 틀 사이 Web `spacing.xxs` 4, Native `spacing.xs` 8. 틀 안 태그·입력 칸 사이 `spacing.xs` 8. 이웃 필드와의 간격은 폼이 정한다 | `.hjm-tags-input`, `react-native/src/tags-input.tsx` |
96
96
  | 순서·정렬 | 라벨 → 입력 틀 → 후보 목록 → 설명. 폼 안에서 다른 [Field](field.md)와 같은 세로 줄에 두고 폭을 꽉 채운다 | `react/src/tags-input.tsx`, `react-native/src/tags-input.tsx` |
97
97
  | 고정·스크롤 | 후보 목록은 틀 바로 아래 문서 흐름에 펼쳐진다(떠 있는 층이 아니다). Web은 최대 높이 12rem에서 스크롤 | `.hjm-tags-input__suggestions` |
@@ -103,7 +103,7 @@ Native 입력 프레임의 `md` 모서리는 Provider의 `tokens.radius.md`를
103
103
  - 거절 사유 문장("이미 있어요")은 제품이 `reason`으로 만든다. HJM은 판정만 한다.
104
104
  - 한국어처럼 공백이 값의 일부인 도메인에서는 `Space`를 확정 키로 켜지 않는다.
105
105
  - 후보 필터링·정렬은 제품이 한다. HJM은 받은 후보를 보여 주고 고른 값을 확정한다.
106
- - 배치는 `layoutStyle`로 한다(Web `className`도 받는다). Native `style`은 deprecated다.
106
+ - 배치는 `layoutStyle`로 한다(Web `className`도 받는다). Native `style`은 제거된 속성이다.
107
107
 
108
108
  ## 플랫폼 차이
109
109
 
@@ -113,7 +113,7 @@ Native 입력 프레임의 `md` 모서리는 Provider의 `tokens.radius.md`를
113
113
  | 빈 입력 Backspace | 첫 번째는 마지막 태그 선택, 두 번째에 삭제 | 해당 키 계약 없음, 태그 옆 삭제 버튼 |
114
114
  | 후보 이동 | ArrowUp/Down(끝에서 순환) | 후보를 버튼으로 누름 |
115
115
  | ref | `forwardRef`(`input`) | 없음 |
116
- | 스타일 prop | `className`, `layoutStyle` | `layoutStyle`(`style`은 deprecated) |
116
+ | 스타일 prop | `className`, `layoutStyle` | `layoutStyle`(`style`은 제거된 속성) |
117
117
 
118
118
 
119
119
  ### 고정 아이콘과 큰 글자
@@ -69,7 +69,7 @@ import { TextArea } from "@hjmds/react-native/inputs";
69
69
  | `onChange`(Web) | `(event: ChangeEvent<HTMLTextAreaElement>) => void` | — | DOM 이벤트. 값은 `event.currentTarget.value` |
70
70
  | `onValueChange`(Native) | `(value: string) => void` | — | 다음 문자열 |
71
71
  | `minVisibleLines` · `maxVisibleLines` | 줄 수 | 최소 높이 80, 상한 없음 | 높이는 줄 수로만 정한다. 최소 높이는 `max(80, 줄 수 × typography.body 줄 높이 20 + spacing.sm 12 × 2)`라 `minVisibleLines`가 1·2여도 80(`fieldRecipe.multilineMinHeight`) 아래로 내려가지 않고 3부터 커진다(3줄 84). Web·Native 같다 |
72
- | `leadingAction` | `ReactNode` | — | 틀 안 글자 앞 행동 버튼. 자라는 글자의 세로 가운데에 맞추고 흐린 affix 색을 쓰지 않는다. 미게시(1.12.1 이후) |
72
+ | `leadingAction` | `ReactNode` | — | 틀 안 글자 앞 행동 버튼. 자라는 글자의 세로 가운데에 맞추고 흐린 affix 색을 쓰지 않는다. 1.13.0 변경 |
73
73
  | `trailing` | `ReactNode` | — | 틀 안 글자 뒤 슬롯 |
74
74
  | `description` · `error` · `required` · `disabled` | Web `ReactNode`, Native `string` · `boolean` | — | Field와 같은 틀로 그려지고 보조기기 설명에 연결된다 |
75
75
  | `busy`(Native) | `boolean` | `false` | — |
@@ -110,5 +110,7 @@ Native는 제품 프로필의 `tokens.fontFamily.ui`를 실제 텍스트/입력
110
110
 
111
111
  ## 함정
112
112
 
113
- - 현재 Web `TextField`의 `onValueChange` 주석은 "Web TextArea와 같은 콜백"이라고 적지만 Web `TextAreaProps`에는
114
- `onValueChange`가 없다(`react/src/forms.tsx`). 공유 폼 코드는 Web TextArea만 `onChange`로 분기한다.
113
+ - Web `TextAreaProps`에는 `onValueChange`가 없다. 공유 폼 코드는 Web TextArea의 `onChange`에서 `event.currentTarget.value`를 읽어 같은 값 변경 함수로 연결한다.
114
+
115
+
116
+ 2026-10-09 번뚝 시뮬레이터 확인: Native bounded 입력은 같은 너비의 비노출 텍스트로 줄 높이를 측정한다. iOS TextInput의 contentSize가 현재 viewport 높이로 제한되는 경우를 피하고, 마지막 줄바꿈도 크기에 포함한다. 화면에서 수동 픽셀 높이를 덧씌우지 않는다. 최대 표시 줄에 도달하기 전에는 커지고 이후 내부 스크롤을 사용한다.
@@ -17,6 +17,7 @@
17
17
 
18
18
  | 상황 | 대신 쓸 것 |
19
19
  | --- | --- |
20
+ | 짧은 상태·결과 문구를 변경 알림으로 전달 | [StatusText](#statustext) |
20
21
  | 문서 제목 단계(`h1`~)가 필요하거나 24px보다 큰 제목 | [Heading](heading.md) |
21
22
  | 화면 첫 자리의 제목 블록(보조 문장·행동 포함) | [Top](top.md) |
22
23
  | 본문 묶음의 헤더 행 | [Section](section.md) |
@@ -33,6 +34,7 @@ Text와 Heading의 경계: Text의 `variant="heading"`(24px)은 **모양만**
33
34
  | 이름 | 역할 | Web | Native |
34
35
  | --- | --- | --- | --- |
35
36
  | `Text` | 기본 | `@hjmds/react`, `/layout` | `@hjmds/react-native`, `/primitives` |
37
+ | `StatusText` | 짧은 상태·결과 알림 companion | `@hjmds/react`, `/status-text` | `@hjmds/react-native`, `/status-text` |
36
38
  | `GravityLetters` | 확장(홍보용 글자 낙하 장식, optional-extension) | `/gravity-letters` | `/gravity-letters` |
37
39
 
38
40
  `GravityLetters`는 granular subpath로만 import 된다. 추가 peer 의존성은 없다(Web은 WAAPI, Native는 RN `Animated`).
@@ -58,8 +60,8 @@ import { Text } from "@hjmds/react-native/primitives";
58
60
  | prop | 값 | 기본값 | 설명 |
59
61
  | --- | --- | --- | --- |
60
62
  | `variant` | `caption`(11) · `label`(12) · `body`(14) · `bodyLarge`(16) · `title`(18) · `titleLarge`(20) · `heading`(24) | `body` | 화면·섹션 제목은 모양이 아니라 [Heading](heading.md)으로 쓴다 |
61
- | `fontRole` | `ui` · `display` · `reading` · `code` | 제목 variant는 display, 본문은 reading, caption/label은 ui | 명시값이 기본을 덮는다. [역할 지침](../tokens/font-roles.md), 1.15.0 이후 미게시 |
62
- | `emphasis` | `regular` · `medium`(semibold) · `strong`(bold) | `regular` | — |
63
+ | `fontRole` | `ui` · `display` · `reading` · `code` | 제목 variant는 display, 본문은 reading, caption/label은 ui | 명시값이 기본을 덮는다. [역할 지침](../tokens/font-roles.md), 1.16.0 변경 |
64
+ | `emphasis` | `regular` · `medium`(semibold) · `strong`(bold) | 프로필이 있으면 variant 굵기, 없으면 `regular` | 명시값이 프로필과 variant보다 우선 |
63
65
  | `tone` | `primary` · `body` · `muted` · `subtle` · `weak` · `brand` · `danger` · `inverse` | `primary` | — |
64
66
  | `as` | `span` · `p` · `div` · `strong` · `small` | `span` | Web만. 문단은 `as="p"` |
65
67
  | `align` | `TextStyle["textAlign"]` | 쓰기 방향의 시작 쪽 | Native만 |
@@ -100,5 +102,84 @@ Native는 Text의 역할을 해당 stack에, 입력/조작 host는 제품 프로
100
102
 
101
103
  ## 함정
102
104
 
103
- - `emphasis`가 `variant`의 굵기를 덮는다. `variant="title"`도 기본 `emphasis="regular"`면 보통 굵기로
104
- 그려진다. 굵은 제목이 필요하면 `emphasis="strong"`을 명시한다(두 renderer 동일).
105
+ - `emphasis`를 명시하면 `variant`의 굵기를 덮는다. `designProfile`이 있으면 생략한 `emphasis`는 해당 프로필의 `tokens.typography[variant].fontWeight`를 따른다. 프로필이 없으면 기존 기본값 `regular`를 유지하므로 `variant="title"`도 보통 굵기로 그려진다. 그 경우 굵은 제목은 `emphasis="strong"`으로 지정한다(두 renderer 동일).
106
+
107
+
108
+ ## StatusText
109
+
110
+ Text와 같은 표현을 유지하면서 상태 변경 알림을 연결하는 공개 companion이다.
111
+ 기존 `본문 글자` Story의 `상태 알림`에서 지속 안내와 저장 결과를 확인한다.
112
+
113
+ ### StatusText 선택 기준
114
+
115
+ 저장 결과, 선택 개수, 요청 진행처럼 **짧은 문자열 하나**를 화면 안에 유지하며 변경을 알릴 때 쓴다.
116
+ Text의 companion으로 같은 `variant`·`tone`·`emphasis`·`layoutStyle`을 받으며 글꼴·색·간격을 새로 만들지 않는다.
117
+ 문구와 성공·실패 판정은 제품이 소유한다.
118
+
119
+ | 상황 | 선택 |
120
+ | --- | --- |
121
+ | 읽기만 하는 본문·계속 표시되는 설명 | Text |
122
+ | 짧은 상태·결과 문자열의 변경 알림 | StatusText |
123
+ | 제목·설명·아이콘·재시도 행동을 묶은 안내 | Notice |
124
+ | 화면 위에 일시적으로 나타나며 닫히는 알림 | Toast |
125
+
126
+ ### 가져오기
127
+
128
+ ```tsx
129
+ // Web
130
+ import { StatusText } from "@hjmds/react/status-text";
131
+ // Native: import { StatusText } from "@hjmds/react-native/status-text";
132
+ // 두 renderer의 root에서도 내보낸다.
133
+ ```
134
+
135
+ ### StatusText가 놓이는 자리
136
+
137
+ ```text
138
+ 관련 입력 또는 행동
139
+ ↕ 부모 Stack의 gap
140
+ StatusText: 결과 문자열
141
+ ```
142
+
143
+ 자체 여백·판·최소 높이는 없다. 관련 행동 가까이에 두고 부모 Stack이 간격을 소유한다.
144
+ 화면 전체를 대체하는 로딩·실패·빈 상태는 해당 영역의 ScreenLayout/StateView/Notice로 구성한다.
145
+
146
+ ### 공개 props
147
+
148
+ | prop | 기본값 | 의미 |
149
+ | --- | --- | --- |
150
+ | `children: string` | 필수 | 제품의 지역화된 상태 문구. 빈 문자열도 허용 |
151
+ | `announcement` | `polite` | `none`·`polite`·`assertive`. 시각적 tone과 알림 우선순위는 독립 |
152
+ | `announceOnMount` | `false` | Native iOS 옵션. 조건부로 새로 나타난 행동 결과를 처음에도 알림 |
153
+ | 나머지 Text props·ref | Text와 같음 | Web role/live/atomic, Native live region은 StatusText가 소유 |
154
+
155
+ ### 지속 안내와 새 결과
156
+
157
+ ```tsx
158
+ // Native
159
+ import { StatusText } from "@hjmds/react-native/status-text";
160
+
161
+ // 계속 유지되는 노드: 최초 안내는 iOS에서 읽지 않고 이후 문자열 변경만 알린다.
162
+ <StatusText>{message}</StatusText>
163
+
164
+ // Native: 행동 뒤 조건부로 새로 마운트되는 결과는 opt-in한다.
165
+ {saved ? <StatusText announceOnMount>{t("save.complete")}</StatusText> : null}
166
+
167
+ <StatusText announcement="assertive" tone="danger">{errorMessage}</StatusText>
168
+ ```
169
+
170
+ Web은 `polite`를 `role="status"`, `assertive`를 `role="alert"`로 연결하고 `aria-live`와
171
+ `aria-atomic`을 설정한다. `none`은 `aria-live="off"`이고 상태 role을 붙이지 않는다.
172
+ 같은 live node의 텍스트를 갱신하는 것이 기본이다. Web에는 `announceOnMount` prop이 없으며,
173
+ 새로 마운트된 live region의 읽힘은 브라우저·보조기술에 따라 달라진다.
174
+
175
+ Native Android는 `accessibilityLiveRegion`만 사용한다. iOS는 앱이 active이고 비어 있지 않은 문구가
176
+ 바뀔 때 `announceForAccessibilityWithOptions`를 호출한다. `polite`는 queue, `assertive`는 즉시 우선순위다.
177
+ `none`, 같은 문구 재렌더, 빈 문구, 배경 변경은 발표하지 않는다. foreground 복귀나 announcement 모드 변경만으로
178
+ 과거 문구를 재생하지 않는다. 빈 문구로 지웠다가 같은 결과를 다시 표시하면 새 변경이다.
179
+ `announceOnMount`는 마운트 시점에 결정하며 나중에 true로 바꿔 초기 안내를 재생하지 않는다.
180
+
181
+ ### 경계
182
+
183
+ 동일 결과를 매 렌더 다시 알리기 위해 key를 바꾸지 않는다. Toast·Notice에서 이미 알리는 결과를 중복 알리지 않는다.
184
+ Showcase의 `PatternStatus`는 이 공개 컴포넌트를 가리키는 내부 별칭일 뿐이며 제품에서 Showcase 파일을 import하지 않는다.
185
+ DOM 속성·Native host 호출 검사는 실제 VoiceOver·TalkBack의 낭독 확인과 구분한다.
@@ -75,7 +75,7 @@ import { Timeline } from "@hjmds/react-native/data-display";
75
75
  | `items[].tone` | `neutral` · `info` · `success` · `attention` | `neutral` | `warning`·`danger`는 없다 |
76
76
  | `composeAccessibleName`(필수) | `(info: { position: number, total: number, label: string }) => string` | — | position은 1부터 |
77
77
  | `layoutStyle` | `HjmCompositionStyleProp` | — | 루트 배치. Web·Native 모두 |
78
- | `style`(Native) | `StyleProp<ViewStyle>` | — | deprecated — `layoutStyle`. 개발 모드에서 한 번 경고하고 다음 major에서 제거된다 |
78
+ | `style`(Native) | 지원하지 않음 | — | 제거된 속성 — `layoutStyle`. 현재 공개 props에서 제거되었다 |
79
79
  | 나머지 | Web `<ol>` 속성, Native `ViewProps`(`style` 제외) | — | — |
80
80
 
81
81
  ## 배치
@@ -94,7 +94,7 @@ import { Timeline } from "@hjmds/react-native/data-display";
94
94
  - 빈 배열, 중복 `id`, 앞뒤 공백이 있는 `id`, 빈 문자열 필드, 목록 밖 tone은 실행 중 오류를 던진다.
95
95
  - 접근 이름의 어순은 언어마다 다르므로 `composeAccessibleName`은 i18n 키로 만든다.
96
96
  - 제품 고유 색(구단 색 등)은 adapter에서 네 tone 중 하나로 먼저 매핑한다. dot 색을 직접 칠하지 않는다.
97
- - 배치는 `layoutStyle`로 한다. Web `className`/`style`과 Native의 deprecated `style`로 dot·connector·글자 색을 덮지 않는다.
97
+ - 배치는 `layoutStyle`로 한다. Web `className`/`style`과 Native에서 제거된 `style`로 dot·connector·글자 색을 덮지 않는다.
98
98
 
99
99
  ## 플랫폼 차이
100
100