@hjmds/design-contracts 1.12.1 → 1.13.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 (288) hide show
  1. package/dist/avatar-fallback.d.ts +11 -0
  2. package/dist/avatar-fallback.d.ts.map +1 -1
  3. package/dist/avatar-fallback.js +21 -0
  4. package/dist/avatar-fallback.js.map +1 -1
  5. package/dist/base-recipes.d.ts +17 -0
  6. package/dist/base-recipes.d.ts.map +1 -1
  7. package/dist/base-recipes.js +17 -0
  8. package/dist/base-recipes.js.map +1 -1
  9. package/dist/catalog.d.ts +25 -0
  10. package/dist/catalog.d.ts.map +1 -1
  11. package/dist/command-palette.d.ts +14 -9
  12. package/dist/command-palette.d.ts.map +1 -1
  13. package/dist/command-palette.js +8 -9
  14. package/dist/command-palette.js.map +1 -1
  15. package/dist/component-recipes.d.ts +17 -0
  16. package/dist/component-recipes.d.ts.map +1 -1
  17. package/dist/component-recipes.js +5 -0
  18. package/dist/component-recipes.js.map +1 -1
  19. package/dist/provider-button.d.ts.map +1 -1
  20. package/dist/provider-button.js +3 -0
  21. package/dist/provider-button.js.map +1 -1
  22. package/dist/reactions.d.ts +10 -0
  23. package/dist/reactions.d.ts.map +1 -1
  24. package/dist/reactions.js +7 -0
  25. package/dist/reactions.js.map +1 -1
  26. package/dist/screen-patterns.d.ts +147 -0
  27. package/dist/screen-patterns.d.ts.map +1 -0
  28. package/dist/screen-patterns.js +149 -0
  29. package/dist/screen-patterns.js.map +1 -0
  30. package/dist/slider.d.ts +8 -0
  31. package/dist/slider.d.ts.map +1 -1
  32. package/dist/slider.js +6 -1
  33. package/dist/slider.js.map +1 -1
  34. package/dist/upload-item.d.ts +5 -0
  35. package/dist/upload-item.d.ts.map +1 -1
  36. package/dist/upload-item.js +5 -0
  37. package/dist/upload-item.js.map +1 -1
  38. package/dist/version.d.ts +1 -1
  39. package/dist/version.js +1 -1
  40. package/dist/version.js.map +1 -1
  41. package/docs/action-session.md +3 -3
  42. package/docs/agreement.md +5 -0
  43. package/docs/avatar-fallback.md +7 -0
  44. package/docs/bottom-navigation.md +6 -0
  45. package/docs/brand-boundary.md +1 -1
  46. package/docs/button-label.md +6 -0
  47. package/docs/clipboard.md +3 -0
  48. package/docs/command-palette.md +45 -2
  49. package/docs/consumer-policy.md +5 -1
  50. package/docs/data-table.md +6 -4
  51. package/docs/dialog.md +8 -2
  52. package/docs/form.md +51 -0
  53. package/docs/generated/component-maturity.md +1 -1
  54. package/docs/generated/renderer-evidence.json +3 -3
  55. package/docs/generated/renderer-evidence.md +1 -1
  56. package/docs/generated/showcase-manifest.json +1 -1
  57. package/docs/link.md +8 -0
  58. package/docs/migration-native-legacy-removal.md +45 -1
  59. package/docs/optional-adapters.md +1 -1
  60. package/docs/password-field.md +5 -0
  61. package/docs/product-composition-adoption.md +40 -0
  62. package/docs/progress.md +19 -1
  63. package/docs/provider-button.md +13 -0
  64. package/docs/result.md +3 -0
  65. package/docs/screen-chrome.md +10 -0
  66. package/docs/screen-patterns.md +376 -0
  67. package/docs/sheet.md +12 -0
  68. package/docs/splitter.md +8 -2
  69. package/docs/theming.md +36 -29
  70. package/docs/toggle-group.md +7 -0
  71. package/docs/tour.md +7 -1
  72. package/docs/tree.md +5 -2
  73. package/docs/upload-item.md +7 -0
  74. package/docs/usage/README.md +236 -0
  75. package/docs/usage/STANDARD.md +108 -0
  76. package/docs/usage/components/accordion.md +107 -0
  77. package/docs/usage/components/activity-heatmap.md +104 -0
  78. package/docs/usage/components/affix.md +86 -0
  79. package/docs/usage/components/agreement.md +129 -0
  80. package/docs/usage/components/alert-dialog.md +130 -0
  81. package/docs/usage/components/anchor.md +96 -0
  82. package/docs/usage/components/aspect-ratio.md +89 -0
  83. package/docs/usage/components/asset.md +126 -0
  84. package/docs/usage/components/auth-provider-button.md +116 -0
  85. package/docs/usage/components/auth-screen-layout.md +129 -0
  86. package/docs/usage/components/avatar.md +114 -0
  87. package/docs/usage/components/badge.md +84 -0
  88. package/docs/usage/components/bottom-cta.md +125 -0
  89. package/docs/usage/components/bottom-info.md +99 -0
  90. package/docs/usage/components/bottom-navigation.md +136 -0
  91. package/docs/usage/components/breadcrumb.md +81 -0
  92. package/docs/usage/components/button.md +118 -0
  93. package/docs/usage/components/calendar.md +122 -0
  94. package/docs/usage/components/card.md +110 -0
  95. package/docs/usage/components/carousel.md +113 -0
  96. package/docs/usage/components/celebration.md +96 -0
  97. package/docs/usage/components/chat-message.md +122 -0
  98. package/docs/usage/components/chat-screen.md +112 -0
  99. package/docs/usage/components/checkbox-group.md +104 -0
  100. package/docs/usage/components/checkbox.md +103 -0
  101. package/docs/usage/components/chip.md +104 -0
  102. package/docs/usage/components/code-block.md +111 -0
  103. package/docs/usage/components/collapsible.md +112 -0
  104. package/docs/usage/components/color-picker.md +86 -0
  105. package/docs/usage/components/combobox.md +137 -0
  106. package/docs/usage/components/command-palette.md +125 -0
  107. package/docs/usage/components/comment-thread-screen.md +125 -0
  108. package/docs/usage/components/container.md +98 -0
  109. package/docs/usage/components/content-transition.md +101 -0
  110. package/docs/usage/components/context-menu.md +136 -0
  111. package/docs/usage/components/counter-badge.md +107 -0
  112. package/docs/usage/components/data-table.md +122 -0
  113. package/docs/usage/components/date-picker.md +142 -0
  114. package/docs/usage/components/date-range-picker.md +111 -0
  115. package/docs/usage/components/description-list.md +103 -0
  116. package/docs/usage/components/design-system-provider.md +124 -0
  117. package/docs/usage/components/dialog.md +176 -0
  118. package/docs/usage/components/divider.md +89 -0
  119. package/docs/usage/components/editor-screen.md +126 -0
  120. package/docs/usage/components/effect-surface.md +120 -0
  121. package/docs/usage/components/empty-state.md +114 -0
  122. package/docs/usage/components/field.md +129 -0
  123. package/docs/usage/components/file-picker.md +114 -0
  124. package/docs/usage/components/floating-action-button.md +138 -0
  125. package/docs/usage/components/form.md +162 -0
  126. package/docs/usage/components/grid.md +99 -0
  127. package/docs/usage/components/heading.md +87 -0
  128. package/docs/usage/components/icon-button.md +126 -0
  129. package/docs/usage/components/icon.md +105 -0
  130. package/docs/usage/components/image.md +122 -0
  131. package/docs/usage/components/keyboard-avoiding.md +93 -0
  132. package/docs/usage/components/keyboard-dock.md +110 -0
  133. package/docs/usage/components/keyboard-form-scroll-view.md +95 -0
  134. package/docs/usage/components/keyboard-motion-provider.md +86 -0
  135. package/docs/usage/components/layout.md +117 -0
  136. package/docs/usage/components/link.md +121 -0
  137. package/docs/usage/components/list-detail-screen.md +103 -0
  138. package/docs/usage/components/list-row.md +124 -0
  139. package/docs/usage/components/list.md +119 -0
  140. package/docs/usage/components/load-more.md +115 -0
  141. package/docs/usage/components/masonry.md +109 -0
  142. package/docs/usage/components/media-selection-screen.md +119 -0
  143. package/docs/usage/components/mentions.md +119 -0
  144. package/docs/usage/components/menu.md +129 -0
  145. package/docs/usage/components/menubar.md +93 -0
  146. package/docs/usage/components/message-composer.md +124 -0
  147. package/docs/usage/components/moderation-screen.md +113 -0
  148. package/docs/usage/components/notice.md +106 -0
  149. package/docs/usage/components/notification-inbox-screen.md +97 -0
  150. package/docs/usage/components/notification-item.md +98 -0
  151. package/docs/usage/components/number-field.md +131 -0
  152. package/docs/usage/components/onboarding-screen.md +106 -0
  153. package/docs/usage/components/otp-field.md +101 -0
  154. package/docs/usage/components/pagination.md +82 -0
  155. package/docs/usage/components/password-field.md +137 -0
  156. package/docs/usage/components/permission-screen.md +107 -0
  157. package/docs/usage/components/photo-source-sheet.md +119 -0
  158. package/docs/usage/components/popover.md +108 -0
  159. package/docs/usage/components/profile-screen.md +89 -0
  160. package/docs/usage/components/progress.md +122 -0
  161. package/docs/usage/components/qr-code.md +122 -0
  162. package/docs/usage/components/radio-group.md +124 -0
  163. package/docs/usage/components/radio.md +104 -0
  164. package/docs/usage/components/result.md +116 -0
  165. package/docs/usage/components/saved-items-screen.md +126 -0
  166. package/docs/usage/components/screen-layout.md +119 -0
  167. package/docs/usage/components/search-field.md +120 -0
  168. package/docs/usage/components/search-screen.md +215 -0
  169. package/docs/usage/components/section.md +111 -0
  170. package/docs/usage/components/segmented-control.md +138 -0
  171. package/docs/usage/components/select.md +142 -0
  172. package/docs/usage/components/settings-screen.md +126 -0
  173. package/docs/usage/components/shared-transition-element.md +111 -0
  174. package/docs/usage/components/shared-transition-screen.md +86 -0
  175. package/docs/usage/components/sheet.md +151 -0
  176. package/docs/usage/components/side-panel.md +104 -0
  177. package/docs/usage/components/sidebar.md +107 -0
  178. package/docs/usage/components/skeleton.md +105 -0
  179. package/docs/usage/components/skip-nav.md +76 -0
  180. package/docs/usage/components/slider.md +121 -0
  181. package/docs/usage/components/sortable-collection.md +127 -0
  182. package/docs/usage/components/spinner.md +86 -0
  183. package/docs/usage/components/splitter.md +103 -0
  184. package/docs/usage/components/stack.md +93 -0
  185. package/docs/usage/components/statistic.md +123 -0
  186. package/docs/usage/components/steps.md +110 -0
  187. package/docs/usage/components/surface.md +91 -0
  188. package/docs/usage/components/swipe-actions.md +124 -0
  189. package/docs/usage/components/switch.md +120 -0
  190. package/docs/usage/components/tabs.md +134 -0
  191. package/docs/usage/components/tag.md +84 -0
  192. package/docs/usage/components/tags-input.md +111 -0
  193. package/docs/usage/components/text-area.md +112 -0
  194. package/docs/usage/components/text-format.md +75 -0
  195. package/docs/usage/components/text-transition.md +104 -0
  196. package/docs/usage/components/text.md +101 -0
  197. package/docs/usage/components/thinking-orb.md +105 -0
  198. package/docs/usage/components/timeline.md +105 -0
  199. package/docs/usage/components/toast.md +145 -0
  200. package/docs/usage/components/toggle-group.md +95 -0
  201. package/docs/usage/components/tooltip.md +103 -0
  202. package/docs/usage/components/top-bar.md +124 -0
  203. package/docs/usage/components/top.md +89 -0
  204. package/docs/usage/components/tour.md +118 -0
  205. package/docs/usage/components/transfer-list.md +115 -0
  206. package/docs/usage/components/tree.md +91 -0
  207. package/docs/usage/components/upload-item.md +99 -0
  208. package/docs/usage/components/virtual-list.md +105 -0
  209. package/docs/usage/components/visually-hidden.md +72 -0
  210. package/docs/usage/components/watermark.md +78 -0
  211. package/docs/usage/compositions/action-recovery-optimistic.md +180 -0
  212. package/docs/usage/compositions/action-recovery-save.md +235 -0
  213. package/docs/usage/compositions/action-recovery-undo.md +193 -0
  214. package/docs/usage/compositions/common-message.md +132 -0
  215. package/docs/usage/compositions/common-notification.md +101 -0
  216. package/docs/usage/compositions/compound-controls.md +186 -0
  217. package/docs/usage/compositions/data-layouts.md +157 -0
  218. package/docs/usage/compositions/disclosure.md +144 -0
  219. package/docs/usage/compositions/environment-matrix.md +139 -0
  220. package/docs/usage/compositions/expo-interactions.md +149 -0
  221. package/docs/usage/compositions/family-drawer.md +201 -0
  222. package/docs/usage/compositions/floating-action-button.md +197 -0
  223. package/docs/usage/compositions/input-sheet.md +148 -0
  224. package/docs/usage/compositions/interaction-adapters.md +190 -0
  225. package/docs/usage/compositions/interaction-flow-apply.md +205 -0
  226. package/docs/usage/compositions/interaction-flow-draft.md +188 -0
  227. package/docs/usage/compositions/interaction-flow-search.md +171 -0
  228. package/docs/usage/compositions/native-renderers.md +106 -0
  229. package/docs/usage/compositions/navigation-bar-collection.md +164 -0
  230. package/docs/usage/compositions/optional-adapters.md +169 -0
  231. package/docs/usage/compositions/optional-motion.md +109 -0
  232. package/docs/usage/compositions/photo-source.md +104 -0
  233. package/docs/usage/compositions/purpose-input-comment.md +110 -0
  234. package/docs/usage/compositions/purpose-input-message.md +119 -0
  235. package/docs/usage/compositions/reference-first.md +96 -0
  236. package/docs/usage/compositions/reference-review.md +107 -0
  237. package/docs/usage/compositions/reference-settings.md +107 -0
  238. package/docs/usage/compositions/selection-scope.md +174 -0
  239. package/docs/usage/compositions/stea-event-ticket.md +166 -0
  240. package/docs/usage/compositions/stea-flip-card.md +162 -0
  241. package/docs/usage/compositions/stea-order-progress.md +184 -0
  242. package/docs/usage/compositions/stea-otp-verify.md +215 -0
  243. package/docs/usage/compositions/stea-pixel-empty.md +140 -0
  244. package/docs/usage/compositions/stea-schedule-card.md +169 -0
  245. package/docs/usage/compositions/stea-stat-summary.md +154 -0
  246. package/docs/usage/compositions/time-selection.md +174 -0
  247. package/docs/usage/compositions/toast-layout.md +128 -0
  248. package/docs/usage/compositions/visual-foundations.md +185 -0
  249. package/docs/usage/compositions/web-additions.md +146 -0
  250. package/docs/usage/compositions/web-navigation.md +143 -0
  251. package/docs/usage/screens/common-chat.md +127 -0
  252. package/docs/usage/screens/common-comments.md +108 -0
  253. package/docs/usage/screens/common-inbox.md +110 -0
  254. package/docs/usage/screens/common-login.md +98 -0
  255. package/docs/usage/screens/common-profile.md +221 -0
  256. package/docs/usage/screens/common-saved.md +127 -0
  257. package/docs/usage/screens/common-search.md +274 -0
  258. package/docs/usage/screens/common-settings.md +126 -0
  259. package/docs/usage/screens/common-shell.md +108 -0
  260. package/docs/usage/screens/dashboard.md +245 -0
  261. package/docs/usage/screens/discovery-gallery.md +306 -0
  262. package/docs/usage/screens/flow-collection.md +96 -0
  263. package/docs/usage/screens/flow-editor.md +120 -0
  264. package/docs/usage/screens/flow-media.md +111 -0
  265. package/docs/usage/screens/flow-moderation.md +120 -0
  266. package/docs/usage/screens/flow-onboarding.md +193 -0
  267. package/docs/usage/screens/flow-permission.md +103 -0
  268. package/docs/usage/screens/landing.md +347 -0
  269. package/docs/usage/screens/mockup-studio.md +190 -0
  270. package/docs/usage/screens/notification-settings.md +206 -0
  271. package/docs/usage/screens/reference-comparison.md +159 -0
  272. package/docs/usage/templates/component.md +61 -0
  273. package/docs/usage/templates/composition.md +47 -0
  274. package/docs/usage/templates/screen.md +56 -0
  275. package/docs/usage/templates/token.md +32 -0
  276. package/docs/usage/tokens/color.md +142 -0
  277. package/docs/usage/tokens/elevation-opacity.md +86 -0
  278. package/docs/usage/tokens/layers.md +98 -0
  279. package/docs/usage/tokens/layout.md +114 -0
  280. package/docs/usage/tokens/motion.md +88 -0
  281. package/docs/usage/tokens/radius.md +53 -0
  282. package/docs/usage/tokens/size.md +74 -0
  283. package/docs/usage/tokens/spacing.md +73 -0
  284. package/docs/usage/tokens/stroke.md +50 -0
  285. package/docs/usage/tokens/theme-studio.md +70 -0
  286. package/docs/usage/tokens/typography-studio.md +70 -0
  287. package/docs/usage/tokens/typography.md +89 -0
  288. package/package.json +7 -1
@@ -0,0 +1,206 @@
1
+ # 알림 설정
2
+
3
+ - 단계: 화면
4
+ - 상태: 배포
5
+ - 지원: Web · Native
6
+ - 적용: 1.12.1
7
+ - 검토일: 2026-10-06
8
+ - 근거: `showcase/web/src/patterns/NotificationSettings.stories.tsx`, `showcase/native/src/NotificationSettings.stories.tsx`, `src/component-recipes.ts`(`topBarRecipe`·`bottomCtaRecipe`·`sectionRecipe`·`switchRecipe`), `src/container.ts`, `src/responsive.ts`(`resolveWindowClass`), `packages/react/src/styles.css`(`.hjm-top-bar`·`.hjm-bottom-cta`)
9
+ - 스토리북: `배포/화면/설정/알림 설정`
10
+
11
+ ## 목적
12
+
13
+ 알림 종류 몇 개를 스위치로 켜고 끈 뒤 하단 버튼 하나로 저장하는 설정 화면이다. 상단 바 · 읽기 폭 본문 · 하단 행동 바의
14
+ 세 층으로 된 화면 골격의 기준 예다. 스위치를 바꾸는 즉시 서버에 반영하는 설정이면 하단 저장 바를 빼고 각 Switch의
15
+ `onCheckedChange`에서 저장한다.
16
+
17
+ ## 영역 구조
18
+
19
+ ```text
20
+ 좁은 폭(Native·모바일 Web) — 상단·하단 바 고정, 본문만 스크롤
21
+ ┌ 상단 안전 영역(TopBar safeAreaTop, Web은 env()와 큰 값) ┐
22
+ │ ① TopBar 알림 설정 │ 최소 높이 52, 좌우 spacing.md 16 (고정)
23
+ ├──────────────────────────────────────────────┤ ↕ spacing.lg 20
24
+ │ ② Container reading (최대 720, │ ─ 스크롤 ─
25
+ │ 좌우 gutter: 폭<600 compact 16 · 이상 20) │
26
+ │ Section │
27
+ │ 필요한 소식만 받아요 ← title │ title-description spacing.xxs 4
28
+ │ 원하는 알림을 골라 주세요… ← description │ 머리-내용 spacing.xs 8
29
+ │ ┌────────────────────────────────────────┐ │
30
+ │ │ 내 활동 알림 (●──) │ │ Switch presentation=row
31
+ │ │ 댓글과 답글이 도착하면… │ │ 라벨 왼쪽, 스위치 끝
32
+ │ │ ↕ spacing.md 16 │ │
33
+ │ │ 주간 모아보기 (──○) │ │
34
+ │ │ 일주일의 소식을 한 번에… │ │
35
+ │ └────────────────────────────────────────┘ │
36
+ │ ┌ Notice success(저장 후) · danger(실패) ┐ │
37
+ │ └────────────────────────────────────────┘ │
38
+ ├──────────────────────────────────────────────┤ ↕ 20
39
+ │ ③ BottomCTA (위 테두리 1 + 위쪽 그림자) │ 최소 높이 64 (고정)
40
+ │ 선택한 알림만 보내드릴게요. ← description │ caption, muted
41
+ │ [ 이 설정으로 저장하기 ] │ ← 주 행동, 폭 전체
42
+ └ 하단 안전 영역(BottomCTA safeAreaBottom) ────┘
43
+ ```
44
+
45
+ 넓은 폭 Web: TopBar와 BottomCTA는 화면 폭 전체, 본문만 Container `reading`으로 가운데 720 폭에 묶인다.
46
+
47
+ | 영역 | 컴포넌트 | 위치 | 크기·간격 |
48
+ | --- | --- | --- | --- |
49
+ | 바깥 틀 | Web `main` > `Stack gap="lg"` > TopBar · Container · BottomCTA `position="sticky"`, 문서 스크롤 · Native `View`(`flex: 1`) > TopBar · `ScrollView contentContainerStyle={{ paddingVertical: spacing.lg }}` > Container · BottomCTA | 화면 전체. 본문만 스크롤하고 하단 바는 고정(Web TopBar는 고정 prop이 없어 문서와 함께 움직이며, 고정하려면 제품 레이아웃이 맡는다) | 세 층 사이 `spacing.lg` 20(Web Stack gap, Native ScrollView 위아래 여백). 좌우 여백은 Container gutter. 안전 영역: 위는 TopBar `safeAreaTop`, 아래는 BottomCTA `safeAreaBottom`(Native는 기기 inset을 넘긴다, 기본 0). 키보드 입력이 없어 키보드 처리는 없다 |
50
+ | ① 상단 바 | TopBar `title` | 맨 위 | 최소 높이 52(`control.buttonHeight.large`), 좌우 `spacing.md` 16, 슬롯 사이 `spacing.xs` 8, 양 끝 슬롯 최소 44 |
51
+ | ② 본문 | Container `size="reading"` `gutter={gutter}` > Section `title` `description` > Stack `gap="md"` > Switch `presentation="row"` ×n, 그 아래 Notice | 상단 바 아래, 스크롤 | 최대 폭 720(`layout.readingMaxWidth`), 좌우 gutter 폭 600 미만 `compact` 16 · 이상 `regular` 20(`layout.pagePadding`), 스위치 사이 `spacing.md` 16, 트랙 52×32 |
52
+ | ③ 하단 행동 | BottomCTA `description` `primaryAction` | 맨 아래 고정. Web `position="sticky"`(`inset-block-end: 0`, `z-index: var(--hjm-layer-sticky)`), Native는 `ScrollView` 바깥 | 최소 높이 64, 위아래 `spacing.sm` 12 + 안전 영역(`max(safeAreaBottom, spacing.sm 12)`), 좌우 `layout.pagePadding.regular` 20, 설명-버튼 `spacing.sm` 12 |
53
+
54
+ gutter는 창 폭으로 고른다: `resolveWindowClass(width) === "compact" ? "compact" : "regular"`([화면 여백과 너비](../tokens/layout.md)).
55
+ 상단·스크롤 본문·하단 행동은 별도 영역으로 둔다. 목록이 길어져도 저장 행동이 본문과 함께 밀려나지 않는다.
56
+
57
+ ```text
58
+ Native 고정 배치
59
+ ┌ TopBar safeAreaTop={insets.top} ─────┐ 고정
60
+ ├ ScrollView paddingVertical 20 ───────┤
61
+ │ Container > Section > Switch … │ 스크롤
62
+ ├ BottomCTA safeAreaBottom={insets.bottom} ┤ 고정
63
+ └──────────────────────────────────────┘
64
+ ```
65
+
66
+ ## 버튼과 행동 위치
67
+
68
+ | 행동 | 컴포넌트·tone | 위치 | 개수·순서 |
69
+ | --- | --- | --- | --- |
70
+ | 저장(주 행동) | BottomCTA `primaryAction`(primary, 폭 전체) | 화면 맨 아래 바 | 1. 저장 중 `loading`, 저장 뒤에는 라벨을 `t("settings.saved")`로 바꾸고 `disabled` |
71
+ | 보조 행동 | BottomCTA `secondaryAction`(기본 `secondary`) | 같은 바, 주 행동 앞(왼쪽) | 스토리에는 없음. 둘 다 있으면 [보조][주] 같은 폭으로 나뉜다 |
72
+ | 항목 켜기·끄기 | Switch `presentation="row"` 행 전체 | 본문 Section 안 | 항목 수만큼, 위→아래 |
73
+ | 다시 불러오기 | Notice `action` > Button `tone="secondary" size="small"` | 불러오기 실패 Notice 안 | 스토리에 없음. 1 |
74
+ | 뒤로 | TopBar `leading` | 상단 바 시작 끝 | 스토리에는 없음. 하위 설정 화면이면 1 |
75
+ | 파괴 행동 | — | — | 없음 |
76
+
77
+ ## 상태
78
+
79
+ | 상태 | 화면 모습 | 행동 |
80
+ | --- | --- | --- |
81
+ | 기본 | 스위치가 현재 값, 저장 버튼 활성 | 스위치 바꾸기, 저장 |
82
+ | 로딩 | 스토리에 없음. 첫 값을 불러오는 동안 Section 안 스위치 자리에 [Skeleton](../components/skeleton.md) `shape="text"`, 저장 버튼 `disabled`. 저장 중이면 `primaryAction`에 `loading`(누름을 막고 같은 자리에 스피너) | 기다림 |
83
+ | 빈 | 해당 없음(설정 항목은 항상 있다). 항목이 조건부면 Section 아래 안내 Text | — |
84
+ | 오류 | 스토리에 없음. **불러오기 실패**: 스위치 대신 [Notice](../components/notice.md) `tone="danger"` + `action` 다시 시도, 저장 버튼 `disabled`. **저장 실패**: Section 끝에 Notice `tone="danger"`(action 없음 — 다시 시도는 저장 버튼이 맡는다), 사용자가 고른 스위치 값을 그대로 두고 `loading`만 푼다. 문구는 네트워크 실패 `settings.error.offline`·서버 실패 `settings.error.server`로 나눈다. 다시 시도가 또 실패하면 같은 Notice가 같은 자리에 남고 문구만 갱신한다. Native는 `announcement="assertive"`(기본 `none`) | 다시 시도 / 다시 저장 |
85
+ | 저장됨 | Section 끝에 Notice `tone="success"`(제목 + 켜짐/꺼짐 요약). 버튼은 "저장했어요"로 바뀌고 비활성. Native Notice `announcement="polite"` | 스위치를 다시 바꾸면 저장 상태가 풀린다 |
86
+
87
+ ## 사용하는 지침
88
+
89
+ | 지침 | 쓰는 곳 |
90
+ | --- | --- |
91
+ | [TopBar](../components/top-bar.md) | ① 상단 바 |
92
+ | [Container](../components/container.md) | ② 읽기 폭 |
93
+ | [Section](../components/section.md) | ② 설정 묶음 제목·설명 |
94
+ | [Switch](../components/switch.md) | ② 항목 행 |
95
+ | [Notice](../components/notice.md) | 저장 결과·오류 |
96
+ | [Skeleton](../components/skeleton.md) | 첫 값 불러오기 |
97
+ | [BottomCTA](../components/bottom-cta.md) | ③ 하단 저장 |
98
+ | [Stack](../components/stack.md) | 세 층 사이, 스위치 목록 |
99
+ | [화면 여백과 너비](../tokens/layout.md) | `layout.readingMaxWidth`, `layout.pagePadding.compact`·`regular`, `resolveWindowClass` |
100
+ | [간격](../tokens/spacing.md) | `spacing.xxs`·`xs`·`sm`·`md`·`lg` |
101
+
102
+ ## 코드 골격
103
+
104
+ 설정 항목·문구는 제품 소유다. 문구 키는 상태→키 표로 고르고 템플릿 문자열로 만들지 않는다.
105
+
106
+ ```tsx
107
+ // Web
108
+ import { TopBar } from "@hjmds/react/top-bar";
109
+ import { BottomCTA } from "@hjmds/react/bottom-cta";
110
+ import { Container, Stack, Section } from "@hjmds/react/layout";
111
+ import { Switch } from "@hjmds/react/selection";
112
+ import { Notice, Skeleton } from "@hjmds/react/feedback";
113
+ import { Button } from "@hjmds/react/actions";
114
+ import { resolveWindowClass } from "@hjmds/design-contracts/responsive";
115
+
116
+ const failureKey = { offline: "settings.error.offline", server: "settings.error.server" } as const;
117
+ const onOffKey = { on: "settings.on", off: "settings.off" } as const;
118
+
119
+ const gutter = resolveWindowClass(window.innerWidth) === "compact" ? "compact" : "regular";
120
+ const summary = t("settings.saved.summary", {
121
+ activity: t(onOffKey[activity ? "on" : "off"]),
122
+ digest: t(onOffKey[digest ? "on" : "off"]),
123
+ });
124
+
125
+ <main><Stack gap="lg">
126
+ <TopBar title={t("settings.notifications.title")} />
127
+ <Container size="reading" gutter={gutter}>
128
+ <Section title={t("settings.notifications.section")} description={t("settings.notifications.hint")}>
129
+ {status === "loading" ? <Stack gap="md"><Skeleton shape="text" width="60%" /><Skeleton shape="text" width="40%" /></Stack> : null}
130
+ {status === "loadFailed" && failure ? <Notice tone="danger" title={t(failureKey[failure])}
131
+ action={<Button tone="secondary" size="small" onClick={reload}>{t("common.retry")}</Button>} /> : null}
132
+ {status === "ready" ? <Stack gap="md">
133
+ <Switch presentation="row" label={t("settings.activity")} description={t("settings.activity.hint")}
134
+ checked={activity} onCheckedChange={v => { setActivity(v); setSaved(false); }} />
135
+ </Stack> : null}
136
+ {status === "ready" && failure ? <Notice tone="danger" title={t(failureKey[failure])} description={t("settings.error.kept")} /> : null}
137
+ {saved ? <Notice tone="success" title={t("settings.saved.title")} description={summary} /> : null}
138
+ </Section>
139
+ </Container>
140
+ <BottomCTA position="sticky" description={t("settings.cta.hint")}
141
+ primaryAction={{ label: saved ? t("settings.saved") : t("settings.save"), onClick: save, loading: saving, disabled: saved || status !== "ready" }} />
142
+ </Stack></main>
143
+ ```
144
+
145
+ ```tsx
146
+ // Native — 상단·하단 바를 고정한 형태
147
+ import { ScrollView, View, useWindowDimensions } from "react-native";
148
+ import { useSafeAreaInsets } from "react-native-safe-area-context"; // 제품 의존성
149
+ import { spacing } from "@hjmds/design-contracts/foundations";
150
+ import { resolveWindowClass } from "@hjmds/design-contracts/responsive";
151
+ import { TopBar } from "@hjmds/react-native/top-bar";
152
+ import { BottomCTA } from "@hjmds/react-native/bottom-cta";
153
+ import { Container, Stack, Section } from "@hjmds/react-native/primitives";
154
+ import { Switch } from "@hjmds/react-native/inputs";
155
+ import { Notice } from "@hjmds/react-native/feedback";
156
+
157
+ const failureKey = { offline: "settings.error.offline", server: "settings.error.server" } as const;
158
+ const insets = useSafeAreaInsets();
159
+ const { width } = useWindowDimensions();
160
+ const gutter = resolveWindowClass(width) === "compact" ? "compact" : "regular";
161
+
162
+ <View style={{ flex: 1 }}>
163
+ <TopBar title={t("settings.notifications.title")} safeAreaTop={insets.top} />
164
+ <ScrollView contentContainerStyle={{ paddingVertical: spacing.lg }}>
165
+ <Container size="reading" gutter={gutter}>
166
+ <Section title={t("settings.notifications.section")} description={t("settings.notifications.hint")}>
167
+ <Stack gap="md">
168
+ <Switch presentation="row" label={t("settings.activity")} description={t("settings.activity.hint")}
169
+ checked={activity} onCheckedChange={v => { setActivity(v); setSaved(false); }} />
170
+ </Stack>
171
+ {failure ? <Notice announcement="assertive" tone="danger" title={t(failureKey[failure])} description={t("settings.error.kept")} /> : null}
172
+ {saved ? <Notice announcement="polite" tone="success" title={t("settings.saved.title")} description={summary} /> : null}
173
+ </Section>
174
+ </Container>
175
+ </ScrollView>
176
+ <BottomCTA safeAreaBottom={insets.bottom} description={t("settings.cta.hint")}
177
+ primaryAction={{ label: saved ? t("settings.saved") : t("settings.save"), onPress: save, loading: saving, disabled: saved }} />
178
+ </View>
179
+ ```
180
+
181
+ `react-native-safe-area-context`는 HJM 의존성이 아니다. 제품이 쓰는 inset 출처를 넘긴다. Native 로딩·불러오기 실패는 Web과 같은
182
+ 자리에 같은 컴포넌트를 둔다(Button은 `onPress`).
183
+
184
+ ## 큰 글자·다크·좁은 폭
185
+
186
+ | 조건 | 바뀌는 것 |
187
+ | --- | --- |
188
+ | 큰 글자(글자 배율 ≥ 1.6, `largeTextThreshold`) | TopBar 제목이 둘째 줄로 내려가 시작 정렬된다. BottomCTA 버튼이 세로로 쌓이고 **주 행동이 위**(`column-reverse`). Switch 행은 설명이 좁은 열이 되지 않게 세로로 쌓인다 |
189
+ | 다크 | 테마 토큰만 쓴다. Switch 꺼짐 상태는 트랙·손잡이 테두리(`trackOffBorder`·`thumbOffBorder`)로 다크에서도 모양이 보인다 |
190
+ | 좁은 폭 | 폭 600 미만이면 Container gutter `compact` 16. Section 머리는 Web 640 이하에서 제목·행동을 세로로 쌓는다 |
191
+ | 넓은 폭 Web | 본문만 720 폭 가운데, 상단·하단 바는 전체 폭 |
192
+
193
+ ## 플랫폼 차이
194
+
195
+ | 항목 | Web | Native |
196
+ | --- | --- | --- |
197
+ | Switch 기본 배치 | `inline`(행으로 쓰려면 `presentation="row"` 명시) | `row` |
198
+ | 하단 바 고정 | `position="sticky"` | prop 없음 — `ScrollView` 바깥에 둔다 |
199
+ | 안전 영역 | CSS `env(safe-area-inset-*)`와 `safeAreaTop`/`safeAreaBottom` 중 큰 값 | `safeAreaTop`/`safeAreaBottom`만(기본 0) |
200
+ | 저장·오류 알림 | Notice가 `role="status"` | Notice `announcement` 명시(기본 `none`): 저장됨 `polite`, 오류 `assertive` |
201
+ | 스토리 상태 | 기본·큰 글자(어두운 테마 스토리 없음) | 기본만 |
202
+
203
+ ## 함정
204
+
205
+ - Native에서 `safeAreaBottom`을 넘기지 않으면 홈 인디케이터가 저장 버튼 위에 겹친다. 기본값은 0이다.
206
+ - 현재 스토리는 저장 요약 문구를 템플릿 문자열(`내 활동 ${…}`)로 조립한다. 제품은 위 코드처럼 켜짐/꺼짐 키 표와 보간 값을 쓴다.
@@ -0,0 +1,159 @@
1
+ # 기록 표현 비교
2
+
3
+ - 단계: 화면
4
+ - 상태: 배포
5
+ - 지원: Web · Native
6
+ - 적용: 미게시(1.12.1 이후)
7
+ - 검토일: 2026-10-06
8
+ - 근거: [반복 화면 조합](../../screen-patterns.md); 공통 API와 실제 Web·Native 예제의 슬롯·상태를 대조해 중복 조립 방지. 2026-10-06 사용자 승인으로 스토리북 배포(이전 `실험/화면/표현 비교/같은 기록의 세 가지 구성`, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
9
+ - 스토리북: `배포/화면/화면 틀과 도구/기록 표현 비교`
10
+
11
+ ## 목적
12
+
13
+ ScreenLayout을 사용해 같은 기록의 세 가지 구성 흐름을 구성한다. 제품이 데이터·권한·서버 확정·문구를 공급하며, 예제의 메모리 저장을 운영 저장으로 취급하지 않는다.
14
+
15
+ ## 영역 구조
16
+
17
+ ```text
18
+ host: 남은 높이·safe area·키보드
19
+ └─ 표현 방식 선택 → 검색 → 같은 데이터 목록·읽기·이미지 표현
20
+ ```
21
+
22
+ | 영역 | 컴포넌트 | 위치 | 크기·간격 |
23
+ | --- | --- | --- | --- |
24
+ | 바깥 틀 | ScreenLayout | route 본문 | [API 배치 규칙](../components/screen-layout.md#배치), host 남은 높이 |
25
+ | 내용 | Stack `gap="xl"` > SegmentedControl → SearchField → 상태 문구 → 카드(Surface `padding="lg"`) | 표현 방식 선택 → 검색 → 같은 데이터 목록·읽기·이미지 표현 | 구획 사이 `spacing.xl` 24. 목록·읽기는 Stack `gap="lg"` 한 열, 이미지는 Grid 두 열(`minColumnWidth` 240 = `spacing.xxxl` 40 × 6) |
26
+ | 상태 | state 또는 해당 API 상태 | 본문 자리·비차단 notice | 입력 중 실패는 본문 높이와 초안을 유지 |
27
+
28
+ ## 버튼과 행동 위치
29
+
30
+ | 행동 | 컴포넌트·tone | 위치 | 개수·순서 |
31
+ | --- | --- | --- | --- |
32
+ | 보기 방식 | SegmentedControl(`label` 보기 방식) | 검색 위 | 세 값, 항상 하나 선택 |
33
+ | 읽기 · 저장 | Button secondary · Button secondary `selected` | 카드 아래 | 카드마다 [읽기][저장] |
34
+ | 검색 초기화 | EmptyState `action` > Button secondary | 결과 없음 자리 | 하나. 이 화면에는 primary가 없다 |
35
+ | 읽기 마치기 | Button(Sheet footer) | 상세 Sheet | 하나 |
36
+
37
+ ## 상태
38
+
39
+ | 상태 | 화면 모습 | 행동 |
40
+ | --- | --- | --- |
41
+ | 기본 | 표현 방식 선택 → 검색 → 같은 데이터 목록·읽기·이미지 표현 | 각 공개 콜백을 제품 상태에 연결 |
42
+ | 로딩 | 최초 조회는 본문 상태, 저장은 해당 행동 pending | 중복 제출 차단; 성공을 먼저 표시하지 않음 |
43
+ | 빈 | 검색 결과 0건: EmptyState `compact`(상태 문구는 0개로 남는다) | `검색 초기화` |
44
+ | 오류 | 데모 저장은 메모리에서만 유지; 표현 전환은 검색·저장 상태를 초기화하지 않음 | 실패 원인과 재시도 경로 제공 |
45
+
46
+ ## 사용하는 지침
47
+
48
+ | 지침 | 쓰는 곳 |
49
+ | --- | --- |
50
+ | [ScreenLayout](../components/screen-layout.md) | 필수 props·슬롯·플랫폼 차이 |
51
+ | [Button](../components/button.md) | 동작·로딩·보조 행동 |
52
+ | [SearchField](../components/search-field.md) | 같은 기록 검색 |
53
+ | [SegmentedControl](../components/segmented-control.md) | 보기 방식 전환 |
54
+ | [Heading](../components/heading.md) | 카드 제목(읽기 중심 `level4`, 나머지 `level5`) |
55
+ | [Grid](../components/grid.md) | 이미지 중심 두 열 |
56
+ | [EmptyState](../components/empty-state.md) | 결과 없음 |
57
+
58
+ ## 코드 골격
59
+
60
+ ```tsx
61
+ // Web
62
+ import { Button } from "@hjmds/react/actions";
63
+ import { SearchField } from "@hjmds/react/forms";
64
+ import { EmptyState } from "@hjmds/react/feedback";
65
+ import { Heading } from "@hjmds/react/heading";
66
+ import { Stack, Surface, Text } from "@hjmds/react/layout";
67
+ import { SegmentedControl } from "@hjmds/react/selection";
68
+ import { ScreenLayout } from "@hjmds/react/screens";
69
+
70
+ // 보기 방식 id → 문구 키 표. 템플릿으로 만든 키는 키 추출·누락 검사가 찾지 못한다.
71
+ const modeKey = { list: "records.mode.list", reading: "records.mode.reading", image: "records.mode.image" } as const;
72
+ type Mode = keyof typeof modeKey;
73
+
74
+ <ScreenLayout
75
+ title={t("records.compare.title")}
76
+ description={t("records.compare.intro")}
77
+ state={loading ? { kind: "loading", title: t("records.loading") } : { kind: "ready" }}
78
+ >
79
+ <Stack gap="xl">
80
+ <SegmentedControl label={t("records.mode.label")} value={mode} onValueChange={(value) => setMode(value as Mode)}
81
+ items={(Object.keys(modeKey) as Mode[]).map((value) => ({ value, label: t(modeKey[value]) }))} />
82
+ <SearchField label={t("records.search")} clearLabel={t("common.clearSearch")} value={query} onValueChange={setQuery} />
83
+ <Text role="status">{t("records.count", { count: results.length })}</Text>
84
+ {results.map((record) => (
85
+ <Surface key={record.id} padding="lg">
86
+ <Stack gap={mode === "list" ? "sm" : "lg"}>
87
+ <Text tone="muted" variant="caption">{record.category}</Text>
88
+ <Heading level={mode === "reading" ? "level4" : "level5"} semanticLevel={2}>{record.title}</Heading>
89
+ {mode !== "list" ? <Text>{record.body}</Text> : null}
90
+ <Stack axis="inline" wrap gap="sm">
91
+ <Button tone="secondary" onClick={() => openRecord(record.id)}>{t("records.read", { title: record.title })}</Button>
92
+ <Button tone="secondary" selected={savedIds.includes(record.id)} onClick={() => toggleSaved(record.id)}>{t("records.save")}</Button>
93
+ </Stack>
94
+ </Stack>
95
+ </Surface>
96
+ ))}
97
+ {results.length === 0 ? <EmptyState density="compact" title={t("records.empty")}
98
+ action={<Button tone="secondary" onClick={() => setQuery("")}>{t("records.resetSearch")}</Button>} /> : null}
99
+ </Stack>
100
+ </ScreenLayout>
101
+ ```
102
+
103
+ ```tsx
104
+ // Native
105
+ import { Button } from "@hjmds/react-native/actions";
106
+ import { EmptyState } from "@hjmds/react-native/feedback";
107
+ import { Heading } from "@hjmds/react-native/heading";
108
+ import { SearchField, SegmentedControl } from "@hjmds/react-native/inputs";
109
+ import { Stack, Surface, Text } from "@hjmds/react-native/primitives";
110
+ import { ScreenLayout } from "@hjmds/react-native/screens";
111
+
112
+ const modeKey = { list: "records.mode.list", reading: "records.mode.reading", image: "records.mode.image" } as const;
113
+ type Mode = keyof typeof modeKey;
114
+
115
+ <ScreenLayout
116
+ title={t("records.compare.title")}
117
+ description={t("records.compare.intro")}
118
+ state={loading ? { kind: "loading", title: t("records.loading") } : { kind: "ready" }}
119
+ >
120
+ <Stack gap="xl">
121
+ <SegmentedControl label={t("records.mode.label")} value={mode} onValueChange={setMode}
122
+ items={(Object.keys(modeKey) as Mode[]).map((value) => ({ value, label: t(modeKey[value]) }))} />
123
+ <SearchField label={t("records.search")} clearLabel={t("common.clearSearch")} busyLabel={t("common.searching")} value={query} onValueChange={setQuery} />
124
+ <Text accessibilityRole="text" accessibilityLiveRegion="polite">{t("records.count", { count: results.length })}</Text>
125
+ {results.map((record) => (
126
+ <Surface key={record.id} padding="lg">
127
+ <Stack gap={mode === "list" ? "sm" : "lg"}>
128
+ <Text tone="muted" variant="caption">{record.category}</Text>
129
+ <Heading level={mode === "reading" ? "level4" : "level5"}>{record.title}</Heading>
130
+ {mode !== "list" ? <Text>{record.body}</Text> : null}
131
+ <Stack axis="inline" wrap gap="sm">
132
+ <Button tone="secondary" onPress={() => openRecord(record.id)}>{t("records.read", { title: record.title })}</Button>
133
+ <Button tone="secondary" selected={savedIds.includes(record.id)} onPress={() => toggleSaved(record.id)}>{t("records.save")}</Button>
134
+ </Stack>
135
+ </Stack>
136
+ </Surface>
137
+ ))}
138
+ {results.length === 0 ? <EmptyState density="compact" announcement="polite" title={t("records.empty")}
139
+ action={<Button tone="secondary" onPress={() => setQuery("")}>{t("records.resetSearch")}</Button>} /> : null}
140
+ </Stack>
141
+ </ScreenLayout>
142
+ ```
143
+
144
+ 기록·검색·저장은 제품 상태다. 표현 전환은 같은 `results`를 다시 그리기만 하고 검색어·저장 상태를 초기화하지 않는다. 콜백·데이터·지역화 함수는 제품에서 공급한다. Web·Native import와 필수 props는 위 API 지침에서 확인한다.
145
+
146
+ ## 큰 글자·다크·좁은 폭
147
+
148
+ | 조건 | 바뀌는 것 |
149
+ | --- | --- |
150
+ | 큰 글자 | 2배 글자에서 제목·행은 내용 높이로 증가. footer·닫기·입력 필드가 겹치지 않는지 확인 |
151
+ | 다크 | semantic 색으로 내용과 표면을 함께 전환; 예제 브랜드 색을 제품 기본값으로 복사하지 않음 |
152
+ | 좁은 폭 | 320px부터 한 열로 읽기 순서 유지. 가상화 본문은 scroll=content, 중첩 스크롤 금지 |
153
+ | 키보드 | Native host가 safe area와 키보드를 한 번 처리; Web은 포커스된 입력과 footer 가림 확인 |
154
+
155
+ ## 함정
156
+
157
+ - 데모 저장은 메모리에서만 유지; 표현 전환은 검색·저장 상태를 초기화하지 않음.
158
+ - 결과 개수 문구는 Web `Text role="status"`, Native는 iOS 알림을 보내는 live region(예제의 `PatternStatus`)으로 둔다. Native `accessibilityLiveRegion`만으로는 iOS에서 읽히지 않는다.
159
+ - Storybook은 실제 서버·OS 권한·라우터 연동 증거가 아니다. 기본·다크·큰 글자와 실패/복구를 각각 확인한다.
@@ -0,0 +1,61 @@
1
+ # ComponentName
2
+
3
+ - 단계: 컴포넌트
4
+ - 상태: 배포
5
+ - 지원: Web · Native
6
+ - 적용: 1.12.1
7
+ - 검토일: YYYY-MM-DD
8
+ - 근거: `../../<계약 문서>.md`, `src/file.ts`
9
+ - 스토리북: `배포/컴포넌트/...`
10
+
11
+ ## 언제 쓰나
12
+
13
+ <한 문장 요약>다.
14
+
15
+ ## 쓰지 않을 때
16
+
17
+ | 상황 | 대신 쓸 것 |
18
+ | --- | --- |
19
+
20
+ ## 공개 이름과 import
21
+
22
+ | 이름 | 역할 | Web | Native |
23
+ | --- | --- | --- | --- |
24
+
25
+ ## 최소 사용 예
26
+
27
+ ```tsx
28
+ // Web
29
+ ```
30
+
31
+ ```tsx
32
+ // Native
33
+ ```
34
+
35
+ ## 축과 기본값
36
+
37
+ | prop | 값 | 기본값 | 설명 |
38
+ | --- | --- | --- | --- |
39
+
40
+ ## 배치
41
+
42
+ | 항목 | 값 | 근거 |
43
+ | --- | --- | --- |
44
+ | 크기 | | |
45
+ | 간격 | | |
46
+ | 순서·정렬 | | |
47
+ | 고정·스크롤 | | |
48
+ | 좁은 폭·큰 글자 | | |
49
+
50
+ ## 꼭 지킬 것
51
+
52
+ -
53
+
54
+ ## 플랫폼 차이
55
+
56
+ | 항목 | Web | Native |
57
+ | --- | --- | --- |
58
+
59
+ ## 함정
60
+
61
+ -
@@ -0,0 +1,47 @@
1
+ # 이름
2
+
3
+ - 단계: 구성
4
+ - 상태: 배포
5
+ - 지원: Web · Native
6
+ - 적용: 1.12.1
7
+ - 검토일: YYYY-MM-DD
8
+ - 근거: `../../<계약 문서>.md`, `src/file.ts`
9
+ - 스토리북: `배포/구성/...`
10
+
11
+ ## 언제 쓰나
12
+
13
+ <한 문장 요약>다.
14
+
15
+ ## 구성 요소
16
+
17
+ | 컴포넌트 | 역할 | 지침 |
18
+ | --- | --- | --- |
19
+
20
+ ## 배치
21
+
22
+ ```text
23
+ ```
24
+
25
+ | 영역 | 컴포넌트 | 위치 | 크기·간격 |
26
+ | --- | --- | --- | --- |
27
+ | 바깥 틀 | | | |
28
+
29
+ ## 흐름과 상태
30
+
31
+ 1.
32
+
33
+ | 상태 | 모습 | 포커스·알림 |
34
+ | --- | --- | --- |
35
+ | 기본 | | |
36
+ | 진행 중 | | |
37
+ | 실패 | | |
38
+
39
+ ## 코드 골격
40
+
41
+ ```tsx
42
+ // Web
43
+ ```
44
+
45
+ ```tsx
46
+ // Native
47
+ ```
@@ -0,0 +1,56 @@
1
+ # 이름
2
+
3
+ - 단계: 화면
4
+ - 상태: 배포
5
+ - 지원: Web · Native
6
+ - 적용: 1.12.1
7
+ - 검토일: YYYY-MM-DD
8
+ - 근거: `../../<계약 문서>.md`, `src/file.ts`
9
+ - 스토리북: `배포/화면/...`
10
+
11
+ ## 목적
12
+
13
+ <한 문장 요약>다.
14
+
15
+ ## 영역 구조
16
+
17
+ ```text
18
+ ```
19
+
20
+ | 영역 | 컴포넌트 | 위치 | 크기·간격 |
21
+ | --- | --- | --- | --- |
22
+ | 바깥 틀 | | | |
23
+
24
+ ## 버튼과 행동 위치
25
+
26
+ | 행동 | 컴포넌트·tone | 위치 | 개수·순서 |
27
+ | --- | --- | --- | --- |
28
+
29
+ ## 상태
30
+
31
+ | 상태 | 화면 모습 | 행동 |
32
+ | --- | --- | --- |
33
+ | 기본 | | |
34
+ | 로딩 | | |
35
+ | 빈 | | |
36
+ | 오류 | | |
37
+
38
+ ## 사용하는 지침
39
+
40
+ | 지침 | 쓰는 곳 |
41
+ | --- | --- |
42
+
43
+ ## 코드 골격
44
+
45
+ ```tsx
46
+ // Web
47
+ ```
48
+
49
+ ```tsx
50
+ // Native
51
+ ```
52
+
53
+ ## 큰 글자·다크·좁은 폭
54
+
55
+ | 조건 | 바뀌는 것 |
56
+ | --- | --- |
@@ -0,0 +1,32 @@
1
+ # 이름
2
+
3
+ - 단계: 토큰
4
+ - 상태: 배포
5
+ - 지원: Web · Native
6
+ - 적용: 1.12.1
7
+ - 검토일: YYYY-MM-DD
8
+ - 근거: `../../<계약 문서>.md`, `src/file.ts`
9
+ - 스토리북: `배포/토큰/...`
10
+
11
+ ## 언제 쓰나
12
+
13
+ <한 문장 요약>다.
14
+
15
+ ## 값
16
+
17
+ | 토큰 | 값 | Web CSS 변수 | Native 경로 | 용도 |
18
+ | --- | --- | --- | --- | --- |
19
+
20
+ ## 쓰는 법
21
+
22
+ ```tsx
23
+ // Web
24
+ ```
25
+
26
+ ```tsx
27
+ // Native
28
+ ```
29
+
30
+ ## 하지 말 것
31
+
32
+ -