@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
@@ -67,7 +67,7 @@ import { EmptyState } from "@hjmds/react-native/feedback";
67
67
  | `description` | Web `ReactNode` ยท Native `string` | โ€” | โ€” |
68
68
  | `action` | `ReactNode`(Button ํ•˜๋‚˜) | โ€” | ์ฝœ๋ฐฑ์€ Button์˜ `onClick`ยท`onPress`๊ฐ€ ๊ฐ–๋Š”๋‹ค |
69
69
  | Web `icon` ยท Native `illustration` | `ReactNode` | โ€” | ์žฅ์‹, ์ ‘๊ทผ์„ฑ์—์„œ ์ˆจ๊น€ |
70
- | `layoutStyle` | ๋ฐฐ์น˜ ์ „์šฉ style | โ€” | ๋ฃจํŠธ ๋ฐฐ์น˜. Native `style`ยท`illustrationStyle`ยท`titleStyle`ยท`descriptionStyle`ยท`actionStyle`์€ deprecated |
70
+ | `layoutStyle` | ๋ฐฐ์น˜ ์ „์šฉ style | โ€” | ๋ฃจํŠธ ๋ฐฐ์น˜. Native `style`ยท`illustrationStyle`ยท`titleStyle`ยท`descriptionStyle`ยท`actionStyle`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ |
71
71
 
72
72
  EmptyState ์ž์ฒด์—๋Š” ์ฝœ๋ฐฑ prop์ด ์—†๋‹ค. 2026-10-07 ๊ธฐ์กด ์˜ˆ์ œ์˜ ์ƒ์„ฑ ๋ฒ„ํŠผ์— ๋™์ž‘์ด ์—†์Œ์„ ํ™•์ธํ•ด
73
73
  ์–‘ ๊ธฐ๋ณธ ์Šคํ† ๋ฆฌ๋ฅผ ์˜ˆ์‹œ ์ƒ์„ฑ โ†’ ๊ฒ€์ƒ‰ 0๊ฑด โ†’ ๊ฒ€์ƒ‰์–ด ์ง€์šฐ๊ธฐ โ†’ ๋ชฉ๋ก ๋ณต๊ตฌ๋กœ ์—ฐ๊ฒฐํ–ˆ๋‹ค. ์ด ๋ฐ์ดํ„ฐ๋Š”
@@ -77,7 +77,7 @@ EmptyState ์ž์ฒด์—๋Š” ์ฝœ๋ฐฑ prop์ด ์—†๋‹ค. 2026-10-07 ๊ธฐ์กด ์˜ˆ์ œ์˜ ์ƒ
77
77
 
78
78
  | ํ•ญ๋ชฉ | ๊ฐ’ | ๊ทผ๊ฑฐ |
79
79
  | --- | --- | --- |
80
- | ํฌ๊ธฐ | ๊ทธ๋ฆผ ์Šฌ๋กฏ์€ `glyph.lg`(28) ์ •์‚ฌ๊ฐํ˜•์ด๋‹ค(Native `illustration` ์ƒ์ž ๊ณ ์ • ํฌ๊ธฐ). ์„ธ๋กœ ์—ฌ๋ฐฑ: `compact` `spacing.xl`(24). `regular` `spacing.xxxl`(40, ๋‘ ํ”Œ๋žซํผ) | `component-recipes.ts` `emptyStateRecipe`, `styles.css` `.hjm-empty-state` |
80
+ | ํฌ๊ธฐ | Native ๊ทธ๋ฆผ ์Šฌ๋กฏ์€ ์ตœ์†Œ `glyph.lg`(28) ํญยท๋†’์ด๋ฅผ ํ™•๋ณดํ•˜๊ณ  ํฐ ์ผ๋Ÿฌ์ŠคํŠธ์˜ ์ž์ฒด ํฌ๊ธฐ๋ฅผ ์กด์ค‘ํ•œ๋‹ค. Web ๊ทธ๋ฆผ ์Šฌ๋กฏ์—๋Š” ๊ณ ์ • ํฌ๊ธฐ๊ฐ€ ์—†๋‹ค. ์„ธ๋กœ ์—ฌ๋ฐฑ: `compact` `spacing.xl`(24). `regular` `spacing.xxxl`(40, ๋‘ ํ”Œ๋žซํผ) | `component-recipes.ts` `emptyStateRecipe`, `styles.css` `.hjm-empty-state` |
81
81
  | ๊ฐ„๊ฒฉ | ํ•ญ๋ชฉ ์‚ฌ์ด ๊ฐ„๊ฒฉ `spacing.xs`(8), ์ขŒ์šฐ ์—ฌ๋ฐฑ `spacing.xl`(24) | `component-recipes.ts` `emptyStateRecipe` |
82
82
  | ์ˆœ์„œยท์ •๋ ฌ | ์œ„โ†’์•„๋ž˜ ์ˆœ์„œ๋Š” ๊ทธ๋ฆผ โ†’ ์ œ๋ชฉ โ†’ ์„ค๋ช… โ†’ ํ–‰๋™์ด๊ณ  ๊ฐ€์šด๋ฐ ์ •๋ ฌ์ด๋‹ค. ํ–‰๋™์€ Button ํ•˜๋‚˜(`tone="secondary"` ๋˜๋Š” `primary`)๋ฅผ ๋‚ด์šฉ ํญ๋งŒํผ ๋‘”๋‹ค | `react-native/src/feedback.tsx` `EmptyState` |
83
83
  | ๊ณ ์ •ยท์Šคํฌ๋กค | ๋น„์–ด ์žˆ๋Š” ๋ชฉ๋กยท๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์˜์—ญ **์•ˆ**์— ๋‘”๋‹ค. ์œ„ TopBarยท๊ฒ€์ƒ‰์นธยทํ•„ํ„ฐ๋Š” ๊ทธ๋Œ€๋กœ ๋‚จ๊ธฐ๊ณ  ๊ทธ ์•„๋ž˜ ๋‚ด์šฉ ์˜์—ญ๋งŒ EmptyState๋กœ ๋ฐ”๊พผ๋‹ค. Native `regular`๋Š” ๋‚จ์€ ๋†’์ด๋ฅผ ์ฑ„์šฐ๊ณ (`flexGrow: 1`) ์„ธ๋กœ ๊ฐ€์šด๋ฐ์— ๋†“๋Š”๋‹ค. `align="upper"`๋Š” ์œ„:์•„๋ž˜ ๋นˆ ๊ณต๊ฐ„์„ 1:3์œผ๋กœ ๋‚˜๋ˆ  ๋‚ด์šฉ์ด ์œ„์ชฝ์— ์˜จ๋‹ค. ํ™”๋ฉด ํ•˜๋‹จ ๊ณ ์ • ํ–‰๋™์ด ํ•„์š”ํ•˜๋ฉด [BottomCTA](bottom-cta.md)๋กœ ๋”ฐ๋กœ ๋‘”๋‹ค | `react-native/src/feedback.tsx` `EmptyState` |
@@ -107,16 +107,16 @@ EmptyState ์ž์ฒด์—๋Š” ์ฝœ๋ฐฑ prop์ด ์—†๋‹ค. 2026-10-07 ๊ธฐ์กด ์˜ˆ์ œ์˜ ์ƒ
107
107
  - ์ œ๋ชฉยท์„ค๋ช…ยทํ–‰๋™ ๋ฌธ๊ตฌ๋Š” i18n ํ‚ค๋กœ ๋„ฃ๋Š”๋‹ค. "๊ฒ€์ƒ‰ 0๊ฑด"๊ณผ "์•„์ง ๋งŒ๋“  ๊ฒƒ ์—†์Œ"์€ ๋‹ค๋ฅธ ๋ฌธ๊ตฌ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.
108
108
  - ๋‹ค์Œ ํ–‰๋™์ด ์žˆ์œผ๋ฉด `action`์— Button ํ•˜๋‚˜๋ฅผ ๋‘”๋‹ค. ์•„์ด์ฝ˜ยท์ผ๋Ÿฌ์ŠคํŠธ๋Š” ์žฅ์‹์ด๋ผ ์ ‘๊ทผ์„ฑ์—์„œ ์ˆจ๊ฒจ์ง„๋‹ค.
109
109
  - Native๋Š” `title`ยท`description`ยท`accessibilityLabel` ์ค‘ ํ•˜๋‚˜๋Š” ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋ชจ๋‘ ์—†์œผ๋ฉด `TypeError`๋ฅผ ๋˜์ง„๋‹ค.
110
- - ์ผ๋Ÿฌ์ŠคํŠธยท์•„์ด์ฝ˜ ์ž์‚ฐ์€ ์ œํ’ˆ ์†Œ์œ ๋‹ค. ์ƒ‰์€ recipe๊ฐ€ ์ •ํ•˜๋ฏ€๋กœ ์Šฌ๋กฏ ์ƒ‰์„ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.
110
+ - ์ผ๋Ÿฌ์ŠคํŠธยท์•„์ด์ฝ˜ ์ž์‚ฐ๊ณผ ์ž์ฒด ํฌ๊ธฐ๋Š” ์ œํ’ˆ ์†Œ์œ ๋‹ค. ํฐ ๊ทธ๋ฆผ์€ `illustration` ๋…ธ๋“œ ์•ˆ์—์„œ ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•œ๋‹ค. EmptyState์˜ ์ œ๋ชฉยท์„ค๋ช… ์ƒ‰์€ recipe๊ฐ€ ์ •ํ•˜๋ฉฐ ์ œ๊ฑฐ๋œ `illustrationStyle`๋กœ ํ”„๋ ˆ์ž„์„ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.
111
111
  - ๋ฐฐ์น˜๋Š” `layoutStyle`๋กœ ํ•œ๋‹ค. Native ์Šฌ๋กฏ style(`style`ยท`illustrationStyle`ยท`titleStyle`ยท`descriptionStyle`ยท`actionStyle`)์€
112
- deprecated(๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ)๋‹ค โ€” ๋ฐฐ์น˜๋Š” `layoutStyle`, ์™ธํ˜•์€ `density`ยท`align`์œผ๋กœ ์˜ฎ๊ธด๋‹ค.
112
+ ์ œ๊ฑฐ๋œ ์†์„ฑ์ด๋‹ค โ€” ๋ฐฐ์น˜๋Š” `layoutStyle`, ์™ธํ˜•์€ `density`ยท`align`์œผ๋กœ ์˜ฎ๊ธด๋‹ค.
113
113
 
114
114
  ## ํ”Œ๋žซํผ ์ฐจ์ด
115
115
 
116
116
  | ํ•ญ๋ชฉ | Web | Native |
117
117
  | --- | --- | --- |
118
- | ๊ทธ๋ฆผ ์Šฌ๋กฏ | `icon`(ReactNode) | `illustration`(ReactNode, ์•„์ด์ฝ˜ ํฌ๊ธฐ ์ƒ์ž) |
118
+ | ๊ทธ๋ฆผ ์Šฌ๋กฏ | `icon`(ReactNode) | `illustration`(ReactNode, ์ตœ์†Œ ์•„์ด์ฝ˜ ํฌ๊ธฐ + ์ฝ˜ํ…์ธ  ์ž์ฒด ํฌ๊ธฐ) |
119
119
  | `title` | ํ•„์ˆ˜, ReactNode | ์„ ํƒ, string |
120
120
  | `description` | ReactNode | string |
121
121
  | ์ •๋ ฌยท์•Œ๋ฆผ | ์—†์Œ | `align`, `announcement`, `accessibilityLabel`, `titleRole` |
122
- | ๋ฐฐ์น˜ | `layoutStyle`(๊ทธ ๋ฐ–์— `className`๊ณผ div ์†์„ฑ) | `layoutStyle`(์Šฌ๋กฏ style ๋‹ค์„ฏ ๊ฐœ๋Š” deprecated) |
122
+ | ๋ฐฐ์น˜ | `layoutStyle`(๊ทธ ๋ฐ–์— `className`๊ณผ div ์†์„ฑ) | `layoutStyle`(์Šฌ๋กฏ style ๋‹ค์„ฏ ๊ฐœ๋Š” ์ œ๊ฑฐ๋œ ์†์„ฑ) |
@@ -30,6 +30,8 @@
30
30
  | `Field` | ๊ธฐ๋ณธ โ€” ์ปค์Šคํ…€ ์ปจํŠธ๋กค์šฉ ํ‹€ | `@hjmds/react`, `/forms` | `@hjmds/react-native`, `/forms` |
31
31
  | `TextField` | ๋™๋ฐ˜ โ€” ํ•œ ์ค„ ํ…์ŠคํŠธ ์ž…๋ ฅ | `@hjmds/react`, `/forms` | `@hjmds/react-native`, `/inputs` |
32
32
  | `GestureSheetInput` | ํ™•์žฅ โ€” GestureSheet ์•ˆ์˜ ํ‚ค๋ณด๋“œ ์ถ”์  ์ž…๋ ฅ | ์—†์Œ | `/sheet-gesture` |
33
+ | `DateEntry` | ํ™•์žฅ โ€” ๋‚ ์งœ ์กฐ๊ฐ ์ง์ ‘ ์ž…๋ ฅ([๊ตฌ์„ฑ ์ง€์นจ](../compositions/date-entry.md)) | `/date-entry` | `/date-entry` |
34
+ | `FieldGroup` | ํ™•์žฅ โ€” ๊ด€๋ จ ์ž…๋ ฅ์˜ ๊ทธ๋ฃน ์•ˆ๋‚ดยท์˜ค๋ฅ˜([๊ตฌ์„ฑ ์ง€์นจ](../compositions/field-group.md)) | `/field-group` | `/field-group` |
33
35
 
34
36
  ## ์ตœ์†Œ ์‚ฌ์šฉ ์˜ˆ
35
37
 
@@ -130,7 +132,7 @@ TextField์™€ ๊ฐ™์€ ํ…Œ๋‘๋ฆฌยท๊ธ€๊ผดยทplaceholder ์ƒ‰์„ ์ž…ํžŒ๋‹ค. ๋ผ๋ฒจยท๋„
130
132
  ์•Š๋Š”๋‹ค(TS2375). ์œ„ ์˜ˆ์ฒ˜๋Ÿผ ์กฐ๊ฑด๋ถ€ spread๋กœ ๋„˜๊ธด๋‹ค. Web์€ `ReactNode`๋ผ `undefined`๋ฅผ ๊ทธ๋Œ€๋กœ ๋„˜๊ฒจ๋„ ๋œ๋‹ค.
131
133
  - Web `Field`๋Š” `controlId`๊ฐ€ ํ•„์ˆ˜์ด๊ณ , Native `Field`์—๋Š” `controlId`๊ฐ€ ์—†๋‹ค. ๊ณต์šฉ ์ฝ”๋“œ์—์„œ ๊ฐ™์€ props ๊ฐ์ฒด๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค.
132
134
 
133
- ### ๋‚ ์งœ ์กฐ๊ฐ ์ง์ ‘ ์ž…๋ ฅ (์‹คํ—˜ยท๋ฏธ๊ฒŒ์‹œ)
135
+ ### ๋‚ ์งœ ์กฐ๊ฐ ์ง์ ‘ ์ž…๋ ฅ (1.14.0 ์ถ”๊ฐ€ยท์‹คํ—˜)
134
136
 
135
137
  ์•Œ๊ณ  ์žˆ๋Š” ๋‚ ์งœ๋ฅผ ๋…„ยท์›”ยท์ผ๋กœ ์ง์ ‘ ํŽธ์ง‘ํ•˜๋ ค๋ฉด `DateEntry`๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
136
138
  Web `@hjmds/react/date-entry`, Native `@hjmds/react-native/date-entry`์˜ Field ํ™•์žฅ์ด๋‹ค.
@@ -143,11 +145,11 @@ Web `@hjmds/react/date-entry`, Native `@hjmds/react-native/date-entry`์˜ Field
143
145
 
144
146
  Web TextField์˜ `aria-invalid={true}`๋Š” ์™ธ๋ถ€ ์˜ค๋ฅ˜ ID๋ฅผ `aria-describedby`๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒฝ์šฐ์—๋„
145
147
  ์˜ค๋ฅ˜ ํ…Œ๋‘๋ฆฌ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค. Native TextField/TextArea์˜ `invalid`๋Š” ์ธ๋ผ์ธ error ๋ฌธ๊ตฌ ์—†์ด ์˜ค๋ฅ˜
146
- ํ…Œ๋‘๋ฆฌ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๋ฏธ๊ฒŒ์‹œ ์˜ต์…˜์ด๋‹ค. ๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ `accessibilityHint`๋กœ ์—ฐ๊ฒฐํ•˜๊ณ  ๊ทธ๋ฃน ์•ˆ๋‚ด๋ฅผ
148
+ ํ…Œ๋‘๋ฆฌ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ์˜ต์…˜์ด๋‹ค(1.14.0 ์ถ”๊ฐ€). ๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ `accessibilityHint`๋กœ ์—ฐ๊ฒฐํ•˜๊ณ  ๊ทธ๋ฃน ์•ˆ๋‚ด๋ฅผ
147
149
  ๋ณ„๋„๋กœ ๋ณด์—ฌ ์ค€๋‹ค. error๊ฐ€ ์žˆ์œผ๋ฉด ํ•ด๋‹น ๋ฌธ๊ตฌ๊ฐ€ hint๋ณด๋‹ค ์šฐ์„ ํ•˜๊ณ , hint๊ฐ€ ์—†์œผ๋ฉด description์„ ์“ด๋‹ค.
148
150
  2026-10-07 ๋‚ ์งœ ์ง์ ‘ ์ž…๋ ฅ์˜ ํฐ ๊ธ€์ž ์˜ค๋ฅ˜๊ฐ€ ์„ธ ๋ฒˆ ๋ฐ˜๋ณต๋œ ๊ด€์ฐฐ์— ๋”ฐ๋ผ ์ด ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
149
151
 
150
- ### ๊ด€๋ จ ์ž…๋ ฅ ๊ทธ๋ฃน (์‹คํ—˜ยท๋ฏธ๊ฒŒ์‹œ)
152
+ ### ๊ด€๋ จ ์ž…๋ ฅ ๊ทธ๋ฃน (1.14.0 ์ถ”๊ฐ€ยท์‹คํ—˜)
151
153
 
152
154
  ์—ฌ๋Ÿฌ ์ž…๋ ฅ์ด ํ•œ ์งˆ๋ฌธ์— ๋‹ตํ•˜๋ฉด `FieldGroup`์„ ์‚ฌ์šฉํ•œ๋‹ค. Form์˜ ์ œ์ถœ ๊ฒฝ๊ณ„์™€ ๊ตฌ๋ถ„ํ•˜๋ฉฐ
153
155
  `@hjmds/react/field-group`, `@hjmds/react-native/field-group`์—์„œ ์ œ๊ณตํ•œ๋‹ค.
@@ -70,7 +70,7 @@ import { FilePicker } from "@hjmds/react-native/file-picker";
70
70
  | Native `onPick` | `() => Promise<readonly FilePickerCandidate[] \| null>` | ํ•„์ˆ˜ | ์ œํ’ˆ adapter. ์ทจ์†Œ๋ฉด `null` |
71
71
  | Native `onPickError` | `(error: unknown) => void` | ํ•„์ˆ˜ | `onPick`์ด rejectํ•˜๋ฉด ์ด์ชฝ์œผ๋กœ๋งŒ ์˜จ๋‹ค |
72
72
  | Web `getCandidateId` | `(file: File, index: number) => string` | `name:size:lastModified:index` | ํ›„๋ณด id ๊ทœ์น™ |
73
- | `disabled` | `true` ยท `false` | `false` | โ€” |
73
+ | `disabled` | `true` ยท `false` | `false` | ์„ ํƒ ์™„๋ฃŒ ์‹œ์—๋„ ์ž ๊ธˆ ์ƒํƒœ๋ฉด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค |
74
74
  | `hint`, `error` | ๋ฌธ๊ตฌ | โ€” | ์„ ํƒ ์‚ฌํ•ญ์ด๋‹ค |
75
75
 
76
76
  - `FilePickerCandidate`: `{ id, name, mimeType, sizeBytes }`(`mimeType`์€ ํ”Œ๋žซํผ์ด ๋ชป ์ •ํ•˜๋ฉด `""`).
@@ -93,6 +93,9 @@ import { FilePicker } from "@hjmds/react-native/file-picker";
93
93
  ๋งŒ๋“ค๊ณ  ์ƒ‰์œผ๋กœ๋งŒ ์•Œ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
94
94
  - `rejected`๊ฐ€ ์žˆ์–ด๋„ `accepted`๋Š” ๊ทธ๋Œ€๋กœ ์“ด๋‹ค. ํ•œ ์žฅ์ด ๋ง‰ํ˜”๋‹ค๊ณ  ์ „์ฒด ์„ ํƒ์„ ๋ฒ„๋ฆฌ์ง€ ์•Š๋Š”๋‹ค.
95
95
  - FilePicker๋Š” ์„ ํƒ ๋ชฉ๋ก์„ ์Œ“์ง€ ์•Š๋Š”๋‹ค. ๊ณ ๋ฅธ ํŒŒ์ผ ๋ชฉ๋กยท์—…๋กœ๋“œ ์ƒํƒœ๋Š” ์ œํ’ˆ ์ƒํƒœ์™€ UploadItem์ด ์†Œ์œ ํ•œ๋‹ค.
96
+ - ์ทจ์†Œ(Web์˜ ๋นˆ ์„ ํƒ, Native adapter์˜ `null`)๋Š” ๊ธฐ์กด ๋ชฉ๋ก์„ ๋ฐ”๊พธ๊ฑฐ๋‚˜ `onSelect`๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ฐ™์€ ํŒŒ์ผ์€ ๋‹ค์‹œ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค.
97
+ - Native ๊ฒฐ๊ณผ๋Š” ์™„๋ฃŒ ์‹œ์ ์˜ `descriptor`ยท`existingCount`๋กœ ํŒ์ •ํ•˜๊ณ  ํ˜„์žฌ ์ฝœ๋ฐฑ์œผ๋กœ ์ „๋‹ฌํ•œ๋‹ค. ๋Œ€๊ธฐ ์ค‘ ๋‹ค๋ฅธ ํŒŒ์ผ์ด ์ถ”๊ฐ€ยท์ œ๊ฑฐ๋˜๋ฉด `existingCount`๋ฅผ ๊ณ„์† ๊ฐฑ์‹ ํ•œ๋‹ค.
98
+ - ํŒŒ์ผ ํ–‰ ์ œ๊ฑฐ์™€ ์ œ๊ฑฐ ํ›„ ์ดˆ์  ๋ณต๊ท€๋Š” ๋ชฉ๋ก์„ ์†Œ์œ ํ•œ ์ œํ’ˆ์ด ์ฒ˜๋ฆฌํ•œ๋‹ค. ์ œ๊ฑฐ ๋ฒ„ํŠผ์„ FilePicker ๋‚ด๋ถ€์— ๊ฐ€์ •ํ•˜๊ฑฐ๋‚˜ ์„ ํƒ ์ฝœ๋ฐฑ์„ ๋ชฉ๋ก ์ดˆ๊ธฐํ™” ์‹ ํ˜ธ๋กœ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
96
99
  - Native ์‹ค์ œ OS document/image picker ์—ฐ๊ฒฐ(`onPick`)์€ ์ œํ’ˆ ์ฑ…์ž„์ด๋‹ค. ํŒจํ‚ค์ง€๋Š” ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜
97
100
  ๊ธฐ๊ธฐ์—์„œ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ œํ’ˆ ๋ฆด๋ฆฌ์Šค QA์—์„œ ํ™•์ธํ•œ๋‹ค.
98
101
 
@@ -106,7 +109,7 @@ import { FilePicker } from "@hjmds/react-native/file-picker";
106
109
  | ์ง„ํ–‰ ์ค‘ ์ž ๊ธˆ | ์—†์Œ | `onPick` ๋Œ€๊ธฐ ์ค‘ ๋ฒ„ํŠผ `busy`ยท๋น„ํ™œ์„ฑ |
107
110
  | `label`ยท`hint`ยท`error` ํƒ€์ž… | `ReactNode` | `string` |
108
111
  | ํ›„๋ณด id | `getCandidateId`(๊ธฐ๋ณธ `name:size:lastModified:index`) | adapter๊ฐ€ `id`๋ฅผ ์ฑ„์›€ |
109
- | ๋ฐฐ์น˜ | `layoutStyle`(๋ฃจํŠธ), `className`๊ณผ div ์†์„ฑ | `layoutStyle`. `style`์€ deprecated(๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle` ๋˜๋Š” recipe |
112
+ | ๋ฐฐ์น˜ | `layoutStyle`(๋ฃจํŠธ), `className`๊ณผ div ์†์„ฑ | `layoutStyle`. `style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle` ๋˜๋Š” recipe |
110
113
 
111
114
  ## ํ•จ์ •
112
115
 
@@ -117,4 +120,4 @@ import { FilePicker } from "@hjmds/react-native/file-picker";
117
120
 
118
121
  2026-10-07 ์†Œ๋น„ ๊ฐ์‚ฌ์—์„œ Native ์„ ํƒ ๋ฒ„ํŠผ์˜ ๋ชจ์„œ๋ฆฌ 12๊ฐ€ ํ”„๋กœํ•„์„ ์šฐํšŒํ–ˆ๋‹ค. Web ๋ฒ„ํŠผ์˜ ๊ธฐ์กด `radius.md`์™€ ๊ฐ™์€ ์—ญํ• ์„ Native๋„ ๊ฐ€๊นŒ์šด ํ”„๋กœํ•„์—์„œ ์ฝ์œผ๋ฉฐ, ํ”„๋กœํ•„์ด ์—†์œผ๋ฉด ๊ธฐ์กด 12๋ฅผ ์œ ์ง€ํ•œ๋‹ค. ์„ ํƒ ์–ด๋Œ‘ํ„ฐยท๋น„ํ™œ์„ฑ/์ง„ํ–‰ ์ƒํƒœยทํŒŒ์ผ ๊ฒ€์ฆ์€ ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค.
119
122
 
120
- ํ”„๋กœํ•„ ์—ฐ๊ฒฐ์€ 1.15.0 ์ดํ›„ ๋ฏธ๊ฒŒ์‹œ ๋ณ€๊ฒฝ์ด๋ฉฐ, ๊ธฐ๋ณธ ๋ฐฐํฌ ๊ณ„์•ฝ๊ณผ ์‹ค์ œ Native ๊ธฐ๊ธฐ ๊ฒ€์ฆ์€ ๊ตฌ๋ถ„ํ•œ๋‹ค.
123
+ ํ”„๋กœํ•„ ์—ฐ๊ฒฐ์€ 1.16.0 ๋ณ€๊ฒฝ์ด๋ฉฐ, ๊ธฐ๋ณธ ๋ฐฐํฌ ๊ณ„์•ฝ๊ณผ ์‹ค์ œ Native ๊ธฐ๊ธฐ ๊ฒ€์ฆ์€ ๊ตฌ๋ถ„ํ•œ๋‹ค.
@@ -157,7 +157,7 @@ useEffect(() => { firstInvalidRef.current = nicknameError ? nicknameInputRef.cur
157
157
  | ์‹คํŒจ ์ฒ˜๋ฆฌ | Promise reject๋ฅผ ์‚ผํ‚จ๋‹ค. ์ œํ’ˆ์ด `formError`๋ฅผ ์„ค์ • | rejectํ•˜๋ฉด `failed`๋กœ ๋ฐ”๊พธ๊ณ  Error ๋ฉ”์‹œ์ง€ ๋˜๋Š” `fallbackErrorMessage`๋ฅผ alert๋กœ ํ‘œ์‹œ |
158
158
  | ์ฒซ ์˜ค๋ฅ˜ ํ•„๋“œ๋กœ ์ด๋™ | ์—†์Œ. ์ œํ’ˆ์ด `onSubmit` ์•ˆ์—์„œ ์ฒซ ๋ฌดํšจ ์ž…๋ ฅ์— `.focus()`ํ•œ๋‹ค | `firstInvalidFieldRef`: ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ์ˆœ๊ฐ„ `current`๋ฅผ ์ฝ๋Š”๋‹ค. non-null์ด๋ฉด ๊ทธ ์ž…๋ ฅ์— focus์™€ ์Šคํฌ๋ฆฐ ๋ฆฌ๋” focus๋ฅผ ์˜ฎ๊ธฐ๊ณ  `onSubmit`ยท`onStatusChange` ์—†์ด ๋ฉˆ์ถ˜๋‹ค(์ƒํƒœ ๊ทธ๋Œ€๋กœ). ref๋Š” `useEffect`์—์„œ ๊ฐฑ์‹ ํ•˜๊ณ , ์ˆœ์„œ ๊ณ„์‚ฐ์€ `resolveFirstInvalidFieldFocusTarget(fieldOrder, invalidIds)`๋ฅผ ์“ด๋‹ค |
159
159
  | ์ ‘๊ทผ์„ฑ ์ด๋ฆ„ | `<form>` ์†์„ฑ(`aria-label` ๋“ฑ) | `label` ํ•„์ˆ˜ |
160
- | ๋ฐฐ์น˜ | `className`, `layoutStyle`(form ์†์„ฑ `style`๋„ ๋ฐ›์Œ) | `layoutStyle`. `style`์€ deprecated(๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle` ๋˜๋Š” `density` |
160
+ | ๋ฐฐ์น˜ | `className`, `layoutStyle`(form ์†์„ฑ `style`๋„ ๋ฐ›์Œ) | `layoutStyle`. `style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle` ๋˜๋Š” `density` |
161
161
  | ๋ฐ–์—์„œ ์ œ์ถœ | `<form>`์ด๋ฏ€๋กœ `type="submit"` ๋ฒ„ํŠผยทEnter๋กœ ๋œ๋‹ค | `ref: Ref<FormHandle>`์˜ `submit()`์œผ๋กœ ๊ฐ™์€ validationยท์ค‘๋ณต ์ œ์ถœ ๋ฐฉ์ง€๋ฅผ ์‹คํ–‰ |
162
162
 
163
163
  ## ํ•จ์ •
@@ -83,14 +83,14 @@ import { Heading } from "@hjmds/react-native/heading";
83
83
  | --- | --- | --- |
84
84
  | ์ถœ๋ ฅ | `h1`~`h6` ์š”์†Œ | `Text` + `accessibilityRole="header"` + `aria-level` |
85
85
  | ์ถ”๊ฐ€ prop | `HTMLAttributes`(`id`, `className`, `style` ๋“ฑ), ref | ์—†์Œ |
86
- | ๋ฐฐ์น˜ | `layoutStyle`. `style`๋„ ํ•ฉ์ณ์ง„๋‹ค(ํฌ๊ธฐ ๋ณ€์ˆ˜๋Š” ๋ฎ์ด์ง€ ์•Š์Œ) | `layoutStyle`. `style`(TextStyle)์€ deprecated(๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle` ๋˜๋Š” `level` |
86
+ | ๋ฐฐ์น˜ | `layoutStyle`. `style`๋„ ํ•ฉ์ณ์ง„๋‹ค(ํฌ๊ธฐ ๋ณ€์ˆ˜๋Š” ๋ฎ์ด์ง€ ์•Š์Œ) | `layoutStyle`. `style`(TextStyle)์€ ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle` ๋˜๋Š” `level` |
87
87
  | ๊ธ€์ž ๋ฐฐ์œจ | `--hjm-text-scale`๋กœ ํ™•๋Œ€ | Native `Text`์˜ ๊ธ€์ž ๋ฐฐ์œจ |
88
88
 
89
89
  ## ํ•จ์ •
90
90
 
91
91
  - Web `style`์€ ์ด์ œ ๋ฒ„๋ ค์ง€์ง€ ์•Š๊ณ  ํ•ฉ์ณ์ง„๋‹ค. ๋‹ค๋งŒ ํฌ๊ธฐยท์ค„ ๋†’์ดยท๊ตต๊ธฐ ๋ณ€์ˆ˜(`--hjm-heading-*`)๋Š” recipe๊ฐ€ ๋งˆ์ง€๋ง‰์— ๋ฎ์œผ๋ฏ€๋กœ
92
92
  `style`๋กœ ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค. ๋ฐฐ์น˜๋Š” `layoutStyle`๋กœ ์ค€๋‹ค.
93
- - Native `style`(deprecated)์€ ์•„์ง ๋งˆ์ง€๋ง‰์— ํ•ฉ์ณ์ ธ ์ƒ‰ยทํฌ๊ธฐ๊นŒ์ง€ ๋ฐ”๋€๋‹ค. ์“ฐ์ง€ ๋ง๊ณ  `layoutStyle`ยท`level`๋กœ ์˜ฎ๊ธด๋‹ค.
93
+ - Native `style`์€ ์ œ๊ฑฐ๋˜์—ˆ๋‹ค. ๋ฐฐ์น˜๋Š” `layoutStyle`, ์ œ๋ชฉ ์œ„๊ณ„๋Š” `level`๋กœ ์ง€์ •ํ•œ๋‹ค.
94
94
 
95
95
  2026-10-07 ์ถ”๊ฐ€: ์ œ๋ชฉ์€ ํ”„๋กœํ•„์˜ optional `tokens.fontFamily.display`๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ƒ๋žต ์‹œ ํ˜„์žฌ ui๋ฅผ ๋”ฐ๋ฅธ๋‹ค.
96
- ๋ฌธ์„œ semanticLevelยทํฌ๊ธฐยท๊ตต๊ธฐ๋Š” ์œ ์ง€ํ•œ๋‹ค. [์„œ์ฒด ์—ญํ• ](../tokens/font-roles.md), 1.15.0 ์ดํ›„ ๋ฏธ๊ฒŒ์‹œ.
96
+ ๋ฌธ์„œ semanticLevelยทํฌ๊ธฐยท๊ตต๊ธฐ๋Š” ์œ ์ง€ํ•œ๋‹ค. [์„œ์ฒด ์—ญํ• ](../tokens/font-roles.md), 1.16.0 ๋ณ€๊ฒฝ.
@@ -80,7 +80,7 @@ import { NotificationBell } from "@hjmds/react-native/notification-bell";
80
80
  | `onPress`(NotificationBell) | `() => void` | ํ•„์ˆ˜ | WebยทNative ๋ชจ๋‘ `onPress`๋‹ค(Web๋„ `onClick`์ด ์•„๋‹ˆ๋‹ค) |
81
81
  | `active`(NotificationBell) | `true` ยท `false` | `true` | โ€” |
82
82
  | `disabled`(NotificationBell) | `true` ยท `false` | `false` | โ€” |
83
- | Web `layoutStyle`(NotificationBell) | `HjmCompositionStyleProp` | โ€” | ๋ฃจํŠธ ๋ฐฐ์น˜. ๊ธฐ๋ณธ `alignSelf: "flex-start"`๋ณด๋‹ค ์šฐ์„ ํ•˜์ง€๋งŒ `width`๋Š” ๋ฌด์‹œ๋œ๋‹ค(๋ฃจํŠธ๋Š” ํ•ญ์ƒ `max-content`). ๋–  ์žˆ๋Š” ๋ฐฐ์ง€๊ฐ€ ๋ฃจํŠธ์˜ ๋ ๋ชจ์„œ๋ฆฌ์— ๋ถ™์–ด ์žˆ์–ด ๋ฃจํŠธ๊ฐ€ ๋„“์–ด์ง€๋ฉด ์•„์ด์ฝ˜์—์„œ ๋–จ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. marginยท`alignSelf`๋กœ ๋ฐฐ์น˜ํ•œ๋‹ค. ๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„) |
83
+ | Web `layoutStyle`(NotificationBell) | `HjmCompositionStyleProp` | โ€” | ๋ฃจํŠธ ๋ฐฐ์น˜. ๊ธฐ๋ณธ `alignSelf: "flex-start"`๋ณด๋‹ค ์šฐ์„ ํ•˜์ง€๋งŒ `width`๋Š” ๋ฌด์‹œ๋œ๋‹ค(๋ฃจํŠธ๋Š” ํ•ญ์ƒ `max-content`). ๋–  ์žˆ๋Š” ๋ฐฐ์ง€๊ฐ€ ๋ฃจํŠธ์˜ ๋ ๋ชจ์„œ๋ฆฌ์— ๋ถ™์–ด ์žˆ์–ด ๋ฃจํŠธ๊ฐ€ ๋„“์–ด์ง€๋ฉด ์•„์ด์ฝ˜์—์„œ ๋–จ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. marginยท`alignSelf`๋กœ ๋ฐฐ์น˜ํ•œ๋‹ค. 1.13.0 ๋ณ€๊ฒฝ |
84
84
 
85
85
  ## ๋ฐฐ์น˜
86
86
 
@@ -117,13 +117,13 @@ TopBar
117
117
  | ์Šคํ”ผ๋„ˆ ๊ต์ฒด | ์—†์Œ | `renderLoadingIndicator` |
118
118
  | ๋น„ํ™œ์„ฑ์ด์ง€๋งŒ ํฌ์ปค์Šค ์œ ์ง€ | `aria-disabled` | `loading` ๊ธฐ๋ณธ ๋™์ž‘ |
119
119
  | NotificationBell ํ”๋“ค๋ฆผ ์ •์ง€ | ๋ฌธ์„œ ์ˆจ๊น€ยทreduced motion | AppState ๋น„ํ™œ์„ฑยทreduced motion |
120
- | ๋ฐฐ์น˜ | `layoutStyle`(IconButtonยทNotificationBell, NotificationBell์€ `width` ๋ฌด์‹œ) | IconButton `layoutStyle`. `style`์€ deprecated(๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle` ๋˜๋Š” `tone`ยท`size`ยท`shape`. NotificationBell์€ ๋ฐฐ์น˜ prop์ด ์—†์–ด ๊ฐ์‹ธ๋Š” View๋กœ ๋ฐฐ์น˜ํ•œ๋‹ค |
120
+ | ๋ฐฐ์น˜ | `layoutStyle`(IconButtonยทNotificationBell, NotificationBell์€ `width` ๋ฌด์‹œ) | IconButton `layoutStyle`. `style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle` ๋˜๋Š” `tone`ยท`size`ยท`shape`. NotificationBell์€ ๋ฐฐ์น˜ prop์ด ์—†์–ด ๊ฐ์‹ธ๋Š” View๋กœ ๋ฐฐ์น˜ํ•œ๋‹ค |
121
121
 
122
122
  ## ํ•จ์ •
123
123
 
124
124
  - children์˜ ์ƒ‰์€ ๋ฒ„ํŠผ์ด ์น ํ•˜์ง€ ์•Š๋Š”๋‹ค. HJM Icon์€ ์ž๊ธฐ `tone` ์ƒ‰์„ ์“ฐ๋ฏ€๋กœ, `primary`ยท`danger` ๋ฒ„ํŠผ ์•ˆ์—์„œ๋Š”
125
125
  `tone="inverse"`๋ฅผ ์ค€๋‹ค. ๋‹ค๋ฅธ ์•„์ด์ฝ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง์ ‘ ๋„ฃ์œผ๋ฉด(Native) ์ƒ‰์„ ์ œํ’ˆ์ด ๋„˜๊ฒจ์•ผ ํ•œ๋‹ค.
126
- - Native `IconButton` `style`์€ deprecated์ง€๋งŒ ๋‹ค์Œ major ์ „๊นŒ์ง€ recipe ๋’ค์— ํ•ฉ์ณ์ ธ ์ง€๋ฆ„ยท๋ฐฐ๊ฒฝ๊นŒ์ง€ ๋ฐ”๋€๋‹ค. ์ƒˆ ์ฝ”๋“œ์—์„œ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
126
+ - Native `IconButton`์˜ `style`์€ ์ œ๊ฑฐ๋˜์—ˆ๋‹ค. ๋ฐฐ์น˜๋Š” `layoutStyle`, ์™ธํ˜•์€ `tone`ยท`size`ยท`shape`๋กœ ์ง€์ •ํ•œ๋‹ค.
127
127
 
128
128
  2026-10-10 ์‚ฌ์šฉ์ž ์š”์ฒญ: Button๊ณผ ๊ฐ™์€ ์„ ํƒ ํ‘œํ˜„์„ ์“ด๋‹ค. ์„ ํƒ์€ bg ๋ฐ”ํƒ•ยทcontentBrand ์•„์ด์ฝ˜์œผ๋กœ
129
129
  ํ‘œ์‹œํ•˜๊ณ  ์ถ”๊ฐ€ ์„ ํƒ ํ…Œ๋‘๋ฆฌ๋Š” ์—†๋‹ค. aria-pressed/Native selected์™€ ํ‚ค๋ณด๋“œ focus outline์€ ์œ ์ง€ํ•œ๋‹ค.
@@ -96,7 +96,7 @@ const renderGlyph = createLucideGlyph({ search: Search, back: ArrowLeft });
96
96
  | glyph | ๋‚ด์žฅ SVG ๊ฒฝ๋กœ, `renderGlyph`๋Š” ์„ ํƒ | `renderGlyph` ํ•„์ˆ˜(๋‚ด์žฅ ๊ทธ๋ฆผ ์—†์Œ) |
97
97
  | ์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฆ„ | `SemanticIconName`๋งŒ | `Icon<Name>` ์ œ๋„ค๋ฆญ์œผ๋กœ ์ œํ’ˆ ์ด๋ฆ„ ํ—ˆ์šฉ |
98
98
  | ์ถœ๋ ฅ | `<svg>`(์žฅ์‹์ด๋ฉด `aria-hidden`) | `View` ํ”„๋ ˆ์ž„(์žฅ์‹์ด๋ฉด `accessible={false}`) |
99
- | ๋ฐฐ์น˜ | `layoutStyle` | `layoutStyle`. `style`์€ deprecated(๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle` ๋˜๋Š” descriptor `size`ยท`tone` |
99
+ | ๋ฐฐ์น˜ | `layoutStyle` | `layoutStyle`. `style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle` ๋˜๋Š” descriptor `size`ยท`tone` |
100
100
 
101
101
  ## ํ•จ์ •
102
102
 
@@ -84,10 +84,11 @@ import { ImageViewer } from "@hjmds/react-native/image-viewer";
84
84
  | ImageViewer `onClose` ยท `onIndexChange` | `() => void` ยท `(index: number) => void` | `onClose` ํ•„์ˆ˜ | โ€” |
85
85
  | ImageViewer `safeAreaInsets` | `{ top: number; bottom: number; left?: number; right?: number }` | ํ•„์ˆ˜, ์ขŒ์šฐ 0 | ๋ฒ„ํŠผยทcaptionยท์ƒํƒœ ์•ˆ๋‚ด๋ฅผ ๋ฌผ๋ฆฌ์  ์ขŒ์šฐ ์•ˆ์ „ ์˜์—ญ ์•ˆ์— ๋ฐฐ์น˜. ์‚ฌ์ง„์€ ์ „์ฒด ๊ฐค๋Ÿฌ๋ฆฌ ํญ ์‚ฌ์šฉ |
86
86
  | ImageViewer `supportedOrientations` | RN Modal์˜ orientation ๋ฐฐ์—ด | RN ๊ธฐ๋ณธ๊ฐ’ | ์ œํ’ˆ manifestยท๊ธฐ๊ธฐ ํšŒ์ „ ์ž ๊ธˆ ๋ฒ”์œ„ ์•ˆ์—์„œ ํ—ˆ์šฉ. Modal์€ fullScreen |
87
- | ImageViewer `renderImage` | `(props: ImageViewerImageRenderProps) => ReactNode` | RN Image | Native ์ „์šฉ, ๋ฏธ๊ฒŒ์‹œ. `item`, ์ธก์ •๋œ `width`ยท`height`, `onReady`ยท`onError`๋ฅผ ์ „๋‹ฌ. ์ œํ’ˆ ์ด๋ฏธ์ง€ host์˜ ์บ์‹œยทํ‘œ์‹œ ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐ |
87
+ | ImageViewer `renderImage` | `(props: ImageViewerImageRenderProps) => ReactNode` | RN Image | Native ์ „์šฉ, 1.14.0 ์ถ”๊ฐ€. `item`, ์ธก์ •๋œ `width`ยท`height`, `onReady`ยท`onError`๋ฅผ ์ „๋‹ฌ. ์ œํ’ˆ ์ด๋ฏธ์ง€ host์˜ ์บ์‹œยทํ‘œ์‹œ ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐ |
88
88
  | ImageViewer `onImageStatusChange` | `({ item, status }) => void` | ์—†์Œ | `loading`ยท`ready`ยท`error`. ๋งˆ์šดํŠธ๋œ ๊ฐ ์ด๋ฏธ์ง€ ๊ธฐ์ค€์ด๋ฉฐ ๋น„์„ ํƒ ํŽ˜์ด์ง€๋„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Œ |
89
89
 
90
90
  - ์‹คํŒจํ•˜๋ฉด ์ค‘๋ฆฝ ๋ฐฐ๊ฒฝ ์œ„์— ์˜ค๋ฅ˜ ๊ธฐํ˜ธ๋ฅผ ๊ทธ๋ฆฌ๊ณ , ์ •๋ณด ์ด๋ฏธ์ง€์˜ ์ด๋ฆ„์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•œ๋‹ค. `fallback`์€ ์‹œ๊ฐ๋งŒ ๋ฐ”๊พผ๋‹ค.
91
+ - ๊ฐ™์€ ์ฃผ์†Œ๋ผ๋„ Web `imageProps.srcSet`/์š”์ฒญ ์ •์ฑ…, Native `sourceAdapter`์˜ ์‹ค์ œ sourceยทํ—ค๋”ยทcache ๋‚ด์šฉ์ด ๋ฐ”๋€Œ๋ฉด ์ƒˆ ์š”์ฒญ์œผ๋กœ ๋ณด๊ณ  loading๋ถ€ํ„ฐ ์‹œ์ž‘ํ•œ๋‹ค. inline adapter ํ•จ์ˆ˜๋งŒ ๋‹ค์‹œ ๋งŒ๋“  ๊ฒƒ์€ ์žฌ์‹œ๋„๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ฐ™์€ ์š”์ฒญ์„ ๋ช…์‹œ์ ์œผ๋กœ ์žฌ์‹œ๋„ํ•˜๊ฑฐ๋‚˜ adapter ๊ตฌํ˜„๋งŒ ๊ต์ฒดํ•˜๋ ค๋ฉด `<Image key={attempt} ... />`์ฒ˜๋Ÿผ ์š”์ฒญ ์‹œ๋„ ํ‚ค๋กœ Image ์ „์ฒด๋ฅผ ๋‹ค์‹œ ๋งˆ์šดํŠธํ•œ๋‹ค. ์‹คํŒจํ•œ ์š”์ฒญ์˜ ๋Šฆ์€ ์ฝœ๋ฐฑ์€ ์ƒˆ ์š”์ฒญ์„ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.
91
92
 
92
93
  ## ๋ฐฐ์น˜
93
94
 
@@ -107,7 +108,7 @@ Native ์ด๋ฏธ์ง€ ํ”„๋ ˆ์ž„์€ `imageRecipe.radius` ์—ญํ• ์„ Provider์˜ `tokens
107
108
  - GridReveal์˜ `ready`๋Š” `onLoadStatusChange`๊ฐ€ `loaded`์ผ ๋•Œ๋งŒ true, ์˜ค๋ฅ˜ยท์†Œ์Šค ๋ณ€๊ฒฝยท์žฌ์‹œ๋„ ์ „์—๋Š” false๋กœ ๋Œ๋ฆฐ๋‹ค.
108
109
  Native์—์„œ ํ™”๋ฉด์ด ๊ฐ€๋ ค์ง„ ์ฑ„ mounted๋ฉด `active={false}`.
109
110
  - ImageViewer๋Š” `open`์œผ๋กœ ์ œ์–ดํ•˜๊ณ  ๋‹ซํžˆ๋ฉด ์ƒํƒœ๋ฅผ ๋ฒ„๋ฆฐ๋‹ค. ๋ผ๋ฒจยท`id`๊ฐ€ ๋น„๊ฑฐ๋‚˜ ์ค‘๋ณต์ด๋ฉด `TypeError`.
110
- - ImageViewer๋Š” ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘(`loadingLabel`)๊ณผ ์‹คํŒจ(`errorLabel`)๋ฅผ ๋ชจ๋‘ ์•Œ๋ฆฐ๋‹ค. ์‹คํŒจ๋Š” Android assertive live region, iOS๋Š” `announceForAccessibility`๋‹ค(๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„). 1.12.1์€ ์‹คํŒจ๋ฅผ ์•Œ๋ฆฌ์ง€ ์•Š์•˜๋‹ค).
111
+ - ImageViewer๋Š” ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘(`loadingLabel`)๊ณผ ์‹คํŒจ(`errorLabel`)๋ฅผ ๋ชจ๋‘ ์•Œ๋ฆฐ๋‹ค. ์‹คํŒจ๋Š” Android assertive live region, iOS๋Š” `announceForAccessibility`๋‹ค(1.13.0 ๋ณ€๊ฒฝ. 1.12.1์€ ์‹คํŒจ๋ฅผ ์•Œ๋ฆฌ์ง€ ์•Š์•˜๋‹ค).
111
112
  - ์›๊ฒฉ ์ด๋ฏธ์ง€ ๊ถŒํ•œยทURL ์ˆ˜๋ช…ยท์บ์‹œ๋Š” ์ œํ’ˆ ์†Œ์œ ๋‹ค. HJM์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š”๋‹ค.
112
113
 
113
114
  ### Native ImageViewer์˜ ์ œํ’ˆ ์ด๋ฏธ์ง€ ํ˜ธ์ŠคํŠธ
@@ -140,7 +141,7 @@ import { ImageViewer } from "@hjmds/react-native/image-viewer";
140
141
  ํšŒ์ „์„ ํ—ˆ์šฉํ•˜๋Š” ์ œํ’ˆ์€ `supportedOrientations={["portrait", "landscape"]}`์™€ ๊ฐฑ์‹ ๋˜๋Š”
141
142
  safeAreaInsets ๋„ค ๋ฐฉํ–ฅ์„ ์ œ๊ณตํ•œ๋‹ค. ์•ฑ manifest๊ฐ€ portrait ๊ณ ์ •์ด๋ฉด ์ด prop๋งŒ์œผ๋กœ ํšŒ์ „์ด ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.
142
143
  ํ™”๋ฉด ํฌ๊ธฐ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ๋ฒ„ํŠผ์„ ์ œ์™ธํ•œ ๋‚จ์€ ๊ฐค๋Ÿฌ๋ฆฌ ์˜์—ญ์„ ๋‹ค์‹œ ์ธก์ •ํ•ด host์— ์ „๋‹ฌํ•œ๋‹ค.
143
- ์•„๋ž˜ inspection ํ™•์žฅ์€ ๋ฏธ๊ฒŒ์‹œ์ด๋ฉฐ, Expo ํ‘œ์‹œ ํ™•์ธยท๊ฒฐ๊ณผ ์Šน์ธ ํšŒ๊ท€์™€ Utilverse ์ฑ„ํƒ์€ ๋ณ„๋„ ๊ฒ€์ฆํ•œ๋‹ค.
144
+ ์•„๋ž˜ inspection ํ™•์žฅ์€ 1.14.0 ์ถ”๊ฐ€ API์ด๋ฉฐ, Expo ํ‘œ์‹œ ํ™•์ธยท๊ฒฐ๊ณผ ์Šน์ธ ํšŒ๊ท€์™€ Utilverse ์ฑ„ํƒ์€ ๋ณ„๋„ ๊ฒ€์ฆํ•œ๋‹ค.
144
145
 
145
146
  ### ๊ฒฐ๊ณผ ๊ฒ€์‚ฌ ํฌ๊ธฐ ๊ณ„์‚ฐ
146
147
 
@@ -157,7 +158,7 @@ const geometry = resolveImageInspectionGeometry(
157
158
  ); // width/height 804, panBounds x=201 y=175 (์ค‘์•™์—์„œ ์–‘๋ฐฉํ–ฅ)
158
159
  ```
159
160
 
160
- ### Native ๊ฒฐ๊ณผ ๊ฒ€์‚ฌ ๋ณด๊ธฐ (๋ฏธ๊ฒŒ์‹œ)
161
+ ### Native ๊ฒฐ๊ณผ ๊ฒ€์‚ฌ ๋ณด๊ธฐ (1.14.0 ์ถ”๊ฐ€)
161
162
 
162
163
  `ImageViewer`์˜ ์„ ํƒ์  `inspection`์€ ์œ„ ๊ณ„์‚ฐ์„ ์‚ฌ์šฉํ•œ๋‹ค. ๋ชจ๋“  `items`์— ์‹ค์ œ ์ถœ๋ ฅ์˜
163
164
  ์–‘์ˆ˜ `width`ยท`height`๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ผ๋ฐ˜ Gallery์˜ pinch/paging๊ณผ ๋ณ„๊ฐœ๋กœ ๊ณ ์ • ๋ฐฐ์œจ์˜ ๊ฒฐ๊ณผ๋ฅผ
@@ -65,7 +65,7 @@ const keyboardOpen = useKeyboardState((state) => state.isVisible);
65
65
  | `enabled` | `true` ยท `false` | `true` | `false`๋ฉด ๋”ฐ๋ผ ์›€์ง์ด์ง€ ์•Š๋Š”๋‹ค |
66
66
  | `clearance` | 0 ์ด์ƒ ์ˆซ์ž(layout point) | `0` | ํ‚ค๋ณด๋“œ ์œ„ ์ถ”๊ฐ€ ๊ฐ„๊ฒฉ. ์Œ์ˆ˜๋‚˜ ์œ ํ•œํ•˜์ง€ ์•Š์€ ๊ฐ’์€ `TypeError` |
67
67
  | `children` | ReactNode(ํ•„์ˆ˜) | โ€” | ํ•˜๋‹จ ํ–‰๋™. ์•ˆ์ชฝ ์—ฌ๋ฐฑยท์•ˆ์ „ ์˜์—ญ์€ ํ˜ธ์ŠคํŠธ๊ฐ€ ์ค€๋‹ค |
68
- | `style` | `StyleProp<ViewStyle>` | โ€” | ๊ฐ์‹ธ๋Š” sticky view์˜ host ์Šคํƒ€์ผ. ํ”Œ๋žซํผ host๋ผ 1.13 deprecated ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค([์ด๊ด€ ๋ฌธ์„œ](../../migration-native-legacy-removal.md#113-deprecated-์‹œ๊ฐ-style-์ œ๊ฑฐ๋Š”-๋‹ค์Œ-major)). ๋ฐฐ์น˜ ๊ฐ’๋งŒ ๋„ฃ๋Š”๋‹ค |
68
+ | `style` | `StyleProp<ViewStyle>` | โ€” | ๊ฐ์‹ธ๋Š” sticky view์˜ host ์Šคํƒ€์ผ. ํ”Œ๋žซํผ host๋ผ 1.13 deprecated ๋Œ€์ƒ์ด ์•„๋‹ˆ๋‹ค([์ด๊ด€ ๋ฌธ์„œ](../../migration-native-legacy-removal.md#2026-10-13-์ž”์—ฌ-์‹œ๊ฐ-style-์ œ๊ฑฐ)). ๋ฐฐ์น˜ ๊ฐ’๋งŒ ๋„ฃ๋Š”๋‹ค |
69
69
 
70
70
  - ์ด๋ฒคํŠธยท์ฝœ๋ฐฑ prop์€ ์—†๋‹ค. ํ‚ค๋ณด๋“œ ์—ด๋ฆผ ์—ฌ๋ถ€๊ฐ€ ํ•„์š”ํ•˜๋ฉด peer์˜ `useKeyboardState((state) => state.isVisible)`๋กœ ์ฝ๋Š”๋‹ค.
71
71
  - ๋‚ด๋ถ€์—์„œ `KeyboardStickyView`์— `offset={{ closed: 0, opened: -clearance }}`๋ฅผ ๋„˜๊ธด๋‹ค.
@@ -113,5 +113,5 @@ Web (persistent sidebar) Native
113
113
 
114
114
  ## ํ•จ์ •
115
115
 
116
- - [๊ณ„์•ฝ ๋ฌธ์„œ](../../layout.md)๋Š” Native `skipLinkLabel`์ด deprecated๋กœ ๋‚จ์•„ ์žˆ๋‹ค๊ณ  ์ ์ง€๋งŒ 1.12.1 Native `LayoutProps`์—๋Š” ์—†๋‹ค.
116
+ - `skipLinkLabel`์€ Web ์ „์šฉ์ด๋‹ค. Native `LayoutProps`์—๋Š” ์—†์œผ๋ฏ€๋กœ ํ”Œ๋žซํผ ๊ณตํ†ต props์— ๋„ฃ์ง€ ์•Š๋Š”๋‹ค.
117
117
  - Native persistent ์‚ฌ์ด๋“œ๋ฐ”๋Š” ์˜†์œผ๋กœ ๋†“์ด์ง€ ์•Š๊ณ  ์„ธ๋กœ๋กœ ์Œ“์ธ๋‹ค. ๋„“์€ ํ™”๋ฉด 2๋‹จ ๋ฐฐ์น˜๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์ œํ’ˆ์ด main ์•ˆ์—์„œ ๊ตฌ์„ฑํ•œ๋‹ค.
@@ -79,7 +79,7 @@ const renderGlyph = createLucideGlyph({ chevronEnd: ChevronRight }); // ์ œํ’ˆ
79
79
  | `renderIcon`(Native) | `(props: { name, size, color, strokeWidth }) => ReactNode` | โ€” | semantic name โ†’ glyph ๊ฒฝ๊ณ„. ๋ณดํ†ต `createLucideGlyph`. ํฌ๊ธฐยท์ƒ‰์€ HJM์ด ๋„˜๊ธด ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค |
80
80
  | `renderAnchor`(Web) | `(props: LinkRenderProps) => ReactElement` | โ€” | ๋ฐ›์€ props(`href`ยท`ref`ยท`className`ยท`data-*`ยท`aria-disabled`ยท`onClick`ยท`children`ยท๋ณ‘ํ•ฉ๋œ `style`)๋ฅผ framework Link์— ๊ทธ๋Œ€๋กœ ๋„˜๊ธด๋‹ค |
81
81
  | `layoutStyle` | ๋ฐฐ์น˜ key๋งŒ | โ€” | ์–‘์ชฝ ์žˆ์Œ. Web์€ `renderAnchor`์—๋„ ๋ณ‘ํ•ฉ๋œ `style`๋กœ ์ „๋‹ฌ๋œ๋‹ค |
82
- | `style`(Native) | โ€” | โ€” | **deprecated**(1.13, ๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle`์„ ์“ด๋‹ค |
82
+ | `style`(Native) | โ€” | โ€” | ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle`์„ ์“ด๋‹ค |
83
83
 
84
84
  - Native๋Š” toneยทvariant๊ฐ€ ์—†๋‹ค. ํ•ญ์ƒ brand ์ƒ‰ ยท ๋ฐ‘์ค„ ยท `bodyLarge` ๊ธ€์ž ยท ์ตœ์†Œ ํ„ฐ์น˜ target์ด๋‹ค.
85
85
 
@@ -118,6 +118,6 @@ const renderGlyph = createLucideGlyph({ chevronEnd: ChevronRight }); // ์ œํ’ˆ
118
118
  - Native์—์„œ descriptor ์•„์ด์ฝ˜์„ ์ฃผ๊ณ  `renderIcon`์„ ๋นผ๋ฉด ๊ฐœ๋ฐœ ๋ชจ๋“œ์—์„œ ํ•œ ๋ฒˆ ๊ฒฝ๊ณ ํ•˜๊ณ  ์•„์ด์ฝ˜์„ ๊ทธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค(throwํ•˜์ง€ ์•Š์Œ).
119
119
  descriptor ์•„์ด์ฝ˜๊ณผ `leading`/`trailing` node๋ฅผ ํ•จ๊ป˜ ์ฃผ๋ฉด descriptor๊ฐ€ ๊ทธ ์ž๋ฆฌ๋ฅผ ๊ฐ–๊ณ  ๊ฒฝ๊ณ ๊ฐ€ ๋‚œ๋‹ค. 1.12๊นŒ์ง€๋Š” Native๊ฐ€
120
120
  descriptor ์•„์ด์ฝ˜์„ ๊ทธ๋ฆฌ์ง€ ์•Š์•˜๋‹ค.
121
- - Native `style`์€ deprecated๋‹ค. ์•„์ง recipe ๋’ค์— ํ•ฉ์ณ์ ธ ์‹œ๊ฐ ๊ฐ’์ด ํ†ต๊ณผํ•˜๋ฏ€๋กœ ๋ฐฐ์น˜๋Š” `layoutStyle`๋กœ๋งŒ ์ค€๋‹ค.
121
+ - Native `style`์€ ์ œ๊ฑฐ๋˜์—ˆ๋‹ค. ๋ฐฐ์น˜๋Š” `layoutStyle`๋กœ ์ง€์ •ํ•˜๊ณ  brand ์ƒ‰ยท๋ฐ‘์ค„ยท๊ธ€์ž ํฌ๊ธฐ๋Š” `linkRecipe`๋ฅผ ๋”ฐ๋ฅธ๋‹ค. Native์—๋Š” `tone`ยท`size` prop์ด ์—†๋‹ค.
122
122
  - ํ˜„์žฌ Native ์Šคํ† ๋ฆฌ(`showcase/native/src/component-examples.tsx` LinkExample)๋Š” descriptor ์•„์ด์ฝ˜ยท`renderIcon` ์˜ˆ๊ฐ€ ์—†๊ณ 
123
123
  ๋ฌธ๊ตฌ๊ฐ€ i18n ํ‚ค๊ฐ€ ์•„๋‹ˆ๋‹ค. ์•„์ด์ฝ˜ ๊ฒฝ๋กœ๋Š” ์œ„ ์ตœ์†Œ ์‚ฌ์šฉ ์˜ˆ๋กœ ํ™•์ธํ•œ๋‹ค.
@@ -3,8 +3,8 @@
3
3
  - ๋‹จ๊ณ„: ์ปดํฌ๋„ŒํŠธ
4
4
  - ์ƒํƒœ: ๋ฐฐํฌ
5
5
  - ์ง€์›: Web ยท Native
6
- - ์ ์šฉ: ๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„)
7
- - ๊ฒ€ํ† ์ผ: 2026-10-06
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
 
@@ -64,11 +64,11 @@ import { ListDetailScreen } from "@hjmds/react-native/screen-flows";
64
64
  | prop | ๊ฐ’ | ๊ธฐ๋ณธ๊ฐ’ | ์„ค๋ช… |
65
65
  | --- | --- | --- | --- |
66
66
  | `list` | `ReactNode` | ํ•„์ˆ˜ | ๋ชฉ๋ก pane ๋ณธ๋ฌธ. ์ƒ์„ธ๊ฐ€ ์—ด๋ ค๋„ mount๋ฅผ ์œ ์ง€ํ•œ๋‹ค |
67
- | `detail` | `{ title: string; content: ReactNode }` | ์—†์Œ | ์žˆ์œผ๋ฉด ์ƒ์„ธ pane์„ ๋ณด์ด๊ณ  ๋ชฉ๋ก pane์„ ์ˆจ๊ธด๋‹ค. ๋‹ซํžŒ ์ƒํƒœ๋Š” prop์„ ๋นผ์„œ ํ‘œํ˜„ํ•œ๋‹ค(`undefined`๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค) |
67
+ | `detail` | `{ title; content; state?; stateAction?; notice? }` | ์—†์Œ | ์žˆ์œผ๋ฉด ์ƒ์„ธ pane์„ ๋ณด์ด๊ณ  ๋ชฉ๋ก pane์„ ์ˆจ๊ธด๋‹ค. ๋‹ซํžŒ ์ƒํƒœ๋Š” prop์„ ๋นผ์„œ ํ‘œํ˜„ํ•œ๋‹ค(`undefined`๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š๋Š”๋‹ค) |
68
68
  | `back` | `ScreenFlowAction`(`{ label, onAction(), disabled?, pending? }`) | ํ•„์ˆ˜ | ์ƒ์„ธ pane `leading` ์ž๋ฆฌ์˜ ghost ๋ฒ„ํŠผ |
69
69
  | `refresh` | `ScreenFlowAction` | ์—†์Œ | ๋ชฉ๋ก pane `actions` ์ž๋ฆฌ์˜ ghost ๋ฒ„ํŠผ. ์ฃผ๋ฉด `actions`๋ฅผ ๋ฎ๋Š”๋‹ค |
70
70
  | `loadMore` | `ScreenFlowAction` | ์—†์Œ | ๋ชฉ๋ก pane footer์˜ ghost ๋ฒ„ํŠผ |
71
- | `layoutStyle` | `HjmCompositionStyleProp` | ์—†์Œ | WebยทNative ๋ชจ๋‘ ๋ชฉ๋กยท์ƒ์„ธ pane์„ ํ•จ๊ป˜ ๋‹ด๋Š” **๋ฐ”๊นฅ ํ‹€**์— ์ ์šฉํ•œ๋‹ค(์•ˆ์ชฝ ๋ชฉ๋ก ScreenLayout์ด ์•„๋‹ˆ๋‹ค). ๋ชฉ๋ก/์ƒ์„ธ ์ „ํ™˜๊ณผ ์ƒ๊ด€์—†์ด ๊ฐ™์€ ๋ฃจํŠธ์— ๋‚จ๋Š”๋‹ค. ๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„) |
71
+ | `layoutStyle` | `HjmCompositionStyleProp` | ์—†์Œ | WebยทNative ๋ชจ๋‘ ๋ชฉ๋กยท์ƒ์„ธ pane์„ ํ•จ๊ป˜ ๋‹ด๋Š” **๋ฐ”๊นฅ ํ‹€**์— ์ ์šฉํ•œ๋‹ค(์•ˆ์ชฝ ๋ชฉ๋ก ScreenLayout์ด ์•„๋‹ˆ๋‹ค). ๋ชฉ๋ก/์ƒ์„ธ ์ „ํ™˜๊ณผ ์ƒ๊ด€์—†์ด ๊ฐ™์€ ๋ฃจํŠธ์— ๋‚จ๋Š”๋‹ค(1.13.0) |
72
72
  | ๋‚˜๋จธ์ง€ | `ScreenLayout`๊ณผ ๊ฐ™์Œ(`children`ยท`footer` ์ œ์™ธ) | โ€” | ๋ชฉ๋ก pane์—๋งŒ ์ ์šฉ๋œ๋‹ค(`title` ํ•„์ˆ˜, `state`, `scroll` ๋“ฑ) |
73
73
 
74
74
  ## ๋ฐฐ์น˜
@@ -84,7 +84,7 @@ import { ListDetailScreen } from "@hjmds/react-native/screen-flows";
84
84
  ## ๊ผญ ์ง€ํ‚ฌ ๊ฒƒ
85
85
 
86
86
  - ๋ผ๋ฒจ์€ ๋ชจ๋‘ i18n ํ‚ค๋กœ ๋„ฃ๋Š”๋‹ค.
87
- - `state`(๋กœ๋”ฉยท๋นˆยท์˜ค๋ฅ˜ยท์ œํ•œ)๋Š” ๋ชฉ๋ก pane์—๋งŒ ์ ์šฉ๋œ๋‹ค. ์ƒ์„ธ์˜ ๋กœ๋”ฉยท์˜ค๋ฅ˜๋Š” `detail.content` ์•ˆ์—์„œ ํ‘œ์‹œํ•œ๋‹ค.
87
+ - `state`(๋กœ๋”ฉยท๋นˆยท์˜ค๋ฅ˜ยท์ œํ•œ)๋Š” ๋ชฉ๋ก pane์—๋งŒ ์ ์šฉ๋œ๋‹ค. ์ƒ์„ธ ์ตœ์ดˆ ์กฐํšŒยท์˜ค๋ฅ˜๋Š” `detail.state`, ์žฌ์‹œ๋„๋Š” `detail.stateAction`, ๊ธฐ์กด ์ƒ์„ธ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฐฑ์‹  ์‹คํŒจ๋Š” `detail.notice`๋กœ ์ „๋‹ฌํ•œ๋‹ค. ๋ฏธ๊ฒŒ์‹œ(1.18.0 ์ดํ›„)์— ์ถ”๊ฐ€๋œ ์„ ํƒ prop์ด๋ฉฐ ์ด์ „ ์„ค์น˜ ๋ฒ„์ „์—์„œ๋Š” ์ƒ์„ธ content ์•ˆ์— ์ƒํƒœ๋ฅผ ๊ตฌ์„ฑํ•œ๋‹ค.
88
88
  - Web์€ ์ƒ์„ธ ์ง„์ž… ์‹œ ๋’ค๋กœ ๋ฒ„ํŠผ์— ํฌ์ปค์Šค๋ฅผ ์˜ฎ๊ธฐ๊ณ  ๋ณต๊ท€ ์‹œ ๋ชฉ๋ก์˜ ์›๋ž˜ ์š”์†Œ๋กœ ๋Œ๋ฆฐ๋‹ค. ์š”์†Œ๊ฐ€ ์‚ญ์ œ๋˜์—ˆ์œผ๋ฉด ๋ชฉ๋ก ๋ณธ๋ฌธ์œผ๋กœ ์ด๋™ํ•œ๋‹ค.
89
89
  ์ฒ˜์Œ๋ถ€ํ„ฐ `detail`์ด ์žˆ๋Š” ์ฑ„๋กœ mount๋˜๋ฉด(๋”ฅ๋งํฌ) ์‚ฌ์šฉ์ž ์ „ํ™˜์ด ์•„๋‹ˆ๋ฏ€๋กœ ํฌ์ปค์Šค๋ฅผ ์˜ฎ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋•Œ ํฌ์ปค์Šค๋Š” ์ œํ’ˆ router๊ฐ€ ์ •ํ•œ๋‹ค.
90
90
  - ์ƒ์„ธ ์—ด๋ฆผ ์ƒํƒœ๋Š” ์ œํ’ˆ์ด ๊ฐ€์ง„๋‹ค. OS ๋’ค๋กœ๊ฐ€๊ธฐยท๋ธŒ๋ผ์šฐ์ € ๋’ค๋กœ๊ฐ€๊ธฐ์™€ `back`์„ ์ œํ’ˆ router์—์„œ ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•œ๋‹ค.
@@ -99,5 +99,5 @@ import { ListDetailScreen } from "@hjmds/react-native/screen-flows";
99
99
  ## ํ•จ์ •
100
100
 
101
101
  - `refresh`๋ฅผ ์ฃผ๋ฉด ScreenLayout `actions`๋Š” ๋ฌด์‹œ๋œ๋‹ค. ๋‘˜ ๋‹ค ํ•„์š”ํ•˜๋ฉด `refresh` ๋Œ€์‹  `actions`์— ์ง์ ‘ ์กฐํ•ฉํ•œ๋‹ค.
102
- - ์ƒ์„ธ pane์€ `title`๊ณผ `back`(leading)๋งŒ ๋ฐ›๋Š”๋‹ค. ์ƒ์„ธ ์ชฝ `description`ยท`actions`ยทfooter ์ž๋ฆฌ๋Š” ์—†๋‹ค.
102
+ - ์ƒ์„ธ pane์€ `title`ยท`state`ยท`stateAction`ยท`notice`์™€ `back`(leading)์„ ๋ฐ›๋Š”๋‹ค. ์ƒ์„ธ ์ชฝ `description`ยท`actions`ยทfooter ์ž๋ฆฌ๋Š” ์—†๋‹ค.
103
103
  - `loadMore`๋Š” ์ƒํƒœ ์—†๋Š” ๋ฒ„ํŠผ์ด๋‹ค. ๋ยท์˜ค๋ฅ˜ยท์ค‘๋ณต ์š”์ฒญ ๋ฐฉ์ง€๊ฐ€ ํ•„์š”ํ•˜๋ฉด LoadMore๋ฅผ ์“ด๋‹ค.
@@ -54,6 +54,8 @@ import { Avatar, ListRow } from "@hjmds/react-native/data-display";
54
54
  <ListRow title={member.name} description={member.role}
55
55
  leading={<Avatar name={member.name} decorative />} leadingShape="circle"
56
56
  trailingText={t("member.joined", { date })} onPress={() => openMember(member.id)} />
57
+
58
+ <ListRow title={t("account.delete")} tone="danger" onPress={openDeleteConfirmation} />
57
59
  ```
58
60
 
59
61
  ## ์ถ•๊ณผ ๊ธฐ๋ณธ๊ฐ’
@@ -62,15 +64,16 @@ import { Avatar, ListRow } from "@hjmds/react-native/data-display";
62
64
  | --- | --- | --- | --- |
63
65
  | `density` | `compact` ยท `comfortable` ยท `relaxed` ยท `spacious` | `comfortable` | ์ตœ์†Œ ๋†’์ด๋Š” ์„ค๋ช… ์œ ๋ฌด(ํ•œ ์ค„ยท๋‘ ์ค„)์™€ ํ•จ๊ป˜ ์ •ํ•ด์ง„๋‹ค |
64
66
  | `leadingShape` | `square` ยท `circle` | `square` | leading ํ”„๋ ˆ์ž„ ํฌ๊ธฐ๋Š” recipe๊ฐ€ ๊ทธ๋ฆฐ๋‹ค |
67
+ | `tone` | `default` ยท `danger` | `default` | ํƒˆํ‡ด ๊ฐ™์€ ํŒŒ๊ดด์  ๋ชฉ์ ์ง€ ์ œ๋ชฉ์€ `danger`๋กœ ๊ฐ•์กฐํ•œ๋‹ค. ์„ ํƒยท์ž ๊ธˆยท๋ฐ€๋„์™€ ๋…๋ฆฝ์ ์ด๋‹ค |
65
68
  | `selected` | `true` ยท `false` | `false` | โ€” |
66
69
  | `disabled` | `true` ยท `false` | `false` | โ€” |
67
70
  | `href`(Web) | ๋ฌธ์ž์—ด | โ€” | ์žˆ์œผ๋ฉด `<a>` ํ–‰ |
68
71
  | `onClick`(Web) | `(event: MouseEvent<HTMLElement>) => void` | โ€” | ์žˆ์œผ๋ฉด `<button>` ํ–‰ |
69
72
  | `onPress`(Native) | `(event: GestureResponderEvent) => void` | โ€” | ์žˆ์œผ๋ฉด ๋ˆ„๋ฅผ ์ˆ˜ ์žˆ๋Š” ํ–‰ |
70
- | `loading`ยท`loadingLabel`(Web) | `boolean` ยท ํ˜„์ง€ํ™” ๋ฌธ์ž์—ด | `false` ยท โ€” | ๊ฐ™์€ ์Šฌ๋กฏ ๋ชจ์–‘์˜ ์ž๋ฆฌํ‘œ์‹œ ํ–‰. `loadingLabel`์ด ์ƒํƒœ๋กœ ์ฝํžŒ๋‹ค |
73
+ | `loading`ยท`loadingLabel` | `boolean` ยท ํ˜„์ง€ํ™” ๋ฌธ์ž์—ด | `false` ยท โ€” | ๊ฐ™์€ ์Šฌ๋กฏ ๋ชจ์–‘์˜ ์ž๋ฆฌํ‘œ์‹œ ํ–‰. `loadingLabel`์ด ์ƒํƒœ๋กœ ์ฝํžŒ๋‹ค |
71
74
  | `trailingAction`(Native) | ReactNode | โ€” | ํ–‰ ๋ช…๋ น ์˜†์— ๋”ฐ๋กœ ๊ทธ๋ฆฌ๋Š” ๋ณ„๋„ target(IconButton ๋“ฑ). ์ž๊ธฐ `onPress`๋ฅผ ๊ฐ€์ง„๋‹ค |
72
75
  | `layoutStyle` | ๋ฐฐ์น˜ key๋งŒ | โ€” | ํ–‰ ๋ฃจํŠธ ๋ฐฐ์น˜. Native๋Š” ์Šฌ๋กฏ ๋ฐฐ์น˜์šฉ `leadingStyle`ยท`contentStyle`ยท`titleRowStyle`ยท`trailingStyle`ยท`trailingActionStyle`(๋ชจ๋‘ ๋ฐฐ์น˜ key๋งŒ)๋„ ๋ฐ›๋Š”๋‹ค |
73
- | `titleStyle`ยท`descriptionStyle`(Native) | โ€” | โ€” | **deprecated**(1.13, ๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `density`ยท`selected`, ๊ธ€์ž๋Š” listRowRecipe๊ฐ€ ์ •ํ•œ๋‹ค |
76
+ | `titleStyle`ยท`descriptionStyle`(Native) | โ€” | โ€” | ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” ๋ฐฐ์น˜๋Š” `layoutStyle`, ์ œ๋ชฉ์˜ ์œ„ํ—˜์ƒ‰์€ `tone="danger"`, ๊ธ€์ž๋Š” listRowRecipe๊ฐ€ ์ •ํ•œ๋‹ค |
74
77
 
75
78
  - ์ƒํ˜ธ์ž‘์šฉ: Web์€ `href`๋ฉด `<a>`(selected๋Š” `aria-current="page"`), `onClick`์ด๋ฉด `<button>`(selected๋Š” `aria-pressed`),
76
79
  ๋‘˜ ๋‹ค ์—†์œผ๋ฉด `<div>`. Native๋Š” `onPress`๊ฐ€ ์žˆ์œผ๋ฉด ๋ˆ„๋ฅผ ์ˆ˜ ์žˆ๋Š” ํ–‰์ด ๋œ๋‹ค.
@@ -116,7 +119,7 @@ Native ์›ํ˜• leading์˜ `full`์€ Provider token์—์„œ ์ฝ์ง€๋งŒ ๊ณ ์ • ์›ํ˜•
116
119
  | ํ•ญ๋ชฉ | Web | Native |
117
120
  | --- | --- | --- |
118
121
  | ์ œ๋ชฉยท์„ค๋ช… ํƒ€์ž… | `ReactNode` | `string` |
119
- | ์ž๋ฆฌํ‘œ์‹œ ํ–‰ | `loading` + `loadingLabel` | โ€” |
122
+ | ์ž๋ฆฌํ‘œ์‹œ ํ–‰ | `loading` + `loadingLabel` | `loading` + `loadingLabel` |
120
123
  | ๋งํฌ ํ–‰ | `href` | ์—†์Œ(`onPress`์—์„œ router ํ˜ธ์ถœ) |
121
124
  | ์ œ๋ชฉ ์˜† ๋ฉ”ํƒ€ยท๋ณ„๋„ ๋’ค ํ–‰๋™ยท๋’ค ๋ฌธ๊ตฌ | โ€” | `titleMetadata`, `trailingAction`, `trailingText` |
122
125
  | ์ ‘๊ทผ์„ฑ ์ด๋ฆ„ ์กฐํ•ฉ | ์š”์†Œ ๋‚ด์šฉ | `accessibilityLabel` ์—†์œผ๋ฉด ์ œ๋ชฉยท`metadataLabel`ยท์„ค๋ช…ยท`trailingLabel`์„ ์ด์–ด ๋ถ™์ž„ |
@@ -125,4 +128,10 @@ Native ์›ํ˜• leading์˜ `full`์€ Provider token์—์„œ ์ฝ์ง€๋งŒ ๊ณ ์ • ์›ํ˜•
125
128
  ## ํ•จ์ •
126
129
 
127
130
  - Web ๋กœ๋”ฉ ํ–‰์€ ์Šฌ๋กฏ์˜ **์กด์žฌ**๋กœ ๋ชจ์–‘์„ ์ •ํ•˜๊ณ  ๋ฌธ๊ตฌ๋Š” ๋ฌด์‹œํ•œ๋‹ค. ์‹ค์ œ ํ–‰๊ณผ ๊ฐ™์€ ์Šฌ๋กฏ์„ ๋„˜๊ฒจ์•ผ ๋†’์ด๊ฐ€ ๋งž๋Š”๋‹ค.
128
- - Native `titleStyle`ยท`descriptionStyle`์€ deprecated์ง€๋งŒ ์•„์ง TextStyle ์ „์ฒด๋ฅผ ๋ฐ›์•„ ์ƒ‰ยท๊ตต๊ธฐ๋„ ๋ฐ”๋€๋‹ค. ์ƒˆ ์ฝ”๋“œ์—์„œ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.
131
+ - Native `titleStyle`ยท`descriptionStyle`์€ ์ œ๊ฑฐ๋˜์—ˆ๋‹ค. ํŒŒ๊ดด์  ๋ชฉ์ ์ง€์˜ ์ œ๋ชฉ ๊ฐ•์กฐ์—๋Š” ์–‘ ํ”Œ๋žซํผ ๊ณตํ†ต `tone="danger"`๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. `tone`์€ ํ™•์ธ ์ ˆ์ฐจ๋‚˜ ์‚ญ์ œ ์‹คํ–‰์„ ๋Œ€์‹ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
132
+
133
+
134
+ ๋กœ๋”ฉ ํ–‰์€ ์‹ค์ œ ListRow์˜ densityยทํ•œ ์ค„/๋‘ ์ค„ ์ตœ์†Œ ๋†’์ด์™€ padding์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋‘ ์ค„ ๊ฒฐ๊ณผ๋ฅผ
135
+ ์˜ˆ์ƒํ•˜๋ฉด `description`์„ ์ œ๊ณตํ•œ๋‹ค(์ž๋ฆฌํ‘œ์‹œ ์ค‘ ๋ฌธ๊ตฌ ์ž์ฒด๋Š” ํ‘œ์‹œํ•˜์ง€ ์•Š๋Š”๋‹ค). loading ๋™์•ˆ ํ–‰๊ณผ
136
+ trailingAction์€ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ์‹ค์ œ ์Šฌ๋กฏ ๋‚ด์šฉ๋„ ๋งˆ์šดํŠธํ•˜์ง€ ์•Š๋Š”๋‹ค. ์—ฌ๋Ÿฌ ๋กœ๋”ฉ ํ–‰ ์ค‘ ์ฒซ ํ–‰์—๋งŒ
137
+ `loadingLabel`์„ ์ฃผ๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ ‘๊ทผ์„ฑ ํŠธ๋ฆฌ์—์„œ ์ˆจ๊ธด๋‹ค. ๊ฒ€์ƒ‰ ํ™”๋ฉด๋„ ์ž„์˜ Skeleton ์กฐ๋ฆฝ ๋Œ€์‹  ์ด ๊ณ„์•ฝ์„ ์“ด๋‹ค.
@@ -19,7 +19,7 @@
19
19
  | ํ™”๋ฉด ํ˜•ํƒœ | ์“ธ ๊ฒƒ |
20
20
  | --- | --- |
21
21
  | ์ˆ˜์‹ญ ๊ฐœ ์ดํ•˜์˜ ํ–‰์„ ํ•œ ๋ฒˆ์— ๊ทธ๋ฆผ(์„ค์ •, ๊ณ„์ • ๋ฉ”๋‰ด, ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ•œ ํŽ˜์ด์ง€) | `List` + `ListRow` |
22
- | ์œ ํ•œ ์นด๋“œ ์—ฌ๋Ÿฌ ์žฅ์˜ ๋…๋ฆฝ ์ž…๋ ฅ/ํ–‰๋™์„ ํ•จ๊ป˜ ๋ณด์—ฌ์ฃผ๋Š” ๊ฐ€๋กœ ํƒ์ƒ‰ | `CollectionRail` (๋ฏธ๊ฒŒ์‹œ ์‹คํ—˜, ์•„๋ž˜ ๊ฐ€๋กœ ๋ฐฐ์น˜ ์ง€์นจ) |
22
+ | ์œ ํ•œ ์นด๋“œ ์—ฌ๋Ÿฌ ์žฅ์˜ ๋…๋ฆฝ ์ž…๋ ฅ/ํ–‰๋™์„ ํ•จ๊ป˜ ๋ณด์—ฌ์ฃผ๋Š” ๊ฐ€๋กœ ํƒ์ƒ‰ | `CollectionRail` (1.16.0 ์ถ”๊ฐ€ยท์‹คํ—˜, ์•„๋ž˜ ๊ฐ€๋กœ ๋ฐฐ์น˜ ์ง€์นจ) |
23
23
  | ํ–‰ ํ•œ ์ค„์˜ ์ œ๋ชฉยท์„ค๋ช…ยท์•ž๋’ค ์Šฌ๋กฏ | [ListRow](list-row.md) |
24
24
  | ๋†’์ด๊ฐ€ ๊ณ ์ •๋œ ํ–‰ ์ˆ˜๋ฐฑ~์ˆ˜์ฒœ ๊ฐœ๋ฅผ ์ฐฝ ์•ˆ์—์„œ ์Šคํฌ๋กค | [VirtualList](virtual-list.md) |
25
25
  | ์ด์–ด์ง€๋Š” ๋ชฉ๋ก์˜ ๋‹ค์Œ ํŽ˜์ด์ง€ ์š”์ฒญ footer | [LoadMore](load-more.md) (ListยทVirtualList ์•„๋ž˜์— ๋‘”๋‹ค) |
@@ -42,6 +42,7 @@
42
42
  | --- | --- | --- | --- |
43
43
  | `List` | ๊ธฐ๋ณธ | `@hjmds/react`, `/display` | `@hjmds/react-native`, `/data-display` |
44
44
  | `TaskList` | ํ™•์žฅ โ€” ์™„๋ฃŒ ์ฒดํฌ ๋ชฉ๋ก(optional) | `/task-list` | `/task-list` |
45
+ | `CollectionRail` | ๋™๋ฐ˜ยท๋Œ€์•ˆ โ€” ๋…๋ฆฝ ํ–‰๋™์„ ๊ฐ€์ง„ ์œ ํ•œ ๊ฐ€๋กœ ๋ชฉ๋ก([๊ตฌ์„ฑ ์ง€์นจ](../compositions/collection-detail.md)) | `/collection-rail` | `/collection-rail` |
45
46
 
46
47
  `TaskList`๋Š” granular subpath๋กœ๋งŒ import ๋œ๋‹ค. ์ถ”๊ฐ€ peer๋Š” ์—†๋‹ค. ์ˆœ์„œ ๋ฐ”๊พธ๊ธฐ๋ฅผ ํ•ฉ์„ฑํ•˜๋ฉด SortableCollection์˜ peer๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
47
48
 
@@ -74,7 +75,7 @@ import { Text } from "@hjmds/react-native/primitives";
74
75
  | `label` | ํ˜„์ง€ํ™” ๋ฌธ์ž์—ด(ํ•„์ˆ˜) | โ€” | ๋ชฉ๋ก์˜ ์ ‘๊ทผ์„ฑ ์ด๋ฆ„. ๋น„๋ฉด `TypeError` |
75
76
  | `separator` | `indented` ยท `full` ยท `none` | `indented` | `indented`๋Š” leading ์Šฌ๋กฏ ํญ๋งŒํผ ๋“ค์—ฌ์”€ |
76
77
  | `appearance` | `plain` ยท `grouped` | `plain` | `grouped`๋Š” ๋ฐฐ๊ฒฝ๊ณผ ๋‘ฅ๊ทผ ๋ชจ์„œ๋ฆฌ๋กœ ํ•œ ๋ฉ์–ด๋ฆฌ |
77
- | `layoutStyle` | ๋ฐฐ์น˜ key๋งŒ | โ€” | ๋ชฉ๋ก ๋ฃจํŠธ ๋ฐฐ์น˜. Native `style`์€ **deprecated**(1.13, ๊ฐœ๋ฐœ ๋ชจ๋“œ 1ํšŒ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) โ€” `layoutStyle`, ๋ชจ์–‘์€ `appearance`ยท`separator` |
78
+ | `layoutStyle` | ๋ฐฐ์น˜ key๋งŒ | โ€” | ๋ชฉ๋ก ๋ฃจํŠธ ๋ฐฐ์น˜. Native `style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ โ€” `layoutStyle`, ๋ชจ์–‘์€ `appearance`ยท`separator` |
78
79
  | TaskList `items` | `readonly TaskItem[]` โ€” `{ id, label, completed, description?, disabled? }` | โ€” | `id`ยท`label`์ด ๋น„๊ฑฐ๋‚˜ `id`๊ฐ€ ์ค‘๋ณต๋˜๊ฑฐ๋‚˜ `completed`๊ฐ€ boolean์ด ์•„๋‹ˆ๋ฉด `TypeError` |
79
80
  | TaskList `onCompletedChange` | `(id: string, completed: boolean) => void` | โ€” | ํ•„์ˆ˜. ์ฒดํฌ ํ•˜๋‚˜๋งˆ๋‹ค ํ•œ ๋ฒˆ. ๋ชฉ๋ก ์ˆœ์„œยท์ €์žฅ์€ ์ œํ’ˆ์ด ์ •ํ•œ๋‹ค |
80
81
  | TaskList `disabled` | `true` ยท `false` | `false` | ์ „์ฒด ์ฒดํฌ๋ฐ•์Šค๋ฅผ ๋ˆ๋‹ค |
@@ -110,7 +111,7 @@ Native `grouped` ํ”„๋ ˆ์ž„์€ Provider์˜ `tokens.radius.lg`๋ฅผ ์ฝ๋Š”๋‹ค. plain
110
111
 
111
112
  ### CollectionRail ๊ฐ€๋กœ ๋ฐฐ์น˜
112
113
 
113
- ์ƒˆ `CollectionRail`์€ ๋ฏธ๊ฒŒ์‹œ(1.15.0 ์ดํ›„) ์‹คํ—˜ companion์ด๋‹ค. ๊ธฐ์กด List์˜ ๋ฐฐํฌ/ํ˜ธํ™˜ ๊ณ„์•ฝ์€ ์œ ์ง€ํ•œ๋‹ค.
114
+ ์ƒˆ `CollectionRail`์€ 1.16.0 ์ถ”๊ฐ€ ์‹คํ—˜ companion์ด๋‹ค. ๊ธฐ์กด List์˜ ๋ฐฐํฌ/ํ˜ธํ™˜ ๊ณ„์•ฝ์€ ์œ ์ง€ํ•œ๋‹ค.
114
115
 
115
116
  #### ์–ธ์ œ ์“ฐ๋‚˜
116
117
 
@@ -196,7 +197,7 @@ import { CollectionRail } from "@hjmds/react/collection-rail";
196
197
  | --- | --- | --- |
197
198
  | ๊ตฌ์กฐ | `role="list"` + ์ž์‹๋งˆ๋‹ค `role="listitem"` | `accessibilityRole="list"` |
198
199
  | ๊ตฌ๋ถ„์„  | CSS(`data-separator`) | ํ–‰ ์‚ฌ์ด 1px `View` |
199
- | ๋ฐฐ์น˜ | `layoutStyle`(+ `className`) | `layoutStyle`(`style`์€ deprecated) |
200
+ | ๋ฐฐ์น˜ | `layoutStyle`(+ `className`) | `layoutStyle`(`style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ) |
200
201
 
201
202
  2026-10-07 Utilverse ํ•ญ๋ชฉ ์‚ญ์ œ ์ฑ„ํƒ์„ ์œ„ํ•ด `renderItemAction`์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์ฒดํฌ์™€ ์‚ญ์ œ์˜ ์ดˆ์ ยท๋ˆ„๋ฆ„์„ ๋ถ„๋ฆฌํ•˜๊ณ  ํฐ ๊ธ€์ž ๋ผ๋ฒจ ํญ์„ ๋ณด์กดํ•˜๋„๋ก ํ–‰๋™์„ ๋‹ค์Œ ์ค„์— ๋‘”๋‹ค. `renderCollection`์˜ `renderItem`์—๋„ ํฌํ•จ๋œ๋‹ค. ์‚ญ์ œ ์ €์žฅยท์‹คํŒจยท๋˜๋Œ๋ฆฌ๊ธฐ๋Š” ์ œํ’ˆ์ด ์ฒ˜๋ฆฌํ•œ๋‹ค.
202
203
 
@@ -88,6 +88,7 @@ import { Masonry } from "@hjmds/react-native/masonry";
88
88
  - `width`๊ฐ€ 0 ์ดํ•˜์ด๊ฑฐ๋‚˜ ์—ด ํญ์ด 0 ์ดํ•˜, `getItemHeight`๊ฐ€ ์–‘์˜ ์œ ํ•œ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ฉด `TypeError`๊ฐ€ ๋‚œ๋‹ค. ํ•ญ๋ชฉ์ด ๋น„์–ด
89
89
  `empty`๋งŒ ๊ทธ๋ฆด ๋•Œ๋„ ๊ธฐํ•˜ ๊ฒ€์‚ฌ๋ฅผ ๋จผ์ € ํ•˜๋ฏ€๋กœ ๊ฐ™๋‹ค. ์ธก์ • ์ „(ํญ 0)์—๋Š” Masonry๋ฅผ ๋ Œ๋”ํ•˜์ง€ ์•Š๋Š”๋‹ค.
90
90
  - ํ™”๋ฉด ํญ์ด ๋ฐ”๋€Œ๋ฉด `width`๋ฅผ ๋‹ค์‹œ ๋„˜๊ธด๋‹ค.
91
+ - ๋นˆ ๋ชฉ๋ก๋„ `width`๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ, `layoutStyle`๋กœ ํ• ๋‹นํ•œ ์˜์—ญ ์•ˆ์—์„œ ์•ˆ๋‚ด๋ฅผ ๊ฐ€๋กœยท์„ธ๋กœ ์ค‘์•™์— ๋†“๋Š”๋‹ค. ๋†’์ด๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๋ณธ๋ฌธ์—์„œ๋Š” ์•ˆ๋‚ด์˜ ๋‚ด์šฉ ๋†’์ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
91
92
 
92
93
  ## ํ”Œ๋žซํผ ์ฐจ์ด
93
94
 
@@ -100,7 +101,7 @@ import { Masonry } from "@hjmds/react-native/masonry";
100
101
  ## ํ•จ์ •
101
102
 
102
103
  - ๋ชจ๋“  ํ•ญ๋ชฉ์„ ํ•œ ๋ฒˆ์— ๊ทธ๋ฆฐ๋‹ค. ํ•ญ๋ชฉ์ด ๋งŽ์€ ๋ฌดํ•œ ํ”ผ๋“œ์—์„œ๋Š” ๋ Œ๋” ๋น„์šฉ์ด ์Œ“์ธ๋‹ค.
103
- - ํ•ญ๋ชฉ์ด ์—†์œผ๋ฉด `empty`๋งŒ ๊ทธ๋ฆฌ๊ณ  ๋ชฉ๋ก role์ด ๋ถ™์ง€ ์•Š๋Š”๋‹ค. Web ๋นˆ ๋ถ„๊ธฐ๋Š” `role="group"` + `label` ์ด๋ฆ„์ด๋‹ค(๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„).
104
+ - ํ•ญ๋ชฉ์ด ์—†์œผ๋ฉด `empty`๋งŒ ๊ทธ๋ฆฌ๊ณ  ๋ชฉ๋ก role์ด ๋ถ™์ง€ ์•Š๋Š”๋‹ค. Web ๋นˆ ๋ถ„๊ธฐ๋Š” `role="group"` + `label` ์ด๋ฆ„์ด๋‹ค(1.13.0 ๋ณ€๊ฒฝ.
104
105
  1.12.1์€ role ์—†๋Š” `<div aria-label>`์ด๋ผ ์ด๋ฆ„์ด ๋…ธ์ถœ๋˜์ง€ ์•Š์•˜๋‹ค). ๋นˆ ์ƒํƒœ ๋ฌธ๊ตฌ๋Š” `empty` ์•ˆ์— ๋ณด์ด๋Š” ๊ธ€๋กœ ๋‘”๋‹ค.
105
106
  - ๋‹ค์Œ ํŽ˜์ด์ง€๋Š” ๋ชฉ๋ก ๋‹ค์Œ ํ˜•์ œ๋กœ [LoadMore](load-more.md)๋ฅผ ๋‘”๋‹ค. Native์—์„œ FlatList ๋ฐ–(ScrollView ์•ˆ Masonry)์ด๋ฉด
106
107
  `onEndReached`๊ฐ€ ์—†์œผ๋ฏ€๋กœ `mode="manual"`๋กœ ๋‘”๋‹ค. Web `automatic`์€ sentinel๋กœ ๋™์ž‘ํ•˜์ง€๋งŒ ๋น„๊ฐ€์ƒํ™”๋ผ ํ•ญ๋ชฉ์ด
@@ -3,8 +3,8 @@
3
3
  - ๋‹จ๊ณ„: ์ปดํฌ๋„ŒํŠธ
4
4
  - ์ƒํƒœ: ๋ฐฐํฌ
5
5
  - ์ง€์›: Web ยท Native
6
- - ์ ์šฉ: ๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„)
7
- - ๊ฒ€ํ† ์ผ: 2026-10-06
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
 
@@ -44,7 +44,7 @@ import { MediaSelectionScreen } from "@hjmds/react/screen-flows";
44
44
  items={picked.map((p) => ({ descriptor: { id: p.id, name: p.fileName, state: p.upload },
45
45
  preview: <img src={p.uri} alt="" width={p.width} height={p.height} /> }))}
46
46
  add={{ label: t("media.add"), onAction: openPicker }}
47
- done={{ label: t("media.done"), onAction: submit, disabled: uploading }}
47
+ done={{ label: t("media.done"), onAction: submit, disabled: uploading || !canComplete }}
48
48
  labels={{ pending: t("upload.pending"), uploading: t("upload.uploading"),
49
49
  success: t("upload.success"), cancel: t("upload.cancel"), retry: t("upload.retry") }}
50
50
  actionLabels={{ remove: t("media.remove"), moveUp: t("media.moveUp"), moveDown: t("media.moveDown") }}
@@ -66,7 +66,7 @@ import { Image } from "react-native";
66
66
  items={picked.map((p) => ({ descriptor: { id: p.id, name: p.fileName, state: p.upload },
67
67
  preview: <Image src={p.uri} width={p.width} height={p.height} /> }))}
68
68
  add={{ label: t("media.add"), onAction: openPicker }}
69
- done={{ label: t("media.done"), onAction: submit, disabled: uploading }}
69
+ done={{ label: t("media.done"), onAction: submit, disabled: uploading || !canComplete }}
70
70
  labels={{ pending: t("upload.pending"), uploading: t("upload.uploading"),
71
71
  success: t("upload.success"), cancel: t("upload.cancel"), retry: t("upload.retry") }}
72
72
  actionLabels={{ remove: t("media.remove"), moveUp: t("media.moveUp"), moveDown: t("media.moveDown") }}
@@ -104,7 +104,7 @@ Web์˜ `<img alt="">`๋Š” ์žฅ์‹์šฉ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋‹ค. ์‚ฌ์ง„ ์ด๋ฆ„์€ `removeLabe
104
104
  | ๊ฐ„๊ฒฉ | ํ™”๋ฉด padding `spacing.md` 16; ๊ฒฉ์ž ๊ฐ„๊ฒฉ `spacing.md` 16; ํ•ญ๋ชฉ ์•ˆ ๋ฏธ๋ฆฌ๋ณด๊ธฐโ€“UploadItemโ€“๋ฒ„ํŠผ ์ค„ `spacing.xs` 8; ๋ฒ„ํŠผ ์‚ฌ์ด `spacing.xxs` 4; footer ์š”์•ฝโ€“์™„๋ฃŒ `spacing.sm` 12 | WebยทNative `MediaSelectionScreen` |
105
105
  | ์ˆœ์„œยท์ •๋ ฌ | ํ—ค๋”(์ œ๋ชฉ โ†’ ์ถ”๊ฐ€) โ†’ ๊ฒฉ์ž(ํ•ญ๋ชฉ๋งˆ๋‹ค ๋ฏธ๋ฆฌ๋ณด๊ธฐ โ†’ UploadItem โ†’ ์œ„๋กœยท์•„๋ž˜๋กœยท์‚ญ์ œ) โ†’ footer(`selectionSummary` โ†’ ์™„๋ฃŒ) | ๋ Œ๋” ์ˆœ์„œ |
106
106
  | ๊ณ ์ •ยท์Šคํฌ๋กค | ํ—ค๋”ยทfooter ๊ณ ์ •, ๊ฒฉ์ž๋Š” ๋ณธ๋ฌธ ์Šคํฌ๋กค(`scroll` ๊ธฐ๋ณธ `"screen"`) | `ScreenLayout` |
107
- | ์ข์€ ํญยทํฐ ๊ธ€์ž | ์ข์€ ํญ์—์„œ๋„ 2์—ด ์œ ์ง€; ํ•ญ๋ชฉ ๋ฒ„ํŠผ ์ค„์€ ์ค„๋ฐ”๊ฟˆ(`flexWrap: "wrap"`)ํ•ด ๋ฒ„ํŠผ์„ ์ž๋ฅด์ง€ ์•Š๋Š”๋‹ค | `screen-flows.tsx` |
107
+ | ์ข์€ ํญ | ์ข์€ ํญ์—์„œ๋„ 2์—ด ์œ ์ง€; ํ•ญ๋ชฉ ๋ฒ„ํŠผ ์ค„์€ ์ค„๋ฐ”๊ฟˆ(`flexWrap: "wrap"`)ํ•ด ๋ฒ„ํŠผ์„ ์ž๋ฅด์ง€ ์•Š๋Š”๋‹ค | `screen-flows.tsx` |
108
108
 
109
109
  ## ๊ผญ ์ง€ํ‚ฌ ๊ฒƒ
110
110
 
@@ -117,3 +117,9 @@ Web์˜ `<img alt="">`๋Š” ์žฅ์‹์šฉ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๋‹ค. ์‚ฌ์ง„ ์ด๋ฆ„์€ `removeLabe
117
117
 
118
118
  - `actions`๋ฅผ ๋„˜๊ฒจ๋„ `add` ๋ฒ„ํŠผ์ด ๊ทธ ์ž๋ฆฌ๋ฅผ ๋ฎ๋Š”๋‹ค. ๋‹ค๋ฅธ ์ƒ๋‹จ ํ–‰๋™์€ `leading`์ด๋‚˜ `notice`๋กœ ๋‘”๋‹ค.
119
119
  - `library`๋ฅผ ์ฃผ๋ฉด `items` ๊ฒฉ์ž์™€ ์—…๋กœ๋“œ ์ƒํƒœ ํ‘œ์‹œ๋Š” ๊ทธ๋ ค์ง€์ง€ ์•Š๋Š”๋‹ค. ์„ ํƒ ๊ฒฐ๊ณผ๋Š” `selectionSummary`๋กœ ๋ณด์—ฌ ์ค€๋‹ค.
120
+
121
+ ## ์‚ญ์ œยท์ˆœ์„œ ๋ณ€๊ฒฝ ํ›„ Web ํ‚ค๋ณด๋“œ ์ดˆ์ 
122
+
123
+ ๊ธฐ๋ณธ ๊ฒฉ์ž๋Š” ์ œํ’ˆ์ด `items` ๋ณ€๊ฒฝ์„ ๋ฐ˜์˜ํ•œ ๋’ค ์ดˆ์ ์„ ๋ณต๊ตฌํ•œ๋‹ค. ํ˜„์žฌ ์‚ฌ์ง„์„ ์ œ๊ฑฐํ•˜๋ฉด ๊ฐ™์€ ์œ„์น˜์˜ ๋‹ค์Œ ์‚ฌ์ง„ ์ œ๊ฑฐ ๋ฒ„ํŠผ, ๋งˆ์ง€๋ง‰์ด๋ฉด ์ด์ „ ์‚ฌ์ง„ ์ œ๊ฑฐ ๋ฒ„ํŠผ์œผ๋กœ ์ด์–ด์ง„๋‹ค. ๋ชจ๋‘ ์ œ๊ฑฐํ•˜๋ฉด ํ™œ์„ฑ `add`๋กœ ์ด๋™ํ•˜๊ณ , ์ถ”๊ฐ€๋„ ์ž ๊ฒผ์œผ๋ฉด ๋ณธ๋ฌธ์— ๋‚จ๋Š”๋‹ค. ๋งˆ์ง€๋ง‰ ์ œ๊ฑฐ์™€ ๋™์‹œ์— `state.kind="empty"`๋กœ ๋ฐ”๊ฟ”๋„ ๊ฐ™์€ ๊ทœ์น™์ด๋‹ค. ์ด๋™ ํ›„ ์ฒซยท๋งˆ์ง€๋ง‰ ์œ„์น˜์˜ ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋˜๋ฉด ๊ฐ™์€ ์‚ฌ์ง„์˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ–‰๋™์œผ๋กœ ์ด์–ด์ง„๋‹ค. ์‚ด์•„ ์žˆ๋Š” ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ž…๋ ฅ๊ณผ ๊ฐ’์€ key์ธ `descriptor.id`๋ฅผ ๋”ฐ๋ผ ์œ ์ง€ํ•œ๋‹ค. ์ด๋™๋œ ์ดˆ์ ์ด ๋ณธ๋ฌธ ๋ฐ–์œผ๋กœ ๊ฐ€๋ ค์ง€๋ฉด `scroll="screen"`์˜ ๋ณธ๋ฌธ๋งŒ ํ•„์š”ํ•œ ๋งŒํผ ์Šคํฌ๋กคํ•œ๋‹ค.
124
+
125
+ 2026-10-13 ์‹คํ–‰ ๊ฒ€์ˆ˜์—์„œ ์‚ญ์ œยท๊ฒฝ๊ณ„ ์ด๋™ ํ›„ ํ‚ค๋ณด๋“œ ๋ฌธ๋งฅ์ด ๋Š๊ฒจ ์ถ”๊ฐ€ํ•œ ๋™์ž‘์ด๋‹ค. ์™ธ๋ถ€ ์ปจํŠธ๋กค๋กœ ์ด๋™ํ•˜๊ฑฐ๋‚˜ ๋ช…์‹œ์ ์œผ๋กœ blurํ•œ ์ดˆ์ ์€ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š”๋‹ค. `library`์˜ ์ดˆ์ ยท์„ ํƒ๊ณผ Native OS ์ ‘๊ทผ์„ฑ ์ดˆ์ ์€ ์ด Web DOM ๋ณต๊ตฌ ๋ฒ”์œ„์— ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค. `done` ํ—ˆ์šฉ ์กฐ๊ฑด๊ณผ ์š”์ฒญ ์ทจ์†Œยท๋Šฆ์€ ์‘๋‹ต ์ฒ˜๋ฆฌ๋Š” ๊ณ„์† ์ œํ’ˆ์ด ์†Œ์œ ํ•œ๋‹ค.
@@ -79,7 +79,7 @@ Native ํ›„๋ณด ๋ชฉ๋ก์˜ ๋ชจ์„œ๋ฆฌ๋Š” `comboboxRecipe.popover.radius` ์—ญํ• ์„ P
79
79
  | ํ•ญ๋ชฉ | ๊ฐ’ | ๊ทผ๊ฑฐ |
80
80
  | --- | --- | --- |
81
81
  | ํฌ๊ธฐ | ํ›„๋ณด ํ•œ ์ค„ ์ตœ์†Œ ๋†’์ด 44(`control.minTouchTarget`). Web ๋ชฉ๋ก ์ตœ๋Œ€ ๋†’์ด `14rem`, ์ž…๋ ฅ ํญ์— ๋งž์ถค | `.hjm-mentions__option`ยท`__list`, Native `minHeight: 44` |
82
- | ๊ฐ„๊ฒฉ | ๋ผ๋ฒจยท์ž…๋ ฅยท์„ค๋ช…ยท์˜ค๋ฅ˜ ์‚ฌ์ด `spacing.xs` 8. Web ๋ชฉ๋ก์€ ์ž…๋ ฅ๊ณผ 8, ํ™”๋ฉด ๊ฐ€์žฅ์ž๋ฆฌ 8, ์•ˆ์ชฝ 8, radius `radius.md` 12 โ€” ๋ชจ๋‘ Combobox ๋ชฉ๋ก๊ณผ ๊ฐ™์€ `comboboxRecipe.popover`(sideOffsetยทcollisionPaddingยทpadding `spacing.xs`). Native ๋ชฉ๋ก ์•ˆ์ชฝ 8(๊ฐ™์€ recipe)ยทํ•ญ๋ชฉ ์‚ฌ์ด 4, radius `radius.md` 12. ํ›„๋ณด ์ขŒ์šฐ ์—ฌ๋ฐฑ 8. 2026-10-06๊นŒ์ง€ Web ๊ฐ€์žฅ์ž๋ฆฌ 16ยท์•ˆ์ชฝ 4, Native ์•ˆ์ชฝ 4์˜€๋‹ค(1.12.1 ์ดํ›„ ๋ฏธ๊ฒŒ์‹œ) | `comboboxRecipe.popover`, `.hjm-mentions__*`, `react-native/src/mentions.tsx` |
82
+ | ๊ฐ„๊ฒฉ | ๋ผ๋ฒจยท์ž…๋ ฅยท์„ค๋ช…ยท์˜ค๋ฅ˜ ์‚ฌ์ด `spacing.xs` 8. Web ๋ชฉ๋ก์€ ์ž…๋ ฅ๊ณผ 8, ํ™”๋ฉด ๊ฐ€์žฅ์ž๋ฆฌ 8, ์•ˆ์ชฝ 8, radius `radius.md` 12 โ€” ๋ชจ๋‘ Combobox ๋ชฉ๋ก๊ณผ ๊ฐ™์€ `comboboxRecipe.popover`(sideOffsetยทcollisionPaddingยทpadding `spacing.xs`). Native ๋ชฉ๋ก ์•ˆ์ชฝ 8(๊ฐ™์€ recipe)ยทํ•ญ๋ชฉ ์‚ฌ์ด 4, radius `radius.md` 12. ํ›„๋ณด ์ขŒ์šฐ ์—ฌ๋ฐฑ 8. 2026-10-06๊นŒ์ง€ Web ๊ฐ€์žฅ์ž๋ฆฌ 16ยท์•ˆ์ชฝ 4, Native ์•ˆ์ชฝ 4์˜€๋‹ค(1.13.0 ๋ณ€๊ฒฝ) | `comboboxRecipe.popover`, `.hjm-mentions__*`, `react-native/src/mentions.tsx` |
83
83
  | ์ˆœ์„œยท์ •๋ ฌ | ํ›„๋ณด ๋ชฉ๋ก์€ ์ž…๋ ฅ **๋ฐ”๋กœ ์•„๋ž˜**. Web์€ ์•„๋ž˜ ๊ณต๊ฐ„์ด ๋ชจ์ž๋ผ๋ฉด ์œ„๋กœ ๋’ค์ง‘๋Š”๋‹ค. Web ํ›„๋ณด๋Š” `label` ์˜†์— `description`, ์ข์œผ๋ฉด ์ค„๋ฐ”๊ฟˆ | `useAnchoredPopup`, `.hjm-mentions__option` |
84
84
  | ๊ณ ์ •ยท์Šคํฌ๋กค | Web ๋ชฉ๋ก์€ ๋–  ์žˆ๋Š” portal(z-index `layer.dropdown` 400)์ด๊ณ  ๋„˜์น˜๋ฉด ๋ชฉ๋ก ์•ˆ ์Šคํฌ๋กค. Native ๋ชฉ๋ก์€ ๋ฌธ์„œ ํ๋ฆ„ ์•ˆ์— ๋ผ์–ด๋“ค์–ด ์•„๋ž˜ ๋‚ด์šฉ์„ ๋ฏผ๋‹ค | `src/mentions.tsx`(WebยทNative) |
85
85
  | ์ข์€ ํญยทํฐ ๊ธ€์ž | ํ‚ค๋ณด๋“œ ์œ„ ์ž…๋ ฅ์ด๋ฉด Native ๋ชฉ๋ก์ด ๊ฐ€๋ ค์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ [KeyboardFormScrollView](keyboard-form-scroll-view.md) ์•ˆ์— ๋‘”๋‹ค | โ€” |
@@ -112,7 +112,7 @@ Web Native
112
112
  | ํ›„๋ณด ํ‘œ์‹œ | ์ž…๋ ฅ ์•„๋ž˜ ๋–  ์žˆ๋Š” listbox(portal) | ์ž…๋ ฅ ์•„๋ž˜ ๋ฌธ์„œ ํ๋ฆ„ ์•ˆ ๋ชฉ๋ก |
113
113
  | ํ‚ค๋ณด๋“œ | โ†‘โ†“ ์ด๋™, Enter ํ™•์ •, Esc ๋‹ซ๊ธฐ(์ž…๋ ฅ์€ ์œ ์ง€) | ํ•ด๋‹น ์—†์Œ(๋ˆ„๋ฆ„์œผ๋กœ ํ™•์ •) |
114
114
  | ๊ธฐ๋ณธ ํ›„๋ณด ๋ Œ๋” | `label` + `description` | `label`๋งŒ |
115
- | ์ถ”๊ฐ€ prop | `className`, ref(`HTMLTextAreaElement`). `style`์€ ์•ˆ์ชฝ textarea์— ๋ถ™๋Š”๋‹ค | `listStyle`์€ deprecated(๋‹ค์Œ major ์ œ๊ฑฐ, ๋Œ€์ฒด ์—†์Œ โ€” ํ›„๋ณด ๋ชฉ๋ก recipe๊ฐ€ ์™ธํ˜•์„ ๊ฐ€์ง„๋‹ค) |
115
+ | ์ถ”๊ฐ€ prop | `className`, ref(`HTMLTextAreaElement`). `style`์€ ์•ˆ์ชฝ textarea์— ๋ถ™๋Š”๋‹ค | `listStyle`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ(ํ›„๋ณด ๋ชฉ๋ก์˜ ์™ธํ˜•์€ recipe๊ฐ€ ์†Œ์œ ํ•œ๋‹ค) |
116
116
 
117
117
  ## ํ•จ์ •
118
118
 
@@ -89,7 +89,7 @@ Native popover์™€ ํ•ญ๋ชฉ ๋ชจ์„œ๋ฆฌ๋Š” Provider token์—์„œ recipe ์—ญํ• ์„ ํ•ด
89
89
  | ํ•ญ๋ชฉ | ๊ฐ’ | ๊ทผ๊ฑฐ |
90
90
  | --- | --- | --- |
91
91
  | ํฌ๊ธฐ | ํ•ญ๋ชฉ ๋†’์ด `comfortable` 56(`layout.rowHeight.singleLine`) ยท `compact` 44(`control.minTouchTarget`). Web ํ‘œ๋ฉด ํญ `13.75rem`~`min(24rem, 90vw)`, ๋†’์ด ์ตœ๋Œ€ `100dvh โˆ’ 2 ร— spacing.md`. Native ํ‘œ๋ฉด ํญ 100%ยท์ตœ๋Œ€ 520, ๋†’์ด ์ตœ๋Œ€ 75% | `menuRecipe.density`, `.hjm-menu__content`, `react-native/src/navigation.tsx` |
92
- | ๊ฐ„๊ฒฉ | ํ•ญ๋ชฉ ์ขŒ์šฐ `spacing.sm` 12, leadingยท๋ฌธ๊ตฌยท๋‹จ์ถ•ํ‚ค ์‚ฌ์ด 12. ์„น์…˜ ์ œ๋ชฉ ์ขŒ์šฐ 12 ยท ์œ„์•„๋ž˜ `spacing.xs` 8. Web: ํŠธ๋ฆฌ๊ฑฐ์™€ 8(`menuRecipe.sideOffset`), ํ™”๋ฉด ๊ฐ€์žฅ์ž๋ฆฌ 8(`collisionPadding`), ์•ˆ์ชฝ `spacing.xs` 8(`menuRecipe.surface.padding`; 2026-10-06๊นŒ์ง€ 4, 1.12.1 ์ดํ›„ ๋ฏธ๊ฒŒ์‹œ), ํ‘œ๋ฉดยทํ•ญ๋ชฉ radius `radius.md` 12, ๊ตฌ๋ถ„์„  ์œ„์•„๋ž˜ 4 ยท ์ขŒ์šฐ 8. Native: ๋ฐ”๊นฅ ์—ฌ๋ฐฑยท์•ˆ์ชฝ `spacing.md` 16, ์ œ๋ชฉยท๋ชฉ๋กยท๋‹ซ๊ธฐ ์‚ฌ์ด 12, radius `radius.lg` 16 | `collectionItemContract`, `menuRecipe.sectionLabel`ยท`surface`, `.hjm-menu__*`, `useAnchoredPopup` |
92
+ | ๊ฐ„๊ฒฉ | ํ•ญ๋ชฉ ์ขŒ์šฐ `spacing.sm` 12, leadingยท๋ฌธ๊ตฌยท๋‹จ์ถ•ํ‚ค ์‚ฌ์ด 12. ์„น์…˜ ์ œ๋ชฉ ์ขŒ์šฐ 12 ยท ์œ„์•„๋ž˜ `spacing.xs` 8. Web: ํŠธ๋ฆฌ๊ฑฐ์™€ 8(`menuRecipe.sideOffset`), ํ™”๋ฉด ๊ฐ€์žฅ์ž๋ฆฌ 8(`collisionPadding`), ์•ˆ์ชฝ `spacing.xs` 8(`menuRecipe.surface.padding`; 2026-10-06๊นŒ์ง€ 4, 1.13.0 ๋ณ€๊ฒฝ), ํ‘œ๋ฉดยทํ•ญ๋ชฉ radius `radius.md` 12, ๊ตฌ๋ถ„์„  ์œ„์•„๋ž˜ 4 ยท ์ขŒ์šฐ 8. Native: ๋ฐ”๊นฅ ์—ฌ๋ฐฑยท์•ˆ์ชฝ `spacing.md` 16, ์ œ๋ชฉยท๋ชฉ๋กยท๋‹ซ๊ธฐ ์‚ฌ์ด 12, radius `radius.lg` 16 | `collectionItemContract`, `menuRecipe.sectionLabel`ยท`surface`, `.hjm-menu__*`, `useAnchoredPopup` |
93
93
  | ์ˆœ์„œยท์ •๋ ฌ | ์ผ๋ฐ˜ ํ–‰๋™์„ ์œ„์—, `danger` ํ–‰๋™์€ ๋งจ ์•„๋ž˜. Web `align="start"`(๊ธฐ๋ณธ)๋Š” ํŠธ๋ฆฌ๊ฑฐ ์‹œ์ž‘ ๋, `end`๋Š” ๋ ๋์— ๋งž์ถ˜๋‹ค(ํ–‰ ๋ โ‹ฏ์€ `end`). Native๋Š” ์œ„โ†’์•„๋ž˜ ์ œ๋ชฉ โ†’ ํ•ญ๋ชฉ โ†’ ๋‹ซ๊ธฐ ๋ฒ„ํŠผ(`secondary`) | `menuRecipe`, `src/overlays.tsx` |
94
94
  | ๊ณ ์ •ยท์Šคํฌ๋กค | Web: ํŠธ๋ฆฌ๊ฑฐ์— ๋ถ™๋Š” portal(z-index `layer.dropdown` 400), ์•„๋ž˜๊ฐ€ ๋ชจ์ž๋ผ๋ฉด ์œ„๋กœ ๋’ค์ง‘๊ณ  ๊ฐ€๋กœ๋Š” ํ™”๋ฉด ์•ˆ์œผ๋กœ ๋ฏผ๋‹ค. ๋„˜์น˜๋ฉด ํ‘œ๋ฉด ์•ˆ ์Šคํฌ๋กค. Native: `Modal`๋กœ ํ™”๋ฉด **๊ฐ€์šด๋ฐ**, scrim์„ ๋ˆ„๋ฅด๋ฉด ๋‹ซํžˆ๊ณ  ํ•ญ๋ชฉ ๋ชฉ๋ก๋งŒ ์Šคํฌ๋กค | `useAnchoredPopup`, `react-native/src/navigation.tsx`(`Menu`) |
95
95
  | ์ข์€ ํญยทํฐ ๊ธ€์ž | Web ํญ ์ƒํ•œ `90vw`, ํ•ญ๋ชฉ ๋ฌธ๊ตฌ๋Š” ์ค„๋ฐ”๊ฟˆ๋œ๋‹ค. Native ๋†’์ด ์ƒํ•œ 75%๋ฅผ ๋„˜์œผ๋ฉด ๋ชฉ๋ก์ด ์Šคํฌ๋กค๋œ๋‹ค | `.hjm-menu__content`, `maxHeight: "75%"` |
@@ -114,6 +114,7 @@ Web (ํŠธ๋ฆฌ๊ฑฐ ์•„๋ž˜, ์•ต์ปค) Native (Modal, ํ™”๋ฉด ๊ฐ€์šด๋ฐ)
114
114
  - ํ•ญ๋ชฉ id๋Š” ๋น„์–ด ์žˆ์ง€ ์•Š๊ณ  ์œ ์ผํ•ด์•ผ ํ•˜๋ฉฐ, ํ™œ์„ฑ ํ•ญ๋ชฉ์ด ํ•˜๋‚˜ ์ด์ƒ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์–ด๊ธฐ๋ฉด ๋ Œ๋” ์ค‘ ๋˜์ง„๋‹ค.
115
115
  - Web์—์„œ `label`์ด ๋ฌธ์ž์—ด์ด ์•„๋‹Œ ํ•ญ๋ชฉ์€ typeahead์šฉ `textValue`๋ฅผ ์ค€๋‹ค. ์—†์œผ๋ฉด ๋˜์ง„๋‹ค.
116
116
  - ๋‹ค๋ฅธ ๋ชจ๋‹ฌยท์‹œํŠธยทํ™”๋ฉด ์ด๋™์„ ์—ฌ๋Š” action์€ `onActionAfterDismiss`๋กœ ์‹คํ–‰ํ•œ๋‹ค. ์ด ์ฝœ๋ฐฑ์€ ๋ฉ”๋‰ด๊ฐ€ ์‹ค์ œ๋กœ ๋‹ซํžŒ ๋’ค(Native๋Š” Modal teardown ๋’ค)์—๋งŒ ์‹คํ–‰๋˜๋ฏ€๋กœ ๋‘ ํ‘œ๋ฉด์ด ๊ฒน์น˜์ง€ ์•Š๋Š”๋‹ค.
117
+ - Native์—์„œ teardown ์™„๋ฃŒ ์ „์— ์žฌ์—ด๊ฑฐ๋‚˜ owner๋ฅผ ๊ต์ฒดํ•˜๋ฉด ์ด์ „์— ๋Œ€๊ธฐํ•˜๋˜ after-dismiss action์€ ํ๊ธฐ๋œ๋‹ค. ๋น„๋™๊ธฐ action์˜ ์š”์ฒญ ์˜ค๋ฅ˜๋Š” ์ œํ’ˆ ์ฝœ๋ฐฑ ์•ˆ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ œํ’ˆ ์˜ค๋ฅ˜ UI์— ์—ฐ๊ฒฐํ•œ๋‹ค. ๋ฉ”๋‰ด๋Š” Promise ์‹คํŒจ์— ๋”ฐ๋ฅธ ์˜ค๋ฅ˜ ํ™”๋ฉด์ด๋‚˜ ์ž๋™ ์žฌ์‹œ๋„๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
117
118
  - ํ•ญ๋ชฉ ๋ฌธ๊ตฌยท์•„์ด์ฝ˜(์ œํ’ˆ ์†Œ์œ )์€ i18n ํ‚ค์™€ ์ œํ’ˆ ์•„์ด์ฝ˜์œผ๋กœ ๋„ฃ๊ณ , ์ƒ‰์€ `tone`์œผ๋กœ๋งŒ ๋ฐ”๊พผ๋‹ค.
118
119
  - `MorphingMenu`๋Š” action ์ „์šฉ์ด๋‹ค. ์„ ํƒยทasync๊ฐ€ ํ•„์š”ํ•˜๋ฉด `Menu`๋ฅผ ์“ด๋‹ค. reduce-motionยทRTL์—์„œ๋Š” ์Šค์Šค๋กœ `Menu`๋กœ ๋Œ์•„๊ฐ„๋‹ค.
119
120
 
@@ -128,4 +129,4 @@ Web (ํŠธ๋ฆฌ๊ฑฐ ์•„๋ž˜, ์•ต์ปค) Native (Modal, ํ™”๋ฉด ๊ฐ€์šด๋ฐ)
128
129
  | ์ƒํƒœ | `disabled` | `disabled`, `readOnly`(+`readOnlyLabel`), `busy`, `onRetry`/`retryLabel` |
129
130
  | ํ‘œ๋ฉด | ํŠธ๋ฆฌ๊ฑฐ์— ๋ถ™๋Š” portal(`portalContainer`) | `Modal` |
130
131
  | ํ•ญ๋ชฉ label | `ReactNode`(+`textValue`) | `string` |
131
- | ๋ฐฐ์น˜ | `className`, `layoutStyle` | `layoutStyle`(`style`์€ deprecated โ€” ๊ฐœ๋ฐœ ๋ชจ๋“œ ๊ฒฝ๊ณ , ๋‹ค์Œ major ์ œ๊ฑฐ) |
132
+ | ๋ฐฐ์น˜ | `className`, `layoutStyle` | `layoutStyle`(`style`์€ ์ œ๊ฑฐ๋œ ์†์„ฑ) |
@@ -93,7 +93,7 @@ Native ์˜ˆ๋Š” ์—†๋‹ค(renderer ์—†์Œ).
93
93
  - `className`ยท`layoutStyle`์€ ๋ฐฐ์น˜์—๋งŒ ์“ด๋‹ค. ์ƒ‰ยท๋†’์ด๋ฅผ ๋ฎ์ง€ ์•Š๋Š”๋‹ค.
94
94
 
95
95
  2026-10-07 Web ์ „์ฒด ํšŒ๊ท€ ์ค‘ ํ‚ค๋ณด๋“œ๋กœ ์˜ฎ๊ธด ํ•ญ๋ชฉ์ด ์ฒซ ํ•ญ๋ชฉ์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ–ˆ๋‹ค.
96
- ๋ฏธ๊ฒŒ์‹œ(1.14.0 ์ดํ›„) ์ˆ˜์ •์€ ํŒจ๋„์˜ ๋Šฆ์€ mouseenter๊ฐ€ ํ‚ค๋ณด๋“œ ์„ ํƒ์„ ๋ฎ์ง€ ์•Š๊ณ  ์‹ค์ œ ๋งˆ์šฐ์Šค ์ด๋™์—
96
+ 1.15.0 ๋ณ€๊ฒฝ ์ˆ˜์ •์€ ํŒจ๋„์˜ ๋Šฆ์€ mouseenter๊ฐ€ ํ‚ค๋ณด๋“œ ์„ ํƒ์„ ๋ฎ์ง€ ์•Š๊ณ  ์‹ค์ œ ๋งˆ์šฐ์Šค ์ด๋™์—
97
97
  ๋งž์ถฐ ํ™œ์„ฑ ํ•ญ๋ชฉ์„ ๋ฐ”๊พผ๋‹ค. ๋ฉ”๋‰ด ๋ง‰๋Œ€ ๋ผ๋ฒจ์˜ hover ์ „ํ™˜ยทํด๋ฆญยท๋น„ํ™œ์„ฑ ๊ฑด๋„ˆ๋›ฐ๊ธฐ๋Š” ์œ ์ง€ํ•œ๋‹ค.
98
98
  ๊ณ ์ • ์ง€์—ฐ์ด๋‚˜ ํ‚ค๋ณด๋“œ ๊ฒ€์‚ฌ ์žฌ์‹œ๋„๋กœ ๊ฐ€๋ฆฌ๋Š” ๋Œ€์‹  ์ž…๋ ฅ ์˜๋„๋ฅผ ๊ตฌ๋ถ„ํ–ˆ๋‹ค.
99
99
  [๊ฒ€์ฆ ๊ธฐ๋ก](../../../../../docs/qa/2026-10-07-command-records.md).
@@ -102,4 +102,4 @@ Native ์˜ˆ๋Š” ์—†๋‹ค(renderer ์—†์Œ).
102
102
 
103
103
  2026-10-07 ์†Œ๋น„ ๊ฐ์‚ฌ์—์„œ Web ๋ผ๋ฒจ์˜ ์ˆซ์ž recipe ๋ชจ์„œ๋ฆฌ๊ฐ€ ํ”„๋กœํ•„์„ ์šฐํšŒํ–ˆ๋‹ค. ๊ธฐ์กด `radius.sm` ์—ญํ• ์„ ๊ฐ€๊นŒ์šด Provider์˜ CSS ๋ณ€์ˆ˜๋กœ ์ฝ๊ณ  ๋ณ€์ˆ˜ ์—†๋Š” ๋…๋ฆฝ ์‚ฌ์šฉ์€ recipe 8์„ ์œ ์ง€ํ•œ๋‹ค. ์—ด๋ฆฐ ๋ฉ”๋‰ดยทroving focusยท๋น„ํ™œ์„ฑ ๊ฑด๋„ˆ๋›ฐ๊ธฐยทํ–‰๋™๊ณผ Web ์ „์šฉ ๋ฒ”์œ„๋Š” ๋ฐ”๊พธ์ง€ ์•Š๋Š”๋‹ค.
104
104
 
105
- ํ”„๋กœํ•„ ์—ฐ๊ฒฐ์€ 1.15.0 ์ดํ›„ ๋ฏธ๊ฒŒ์‹œ ๋ณ€๊ฒฝ์ด๋ฉฐ, ๊ธฐ๋ณธ ๋ฐฐํฌ ๊ณ„์•ฝ๊ณผ ์‹ค์ œ Native ๊ธฐ๊ธฐ ๊ฒ€์ฆ์€ ๊ตฌ๋ถ„ํ•œ๋‹ค.
105
+ ํ”„๋กœํ•„ ์—ฐ๊ฒฐ์€ 1.16.0 ๋ณ€๊ฒฝ์ด๋ฉฐ, ๊ธฐ๋ณธ ๋ฐฐํฌ ๊ณ„์•ฝ๊ณผ ์‹ค์ œ Native ๊ธฐ๊ธฐ ๊ฒ€์ฆ์€ ๊ตฌ๋ถ„ํ•œ๋‹ค.
@@ -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), WebยทNative `src/screens.tsx`ยท`src/screen-flows.tsx`; ๊ธฐ์กด ๊ฐœ๋ณ„ ์ง€์นจ์„ ์ƒˆ ๊ทœ๊ฒฉ์œผ๋กœ ํ†ตํ•ฉ. ์˜ˆ์ œ ์Šคํ† ๋ฆฌ๋Š” 2026-10-06 ์‚ฌ์šฉ์ž ์Šน์ธ์œผ๋กœ ์Šคํ† ๋ฆฌ๋ถ ๋ฐฐํฌ([์Šน์ธ ๊ธฐ๋ก](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-์ „์ฒด-์Šน๊ฒฉ๊ณผ-๊ทœ๊ฒฉ-ํ™•์ •)). ์Šคํ† ๋ฆฌ๋ถ ๋ฐฐํฌ๋Š” API ๊ฒŒ์‹œ๊ฐ€ ์•„๋‹ˆ๋‹ค(`์ ์šฉ` ์ฐธ๊ณ )
9
9
  - ์Šคํ† ๋ฆฌ๋ถ: `๋ฐฐํฌ/๊ตฌ์„ฑ/์ž…๋ ฅ๊ณผ ์ž‘์„ฑ/๋ฉ”์‹œ์ง€ ์ž‘์„ฑ`, `๋ฐฐํฌ/๊ตฌ์„ฑ/์ž…๋ ฅ๊ณผ ์ž‘์„ฑ/๋Œ“๊ธ€ ์ž‘์„ฑ`, `๋ฐฐํฌ/ํ™”๋ฉด/์†Œํ†ต/์ฑ„ํŒ…`
@@ -95,7 +95,7 @@ import { Image } from "react-native";
95
95
  | `attachmentAction` | `{ label, icon, onPress(), disabled? }` | ์—†์Œ | ์ฒจ๋ถ€ ๋ฒ„ํŠผ(ghost `IconButton`) |
96
96
  | `attachments` | `readonly { id, removeLabel, preview, disabled? }[]` | `[]` | ์ฒจ๋ถ€ ๋ฏธ๋ฆฌ๋ณด๊ธฐ. ์žˆ์œผ๋ฉด `onRemoveAttachment` ํ•„์ˆ˜ |
97
97
  | `onRemoveAttachment` | `(id: string) => void` | ์—†์Œ | ์ฒจ๋ถ€ ์ œ๊ฑฐ |
98
- | Web `layoutStyle` | `HjmCompositionStyleProp` | ์—†์Œ | ์ž‘์„ฑ์ฐฝ ๋ฃจํŠธ ๋ฐฐ์น˜(marginยทwidthยทflex ๋“ฑ). ๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„) |
98
+ | Web `layoutStyle` | `HjmCompositionStyleProp` | ์—†์Œ | ์ž‘์„ฑ์ฐฝ ๋ฃจํŠธ ๋ฐฐ์น˜(marginยทwidthยทflex ๋“ฑ). 1.13.0 ๋ณ€๊ฒฝ |
99
99
 
100
100
  ์ „์†ก ๊ฐ€๋Šฅ ์กฐ๊ฑด: `disabled`ยท`pending`ยท`sendDisabled`๊ฐ€ ์•„๋‹ˆ๊ณ , ๊ธ€(๊ณต๋ฐฑ ์ œ์™ธ)ยท์ฒจ๋ถ€ยท`additionalContent` ์ค‘ ํ•˜๋‚˜๊ฐ€ ์žˆ์„ ๋•Œ(`canSubmitMessage`).
101
101
 
@@ -104,7 +104,7 @@ import { Image } from "react-native";
104
104
  | ํ•ญ๋ชฉ | ๊ฐ’ | ๊ทผ๊ฑฐ |
105
105
  | --- | --- | --- |
106
106
  | ํฌ๊ธฐ | ์ž…๋ ฅ `composerMinLines` 1 ~ `composerMaxLines` 5์ค„(๋„˜์œผ๋ฉด ์ž…๋ ฅ ์•ˆ์—์„œ ์Šคํฌ๋กค), `shape="large"`; ์ฒจ๋ถ€ ์ธ๋„ค์ผ `attachmentSize` 80(radius `radius.md`); ์ œ๊ฑฐ ๋ฒ„ํŠผ์€ `IconButton size="small"` 36 + ์‚ฌ๋ฐฉ hit 4(์‹ค์ œ ํƒ€๊นƒ 44), ๊ทธ ์•ˆ ๋ณด์ด๋Š” ์› `attachmentRemoveSize` 24; circle ์ „์†ก์€ `IconButton size="small"` 36 | `screen-patterns.ts`, `icon-button-recipe.ts` `sizes.small`, Web `styles.css`, Native `MessageComposer` |
107
- | ๊ฐ„๊ฒฉ | ์„ธ๋กœ ๋ฌถ์Œ(contextยท๋‹ต์žฅ ๋Œ€์ƒยท์ฒจ๋ถ€ยท์ž…๋ ฅ ์ค„) ์‚ฌ์ด์™€ ์ž…๋ ฅโ€“ํ…์ŠคํŠธ ์ „์†ก ๋ฒ„ํŠผ ์‚ฌ์ด `screenPatternRecipe.itemGap`(`spacing.sm` 12, ๋‘ ํ”Œ๋žซํผ. 2026-10-06๊นŒ์ง€ Web์€ 8, 1.12.1 ์ดํ›„ ๋ฏธ๊ฒŒ์‹œ); ๋‹ต์žฅ ๋Œ€์ƒ ์ค„ยท์ฒจ๋ถ€ ์‚ฌ์ด `spacing.sm` 12; circle ์ „์†ก์€ ์ž…๋ ฅ ๊ธ€์ž์™€ `spacing.sm` 12, ์˜ค๋ฅธ์ชฝ ๋ 8 | `screenPatternRecipe.itemGap`, Web `.hjm-message-composer`ยท`__row`(`--hjm-message-composer-gap`), Native `Stack gap="sm"`ยท`itemGap` |
107
+ | ๊ฐ„๊ฒฉ | ์„ธ๋กœ ๋ฌถ์Œ(contextยท๋‹ต์žฅ ๋Œ€์ƒยท์ฒจ๋ถ€ยท์ž…๋ ฅ ์ค„) ์‚ฌ์ด์™€ ์ž…๋ ฅโ€“ํ…์ŠคํŠธ ์ „์†ก ๋ฒ„ํŠผ ์‚ฌ์ด `screenPatternRecipe.itemGap`(`spacing.sm` 12, ๋‘ ํ”Œ๋žซํผ. 2026-10-06๊นŒ์ง€ Web์€ 8, 1.13.0 ๋ณ€๊ฒฝ); ๋‹ต์žฅ ๋Œ€์ƒ ์ค„ยท์ฒจ๋ถ€ ์‚ฌ์ด `spacing.sm` 12; circle ์ „์†ก์€ ์ž…๋ ฅ ๊ธ€์ž์™€ `spacing.sm` 12, ์˜ค๋ฅธ์ชฝ ๋ 8 | `screenPatternRecipe.itemGap`, Web `.hjm-message-composer`ยท`__row`(`--hjm-message-composer-gap`), Native `Stack gap="sm"`ยท`itemGap` |
108
108
  | ์ˆœ์„œยท์ •๋ ฌ | `context` โ†’ ๋‹ต์žฅ ๋Œ€์ƒ(์ž‘์„ฑ์žยท๋ฐœ์ทŒ โ†’ ์ทจ์†Œ) โ†’ ์ฒจ๋ถ€ ์ธ๋„ค์ผ(โ†’ ์ฒจ๋ถ€ ๋ฒ„ํŠผ) โ†’ ์ž…๋ ฅยท์ „์†ก ํ•œ ์ค„, ์ „์†ก์€ ์ž…๋ ฅ ์•„๋ž˜์ชฝ(`flex-end`)์— ๋งž์ถ˜๋‹ค. ์ž…๋ ฅ ์ค„ ์•ˆ์€ `leadingAction` โ†’ ๊ธ€์ž โ†’ (์•„์ด์ฝ˜ ๋ชจ๋“œ) ์ „์†ก/์ฒจ๋ถ€ | ๋ Œ๋” ์ˆœ์„œ, Web `forms.tsx` `hjm-field__leading` |
109
109
  | ๊ณ ์ •ยท์Šคํฌ๋กค | ์ž์ฒด ๊ณ ์ • ์—†์Œ: ํ™”๋ฉด composer ์Šฌ๋กฏ(footer)์— ๋„ฃ๋Š”๋‹ค; ์ฒจ๋ถ€๋Š” ๊ฐ€๋กœ ์Šคํฌ๋กค; ํ‚ค๋ณด๋“œ adapter๋Š” host ํ•˜๋‚˜๋งŒ | ChatScreenยทCommentThreadScreen `composer` |
110
110
  | ์ข์€ ํญยทํฐ ๊ธ€์ž | ์ž…๋ ฅ์ด ๋‚จ์€ ํญ์„ ์ฑ„์šฐ๊ณ (`flex: 1`, ์ตœ์†Œ ํญ 0) ์ „์†ก ๋ฒ„ํŠผ์€ ์ค„์ง€ ์•Š๋Š”๋‹ค; ํฐ ๊ธ€์ž์—์„œ๋„ 5์ค„ ์ƒํ•œ ๋’ค ์ž…๋ ฅ ์•ˆ ์Šคํฌ๋กค๋กœ ๊ธฐ๋ก์„ ๊ฐ€๋ฆฌ์ง€ ์•Š๋Š”๋‹ค | Web `.hjm-message-composer__row`, Native `layoutStyle={{ flex: 1 }}` |
@@ -3,8 +3,8 @@
3
3
  - ๋‹จ๊ณ„: ์ปดํฌ๋„ŒํŠธ
4
4
  - ์ƒํƒœ: ๋ฐฐํฌ
5
5
  - ์ง€์›: Web ยท Native
6
- - ์ ์šฉ: ๋ฏธ๊ฒŒ์‹œ(1.12.1 ์ดํ›„)
7
- - ๊ฒ€ํ† ์ผ: 2026-10-06
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
 
@@ -111,3 +111,4 @@ import { ModerationScreen } from "@hjmds/react-native/screen-flows";
111
111
  - ์ฐจ๋‹จ ๋ฒ„ํŠผ์˜ `block.action.onAction`์€ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค. ๋ฒ„ํŠผ์€ ํ™•์ธ ๋Œ€ํ™”์ƒ์ž๋งŒ ์—ด๊ณ , ์‹ค์ œ ์ฐจ๋‹จ์€ `confirmation.onConfirm`์—์„œ ํ•œ๋‹ค.
112
112
  - ์„œ๋ฒ„ ์‹ ๊ณ ยท๊ถŒํ•œยท์ฐจ๋‹จ mutation, ์™„๋ฃŒ ํ›„ ์ด๋™์€ ์ œํ’ˆ ์†Œ์œ ๋‹ค. ์‚ฌ์œ  ๋ชฉ๋ก๊ณผ ์ •์ฑ… ๋ฌธ๊ตฌ๋„ ์ œํ’ˆ์ด ์ •ํ•œ๋‹ค.
113
113
  - ํ™•์ธ ๋Œ€ํ™”์ƒ์ž์˜ ์„ฑ๊ณต ํ›„ ๋‹ซํž˜ยท์‹คํŒจ ๋ฌธ๊ตฌ๋Š” [AlertDialog](alert-dialog.md) ๊ณ„์•ฝ์„ ๋”ฐ๋ฅธ๋‹ค.
114
+ - `block`์„ ์ œ๊ฑฐํ•˜๋ฉด ์—ด๋ฆฐ ํ™•์ธ ์„ธ์…˜๋„ ์ข…๋ฃŒํ•œ๋‹ค. ๋‚˜์ค‘์— ์ฐจ๋‹จ ํ–‰๋™์„ ๋‹ค์‹œ ๊ณต๊ธ‰ํ•ด๋„ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ์ƒˆ๋กœ ๋ˆŒ๋Ÿฌ์•ผ ํ™•์ธ์ฐฝ์ด ์—ด๋ฆฐ๋‹ค. 2026-10-13 ์‚ฌ๋ผ์ง„ ํ–‰๋™์˜ ํ™•์ธ ์ƒํƒœ๊ฐ€ ๋ถ€ํ™œํ•˜๋˜ ๊ฒฝ๋กœ๋ฅผ ์ˆ˜์ •ํ–ˆ๋‹ค. ๋Œ€์ƒ์ด ๋ฐ”๋€Œ๋Š” ์ œํ’ˆ์€ ๋Œ€์ƒ id๋ฅผ ํ™”๋ฉด key/์ดˆ์•ˆยท์š”์ฒญ ์ˆ˜๋ช…์— ํ•จ๊ป˜ ์—ฐ๊ฒฐํ•œ๋‹ค.