@hjmds/design-contracts 1.26.0 → 1.27.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 (278) hide show
  1. package/dist/agreement.d.ts +1 -0
  2. package/dist/agreement.d.ts.map +1 -1
  3. package/dist/agreement.js +2 -1
  4. package/dist/agreement.js.map +1 -1
  5. package/dist/auth-screen.d.ts +1 -1
  6. package/dist/behaviors.d.ts +1 -1
  7. package/dist/calendar.d.ts +1 -0
  8. package/dist/calendar.d.ts.map +1 -1
  9. package/dist/calendar.js +4 -1
  10. package/dist/calendar.js.map +1 -1
  11. package/dist/catalog.d.ts +78 -30
  12. package/dist/catalog.d.ts.map +1 -1
  13. package/dist/catalog.js +10 -5
  14. package/dist/catalog.js.map +1 -1
  15. package/dist/chart.d.ts +2 -0
  16. package/dist/chart.d.ts.map +1 -1
  17. package/dist/chart.js +1 -1
  18. package/dist/chart.js.map +1 -1
  19. package/dist/component-definitions.d.ts +1 -0
  20. package/dist/component-definitions.d.ts.map +1 -1
  21. package/dist/component-definitions.js +1 -0
  22. package/dist/component-definitions.js.map +1 -1
  23. package/dist/component-recipes.d.ts +53 -6
  24. package/dist/component-recipes.d.ts.map +1 -1
  25. package/dist/component-recipes.js +64 -10
  26. package/dist/component-recipes.js.map +1 -1
  27. package/dist/data-table.d.ts +11 -0
  28. package/dist/data-table.d.ts.map +1 -1
  29. package/dist/data-table.js +5 -0
  30. package/dist/data-table.js.map +1 -1
  31. package/dist/description-list.d.ts +3 -0
  32. package/dist/description-list.d.ts.map +1 -1
  33. package/dist/description-list.js +5 -1
  34. package/dist/description-list.js.map +1 -1
  35. package/dist/design-profile-layout.d.ts +28 -0
  36. package/dist/design-profile-layout.d.ts.map +1 -1
  37. package/dist/design-profile-layout.js +27 -3
  38. package/dist/design-profile-layout.js.map +1 -1
  39. package/dist/design-profile.d.ts.map +1 -1
  40. package/dist/design-profile.js +40 -8
  41. package/dist/design-profile.js.map +1 -1
  42. package/dist/field-group.d.ts +13 -0
  43. package/dist/field-group.d.ts.map +1 -1
  44. package/dist/field-group.js +17 -2
  45. package/dist/field-group.js.map +1 -1
  46. package/dist/foundations.d.ts +24 -11
  47. package/dist/foundations.d.ts.map +1 -1
  48. package/dist/foundations.js +40 -7
  49. package/dist/foundations.js.map +1 -1
  50. package/dist/heading.d.ts +5 -5
  51. package/dist/image-choice.d.ts +23 -0
  52. package/dist/image-choice.d.ts.map +1 -0
  53. package/dist/image-choice.js +26 -0
  54. package/dist/image-choice.js.map +1 -0
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/masonry.d.ts +8 -0
  60. package/dist/masonry.d.ts.map +1 -1
  61. package/dist/masonry.js +12 -1
  62. package/dist/masonry.js.map +1 -1
  63. package/dist/number-field.d.ts +2 -2
  64. package/dist/number-field.d.ts.map +1 -1
  65. package/dist/number-field.js +4 -2
  66. package/dist/number-field.js.map +1 -1
  67. package/dist/qr-code-recipe.d.ts +1 -0
  68. package/dist/qr-code-recipe.d.ts.map +1 -1
  69. package/dist/qr-code-recipe.js +3 -1
  70. package/dist/qr-code-recipe.js.map +1 -1
  71. package/dist/recipes.d.ts +1 -1
  72. package/dist/recipes.d.ts.map +1 -1
  73. package/dist/recipes.js +1 -1
  74. package/dist/recipes.js.map +1 -1
  75. package/dist/result.d.ts +9 -0
  76. package/dist/result.d.ts.map +1 -1
  77. package/dist/result.js +5 -0
  78. package/dist/result.js.map +1 -1
  79. package/dist/screen-patterns.d.ts +139 -2
  80. package/dist/screen-patterns.d.ts.map +1 -1
  81. package/dist/screen-patterns.js +140 -1
  82. package/dist/screen-patterns.js.map +1 -1
  83. package/dist/sheet.d.ts +15 -1
  84. package/dist/sheet.d.ts.map +1 -1
  85. package/dist/sheet.js +20 -1
  86. package/dist/sheet.js.map +1 -1
  87. package/dist/showcase.d.ts +27 -27
  88. package/dist/showcase.js +27 -27
  89. package/dist/showcase.js.map +1 -1
  90. package/dist/tag.d.ts +10 -2
  91. package/dist/tag.d.ts.map +1 -1
  92. package/dist/tag.js +3 -2
  93. package/dist/tag.js.map +1 -1
  94. package/dist/tags-input.d.ts +6 -0
  95. package/dist/tags-input.d.ts.map +1 -1
  96. package/dist/tags-input.js +3 -1
  97. package/dist/tags-input.js.map +1 -1
  98. package/dist/text-formats.d.ts +2 -2
  99. package/dist/top.d.ts +2 -2
  100. package/dist/transfer-list.d.ts +1 -1
  101. package/dist/transfer-list.d.ts.map +1 -1
  102. package/dist/transfer-list.js +2 -1
  103. package/dist/transfer-list.js.map +1 -1
  104. package/dist/upload-item.d.ts +1 -10
  105. package/dist/upload-item.d.ts.map +1 -1
  106. package/dist/upload-item.js +1 -2
  107. package/dist/upload-item.js.map +1 -1
  108. package/dist/version.d.ts +1 -1
  109. package/dist/version.js +1 -1
  110. package/dist/version.js.map +1 -1
  111. package/docs/activity-chip.md +4 -3
  112. package/docs/catalog-freeze.json +5 -2
  113. package/docs/chart.md +1 -1
  114. package/docs/consumer-policy.md +13 -6
  115. package/docs/description-list.md +4 -0
  116. package/docs/design-profile.md +28 -2
  117. package/docs/font-roles.md +1 -1
  118. package/docs/generated/component-maturity.md +5 -4
  119. package/docs/generated/renderer-evidence.json +92 -6
  120. package/docs/generated/renderer-evidence.md +5 -3
  121. package/docs/generated/showcase-manifest.json +49 -1
  122. package/docs/gravity-letters.md +7 -2
  123. package/docs/masonry.md +4 -2
  124. package/docs/screen-patterns.md +5 -2
  125. package/docs/showcase.md +7 -9
  126. package/docs/stable-promotion.md +13 -1
  127. package/docs/usage/README.md +40 -10
  128. package/docs/usage/SELECTION.md +30 -4
  129. package/docs/usage/STANDARD.md +11 -2
  130. package/docs/usage/components/account-switcher.md +98 -0
  131. package/docs/usage/components/activity-chip.md +4 -4
  132. package/docs/usage/components/badge.md +1 -1
  133. package/docs/usage/components/bezier-editor.md +99 -0
  134. package/docs/usage/components/bottom-cta.md +2 -1
  135. package/docs/usage/components/button.md +26 -12
  136. package/docs/usage/components/carousel.md +4 -4
  137. package/docs/usage/components/chart.md +1 -0
  138. package/docs/usage/components/chat-message.md +18 -12
  139. package/docs/usage/components/chat-screen.md +6 -3
  140. package/docs/usage/components/cohort-retention-table.md +83 -0
  141. package/docs/usage/components/collapsible.md +7 -2
  142. package/docs/usage/components/comment-thread-row.md +102 -0
  143. package/docs/usage/components/comment-thread-screen.md +27 -13
  144. package/docs/usage/components/composition-layout.md +1 -0
  145. package/docs/usage/components/context-menu.md +32 -15
  146. package/docs/usage/components/conversation-row.md +11 -4
  147. package/docs/usage/components/conversion-funnel.md +85 -0
  148. package/docs/usage/components/correlation-matrix.md +80 -0
  149. package/docs/usage/components/data-table.md +4 -0
  150. package/docs/usage/components/description-list.md +2 -1
  151. package/docs/usage/components/editor-screen.md +9 -5
  152. package/docs/usage/components/effect-surface.md +4 -2
  153. package/docs/usage/components/empty-state.md +2 -2
  154. package/docs/usage/components/event-attendance-card.md +104 -0
  155. package/docs/usage/components/expandable-search.md +105 -0
  156. package/docs/usage/components/file-picker.md +5 -0
  157. package/docs/usage/components/filter-recovery.md +97 -0
  158. package/docs/usage/components/follow-profile-card.md +100 -0
  159. package/docs/usage/components/heading.md +6 -2
  160. package/docs/usage/components/histogram-explorer.md +89 -0
  161. package/docs/usage/components/icon-button.md +18 -2
  162. package/docs/usage/components/icon-tile.md +12 -4
  163. package/docs/usage/components/image-choice-group.md +81 -0
  164. package/docs/usage/components/import-field-mapping.md +94 -0
  165. package/docs/usage/components/inline-edit.md +105 -0
  166. package/docs/usage/components/keyboard-avoidance-context.md +60 -0
  167. package/docs/usage/components/keyboard-avoiding.md +5 -1
  168. package/docs/usage/components/list-detail-screen.md +4 -4
  169. package/docs/usage/components/list.md +1 -1
  170. package/docs/usage/components/masonry.md +6 -7
  171. package/docs/usage/components/media-selection-screen.md +7 -5
  172. package/docs/usage/components/media-transport.md +104 -0
  173. package/docs/usage/components/message-composer.md +13 -3
  174. package/docs/usage/components/moderation-screen.md +5 -2
  175. package/docs/usage/components/notification-inbox-screen.md +3 -3
  176. package/docs/usage/components/notification-row.md +64 -8
  177. package/docs/usage/components/onboarding-screen.md +1 -1
  178. package/docs/usage/components/overview-screen.md +9 -3
  179. package/docs/usage/components/pagination.md +18 -3
  180. package/docs/usage/components/password-rules-field.md +90 -0
  181. package/docs/usage/components/permission-screen.md +1 -1
  182. package/docs/usage/components/photo-source-sheet.md +1 -1
  183. package/docs/usage/components/popover.md +6 -3
  184. package/docs/usage/components/pricing-choice.md +85 -0
  185. package/docs/usage/components/profile-summary.md +56 -8
  186. package/docs/usage/components/progress.md +3 -3
  187. package/docs/usage/components/qr-code.md +5 -9
  188. package/docs/usage/components/repeatable-field-group.md +92 -0
  189. package/docs/usage/components/reply-composer.md +83 -0
  190. package/docs/usage/components/reply-message.md +85 -0
  191. package/docs/usage/components/result.md +3 -3
  192. package/docs/usage/components/saved-items-screen.md +7 -5
  193. package/docs/usage/components/screen-layout.md +21 -10
  194. package/docs/usage/components/search-field.md +1 -1
  195. package/docs/usage/components/section.md +2 -2
  196. package/docs/usage/components/selection-action-bar.md +89 -0
  197. package/docs/usage/components/settings-screen.md +13 -11
  198. package/docs/usage/components/sheet.md +19 -7
  199. package/docs/usage/components/shortcut-recorder.md +77 -0
  200. package/docs/usage/components/split-action.md +94 -0
  201. package/docs/usage/components/streaming-answer.md +94 -0
  202. package/docs/usage/components/switch.md +6 -2
  203. package/docs/usage/components/table-column-settings.md +88 -0
  204. package/docs/usage/components/target-summary.md +79 -0
  205. package/docs/usage/components/text.md +11 -5
  206. package/docs/usage/components/toggle-feedback-button.md +94 -0
  207. package/docs/usage/components/top-bar.md +8 -12
  208. package/docs/usage/components/transfer-task.md +87 -0
  209. package/docs/usage/compositions/action-recovery-optimistic.md +18 -14
  210. package/docs/usage/compositions/action-recovery-save.md +18 -14
  211. package/docs/usage/compositions/action-recovery-undo.md +18 -14
  212. package/docs/usage/compositions/activity-status.md +1 -1
  213. package/docs/usage/compositions/adaptive-content.md +2 -1
  214. package/docs/usage/compositions/collection-detail.md +6 -5
  215. package/docs/usage/compositions/collection-editing.md +13 -6
  216. package/docs/usage/compositions/command-records.md +5 -4
  217. package/docs/usage/compositions/communication.md +7 -5
  218. package/docs/usage/compositions/compound-controls.md +7 -3
  219. package/docs/usage/compositions/content-transition-comparison.md +10 -5
  220. package/docs/usage/compositions/data-layouts.md +12 -16
  221. package/docs/usage/compositions/data-workflows.md +7 -4
  222. package/docs/usage/compositions/date-time-selection.md +5 -5
  223. package/docs/usage/compositions/design-profile-comparison.md +22 -6
  224. package/docs/usage/compositions/disclosure.md +14 -9
  225. package/docs/usage/compositions/document-resource.md +1 -1
  226. package/docs/usage/compositions/environment-matrix.md +16 -12
  227. package/docs/usage/compositions/expo-interactions.md +9 -8
  228. package/docs/usage/compositions/family-drawer.md +9 -5
  229. package/docs/usage/compositions/field-group.md +7 -3
  230. package/docs/usage/compositions/interaction-adapters.md +11 -9
  231. package/docs/usage/compositions/interaction-flow-apply.md +17 -15
  232. package/docs/usage/compositions/interaction-flow-search.md +11 -7
  233. package/docs/usage/compositions/live-list.md +12 -8
  234. package/docs/usage/compositions/navigation-bar-collection.md +8 -3
  235. package/docs/usage/compositions/optional-motion.md +2 -2
  236. package/docs/usage/compositions/paper-surface.md +11 -6
  237. package/docs/usage/compositions/purpose-input-comment.md +10 -4
  238. package/docs/usage/compositions/purpose-input-message.md +10 -4
  239. package/docs/usage/compositions/reference-first.md +4 -4
  240. package/docs/usage/compositions/reference-review.md +4 -4
  241. package/docs/usage/compositions/reference-settings.md +4 -4
  242. package/docs/usage/compositions/selection-motion.md +2 -1
  243. package/docs/usage/compositions/social-compositions.md +7 -6
  244. package/docs/usage/compositions/stea-event-ticket.md +2 -4
  245. package/docs/usage/compositions/stea-order-progress.md +19 -21
  246. package/docs/usage/compositions/stea-pixel-empty.md +26 -26
  247. package/docs/usage/compositions/task-controls.md +7 -2
  248. package/docs/usage/compositions/texture-comparison.md +5 -5
  249. package/docs/usage/compositions/toast-layout.md +7 -3
  250. package/docs/usage/compositions/toggle-feedback.md +1 -1
  251. package/docs/usage/compositions/visual-foundations.md +10 -5
  252. package/docs/usage/compositions/web-additions.md +5 -1
  253. package/docs/usage/screens/common-chat.md +5 -3
  254. package/docs/usage/screens/common-comments.md +14 -9
  255. package/docs/usage/screens/common-conversation-list.md +109 -0
  256. package/docs/usage/screens/common-inbox.md +5 -3
  257. package/docs/usage/screens/common-login.md +7 -4
  258. package/docs/usage/screens/common-profile.md +16 -12
  259. package/docs/usage/screens/common-saved.md +12 -8
  260. package/docs/usage/screens/common-search.md +16 -8
  261. package/docs/usage/screens/common-settings.md +12 -11
  262. package/docs/usage/screens/common-shell.md +12 -10
  263. package/docs/usage/screens/dashboard.md +59 -56
  264. package/docs/usage/screens/discovery-gallery.md +18 -9
  265. package/docs/usage/screens/flow-collection.md +10 -6
  266. package/docs/usage/screens/flow-editor.md +9 -6
  267. package/docs/usage/screens/flow-media.md +12 -7
  268. package/docs/usage/screens/flow-moderation.md +9 -3
  269. package/docs/usage/screens/flow-onboarding.md +13 -8
  270. package/docs/usage/screens/flow-permission.md +5 -3
  271. package/docs/usage/screens/landing.md +20 -14
  272. package/docs/usage/screens/mockup-studio.md +100 -88
  273. package/docs/usage/screens/notification-settings.md +9 -7
  274. package/docs/usage/screens/product-bento.md +22 -10
  275. package/docs/usage/screens/reference-comparison.md +2 -2
  276. package/docs/usage/tokens/font-roles.md +18 -2
  277. package/docs/usage/tokens/typography.md +22 -11
  278. package/package.json +7 -1
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 구성 API 지침 참조
7
- - 검토일: 2026-10-15
7
+ - 검토일: 2026-10-17
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md); 공통 API와 실제 Web·Native 예제의 슬롯·상태를 대조해 중복 조립 방지. 2026-10-06 사용자 승인으로 스토리북 배포(이전 `실험/화면/기본 흐름/사진 선택과 업로드`, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
9
9
  - 스토리북: `배포/화면/콘텐츠/사진 선택과 업로드`
10
10
 
@@ -31,7 +31,7 @@ host: 남은 높이·safe area·키보드
31
31
 
32
32
  | 행동 | 컴포넌트·tone | 위치 | 개수·순서 |
33
33
  | --- | --- | --- | --- |
34
- | 작업 | `add` Button·secondary / `done` Button·primary / 항목 행동 Button·ghost·small | 추가는 헤더 actions, 완료는 footer(선택 요약 아래), 위로·아래로·제거는 각 칸 미리보기 아래 | primary는 완료 하나. 칸마다 위로 → 아래로 → 제거, 첫 칸의 위로·마지막 칸의 아래로는 비활성 |
34
+ | 작업 | `exit` 아이콘 / `add` IconButton·ghost(선택) / `done` Button·primary / 항목 행동 Button·ghost·small | 나가기는 헤더 시작, 추가는 헤더 actions 끝, 완료는 footer(선택 요약 아래), 위로·아래로·제거는 각 칸 미리보기 아래 | primary는 완료 하나. 칸마다 위로 → 아래로 → 제거, 첫 칸의 위로·마지막 칸의 아래로는 비활성 |
35
35
  | 복구 | Button·secondary | 오류 근처 | 재시도할 대상과 범위를 표시 |
36
36
 
37
37
  ## 상태
@@ -48,11 +48,9 @@ host: 남은 높이·safe area·키보드
48
48
 
49
49
  Web·Native `media-picker-preview.tsx`는 최대 5장을 순서대로 고른 뒤 공통 `items` 격자에서 메모리 업로드를 시연한다. `실패와 복구`는 첫 항목 한 번만 실패하며, 항목의 재시도로 해당 사진만 다시 처리한다. 업로드·실패·0장 상태에서는 완료를 막고, 사진 제거·선택 화면 복귀 뒤 도착한 이전 결과는 무시한다. 모두 성공한 뒤 완료하면 순서를 포함한 읽기 전용 결과가 남고 `새로 선택`으로 초기화한다. `showcase/shared/media-picker-example.ts`는 이 예제만의 메모리 어댑터이며 실제 OS 사진 접근·권한이나 서버 업로드를 수행하지 않는다.
50
50
 
51
- 2026-10-13 전수 점검에서 최초 조회와 변경 요청의 상태를 같은 골격으로 설명하던 부분을 구체화했다.
52
-
53
51
  | 상황 | 연결 | 유지·복구 |
54
52
  | --- | --- | --- |
55
- | 선택 0개 | empty + add | 새 사진 선택은 계속 가능하고 done은 제품 정책에 따라 잠근다 |
53
+ | 선택 0개 | empty (+ add가 있으면 활성) | 새 사진 선택은 계속 가능하고 done은 제품 정책에 따라 잠근다 |
56
54
  | 업로드 혼재 | 썸네일·순서와 각 UploadItem 상태 유지 | 실패한 항목만 재시도한다. 성공한 사진을 다시 업로드하지 않는다 |
57
55
  | 완료 가능 | 필수 항목 모두 서버 확정 | 업로드 중이 아니어도 실패·취소 항목이 남으면 done을 바로 활성화하지 않는다 |
58
56
  | 권한 제한 | restricted + 권한 안내 행동 | 로컬 썸네일이 존재한다는 이유로 OS 접근 권한을 얻었다고 판단하지 않는다 |
@@ -76,7 +74,8 @@ import { MediaSelectionScreen } from "@hjmds/react/screen-flows";
76
74
  title={t("media.title")}
77
75
  items={picked.map((p) => ({ descriptor: { id: p.id, name: p.fileName, state: p.upload },
78
76
  preview: <img src={p.uri} alt="" width={p.width} height={p.height} /> }))}
79
- add={{ label: t("media.add"), onAction: openPicker }}
77
+ exit={{ kind: "close", label: t("media.close"), onClick: close }}
78
+ add={{ label: t("media.add"), icon: <PlusIcon aria-hidden />, onAction: openPicker }}
80
79
  done={{ label: t("media.done"), onAction: submit, disabled: uploading || !canComplete }}
81
80
  labels={{ pending: t("upload.pending"), uploading: t("upload.uploading"),
82
81
  success: t("upload.success"), cancel: t("upload.cancel"), retry: t("upload.retry") }}
@@ -98,7 +97,8 @@ import { Image } from "react-native";
98
97
  title={t("media.title")}
99
98
  items={picked.map((p) => ({ descriptor: { id: p.id, name: p.fileName, state: p.upload },
100
99
  preview: <Image src={p.uri} width={p.width} height={p.height} /> }))}
101
- add={{ label: t("media.add"), onAction: openPicker }}
100
+ exit={{ kind: "close", label: t("media.close"), onPress: close }}
101
+ add={{ label: t("media.add"), icon: <PlusIcon color={colors.text} />, onAction: openPicker }}
102
102
  done={{ label: t("media.done"), onAction: submit, disabled: uploading || !canComplete }}
103
103
  labels={{ pending: t("upload.pending"), uploading: t("upload.uploading"),
104
104
  success: t("upload.success"), cancel: t("upload.cancel"), retry: t("upload.retry") }}
@@ -127,3 +127,8 @@ import { Image } from "react-native";
127
127
 
128
128
  - 업로드 실패 항목만 재시도, 완료 버튼은 제품 정책으로 제한.
129
129
  - Storybook은 실제 서버·OS 권한·라우터 연동 증거가 아니다. 기본·다크와 실패/복구를 확인한다. 최대 글자와 이를 모사하는 확대 조건은 공통 사용자 지침에 따라 검증·설계 고려에서 제외한다.
130
+
131
+ ## 근거
132
+
133
+ - 항목별 업로드와 완료 조건 상황 표: 2026-10-13 전수 점검 — 최초 조회와 변경 요청의 상태를 같은 골격으로 설명하던 부분을 구체화했다.
134
+ - 나가기 `exit`·아이콘 `add`: 2026-10-17 화면 검토 — 필수 글자 `add`에 "취소"가 들어가 헤더 끝 글자 버튼이 가운데 제목을 밀었고 Native에서 "취"로 잘렸다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 구성 API 지침 참조
7
- - 검토일: 2026-10-15
7
+ - 검토일: 2026-10-17
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md); 공통 API와 실제 Web·Native 예제의 슬롯·상태를 대조해 중복 조립 방지. 2026-10-06 사용자 승인으로 스토리북 배포(이전 `실험/화면/기본 흐름/신고와 차단`, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
9
9
  - 스토리북: `배포/화면/소통/신고와 차단`
10
10
 
@@ -31,6 +31,7 @@ host: 남은 높이·safe area·키보드
31
31
 
32
32
  | 행동 | 컴포넌트·tone | 위치 | 개수·순서 |
33
33
  | --- | --- | --- | --- |
34
+ | 닫기 | ScreenLayout `exit` `kind="close"` | 헤더 시작 끝 아이콘 버튼 | 1. 신고하지 않고 화면을 닫는다 |
34
35
  | 작업 | ModerationScreen 공개 행동 슬롯 | 신고는 footer; 차단은 별도 확인 후 실행 | 같은 표면에 경쟁하는 primary 하나만 |
35
36
  | 복구 | Button·secondary | 오류 근처 | 재시도할 대상과 범위를 표시 |
36
37
 
@@ -46,8 +47,6 @@ host: 남은 높이·safe area·키보드
46
47
 
47
48
  ### 신고와 차단의 서로 다른 결과
48
49
 
49
- 2026-10-13 전수 점검에서 최초 조회와 변경 요청의 상태를 같은 골격으로 설명하던 부분을 구체화했다.
50
-
51
50
  | 상황 | 연결 | 유지·복구 |
52
51
  | --- | --- | --- |
53
52
  | 사유 미선택 | submit 비활성 | reason은 현재 reasons의 값이어야 한다 |
@@ -72,6 +71,7 @@ import { ModerationScreen } from "@hjmds/react/screen-flows";
72
71
 
73
72
  <ModerationScreen
74
73
  title={t("report.title")}
74
+ exit={{ kind: "close", label: t("common.close"), onClick: closeReport }}
75
75
  reasonLabel={t("report.reason")}
76
76
  reasons={[
77
77
  { value: "spam", label: t("report.reason.spam") },
@@ -98,6 +98,7 @@ import { ModerationScreen } from "@hjmds/react-native/screen-flows";
98
98
 
99
99
  <ModerationScreen
100
100
  title={t("report.title")}
101
+ exit={{ kind: "close", label: t("common.close"), onPress: closeReport }}
101
102
  reasonLabel={t("report.reason")}
102
103
  reasons={[
103
104
  { value: "spam", label: t("report.reason.spam") },
@@ -133,3 +134,8 @@ import { ModerationScreen } from "@hjmds/react-native/screen-flows";
133
134
 
134
135
  - 신고 실패에 선택 사유·설명 유지; 차단은 성공 후 확정.
135
136
  - Storybook은 실제 서버·OS 권한·라우터 연동 증거가 아니다. 기본·다크·큰 글자와 실패/복구를 각각 확인한다.
137
+
138
+ ## 근거
139
+
140
+ - 신고와 차단의 서로 다른 결과 상황 표: 2026-10-13 전수 점검 — 최초 조회와 변경 요청의 상태를 같은 골격으로 설명하던 부분을 구체화했다.
141
+ - 닫기 `exit`: 2026-10-17 화면 검토(S5)에서 exit 없는 신고 예제가 나갈 길 없는 화면으로 렌더링돼 예제·코드 골격에 추가했다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 구성 API 지침 참조
7
- - 검토일: 2026-10-15
7
+ - 검토일: 2026-10-17
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md), Web·Native `src/screen-flows.tsx`(`OnboardingScreen`), 예제 `showcase/*/screen-flow-previews.tsx`(`OnboardingFlowPreview`)·`showcase/shared/onboarding-pattern.ts`(주제·요약). 2026-10-06 사용자 승인으로 실험 `기본 흐름/온보딩`(OnboardingScreen)을 배포하면서 같은 일을 직접 조립하던 배포 `화면/온보딩`을 대체했다(Web id `patterns-onboarding` 보존, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
9
9
  - 스토리북: `배포/화면/소개/온보딩`
10
10
 
@@ -16,8 +16,7 @@
16
16
  단계 제목·설명은 화면 맨 위, 진행 문구는 그 아래에 둔다. Web은 머리를 고정하고 Native는 제목·설명·진행을 본문과 함께 스크롤한다. 이동 버튼은 footer에 고정한다. 권한 요청·로그인·가입은
17
17
  이 화면에 없다([권한 안내](flow-permission.md), [로그인](common-login.md)).
18
18
  스토리는 `기본`(1단계부터 직접 넘기기), `관심 주제 고르기`(2단계를 바로 연 상태), `실패와 복구`(다음 완료 저장 실패 → 다시 시작하기)다.
19
- 2026-10-06 배포 직접 조립 온보딩(Steps·ContentTransition·여러 개 고르는 주제 버튼)을 이 항목으로 합쳤고, 그 고유 상태인
20
- 관심 주제 여러 개 고르기는 OnboardingScreen 2단계의 Chip 다중 선택으로 옮겼다(두 플랫폼 `관심 주제 고르기` 스토리가 같은 화면을 연다).
19
+ 관심 주제 여러 개 고르기는 OnboardingScreen 2단계의 Chip 다중 선택이다(두 플랫폼 `관심 주제 고르기` 스토리가 같은 화면을 연다).
21
20
  단계·주제·문구·저장은 제품이 공급한다.
22
21
 
23
22
  ## 영역 구조
@@ -37,7 +36,7 @@
37
36
  │ (완료 저장 실패면) Notice danger + 다시 시도 │
38
37
  ├──────────────────────────── footer(고정, 위 테두리 1) ─────────────────┤
39
38
  │ [ 다음 / 시작하기 ] ← primary, 마지막 단계는 complete │
40
- │ [ 이전 ] ← ghost, 첫 단계에는 없음 │ 사이 spacing.sm 12
39
+ │ [ 이전 ] ← ghost, 첫 단계에는 없음 │ 사이 spacing.xs 8
41
40
  └ 아래 safe area(Web은 footer padding이 늘어난다) ──────────────────────┘
42
41
  ```
43
42
 
@@ -51,7 +50,7 @@
51
50
  | 단계 본문 | `steps[index].content` | 진행 문구 아래, 본문 스크롤 | 본문 안 간격은 제품 소유. 예제는 Stack `gap="lg"` 20 |
52
51
  | 관심 주제 | Stack `axis="inline" wrap gap="xs"`(Web `role="group"` + 이름) > [Chip](../components/chip.md) `selectionMode="multiple"` | 2단계 content 안 | 칩 높이 `small` 36(Native hitSlop으로 터치 44), 사이 `spacing.xs` 8 |
53
52
  | 저장 실패 | [Notice](../components/notice.md) `tone="danger"` + `action` | 마지막 단계 content 맨 아래 | 본문 Stack 간격을 따른다 |
54
- | footer | Stack `gap="sm"` > Button primary(다음·완료) → Button ghost(이전) | 맨 아래, 고정 | 사이 `spacing.sm` 12, 위 테두리 1 |
53
+ | footer | Stack `gap="xs"` > Button primary(다음·완료) → Button ghost(이전) | 맨 아래, 고정 | 사이 `spacing.xs` 8(세로로 쌓은 버튼), 위 테두리 1 |
55
54
 
56
55
  ## 버튼과 행동 위치
57
56
 
@@ -67,8 +66,7 @@
67
66
 
68
67
  한 단계에 primary는 footer의 다음·완료 하나다. 진행·이동이 footer에 고정돼 단계 본문이 바뀌어도 버튼 자리가 흔들리지 않는다.
69
68
 
70
- 2026-10-06 관심 주제를 ghost+`selected` Button에서 Chip `multiple`로 바꿨다. 여러 개 고르는 선택은 checkbox 역할로 읽혀야 하는데
71
- Button `selected`는 눌림 토글(`aria-pressed`)로 읽히고, 한 줄짜리 주제 선택에 CheckboxGroup은 세로 목록이라 화면을 많이 차지한다.
69
+ 관심 주제는 Chip `multiple`로 고른다. ghost+`selected` Button이나 세로 CheckboxGroup으로 조립하지 않는다.
72
70
 
73
71
  ## 상태
74
72
 
@@ -194,4 +192,11 @@ const topicPicker = <Stack axis="inline" wrap gap="xs">
194
192
  - 현재 스토리의 진행 문구는 `` `${index} / ${total}` `` 고정 문자열이다. 제품은 보간 키 하나(`onboarding.progress`)를 쓴다.
195
193
  - Storybook은 실제 서버·라우터 연동 증거가 아니다. 기본·어두운 테마·큰 글자와 실패와 복구를 각각 확인한다.
196
194
 
197
- 2026-10-07 iOS 26.5 / 200% 글자에서 키보드가 열린 시작 안내의 고정 머리가 본문 높이를 모두 소비했다. Native는 기존 ScreenLayout의 본문 스크롤 안으로 단계 안내를 옮겨 입력에 도달하게 하고 footer의 완료·이전 버튼은 유지한다. [검토 결과](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md).
195
+ Native는 기존 ScreenLayout의 본문 스크롤 안으로 단계 안내를 옮겨 입력에 도달하게 하고 footer의 완료·이전 버튼은 유지한다.
196
+
197
+ ## 근거
198
+
199
+ - 한 항목 구성: 2026-10-06 배포 직접 조립 온보딩(Steps·ContentTransition·여러 개 고르는 주제 버튼)을 이 항목으로 합치고 그 고유 상태인 관심 주제 고르기를 2단계로 옮겼다.
200
+ - 관심 주제 Chip `multiple`: 2026-10-06 ghost+`selected` Button에서 바꿨다. 여러 개 고르기는 checkbox 역할로 읽혀야 하는데 Button `selected`는 눌림 토글(`aria-pressed`)로 읽히고, 한 줄짜리 주제 선택에 CheckboxGroup은 세로 목록이라 화면을 많이 차지한다.
201
+ - Native 단계 안내를 본문 스크롤 안에 둠: 2026-10-07 iOS 26.5 / 200% 글자에서 키보드가 열린 시작 안내의 고정 머리가 본문 높이를 모두 소비했다([검토 결과](../../../../../docs/qa/2026-10-07-experiment-promotion-release.md)).
202
+ - footer 버튼 간격 8: 2026-10-17 사용자 지시(button.md 간격) — 세로로 쌓은 하단 버튼의 12 간격이 벌어져 보였다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 구성 API 지침 참조
7
- - 검토일: 2026-10-15
7
+ - 검토일: 2026-10-17
8
8
  - 근거: [반복 화면 조합](../../screen-patterns.md); 공통 API와 실제 Web·Native 예제의 슬롯·상태를 대조해 중복 조립 방지. 2026-10-06 사용자 승인으로 스토리북 배포(이전 `실험/화면/기본 흐름/권한 안내`, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
9
9
  - 스토리북: `배포/화면/소개/권한 안내`
10
10
 
@@ -47,8 +47,6 @@ host: 남은 높이·safe area·키보드
47
47
 
48
48
  ### OS 상태에 맞는 다음 행동
49
49
 
50
- 2026-10-13 전수 점검에서 최초 조회와 변경 요청의 상태를 같은 골격으로 설명하던 부분을 구체화했다.
51
-
52
50
  | 상황 | 연결 | 유지·복구 |
53
51
  | --- | --- | --- |
54
52
  | prompt | request | 사용자 행동에서만 OS 권한 요청 |
@@ -117,3 +115,7 @@ import { Linking } from "react-native";
117
115
 
118
116
  - 렌더 시 OS 요청 금지; 설정 복귀 시 제품이 상태 재조회.
119
117
  - Storybook은 실제 서버·OS 권한·라우터 연동 증거가 아니다. 기본·다크·큰 글자와 실패/복구를 각각 확인한다.
118
+
119
+ ## 근거
120
+
121
+ - OS 상태에 맞는 다음 행동 상황 표: 2026-10-13 전수 점검 — 최초 조회와 변경 요청의 상태를 같은 골격으로 설명하던 부분을 구체화했다.
@@ -4,7 +4,7 @@
4
4
  - 상태: 배포
5
5
  - 지원: Web · Native
6
6
  - 적용: 1.12.1
7
- - 검토일: 2026-10-15
7
+ - 검토일: 2026-10-17
8
8
  - 근거: `showcase/web/src/patterns/Landing.stories.tsx`·`Landing.previews.tsx`(진입점)·`showcase/web/src/patterns/landing-preview.tsx`(기본 본체), `showcase/native/src/Landing.stories.tsx`·`introduction-preview.tsx`(진입점)·`showcase/native/src/landing-preview.tsx`(기본 본체), 변형 `showcase/*/reference-flow-previews.tsx`(`ServiceIntroduction`), `showcase/shared/landing-pattern.ts`, `showcase/native/src/pattern-status.tsx`, `packages/react/src/effect-surface.tsx`, `packages/react-native/src/effect-surface.tsx`. 2026-10-06 사용자 승인으로 실험 `서비스 소개/제품 체험 중심`(설명과 사례 중심 포함)을 배포하면서 같은 소개 목적의 배포 `화면/랜딩 화면`과 한 항목으로 합쳤다(Web id `patterns-landing` 보존, [승인 기록](../../../../../docs/STORYBOOK_NAVIGATION.md#21-2026-10-06-전체-승격과-규격-확정))
9
9
  - 스토리북: `배포/화면/소개/서비스 소개`
10
10
 
@@ -93,15 +93,15 @@ ScreenLayout(제목 = 소개 문장, 최대 720, 바깥 padding spacing.md 16)
93
93
 
94
94
  | 행동 | 컴포넌트·tone | 위치 | 개수·순서 |
95
95
  | --- | --- | --- | --- |
96
- | 주 행동(체험 시작) | Button 기본 primary, `medium` | ① 히어로 소개문 바로 아래 | 1 |
97
- | 같은 행동 반복 | Button `secondary`, 같은 라벨·같은 동작 | ⑤ FAQ 다음 | 1. 기능·FAQ를 읽은 뒤 위로 돌아가지 않고 체험할 수 있도록 끝에 한 번 더 둔다 |
96
+ | 주 행동(체험 시작) | Button 기본 primary, `medium` | ① 히어로 소개문 바로 아래. Web은 히어로 Stack `align="start"`로 내용 폭을 유지한다(넓은 폭에서 1200 Container 폭으로 늘리지 않는다) | 1 |
97
+ | 같은 행동 반복 | Button `secondary`, 같은 라벨·같은 동작 | ⑤ FAQ 다음. Web은 범위 안내와 함께 `Stack gap="xl" align="start"`로 감싸 내용 폭 | 1. 기능·FAQ를 읽은 뒤 위로 돌아가지 않고 체험할 수 있도록 끝에 한 번 더 둔다 |
98
98
  | FAQ 펼치기 | Collapsible 트리거 | ④ 각 질문 행 전체 | 질문마다 1 |
99
99
  | 입력 제출 | Button 기본 primary | ⑥ Sheet `footer`(Web 끝 정렬, Native 꽉 찬 폭) | 1. 시트 안에서 따로 센다([Button](../components/button.md#꼭-지킬-것)) |
100
100
  | 시트 닫기 | Sheet `closeLabel` | 시트 머리 끝 | 1. 기본 예제는 닫아도 초안을 유지한다. 제품이 비동기 저장을 연결하면 저장 중에는 Sheet `busy`로 막는다 |
101
101
  | 파괴 행동 | — | — | 없음 |
102
102
 
103
103
  화면의 primary는 히어로 행동 하나다. 시트 `footer`의 제출은 시트 안에서 따로 센다.
104
- 두 변형은 히어로 행동과 끝 행동 카드의 버튼이 같은 Sheet를 연다(같은 행동 반복). FAQ는 Collapsible 대신 `selected` 토글 Button 하나로 답을 연다.
104
+ 두 변형은 히어로 행동과 끝 행동 카드의 버튼이 같은 Sheet를 연다(같은 행동 반복). FAQ도 기본처럼 Collapsible로 답을 연다. 펼치고 접기를 `selected` 토글 Button으로 흉내 내지 않는다([선택 조립 규칙](../SELECTION.md#조립-규칙필수)).
105
105
 
106
106
  키보드: Native 시트는 `keyboardAvoidance`로 키보드 위에 붙고 `footer`가 키보드 위에 고정돼 제출 버튼이 가려지지 않는다.
107
107
  바깥 ScrollView에는 입력이 없다.
@@ -111,7 +111,6 @@ footer의 저장과 같은 동작을 실행한다. Web에서 IME 조합 확정
111
111
  빈 입력을 제출하면 시트를 유지하고 오류가 있는 입력칸에 초점을 돌린다. 닫기·Escape 또는 저장으로 시트가 끝나면
112
112
  `returnFocusRef`로 실제 누른 위·아래 CTA에 복귀한다(Native는 접근성 초점).
113
113
 
114
- 2026-10-13 실제 예제 검수에서 닫은 뒤 초안 소실과 연속 제출 시 중복 행을 재현해 수정했다.
115
114
  기본 예제는 닫을 때 초안을 보존하고, 성공한 제출만 한 번 추가한 뒤 초안을 비운다. 다시 열면 새로운 기록을 시작한다.
116
115
 
117
116
  ## 상태
@@ -178,7 +177,7 @@ const gutter = resolveWindowClass(window.innerWidth) === "compact" ? "compact" :
178
177
  <main><Container size="content" gutter={gutter}><Stack gap="xl">
179
178
  {/* 장식과 콘텐츠 여백은 기존 EffectSurface + Surface로 분리한다. */}
180
179
  <EffectSurface descriptor={{ layers: ["mesh", "grain"], seed: "landing", active: false }}><Surface padding="xl">
181
- <Stack gap="lg">
180
+ <Stack gap="lg" align="start">
182
181
  <Text tone="muted">{t("landing.eyebrow")}</Text>
183
182
  <Heading level="level1">{t("landing.title")}</Heading>
184
183
  <Text as="p">{t("landing.intro")}</Text>
@@ -195,8 +194,8 @@ const gutter = resolveWindowClass(window.innerWidth) === "compact" ? "compact" :
195
194
  <Heading level="level3">{t(f.titleKey)}</Heading><Text>{t(f.bodyKey)}</Text></Stack></Surface>)}
196
195
  <Heading level="level2">{t("landing.faq")}</Heading>
197
196
  {faqs.map(q => <Collapsible key={q.id} trigger={t(q.questionKey)}><Text>{t(q.answerKey)}</Text></Collapsible>)}
198
- <Button tone="secondary" onClick={start}>{t("landing.cta")}</Button>
199
- <Text tone="muted">{t("landing.scope")}</Text>
197
+ <Stack gap="xl" align="start"><Button tone="secondary" onClick={start}>{t("landing.cta")}</Button>
198
+ <Text tone="muted">{t("landing.scope")}</Text></Stack>
200
199
  </Stack></Container>
201
200
  <Sheet title={t("landing.sheetTitle")} closeLabel={t("common.close")} open={open} onOpenChange={setOpen} busy={saving}
202
201
  footer={<Button loading={saving} onClick={submit}>{t("landing.submit")}</Button>}>
@@ -256,6 +255,7 @@ const gutter = resolveWindowClass(width) === "compact" ? "compact" : "regular";
256
255
  ```tsx
257
256
  // Web
258
257
  import { Button } from "@hjmds/react/actions";
258
+ import { Collapsible } from "@hjmds/react/collapsible";
259
259
  import { Heading } from "@hjmds/react/heading";
260
260
  import { TextField } from "@hjmds/react/forms";
261
261
  import { Grid, Stack, Surface, Text } from "@hjmds/react/layout";
@@ -276,8 +276,7 @@ import { ScreenLayout } from "@hjmds/react/screens";
276
276
  <Grid columns={{ compact: 3 }} gap={{ compact: "xl" }} minColumnWidth={{ compact: 240 }}>
277
277
  {features.map((item) => <Stack key={item.id} gap="sm"><Heading level="level5" semanticLevel={2}>{item.title}</Heading><Text>{item.body}</Text></Stack>)}
278
278
  </Grid>
279
- <Button tone="secondary" selected={faqOpen} onClick={toggleFaq}>{t("intro.faq.question")}</Button>
280
- {faqOpen ? <Text>{t("intro.faq.answer")}</Text> : null}
279
+ <Collapsible trigger={t("intro.faq.question")}><Text>{t("intro.faq.answer")}</Text></Collapsible>
281
280
  <Surface padding="lg">
282
281
  <Stack gap="md">
283
282
  <Heading level="level5" semanticLevel={2}>{t("intro.closing")}</Heading>
@@ -296,6 +295,7 @@ import { ScreenLayout } from "@hjmds/react/screens";
296
295
  ```tsx
297
296
  // Native
298
297
  import { Button } from "@hjmds/react-native/actions";
298
+ import { Collapsible } from "@hjmds/react-native/collapsible";
299
299
  import { Heading } from "@hjmds/react-native/heading";
300
300
  import { TextField } from "@hjmds/react-native/inputs";
301
301
  import { Grid, Stack, Surface, Text } from "@hjmds/react-native/primitives";
@@ -316,8 +316,7 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
316
316
  <Grid columns={{ compact: 3 }} gap={{ compact: "xl" }} minColumnWidth={{ compact: 240 }}>
317
317
  {features.map((item) => <Stack key={item.id} gap="sm"><Heading level="level5">{item.title}</Heading><Text>{item.body}</Text></Stack>)}
318
318
  </Grid>
319
- <Button tone="secondary" selected={faqOpen} onPress={toggleFaq}>{t("intro.faq.question")}</Button>
320
- {faqOpen ? <Text>{t("intro.faq.answer")}</Text> : null}
319
+ <Collapsible trigger={t("intro.faq.question")}><Text>{t("intro.faq.answer")}</Text></Collapsible>
321
320
  <Surface padding="lg">
322
321
  <Stack gap="md">
323
322
  <Heading level="level5">{t("intro.closing")}</Heading>
@@ -357,10 +356,17 @@ import { ScreenLayout } from "@hjmds/react-native/screens";
357
356
 
358
357
  ## 함정
359
358
 
360
- - 히어로는 Surface padding="xl"로 내부 여백을 갖고, 바깥 폭·gutter는 Container가 소유한다. 시트 저장은 footer에 둔다(2026-10-06 지침과 예제 정합성 수정).
359
+ - 히어로는 Surface padding="xl"로 내부 여백을 갖고, 바깥 폭·gutter는 Container가 소유한다. 시트 저장은 footer에 둔다.
361
360
  - 기본 예제의 위·아래 CTA는 같은 시트를 연다. 히어로는 primary, FAQ 뒤의 반복 행동은 secondary다.
362
361
  - 미리보기 행은 번역 문구나 배열 위치 대신 생성 시 부여한 id로 유지한다.
363
362
  - 기본·변형 예제의 저장은 메모리에만 남는다. 기본 예제는 저장 없이 닫으면 초안을 보존하고 성공하면 비운다. 변형은 Sheet를 닫아도 입력 초안이 남는다. 운영 저장·실패 처리는 위 오류 행 규칙을 따른다.
364
- - 현재 변형 스토리는 FAQ를 Collapsible이 아니라 `selected` 토글 Button 하나로 그린다. 질문이 여럿이면 기본처럼 Collapsible을 쓴다.
363
+ - 변형 스토리도 FAQ를 Collapsible로 그린다.
365
364
 
366
365
  제품 체험·편집형 ServiceIntroduction 변형도 Web에서 CTA 클릭의 `event.currentTarget`을 복귀 대상으로 기록한다. Safari의 포인터 클릭은 버튼에 초점을 주지 않을 수 있어, 열기 직전 `document.activeElement`만으로 복귀 대상을 추정하지 않는다. 이 변형은 저장한 한 장면을 다시 편집하는 예제이므로 닫기뿐 아니라 저장 뒤 재열기에도 입력값을 유지한다. 새 기록을 계속 추가하는 기본 랜딩의 성공 후 입력 초기화와 구분한다.
366
+
367
+ ## 근거
368
+
369
+ - FAQ는 Collapsible(기본·변형): 2026-10-16 사용자 지적 — 변형 스토리가 `selected` 토글 Button 하나로 펼침을 흉내 내 눌림 토글로 읽혔다.
370
+ - 닫을 때 초안 보존·성공 제출만 한 번 추가: 2026-10-13 실제 예제 검수에서 닫은 뒤 초안 소실과 연속 제출 시 중복 행을 재현했다.
371
+ - 히어로 padding·시트 저장 footer: 2026-10-06 지침과 예제 정합성 수정.
372
+ - Web CTA 내용 폭(`align="start"`): 2026-10-17 화면 리뷰 — 1280 폭에서 두 CTA가 Container 폭(약 1160)으로 늘어났다. 히어로 장식은 EffectSurface `radius`(기본 Surface `lg`)로 잘라 둥근 모서리 밖으로 비치지 않게 했다.