@hjmds/design-contracts 1.7.0 → 1.8.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 (228) hide show
  1. package/THIRD_PARTY_NOTICES.md +58 -0
  2. package/dist/agreement.d.ts +3 -3
  3. package/dist/agreement.js +1 -1
  4. package/dist/agreement.js.map +1 -1
  5. package/dist/asset.d.ts +1 -1
  6. package/dist/asset.js +1 -1
  7. package/dist/asset.js.map +1 -1
  8. package/dist/base-recipes.d.ts +12 -12
  9. package/dist/base-recipes.d.ts.map +1 -1
  10. package/dist/base-recipes.js +15 -14
  11. package/dist/base-recipes.js.map +1 -1
  12. package/dist/behaviors.d.ts +1 -1
  13. package/dist/catalog.d.ts +417 -561
  14. package/dist/catalog.d.ts.map +1 -1
  15. package/dist/catalog.js +138 -90
  16. package/dist/catalog.js.map +1 -1
  17. package/dist/command-palette.d.ts +3 -3
  18. package/dist/component-contracts.d.ts +4 -4
  19. package/dist/component-contracts.d.ts.map +1 -1
  20. package/dist/component-contracts.js +5 -4
  21. package/dist/component-contracts.js.map +1 -1
  22. package/dist/component-definitions.d.ts +1 -4
  23. package/dist/component-definitions.d.ts.map +1 -1
  24. package/dist/component-definitions.js +1 -4
  25. package/dist/component-definitions.js.map +1 -1
  26. package/dist/component-recipes.d.ts +76 -83
  27. package/dist/component-recipes.d.ts.map +1 -1
  28. package/dist/component-recipes.js +29 -49
  29. package/dist/component-recipes.js.map +1 -1
  30. package/dist/component-references.d.ts +0 -15
  31. package/dist/component-references.d.ts.map +1 -1
  32. package/dist/component-references.js +0 -3
  33. package/dist/component-references.js.map +1 -1
  34. package/dist/data-table.d.ts +3 -3
  35. package/dist/data-table.js +1 -1
  36. package/dist/data-table.js.map +1 -1
  37. package/dist/date-picker.d.ts +2 -2
  38. package/dist/icon-button-recipe.d.ts +2 -2
  39. package/dist/icon-button-recipe.js +1 -1
  40. package/dist/icon-button-recipe.js.map +1 -1
  41. package/dist/image.d.ts +2 -2
  42. package/dist/image.js +2 -2
  43. package/dist/image.js.map +1 -1
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/internal/thinking-orb/braid.d.ts +3 -0
  49. package/dist/internal/thinking-orb/braid.d.ts.map +1 -0
  50. package/dist/internal/thinking-orb/braid.js +47 -0
  51. package/dist/internal/thinking-orb/braid.js.map +1 -0
  52. package/dist/internal/thinking-orb/core.d.ts +60 -0
  53. package/dist/internal/thinking-orb/core.d.ts.map +1 -0
  54. package/dist/internal/thinking-orb/core.js +86 -0
  55. package/dist/internal/thinking-orb/core.js.map +1 -0
  56. package/dist/internal/thinking-orb/lattice.d.ts +5 -0
  57. package/dist/internal/thinking-orb/lattice.d.ts.map +1 -0
  58. package/dist/internal/thinking-orb/lattice.js +187 -0
  59. package/dist/internal/thinking-orb/lattice.js.map +1 -0
  60. package/dist/internal/thinking-orb/morph.d.ts +3 -0
  61. package/dist/internal/thinking-orb/morph.d.ts.map +1 -0
  62. package/dist/internal/thinking-orb/morph.js +127 -0
  63. package/dist/internal/thinking-orb/morph.js.map +1 -0
  64. package/dist/internal/thinking-orb/orbits.d.ts +3 -0
  65. package/dist/internal/thinking-orb/orbits.d.ts.map +1 -0
  66. package/dist/internal/thinking-orb/orbits.js +68 -0
  67. package/dist/internal/thinking-orb/orbits.js.map +1 -0
  68. package/dist/internal/thinking-orb/presets.d.ts +21 -0
  69. package/dist/internal/thinking-orb/presets.d.ts.map +1 -0
  70. package/dist/internal/thinking-orb/presets.js +77 -0
  71. package/dist/internal/thinking-orb/presets.js.map +1 -0
  72. package/dist/internal/thinking-orb/profiles.d.ts +8 -0
  73. package/dist/internal/thinking-orb/profiles.d.ts.map +1 -0
  74. package/dist/internal/thinking-orb/profiles.js +158 -0
  75. package/dist/internal/thinking-orb/profiles.js.map +1 -0
  76. package/dist/internal/thinking-orb/registry.d.ts +9 -0
  77. package/dist/internal/thinking-orb/registry.d.ts.map +1 -0
  78. package/dist/internal/thinking-orb/registry.js +27 -0
  79. package/dist/internal/thinking-orb/registry.js.map +1 -0
  80. package/dist/internal/thinking-orb/ribbon.d.ts +3 -0
  81. package/dist/internal/thinking-orb/ribbon.d.ts.map +1 -0
  82. package/dist/internal/thinking-orb/ribbon.js +87 -0
  83. package/dist/internal/thinking-orb/ribbon.js.map +1 -0
  84. package/dist/internal/thinking-orb/types.d.ts +15 -0
  85. package/dist/internal/thinking-orb/types.d.ts.map +1 -0
  86. package/dist/internal/thinking-orb/types.js +4 -0
  87. package/dist/internal/thinking-orb/types.js.map +1 -0
  88. package/dist/internal/thinking-orb/web.d.ts +3 -0
  89. package/dist/internal/thinking-orb/web.d.ts.map +1 -0
  90. package/dist/internal/thinking-orb/web.js +92 -0
  91. package/dist/internal/thinking-orb/web.js.map +1 -0
  92. package/dist/masonry.d.ts +17 -0
  93. package/dist/masonry.d.ts.map +1 -0
  94. package/dist/masonry.js +18 -0
  95. package/dist/masonry.js.map +1 -0
  96. package/dist/menubar.d.ts +3 -3
  97. package/dist/menubar.js +1 -1
  98. package/dist/menubar.js.map +1 -1
  99. package/dist/number-field.d.ts +2 -2
  100. package/dist/otp-field.d.ts +1 -1
  101. package/dist/password-field.d.ts +2 -2
  102. package/dist/popover.d.ts +7 -8
  103. package/dist/popover.d.ts.map +1 -1
  104. package/dist/popover.js +2 -0
  105. package/dist/popover.js.map +1 -1
  106. package/dist/qr-code-recipe.d.ts +7 -0
  107. package/dist/qr-code-recipe.d.ts.map +1 -0
  108. package/dist/qr-code-recipe.js +2 -0
  109. package/dist/qr-code-recipe.js.map +1 -0
  110. package/dist/qr-code.d.ts +16 -0
  111. package/dist/qr-code.d.ts.map +1 -0
  112. package/dist/qr-code.js +37 -0
  113. package/dist/qr-code.js.map +1 -0
  114. package/dist/semantic-colors.d.ts +1 -1
  115. package/dist/semantic-colors.js +1 -1
  116. package/dist/semantic-colors.js.map +1 -1
  117. package/dist/showcase.d.ts +5 -1
  118. package/dist/showcase.d.ts.map +1 -1
  119. package/dist/showcase.js +51 -13
  120. package/dist/showcase.js.map +1 -1
  121. package/dist/sidebar.d.ts +3 -3
  122. package/dist/sidebar.js +1 -1
  123. package/dist/sidebar.js.map +1 -1
  124. package/dist/tag.d.ts +4 -4
  125. package/dist/tag.js +3 -3
  126. package/dist/tag.js.map +1 -1
  127. package/dist/tags-input.d.ts +3 -3
  128. package/dist/tags-input.js +1 -1
  129. package/dist/tags-input.js.map +1 -1
  130. package/dist/text-formats.d.ts +2 -2
  131. package/dist/text-formats.js +2 -2
  132. package/dist/text-formats.js.map +1 -1
  133. package/dist/thinking-orb-recipe.d.ts +15 -0
  134. package/dist/thinking-orb-recipe.d.ts.map +1 -0
  135. package/dist/thinking-orb-recipe.js +9 -0
  136. package/dist/thinking-orb-recipe.js.map +1 -0
  137. package/dist/thinking-orb.d.ts +25 -0
  138. package/dist/thinking-orb.d.ts.map +1 -0
  139. package/dist/thinking-orb.js +40 -0
  140. package/dist/thinking-orb.js.map +1 -0
  141. package/dist/toast-liquid.d.ts +116 -0
  142. package/dist/toast-liquid.d.ts.map +1 -0
  143. package/dist/toast-liquid.js +100 -0
  144. package/dist/toast-liquid.js.map +1 -0
  145. package/dist/toast.d.ts +7 -1
  146. package/dist/toast.d.ts.map +1 -1
  147. package/dist/toast.js +5 -0
  148. package/dist/toast.js.map +1 -1
  149. package/dist/toggle-group.d.ts +2 -2
  150. package/dist/toggle-group.js +3 -3
  151. package/dist/toggle-group.js.map +1 -1
  152. package/dist/transfer-list.d.ts +3 -3
  153. package/dist/transfer-list.js +1 -1
  154. package/dist/transfer-list.js.map +1 -1
  155. package/dist/tree.d.ts +2 -2
  156. package/dist/version.d.ts +1 -1
  157. package/dist/version.js +1 -1
  158. package/dist/version.js.map +1 -1
  159. package/dist/virtual-list.d.ts +13 -0
  160. package/dist/virtual-list.d.ts.map +1 -0
  161. package/dist/virtual-list.js +13 -0
  162. package/dist/virtual-list.js.map +1 -0
  163. package/docs/anchor.md +5 -4
  164. package/docs/ant-design-coverage.md +2 -2
  165. package/docs/architecture.md +6 -2
  166. package/docs/authoring-brief.md +3 -2
  167. package/docs/bottom-navigation.md +7 -6
  168. package/docs/breadcrumb.md +5 -2
  169. package/docs/calendar.md +6 -3
  170. package/docs/carousel.md +2 -2
  171. package/docs/cascader.md +6 -0
  172. package/docs/catalog-cleanup.md +7 -0
  173. package/docs/catalog-decision-status.md +3 -3
  174. package/docs/catalog-freeze.json +9 -7
  175. package/docs/collapsible.md +12 -0
  176. package/docs/command-palette.md +5 -3
  177. package/docs/consumer-policy.md +29 -12
  178. package/docs/context-menu.md +12 -2
  179. package/docs/data-table.md +11 -6
  180. package/docs/date-picker.md +6 -4
  181. package/docs/date-range.md +4 -2
  182. package/docs/description-list.md +8 -9
  183. package/docs/dialog.md +39 -0
  184. package/docs/expansion-roadmap.md +11 -7
  185. package/docs/file-picker.md +5 -3
  186. package/docs/form.md +16 -4
  187. package/docs/generated/component-maturity.md +88 -91
  188. package/docs/generated/renderer-evidence.json +1848 -1023
  189. package/docs/generated/renderer-evidence.md +153 -145
  190. package/docs/generated/showcase-manifest.json +431 -497
  191. package/docs/layout.md +8 -9
  192. package/docs/library-gap-analysis.md +1 -1
  193. package/docs/masonry.md +11 -0
  194. package/docs/mentions.md +14 -7
  195. package/docs/optional-adapters.md +106 -0
  196. package/docs/otp-field.md +2 -1
  197. package/docs/pagination.md +4 -1
  198. package/docs/password-field.md +2 -1
  199. package/docs/popover.md +9 -6
  200. package/docs/promotion-candidates.md +2 -1
  201. package/docs/qr-code.md +11 -65
  202. package/docs/react-native-completion.md +1 -1
  203. package/docs/result.md +8 -5
  204. package/docs/screen-chrome.md +2 -1
  205. package/docs/sheet.md +8 -2
  206. package/docs/showcase.md +10 -2
  207. package/docs/side-panel.md +12 -6
  208. package/docs/sidebar.md +3 -0
  209. package/docs/splitter.md +6 -6
  210. package/docs/stable-core.md +72 -0
  211. package/docs/stable-promotion.md +47 -43
  212. package/docs/tags-input.md +5 -2
  213. package/docs/theme-palette.md +27 -0
  214. package/docs/thinking-orb.md +124 -0
  215. package/docs/timeline.md +2 -3
  216. package/docs/toast.md +6 -0
  217. package/docs/tooltip.md +2 -1
  218. package/docs/tour.md +14 -8
  219. package/docs/transfer-list.md +24 -21
  220. package/docs/tree-select.md +2 -1
  221. package/docs/tree.md +12 -7
  222. package/docs/upload-item.md +7 -3
  223. package/docs/virtual-list.md +10 -67
  224. package/package.json +30 -3
  225. package/docs/app-provider.md +0 -50
  226. package/docs/border-beam.md +0 -66
  227. package/docs/chart.md +0 -33
  228. package/docs/utility.md +0 -53
@@ -1,5 +1,77 @@
1
1
  # Stable Core
2
2
 
3
+ ## 2026-09-29 컴포넌트 승격 (다음 minor)
4
+
5
+ `Divider`, `Section`, `ListRow`, `Statistic`, `DescriptionList`, `EmptyState`, `Result`, `Layout`, `Splitter`, `Accordion`, `Agreement`, `FilePicker`, `Tabs`, `BottomNavigation`, `LoadMore`, `Mentions`,
6
+ `Heading`, `Top`, `BottomCTA`, `AspectRatio`, `Grid`, `Steps`, `TopBar`, `AuthScreenLayout`, `Radio`,
7
+ `Avatar`, `Asset`, `CounterBadge`, `Image`, `VisuallyHidden`, `List`, `Timeline`, `BottomInfo`, `Link`, `AuthProviderButton`, `PasswordField`, `CheckboxGroup`, `RadioGroup`, `Chip`, `SegmentedControl`, `SearchField`, `NumberField`, `Toast`, `FloatingActionButton`, `Checkbox`, `Switch`, `ToggleGroup`, `Slider`, `OtpField`, `TagsInput`, `DatePicker`, `DateRangePicker`, `Breadcrumb`, `Pagination`, `Menubar`, `Form`, `Sidebar(Web)`, `TransferList`, `UploadItem`, `ContextMenu(Web)`, `Menu`, `Anchor(Web)`, `Collapsible`, `DataTable(Web)`, `Tree(Web)`, `Calendar`, `Carousel`, `Tour(Web)`, `ThinkingOrb`, `Dialog`, `AlertDialog`, `Sheet`, `SidePanel(Web)`, `Popover(Web)`, `Tooltip(Web)`, `CommandPalette(Web)`, `SkipNav(Web)`을 각 지원 surface에서 stable로 승격합니다.
8
+ TextFormat, Splitter, Breadcrumb, Pagination, Menubar, Sidebar와 Web 전용 overlay/navigation 컴포넌트는 Web-only stable입니다. DateRangePicker, Accordion, Agreement, FilePicker, Tabs, BottomNavigation, LoadMore, Mentions, Form, TransferList, UploadItem, Menu, Collapsible, Calendar, Carousel, Dialog, AlertDialog, Sheet는 Web·Native stable입니다. ThinkingOrb도 Web·Native stable입니다. 현재 계약 stable은 100개, Web stable은 100개, Native stable은 83개입니다.
9
+
10
+ ## 2026-09-29 Beta → Stable 확인
11
+
12
+ - TransferList와 UploadItem은 두 renderer의 Web keyboard·Native host action 및 긴 문구 증거를 연결했습니다. TransferList의 narrow panel 라벨은 flex item intrinsic minimum을 초기화해 wrap되도록 고쳤습니다. UploadItem의 실제 transfer/network lifecycle은 소비 제품 소유라 maturity gate가 아닙니다.
13
+ - ContextMenu, Menu, Anchor, Collapsible, DataTable, Tree, Calendar는 각 surface에 적용되는 interaction과 긴 문구를 component-owned test로 확인했습니다. Unsupported surface는 계속 unsupported입니다.
14
+ - Carousel, Tour, Dialog, AlertDialog, Sheet, SidePanel, Popover, Tooltip, CommandPalette, SkipNav는 keyboard/focus/action과 좁은 viewport·긴 localized copy를 전용 renderer test로 확인했습니다. Native 증거는 host action simulation이며 실제 OS screen-reader claim이 아닙니다.
15
+ - Form Native는 `firstInvalidFieldRef`가 가리킨 제품 선택 입력으로 focus와 accessibility focus를 옮기고 제출 callback을 막는 경로를 추가했습니다. 제품은 validation·필드 순서를 계속 소유합니다.
16
+ - ThinkingOrb Web 전용 matrix는 dark, 200% text, RTL, reduced motion, accessibility semantics를 확인합니다. Native도 환경 matrix와 설치한 iOS·Android Skia smoke를 통과했습니다([검증 기록](thinking-orb.md)).
17
+ - 새 stable surface는 생성된 renderer evidence와 canonical `pnpm ci:check`가 통과해야 완료로 기록합니다. 제품 채택·배포·실기기 보조기기 QA는 소비자 릴리스에서 별도로 검증합니다.
18
+
19
+ - TextFormat은 `<kbd>`, `<code>`, `<blockquote>` 의미를 Web에서 제공하고 Native는 unsupported입니다.
20
+ 실제 긴 코드를 `<code>` slot에 넣는 Chromium matrix proof를 새로 연결했습니다.
21
+ - AspectRatio는 Web Chromium과 Native renderer matrix에서 비율 컨테이너 안의 긴 자식 콘텐츠를 검증했습니다.
22
+ 미디어 의미와 crop은 계속 제품이 소유합니다.
23
+ - Grid는 Web Chromium과 Native renderer matrix에서 셀 안의 긴 텍스트 줄바꿈을 검증했습니다.
24
+ - Steps는 계약이 요구하는 두 단계 이상 흐름에서 긴 단계 label을 Web Chromium과 Native matrix로 검증했습니다.
25
+ - TopBar Native compact title의 잘림을 제거해 `screen-chrome.md`의 줄바꿈 계약에 맞췄고, 긴 제목 matrix를 통과했습니다.
26
+ - AuthScreenLayout은 제품 소유 긴 제목을 hero slot에 넣어 Web Chromium과 Native matrix에서 검증했습니다.
27
+ - Radio는 긴 option label이 좁은 Web 열을 넓히지 않도록 선택 label의 최대 폭을 제한하고 Web/Native matrix에서 확인했습니다.
28
+ - List는 행 title에 긴 문구를 넣어 Web Chromium과 Native renderer matrix에서 줄바꿈을 확인했습니다.
29
+ - Timeline은 실제 이벤트 label의 긴 문구를 Web Chromium과 Native matrix에서 검증했습니다.
30
+ - BottomInfo는 제품 소유 안내 문구를 길게 넣어 Web Chromium과 Native matrix에서 줄바꿈을 확인했습니다.
31
+ - Link는 browser의 anchor Enter 활성화와 Native router host action을 각각 별도 interaction proof로 연결했습니다.
32
+ - AuthProviderButton은 Web Enter/Space와 Native host press에서 제품 소유 동작 호출을 확인했습니다.
33
+ - PasswordField는 Web Enter/Space로 값은 보존한 채 표시 상태가 바뀌고, Native host press도 같은 상태 전이를 일으키는지 검증했습니다.
34
+ - CheckboxGroup은 Web Space와 Native host press에서 선택 집합이 바뀌는 것을 각각 확인했습니다.
35
+ - RadioGroup은 Web Space와 Native host press에서 선택 옵션이 바뀌는 것을 각각 확인했습니다.
36
+ - Chip은 Web Space와 Native host press에서 선택 상태가 바뀌는 것을 각각 확인했습니다.
37
+ - SegmentedControl은 Web 화살표 키와 Native host press에서 선택값 전이를 확인했습니다.
38
+ - SearchField는 label 긴 문구 줄바꿈과 Web typing/clear, Native input/clear action을 검증했습니다.
39
+ - NumberField는 긴 label, Web ArrowUp, Native adjustable increment를 확인했습니다.
40
+ - Toast는 Web Enter 닫기와 Escape 해제, Native 접근성 닫기 action을 별도 회귀로 검증했습니다. Liquid presentation은 선택형 adapter로 stable을 상속하지 않습니다.
41
+ - FloatingActionButton은 Web/Native 긴 이름 렌더와 Web Enter·Native host press 활성화를 회귀로 확인했습니다. 기존 scroll 방향·focus 유지·safe-area 검증도 유지합니다.
42
+ - Checkbox는 Web/Native 긴 label과 Web Space·Native host press에서 선택값 전이를 확인했습니다.
43
+ - Switch는 Web/Native 긴 label과 Web Space·Native host press에서 checked 전이를 확인했습니다.
44
+ - ToggleGroup은 Web/Native 긴 option label과 Web Space·Native host press에서 pressed-id 집합 전이를 확인했습니다.
45
+ - Slider는 Web/Native 긴 label, Web ArrowRight, Native adjustable increment를 검증했습니다.
46
+ - OtpField는 양 renderer의 긴 label과 키보드 입력·숫자 정리 동작을 검증했습니다. 인증 절차 전체는 제품 소유로 남습니다.
47
+ - TagsInput은 Web Enter 확정과 Native Return 확정·이름 있는 삭제 action을 각각 검증했습니다. Native blur는 초안을 확정하지 않으며, Web 후보 키 탐색과 2단계 Backspace 동작은 Native parity로 주장하지 않습니다.
48
+ - Select는 긴 field label과 Web ArrowDown/Enter 선택, Native option host action을 확인했습니다. Native 선택은 실제 OS dialog 시각·접근성 검증을 포함하지 않습니다.
49
+ - Combobox는 긴 label과 Web 입력·ArrowDown/Enter 선택, Native 후보 host action 후 sheet dismissal commit을 검증했습니다. 실제 IME와 OS sheet·스크린 리더 동작은 기기에서 확인하지 않았습니다.
50
+ - Layout은 두 renderer의 긴 본문·접근성·환경 matrix와 Web skip-link Tab/Enter를 검증했습니다. Native에는 skip-link나 host action 계약이 없어 keyboard proof를 요구하지 않습니다. 제품 shell의 스크린 리더·실기기 확인은 제품 릴리스 QA 범위입니다.
51
+ - Splitter는 Web long-copy·접근성·환경 matrix와 실제 Tab focus 뒤 focused separator에서의 ArrowRight 조절을 검증했습니다. 기존 회귀는 drag/keyboard 동일 step grid·Home/End·RTL·disabled·44px hit target을 검사합니다. 제품 화면과 스크린 리더 실측은 보증하지 않습니다.
52
+ - DatePicker는 양 renderer의 긴 label·접근성·환경 matrix, Web의 trigger Tab/Enter와 날짜 ArrowRight/Enter 선택·닫힘·focus 복귀, Native 날짜 선택 host action을 검증했습니다. 제품 폼 및 실제 OS 스크린 리더 검증은 소비 앱 QA입니다.
53
+ - Breadcrumb는 긴 label matrix와 Tab/Shift+Tab·Enter 조상 링크 이동, 현재 위치의 non-interactive `aria-current` 동작을 Web에서 확인했습니다. Pagination은 Tab focus 순서, Space/Enter 페이지 전환, 현재 페이지 발표, 양쪽 경계의 focus 유지와 중복 전환 차단을 Web에서 검증했습니다. Pagination은 소비자 문장을 표시하지 않으므로 long-copy 요구를 제외했고, 숫자 폭은 320px·200%·RTL 테스트에 남겼습니다.
54
+ - Accordion은 Web Tab/Enter 확장·축소와 Native 이름 있는 press action의 expanded 상태를 검증했습니다. Agreement는 양쪽 표면에서 개별/전체 동의와 전문 보기 분리를 확인했고, FilePicker는 Web 키보드 trigger와 선택 결과 및 Native 제품 adapter action·공통 선택 판정을 검증했습니다. FilePicker OS 피커 연결과 법적 문구·동의 기록은 소비 앱 소유입니다.
55
+ - Tabs는 disabled skip, manual selection, 긴 이름의 실제 keyboard focus/activation을 검증했습니다. Chromium에서 overflow strip 안 긴 탭이 키보드 포커스 뒤 보이지 않는 문제를 고쳐 `scrollIntoView`를 연결하고 reduced motion일 때 즉시 이동을 확인했습니다. Native `activate` action도 확인했습니다. BottomNavigation은 Web Tab/Enter와 Native navigate/reselect action이 선택 상태를 외부 navigator에 남기는지, LoadMore는 observer/onEndReached gate·수동 retry·긴 상태 문구를 확인했습니다.
56
+ - Mentions는 Web/Native long-label matrix, Web Arrow/Enter/Escape/pointer 흐름, Native caret query callback과 이름 있는 후보 press action을 검증했습니다. Native callback은 parent state update를 render 중 실행하지 않습니다. Candidate filtering과 실제 IME device QA는 제품 소유입니다.
57
+ - Sidebar는 Web에서 disabled 항목을 건너뛰는 실제 Tab 순서, Enter로 접기, 접힌 상태의 접근성 이름, 긴 그룹·항목 라벨 줄바꿈을 Chromium으로 검증했습니다. 모바일 목적지는 기존 BottomNavigation 계약을 사용합니다.
58
+ - Avatar는 이름을 visible 문장으로 렌더하지 않고 initials/media로 나타내며, Asset과 Image는 visible media와 alt accessibility semantics를 제공합니다.
59
+ CounterBadge는 숫자/dot만, VisuallyHidden은 의도적으로 숨긴 accessibility text만 내므로 long-copy overflow는 이들의 계약을 시험하지 않습니다.
60
+ 이를 확인해 required scenario를 제외하고 기본·접근성·fallback proof를 유지했습니다. 기존 Icon·Skeleton 등 예외에 이 다섯 이름을 추가했습니다.
61
+ - 처음 7개는 변경 전에도 양쪽 renderer의 필수 시나리오 누락이 0이었습니다. 제품 채택 수만으로
62
+ 보류했던 조건을 [승격 기준](stable-promotion.md)에서 제거했습니다.
63
+ - Heading/Top은 행동이 없는 계약에 붙은 keyboard 요구만, BottomCTA는 중복 parity 요구만
64
+ 남아 있었습니다. TopBar는 Native 긴 제목 잘림을 고친 뒤 세 surface를 모두 승격합니다.
65
+ - Web은 `test/scenario-matrix.browser.test.tsx`, Native는 `test/scenario-matrix.test.tsx`의
66
+ default/접근성/환경 증거와 기존 컴포넌트 회귀를 사용합니다. Native 검사는 renderer mock이며
67
+ 기기·VoiceOver/TalkBack 실측을 주장하지 않습니다.
68
+ - 검증 명령은 canonical `pnpm ci:check`입니다. 실행 결과는
69
+ [이번 변경 기록](../../../docs/plans/beta-to-stable.md)에 남깁니다.
70
+ - 실제 제품 수·제품 배포 여부는 승격 조건이 아닙니다. 선택형 AnimatedStatistic·Liquid Toast·
71
+ 기타 확장은 기본 컴포넌트의 stable 상태를 상속하지 않습니다.
72
+
73
+ 아래 절은 각 릴리스 당시 기록입니다. 현재 조건은 위 승격 기준을 따릅니다.
74
+
3
75
  ## 1.5.0 승격
4
76
 
5
77
  다음 13개를 stable로 올렸습니다: `Text`, `Icon`, `Stack`, `Container`, `DesignSystemProvider`,
@@ -1,51 +1,55 @@
1
- # stable 승격 절차
1
+ # Stable 승격 기준
2
2
 
3
- 2026-09-18 기준 `stable`은 네 개다: Surface, Button, Field, TextArea. 나머지 90여 개
4
- Web renderer는 `beta`이고, 그 뜻은 **"renderer는 있고 제품 실측은 없다"**이다. 커버리지
5
- 감사가 "컴포넌트 수가 아니라 이 숫자가 배포 준비를 막는다"고 지적한 자리다.
3
+ 검토일: 2026-09-29. 이 문서가 성숙도 승격 조건의 원문입니다.
6
4
 
7
- 이 문서는 그 숫자를 움직이는 **조건과 순서**만 정한다. 승격 자체는 증거가 모인 뒤에 한다.
5
+ `stable`은 공개 API와 동작을 SemVer로 지원한다는 약속입니다. 변경을 영구히 금지하거나
6
+ 모든 제품·OS에서 검증을 마쳤다는 뜻은 아닙니다. `beta`는 API·동작 또는 renderer 검증에
7
+ 구체적인 미완료 항목이 있다는 뜻입니다. 채택 제품 수나 사용 기간으로 구분하지 않습니다.
8
8
 
9
- ## 왜 자동으로 올리지 않는가
9
+ ## 컴포넌트 승격에 필요한 것
10
10
 
11
- `beta → stable`은 "이 API를 바꾸지 않겠다"는 약속이다. 테스트가 초록이라는 것은 우리가
12
- 작성한 시나리오를 통과했다는 뜻이지, 실제 사용자가 그 화면을 통과했다는 뜻이 아니다.
13
- 정적 검사로 승격하면 그 약속의 근거가 우리 자신의 테스트뿐이게 된다.
11
+ 1. 공개 타입·기본값·지원 동작이 문서와 일치하고, 알려진 계약 공백이 없어야 합니다.
12
+ 2. 승격할 surface의 실제 renderer에 default·접근성·적용되는 환경/행동 회귀 증거가 있어야
13
+ 합니다. 필수 목록은 `showcaseManifest`이며 canonical `pnpm ci:check`를 통과해야 합니다.
14
+ 문서 등록, story 존재 또는 mock 실행을 실제 기기 검증으로 바꿔 부르지 않습니다.
15
+ 3. catalog와 생성물, Changeset에 승격 범위를 함께 반영합니다. 기록은
16
+ [Stable Core](stable-core.md)에 대상·검사·남은 제한을 간단히 남깁니다.
14
17
 
15
- ## 승격 조건 (네 가지 전부)
18
+ 별도 승격 전용 JSON, 승인 단계, 소비 앱 배포 영수증을 추가하지 않습니다.
19
+ Web과 Native는 `surfaceStatus`로 각각 판정합니다. Web-only의 승격에 Native 구현은 필요
20
+ 없습니다. 공유 contract의 승격과 각 renderer의 상태도 구분하고, 미구현 surface를 함께
21
+ stable로 올리지 않습니다. 선택형 모션·네이티브 확장은 기본 컴포넌트의 상태를 상속하지 않습니다.
16
22
 
17
- 1. **제품 채택** — 등록된 제품 최소 한 곳의 실제 화면에서 쓰이고, 그 화면이 배포돼 있다.
18
- Showcase 사용은 채택이 아니다.
19
- 2. **우회 없음** — 그 제품이 이 컴포넌트를 `.hjm-*` CSS로 덮거나 recipe 값을 다시 읽어
20
- 인라인 style로 싣고 있지 않다. 우회가 있으면 그것이 곧 API 공백이고, 공백이 있는 API를
21
- 고정하면 안 된다.
22
- 3. **보조기기 실측** — 해당 표면에서 한 번 이상 실제 확인. Web은 화면 리더 1종 + 키보드
23
- 전용 통과, Native는 VoiceOver 또는 TalkBack 통과. 기록은 제품 저장소에 남긴다.
24
- 4. **환경 4종** — dark, RTL, 2배 글자, reduced motion에서 그 **제품 화면**이 깨지지 않는다.
25
- (renderer evidence의 시나리오와 별개다. 그쪽은 우리 스토리, 이쪽은 실제 화면이다.)
23
+ ## 별도로 확인할 것
26
24
 
27
- ## 첫 후보 (다음 minor 게시 이후)
28
-
29
- BurnTok·Diairy가 실제로 소비 중이고 우회가 남아 있지 않은 것부터 본다.
30
-
31
- | 후보 | 채택처 | 남은 확인 |
25
+ | 항목 | 소유 범위 | 성숙도와의 관계 |
32
26
  | --- | --- | --- |
33
- | ListRow | BurnTok, Diairy, Taground | 우회 제거 후 재확인, 보조기기 |
34
- | Dialog | BurnTok(AppModal) | `onDismissComplete` 소비 후 0ms 타이머 제거 |
35
- | Sheet | BurnTok(AppSheet) | 같음 |
36
- | Toast | BurnTok | DS-01 우회 제거 |
37
- | Notice | Diairy | DS-11 우회 제거 |
38
- | Tabs | BurnTok | compact 우회가 제품 선택인지 API 공백인지 판정 |
39
- | TextField | BurnTok, Diairy | 설명·오류 동시 표시 변경 반영 확인 |
40
- | Select · Checkbox · Switch | 3개 제품 | 보조기기 |
41
-
42
- **순서**: minor 게시 → 소비 앱 dependency·lock 갱신 → 우회 제거 → 보조기기·환경 확인 →
43
- 증거를 제품 저장소에 기록 → 이 표를 근거로 승격 PR.
44
-
45
- ## 승격하지 않는 것
46
-
47
- - 제품이 아직 쓰지 않는 컴포넌트(이번에 추가한 Sidebar·TagsInput·Agreement 등). renderer가
48
- 있다는 것과 안심하고 쓸 수 있다는 것은 다른 말이다.
49
- - Native가 `planned`인 채로 Web만 성숙한 항목의 **contract status**. `status`는 계약
50
- 성숙도이고 표면별 성숙도는 `surfaceStatus`가 따로 갖는다 — 한쪽 표면만으로 계약을
51
- stable로 올리면 다른 표면이 조용히 약속에 포함된다.
27
+ | 제품 채택 수·사용 기간·배포 이력 | 채택 관측 | 우선순위와 개선 신호. 승격 최소치 없음 |
28
+ | 제품 화면의 키보드·스크린 리더·기기 QA | 소비 앱 릴리스 | 바뀐 흐름과 플랫폼 위험에 맞춰 실행 |
29
+ | HJM renderer 키 동작 / Native 접근성 action | Web `keyboard` / Native `native-actions` 증거 | 각 surface behavior contract에 실제 선언된 입력 방식만 요구 |
30
+ | 제품 화면의 dark·RTL·200%·reduced motion | 소비 앱 릴리스 | 제품이 지원하는 환경 검증. HJM 테스트와 중복 영수증을 요구하지 않음 |
31
+ | Web/Native 의미 일치 | 공통 계약과 관련 행동 회귀 | `adaptive` 전체에 별도 parity 테스트를 일괄 강제하지 않음 |
32
+ | 제품의 style 우회 | API 공백 또는 제품 이관 | HJM API 공백이면 해결. 단순 제품 이관 지연은 승격 조건 아님 |
33
+
34
+ 컴포넌트의 접근성·환경 검증은 계속 필요합니다. 제품의 임의 조합과 도메인 흐름까지 HJM
35
+ 성숙도 하나로 보증하려는 조건을 분리한 것입니다. 모달 focus/dismiss, 선택값 전이, 입력 복구
36
+ 같은 고유 행동의 검증은 생략하지 않습니다. 실제 OS에 의존하는 확장의 미검증 제한도 유지합니다.
37
+
38
+ Web keyboard는 DOM focus와 문서화된 key binding을 browser renderer에서 확인합니다. Native
39
+ behavior contract은 물리 키가 아니라 접근성 role·state·action을 선언하므로, `onPress`나
40
+ TalkBack action 테스트를 keyboard 증거로 기록하지 않습니다. Native `native-actions`는 그
41
+ host action과 상태 전이를 renderer test에서 확인하며 실제 키보드·VoiceOver·TalkBack 기기 QA는
42
+ 소비 앱 릴리스에서 수행합니다.
43
+
44
+ ## 변경 이유
45
+
46
+ 2026-09-29 감사에서 architecture는 ‘두 제품 또는 두 플랫폼’, 이 문서는 ‘한 제품 배포 +
47
+ 제품 화면 실측’, 과거 Stable Core 기록은 ‘세 제품’을 사용하고 있었습니다. 이미 양쪽 renderer
48
+ 필수 시나리오가 갖춰진 표시 컴포넌트 7개도 채택 수 때문에 beta에 머물렀습니다.
49
+ 제품 인기도와 릴리스 절차가 API 지원 약속을 가로막는 문제를 없애기 위해 조건을 통일했습니다.
50
+ 소비 Beta는 [소비 정책 §2](consumer-policy.md#2-성숙도별-채택)의 간단한 채택 기록으로 관리합니다.
51
+
52
+ 2026-09-29 후속 증거 감사에서는 Native 실행 레지스트리의 `keyboard` 증거가 실제 물리 키보드
53
+ 입력이 아니라 React Native host action 테스트에 연결된 것을 확인했습니다. Native 계약에 없는
54
+ 입력을 공통 keyboard gate로 강제하거나 터치 action을 키보드 검증이라고 부르지 않도록 surface별
55
+ 시나리오를 분리했습니다.
@@ -21,5 +21,8 @@
21
21
 
22
22
  **삭제는 위치 기준이다.** 중복을 허용한 제품에서 값 기준으로 지우면 엉뚱한 것이 사라진다.
23
23
 
24
- **Native.** 아직 renderer가 없다(catalog `planned`). 자유 입력 + 칩 목록은 키보드
25
- 회피·IME와 함께 검증해야 해서 Web 먼저 낸다.
24
+ **Native.** 현재 renderer는 `TextInput`의 Return으로 값을 확정하고 각 태그 옆의 이름
25
+ 있는 button action으로 삭제한다. 제안 목록이 있으면 후보도 button으로 고를 수 있다.
26
+ 초안은 포커스를 잃는 것만으로 확정하지 않는다. Web의 ArrowUp/Down 후보 탐색과 빈 입력
27
+ Backspace의 2단계 삭제는 Web 키보드 계약이며 Native에서 같은 키 동작을 주장하지 않는다.
28
+ Native 입력·Return·삭제는 renderer 회귀로 확인하고, IME와 OS별 키보드 동작은 기기 검증 범위다.
@@ -62,3 +62,30 @@ contracts·tree-select까지 연쇄로 초과).
62
62
  `borderControl`은 `#6b7684`를 그대로 둔다. 비텍스트 기준(3:1)이고 `surface` 위 4.19:1로 충분하다.
63
63
 
64
64
  **버린 대안:** 검사에서 `textSub`를 본문 기준에서 빼기. 실제 글자에 쓰이는 색을 기준에서 빼면 검사가 존재 이유를 잃는다.
65
+
66
+ ## 입력과 선택 항목은 흰 내부와 상태 테두리로 구분한다 (2026-09-29)
67
+
68
+ 전수 기기 확인 중 사용자가 회색·푸른색 입력/선택 배경을 제거하고, "푸른 테두리는 쓰는데 input 안은 흰색"으로 요청했다.
69
+ 입력 프레임, 검색·OTP·숫자·날짜 입력, 선택 카드·Chip·SegmentedControl·ToggleGroup은 라이트의 `bg`(`#ffffff`)를 사용한다.
70
+ 다크에는 같은 역할의 `bg`를 사용해 밝은 사각형이 따로 뜨지 않도록 한다. 포커스/선택 테두리와 체크 표시는 기존 브랜드색을 유지한다.
71
+ 휴지 상태 입력 테두리는 글자색 `textMuted` 대신 전용 `borderControl`을 사용한다.
72
+
73
+ 공식 참조는 [Ant Design Input](https://ant.design/components/input/)의 outlined 변형(흰 active/hover 내부, 파란 active 테두리),
74
+ [Radix Text Field](https://www.radix-ui.com/themes/docs/components/text-field)의 surface/soft 변형 분리,
75
+ [Atlassian Border](https://atlassian.design/foundations/border)의 기본·선택·포커스 테두리 역할 분리다.
76
+ Ant의 원시 색상이나 낮은 테두리 대비까지 복제하지 않고, HJM의 의미 토큰과 대비를 유지한다.
77
+ 포커스 링은 기존 2px 계약을 유지하며, 작은 체크·스위치 트랙·선택 날짜 표식과 주요 CTA는 넓은 입력 채움 배경과 구분한다.
78
+
79
+ **버린 대안:** 선택을 넓은 불투명 브랜드색 판으로 표현하거나 소비 앱에서 흰색 CSS만 덮어쓰기.
80
+ 전자는 이번 사용자 방향과 맞지 않고 후자는 웹·네이티브 및 다크 테마에 서로 다른 표현을 남긴다.
81
+
82
+ ### 전체 중립 표면으로 확대
83
+
84
+ 같은 화면 검토에서 사용자가 입력뿐 아니라 회색·연한 파란색 배경 전체를 제거하되 Create draft의 진한 파란색은 유지하도록 명확히 했다.
85
+ `Surface`·Card·메뉴·목록·아바타·Skeleton·보조 버튼도 canvas를 사용하며, 경계가 사라지는 곳은 테두리로 구분한다.
86
+ `ButtonTone.primary`와 주요 CTA/FAB, 작은 체크·스위치·진행 표시, 성공·위험 상태색은 그대로 유지한다.
87
+ 원시 팔레트의 surface/primary 색 자체를 흰색으로 덮지 않고 컴포넌트 배경 역할만 바꿔, 글자·아이콘·진행선의 의미가 바뀌지 않게 한다.
88
+
89
+ 버튼의 배경색은 소비 화면에서 직접 지정하지 않고 `ButtonTone`의 `primary | secondary | ghost | danger | link`로 선택한다.
90
+ 웹과 네이티브는 같은 `buttonRecipe`의 배경·글자·테두리 역할을 해석한다. Create draft는 `primary`를 유지하므로
91
+ 일반 표면의 canvas 전환과 독립적으로 기존 브랜드 채움색을 보존한다.
@@ -0,0 +1,124 @@
1
+ # ThinkingOrb — AI 작업 상태
2
+
3
+ 검토일: 2026-09-29. 원본: [Thinking Orbs](https://github.com/Jakubantalik/thinking-orbs/tree/de85557ca220332586d070d8788c0e1d6e877a0d), MIT.
4
+
5
+ ## 결정과 범위
6
+
7
+ 사용자가 Thinking Orbs의 HJM 흡수를 요청했다. catalog 동결의 이번 예외는 실제 AI 작업의
8
+ 검색·듣기·생성 상태를 표시하는 컴포넌트 하나다. 기존 Spinner를 대체하거나 장식용으로
9
+ 자동 순환시키지 않는다. upstream 패키지를 runtime dependency로 연결하는 대신 고정 커밋의
10
+ 기하 엔진·튜닝만 편입한다. 두 renderer가 같은 엔진을 사용하고 HJM의 테마·접근성·생명주기를
11
+ 유지해야 하기 때문이다. 원본 고지는 배포 패키지의 THIRD_PARTY_NOTICES.md에 포함한다.
12
+
13
+ ## API
14
+
15
+ 웹은 `@hjmds/react/thinking-orb`, Native는 `@hjmds/react-native/thinking-orb`.
16
+ 공통 계약은 `@hjmds/design-contracts/components/thinking-orb`로만 가져온다.
17
+ 선택형 코드가 일반 컴포넌트 번들에 들어가지 않도록 root barrel에서는 재수출하지 않는다.
18
+
19
+ ```tsx
20
+ <ThinkingOrb state="searching" size={64} label={t('agent.searching')} active={screenVisible} />
21
+ ```
22
+
23
+ - `state`: working, searching, solving, listening, connecting, weaving, composing, breathing, shaping.
24
+ 실제 상태를 앱에서 전달한다. listening은 음성 크기에 반응하는 오디오 시각화가 아니다.
25
+ - `size`: 20 또는 64. 원본의 점 수·반지름 튜닝을 유지하며 임의 CSS 확대는 지원하지 않는다.
26
+ - `label`: 필수. 앱에서 번역한 현재 작업 설명. 완료·오류 때는 별도 결과 UI로 교체한다.
27
+ - `speed`: 기본 1, 유한수 0 초과 4 이하. 무제한 속도는 읽기 어려운 모션을 만들므로 제한한다.
28
+ - `paused`: 프레임 시간을 유지. 재개 시 숨겨진 시간만큼 건너뛰지 않는다.
29
+ - `active`: 기본 true. Native의 탭/내비게이션/가상 목록에서 보이지 않을 때 false를 전달한다.
30
+ AppState만으로는 여전히 mounted인 숨긴 화면을 알아낼 수 없기 때문이다.
31
+
32
+ HJM provider의 `text` 색을 깊이에 따른 opacity와 조합한다. 원본의 고정 grayscale 팔레트는
33
+ 브랜드 테마와 배경에서 어긋날 수 있어 사용하지 않는다. 기하 좌표는 원본과 동일하다.
34
+ 모션 줄이기에서는 elapsed 0.6초 프레임만 그린다. 긴 JS 정체 후 이동은 최대 64ms로 제한해
35
+ 순간적인 모션 점프를 줄인다. 상태 전환은 새 모양으로 즉시 바뀌며 morph 전환은 제공하지 않는다.
36
+ 웹은 role=status와 숨긴 텍스트, Native는 접근 가능한 progressbar host를 사용한다.
37
+ Canvas는 접근성 트리에서 제외한다. 외부에 문구를 함께 표시할 때 중복 live region을 두지 않는다.
38
+
39
+ ## 호환성과 증거 경계
40
+
41
+ 웹: React 19 + Canvas 2D. IntersectionObserver, document visibility, provider reduced motion에 반응.
42
+ Native: 선택형 Skia 2.6.2 + Reanimated 4.5.1 + Worklets 0.10.1, Expo 57/RN 0.86.2 조합을 검증 대상으로 한다.
43
+ 기본 renderer의 RN >=0.81 계약이 이 선택형 효과의 지원 범위를 보장하지 않는다.
44
+ Skia Picture를 shared value로 전달해 매 프레임 React commit을 피하지만 기하 계산과 picture
45
+ recording은 JS thread에서 실행한다. UI worklet 기반이라는 주장은 하지 않는다.
46
+
47
+ 원본 Native는 기기 미검증을 명시하지만, HJM은 아래 설치 smoke를 별도로 수행했다.
48
+ HJM Native 승격 조건은 실제 설치 앱에서 Skia가 그려지는 기본 smoke를 iOS와 Android에서 확인하는 것이다. 이 gate는 선택형 네이티브 모듈과
49
+ 렌더러 연결을 확인한다. Metro bundle과 mock lifecycle 검사만으로 이 연결을 증명할 수 없기
50
+ 때문이다.
51
+ Web 승격에는 showcase manifest의 dark·large-text·RTL·reduced-motion·accessibility 행렬을
52
+ 실제 browser renderer에서 확인해야 한다. 제품 채택 수와 제품 화면의 VoiceOver/TalkBack 확인은
53
+ 소비 앱 QA이며 HJM renderer 성숙도의 추가 gate가 아니다([stable-promotion.md](stable-promotion.md)).
54
+ Native smoke는 각 OS에서 설치 앱의 대표 상태 한 가지를 light/dark theme으로 렌더링하고 label이
55
+ 포함된 progressbar host를 확인한다. 9개 상태·두 크기의 geometry와 host 접근성 속성은 Native
56
+ renderer 테스트에서 확인하며 reduced-motion·navigation·background/resume lifecycle도 mock
57
+ 회귀 테스트에서 확인한다. 이 분리는 모든 조합의 실제 device 캡처와 장시간 메모리 stress를
58
+ 승격 gate로 요구했던 이전 안이 소비 앱 QA와 성능 보증까지 HJM maturity에 넣었기 때문이다.
59
+ VoiceOver/TalkBack 사용성은 소비 앱에서 확인하고, 성능 stress는 실측 이슈나 성능 주장이 생길
60
+ 때 수행한다. Native는 아래 iOS·Android smoke와 renderer matrix 통과 후 stable로 승격했다.
61
+
62
+ 원본 golden fixture 72개는 engine 좌표·반지름·깊이·정렬을 비교한다. Canvas lifecycle 검사는
63
+ 정지/재개/viewport/테마를 확인한다. default renderer proof와 실측 모션/성능 증거는 구별한다.
64
+
65
+ ## 이번 checkout 검증 — 2026-09-29
66
+
67
+ - 공통 계약 테스트 883개(원본 72개 golden 포함), Web SSR 172개, Web Chromium 773개,
68
+ Native mock 731개 통과. 공개 export 목록 갱신 후 실패했던 경계 검사를 재실행했다.
69
+ Native 기존 provider-theme 테스트는 병렬 부하에서 timeout 후 worker 2개로 전체 재실행해 통과했다.
70
+ - Web showcase 테스트·token 검사·production build 통과. 112 canonical story 중 97 Web renderer.
71
+ 실제 브라우저에서 AllStates의 9상태 × 20/64, light/dark 화면 확인.
72
+ - Native showcase typecheck/test, 기본 Metro Android production fixture 통과. ThinkingOrb Native
73
+ mock renderer regression now covers all 9 states × 2 sizes × 2 themes and lifecycle; this is not
74
+ installed-app Skia runtime proof.
75
+ Expo 57 showcase의 iOS/Android Hermes export 성공. 이것은 native binary 설치/실행 증거가 아니다.
76
+ - contract/renderer bundle 예산, workspace/evidence 동기화, 문서 링크, release governance,
77
+ 중앙 library-policy 정적 검사 통과. 원격 CI·게시·소비 앱 적용은 실행하지 않았다.
78
+ - 기존 Device Hub 프로세스와 부팅된 iPhone 18 Pro / iOS 27.0을 확인했지만,
79
+ `com.apple.dt.Devices` 화면 조회는 `timeoutReached`로 실패했다. 새 기기를 만들거나
80
+ 부팅하지 않았으며 Native visual/performance/assistive-technology 증거는 미완료다.
81
+
82
+ ### 설치 smoke 전 자동 검증 — 2026-09-29
83
+
84
+ Native renderer 테스트가 820개로 확장되어 ThinkingOrb의 9상태 × 두 크기 × 두 테마,
85
+ 접근 가능한 progressbar host와 숨긴 Canvas semantics, reduced-motion/navigation/background
86
+ lifecycle을 확인한다. React Native typecheck와 canonical `pnpm ci:check`가 통과했다.
87
+ 이 검사는 mock renderer 범위다. iOS·Android 각각의 설치 앱에서 Skia가 실제로 그려지는 smoke는
88
+ 아직 실행하지 않아 Native surface는 planned로 유지한다.
89
+
90
+ ### 설치 앱 검증 및 Native 승격 — 2026-09-29
91
+
92
+ - 기존 iPhone 17 시뮬레이터(iOS 27.0)와 Android emulator-5554(Android 16/API 36)에서
93
+ 설치된 HJM showcase의 Skia 렌더링을 확인했다. 물리 기기 검증은 아니다.
94
+ - 두 OS 모두 9상태 × 두 크기 light/dark 화면을 확인했다. 접근성 snapshot에서
95
+ `검색 중` label과 busy 상태를 확인했다. iOS는 UpdatesFrequently trait, Android는
96
+ focusable host를 노출한다. progressbar React Native prop은 renderer 테스트로 확인하며
97
+ OS snapshot의 GenericElement/View 표기를 별도 progressbar class로 과장하지 않는다.
98
+ - Android background 후 Playground 복귀 화면도 확인했다. 5개 환경 scenario와 canonical
99
+ default-render proof를 추가했으며 관련 renderer 검사 88개가 통과했다.
100
+ - iOS 최초 실행은 UIScene 누락으로 SIGTRAP 종료됐다. Expo ~57.0.25와 scene lifecycle
101
+ config plugin 적용 후 빌드(오류/경고 0), 설치, 실행, light/dark 전환이 성공했다.
102
+ 개발 서버는 RCT_jsLocation=localhost:8084로 연결했다.
103
+ - Device Hub 조회는 timeoutReached로 두 번 실패하여 같은 시뮬레이터에서 simctl 캡처와
104
+ idb 접근성 조회로 검증했다. 새 기기는 만들거나 부팅하지 않았다.
105
+ - iOS는 ThinkingOrb 집중 profile로 unrelated menu adapters를 제외했다. 전체 optional
106
+ showcase의 RCT-Folly 충돌을 해결했다는 뜻은 아니다. VoiceOver/TalkBack 제품 QA,
107
+ 장시간 성능 검증, 게시 및 소비 앱 적용은 이 smoke 범위 밖이다.
108
+
109
+ [캡처와 접근성 증거](../../../docs/evidence/thinking-orb-2026-09-29/README.md),
110
+ [재현 절차](../../../showcase/native/README.md),
111
+ [호스트 수정 근거](../../../docs/LIBRARY_POLICY.md)를 함께 유지한다.
112
+
113
+ ### 설치 smoke 후 최종 검사 — 2026-09-29
114
+
115
+ Contracts 885, React SSR 174 + Chromium 886, React Native 826, Web Showcase 19,
116
+ Native Showcase 1: 기능 테스트 총 2,791개 통과. 승격 과정에서 Native evidence export 목록과
117
+ Storybook registry 누락을 수정해 해당 검사를 다시 통과했다. Evidence 메타데이터는
118
+ 10.7 kB raw / 2.72 kB gzip으로 늘어 한 모듈 graph 유지 확인 후 예산만 갱신했다.
119
+ `pnpm ci:check` 단일 실행은 기존 evidence budget에서 중단되었고, 수정 후 그 단계부터
120
+ 나머지 canonical 명령을 순서대로 재실행하여 모두 통과했다. 최종 전체 명령을 다시
121
+ 한 번 실행했다고 주장하지 않는다. Renderer/contract budgets, Android Metro fixture,
122
+ workspace/evidence/docs/governance, 양쪽 showcase 검사, Web Storybook build 및
123
+ 112 canonical story inventory, 중앙 library-policy 정적 검사, `git diff --check` 통과.
124
+ 게시·소비 앱 갱신은 실행하지 않았다.
package/docs/timeline.md CHANGED
@@ -141,6 +141,5 @@ Ant Design Timeline의 `mode="alternate"`(항목이 좌우로 번갈아 배치)
141
141
  `LiveScreen.tsx:797-821`의 PBP 플레이 기록이 실제로 존재하는 후보다 — "일어난 일,
142
142
  순서, 커서 없음"이라는 경계는 정확히 일치한다. 다만 지금은 `timelineRecipe`의 dot/
143
143
  connector 시각이 아니라 평평한 `AppListRow` 목록으로 그려져 있어, 시각 recipe 쪽
144
- vertical slice는 아직 없다. `planned → beta` 승격은 실제 제품 vertical slice 이후
145
- 리드가 진행한다(로드맵 maturity gate). 구단 상세의 영입·유출 이력은 여전히 미확인
146
- 후보로 남긴다.
144
+ vertical slice는 이 조사에서 확인하지 못했다. 구단 상세의 영입·유출 이력도 미확인 후보였다.
145
+ 2026-09-29부터 제품 채택은 관측으로 분리하며 [현재 승격 기준](stable-promotion.md)을 따른다.
package/docs/toast.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Toast contract
2
2
 
3
+ Native의 선택형 `liquid` presentation은 같은 descriptor/store를 사용합니다.
4
+ [사용 및 호환성](../../react-native/docs/liquid-toast.md),
5
+ [설계·검증 경계](../../../docs/plans/liquid-toast.md)를 따릅니다.
6
+ Web 또는 adapter 없는 Native는 같은 알림을 standard surface로 표시합니다.
7
+ `presentation`·`occlusion`은 renderer가 소유하는 독립 pause reason입니다.
8
+
3
9
  Toast는 사용자가 응답해야만 진행되는 modal UI가 아니라, 무시해도 안전한 짧은 알림입니다.
4
10
  필수 선택·삭제 확인·시간 안에 응답해야 하는 작업은 `AlertDialog`를 사용합니다.
5
11
 
package/docs/tooltip.md CHANGED
@@ -3,7 +3,8 @@
3
3
  `Tooltip`은 Web에서 이미 의미와 focus를 가진 interactive trigger에 짧은 보충 설명을
4
4
  제공합니다. 중요한 정보, 오류, 행동, link를 Tooltip 안에 숨기지 않으며 Native에 억지로
5
5
  동일한 hover UI를 만들지 않습니다. BurnTok Web renderer와 실제 알림 trigger에서 아래
6
- 수명주기·RTL·접근성 계약을 검증했으므로 catalog는 `web / beta`입니다.
6
+ 수명주기·RTL·접근성 계약과 전용 keyboard·320px long-copy browser proof를 통과해 catalog는
7
+ 2026-09-29부터 `Web / stable`입니다. Native는 `unsupported`입니다.
7
8
 
8
9
  ## Public descriptor
9
10
 
package/docs/tour.md CHANGED
@@ -130,10 +130,13 @@ Popover처럼 순수 판정 함수(`resolveTourAdvance`, `validateTourOpenState`
130
130
  | "다시 보지 않기" 영속화 | **배제** — 제품이 `TourCloseReason`을 받아 직접 저장할 몫 |
131
131
  | 비동기 busy/error 상태 | **배제** — Tour에는 되돌릴 수 없는 side effect가 없다. AlertDialog의 세션 패턴을 가져올 이유가 없다 |
132
132
 
133
- ## Web renderer (2026-09-18)
133
+ ## Web renderer (promotion scope reviewed 2026-09-29)
134
134
 
135
- `@hjmds/react/tour`의 `Tour`가 이 계약을 실행한다. catalog는 Web `beta`,
136
- Native `unsupported`다. 제품 vertical slice와 보조기기 실측은 아직 없다.
135
+ `@hjmds/react/tour`의 `Tour`가 이 계약을 실행한다. 정확한 승격 범위는 Web
136
+ renderer이며 Native는 계속 `unsupported`다. Web renderer 증거는 stable 승격에
137
+ 준비됐다. 전용 Chromium proof가 긴 번역 copy와 키보드 단계 진행·anchor 이동을
138
+ 확인하며, 테스트를 중앙 evidence 및 실행 시나리오에 등록했다. 생성 evidence와 canonical
139
+ `pnpm ci:check`가 모두 통과한 뒤 catalog에 반영한다.
137
140
 
138
141
  - **anchor는 끝까지 제품 소유다.** props는 노드가 아니라
139
142
  `resolveAnchor(anchorId)`를 받는다. renderer는 단계가 바뀔 때마다, 그리고 스크롤·
@@ -147,11 +150,14 @@ Native `unsupported`다. 제품 vertical slice와 보조기기 실측은 아직
147
150
  포인터가 둘러보기를 끝내지 못한다. Escape와 건너뛰기는 어느 단계에서나 나간다.
148
151
  - **unmount는 `interrupted`로 한 번만 정산한다.** StrictMode의 probe cleanup과 실제
149
152
  unmount를 epoch로 구분한다(Sheet와 같은 방식).
150
- - 로컬 검증: `test/tour.browser.test.tsx` 6개(이름·안내·단계마다 초점 이동, 배경 inert와
151
- 바깥 pointer 무시, 첫 단계 이전은 no-op·마지막 다음은 complete, Escape·건너뛰기 탈출,
152
- unmount의 1회 interrupted, controlled owner 종료와 320px 배치)와 `Patterns/Tour`.
153
+ - 로컬 검증: `test/tour.browser.test.tsx` 7개(이름·안내·단계마다 초점 이동과 키보드
154
+ 다음 단계에 맞춘 anchor 하이라이트, 배경 inert와 바깥 pointer 무시, 첫 단계 이전은
155
+ no-op·마지막 다음은 complete, Escape·건너뛰기 탈출, unmount의 1회 interrupted,
156
+ controlled owner 종료와 320px 배치, 긴 번역 copy 내부 스크롤·키보드 건너뛰기·호출자
157
+ focus 복귀)와 `Patterns/Tour`.
153
158
 
154
159
  ## 검증 화면
155
160
 
156
- 제품 vertical slice는 아직 없다. 유력 후보는 Yajalal 홈 화면 첫 진입
157
- 안내(검색 → 즐겨찾기 → 알림)이며, 채택 전까지 `beta`는 renderer 수준 증거만 뜻한다.
161
+ 제품 화면 통합과 실제 OS 스크린 리더·보조기기 확인은 소비 앱 릴리스 QA에서 수행한다.
162
+ 이는 [Stable 승격 기준](stable-promotion.md)의 consumer QA 범위이며 HJM Web renderer
163
+ 승격 조건이 아니다. 제품별 앵커 선택과 안내 문구 품질도 제품 소유 계약으로 남는다.
@@ -91,24 +91,27 @@ Native의 "터치 전용"에도 같게 적용되므로, 버튼이 항상 스와
91
91
 
92
92
  ## 검증 화면
93
93
 
94
- 아직 없음. `planned → beta` 승격은 실제 제품 vertical slice 이후 리드가 진행한다.
95
-
96
- ## Web renderer (2026-09-18)
97
-
98
- `@hjmds/react/transfer-list`의 `TransferList`가 이 계약을 실행한다. catalog는 Web `beta`,
99
- Native `planned`다 — Native renderer는 아직 없다.
100
-
101
- - **이동은 키보드만으로 끝난다.** Space로 고르고 이동 버튼을 누르거나, 초점이 있는 행에서
102
- Enter로 그 행 하나만 바로 옮긴다. 후자는 계약의 "단일 이동에 다중 선택을 먼저 만들게
103
- 하지 않는다"는 항목이다.
104
- - **이동 후 초점은 계약이 정한다.** `resolveTransferListFocusAfterMove`가 미끄러져 들어온
105
- 행을 돌려주고, 패널이 비면 빈 상태 문구(`tabIndex=-1`)로 보낸다. 문서 body로 초점이
106
- 풀리는 경우가 없다.
107
- - **옮긴 항목은 도착 패널에서 선택되지 않는다.** 이동은 값을 확정하는 것이지 사용자가 하지
108
- 않은 새 선택을 만드는 것이 아니다.
109
- - **모두 선택은 disabled를 분모에서 뺀다.** 분자·분모 모두에서 빠지므로 잠긴 행이 있어도
110
- "모두 선택"이 mixed로 굳지 않는다.
111
- - **문장은 제품이 만든다.** `onMove`는 옮긴 id를 원래 패널 순서로만 넘긴다.
112
- - 로컬 검증: `test/transfer-list.browser.test.tsx` 5개(키보드 다중 이동과 id 보고, 단일
113
- 행 즉시 이동, 이동 후 초점과 빈 상태 초점, disabled 제외와 이동 금지, 되돌리기와 패널당
114
- tab stop 하나)와 `Patterns/TransferList`.
94
+ 이 조사 당시 제품 채택은 미확인이었다. 2026-09-29부터 제품 채택은 관측으로 분리하며,
95
+ 현재 성숙도는 catalog와 [승격 기준](stable-promotion.md)을 따른다.
96
+
97
+ ## Renderer notes (2026-09-29)
98
+
99
+ Web and Native both implement TransferList. These renderer notes describe source-level behavior;
100
+ they do not claim installed-device, VoiceOver, or TalkBack validation.
101
+
102
+ - **Web keyboard interaction:** Space toggles the focused row and the shared move button commits
103
+ a selection; Enter moves one focused row directly. ArrowUp/ArrowDown/Home/End change the roving
104
+ row focus. After a move, focus goes to the row that slides into the vacated position or to the
105
+ empty-state message, so it does not fall to the document body. See
106
+ `packages/react/test/transfer-list.browser.test.tsx`.
107
+ - **Native host interaction:** each panel's `ScrollView` is exposed as a named list and each row is
108
+ an individually labelled checkbox. Selecting a row and activating the shared move button moves
109
+ it without relying on a swipe gesture. React Native's host renderer proves the accessibility
110
+ props and handler wiring, not physical keyboard or screen-reader behavior. See
111
+ `packages/react-native/test/transfer-list-actions.test.tsx`.
112
+ - **Long copy:** both renderers leave row copy untruncated. Web wraps at narrow viewport widths;
113
+ Native leaves font scaling enabled and does not set a line limit. The browser and host-renderer
114
+ tests verify those source-level constraints.
115
+ - **Shared behavior:** moved rows are not preselected at the destination, disabled rows cannot be
116
+ selected or moved, and select-all excludes disabled rows from its denominator. `onMove` gives
117
+ the product moved ids in source-panel order so it can compose an announcement.
@@ -98,7 +98,8 @@ antd `TreeSelect`의 `checkStrictly`(부모/자식을 독립적으로 체크할
98
98
 
99
99
  ## 검증 화면
100
100
 
101
- 아직 없음. `planned → beta` 승격은 실제 제품 vertical slice 이후 리드가 진행한다.
101
+ 이 조사 당시 제품 채택은 미확인이었다. 2026-09-29부터 제품 채택은 관측으로 분리하며,
102
+ 현재 성숙도는 catalog와 [승격 기준](stable-promotion.md)을 따른다.
102
103
 
103
104
  ## 조합으로 제공한다 (2026-09-18)
104
105
 
package/docs/tree.md CHANGED
@@ -110,7 +110,8 @@ Carousel과 같은 이유로 어순·조사를 여기서 조립하지 않는다)
110
110
 
111
111
  ## 검증 화면
112
112
 
113
- 아직 없음. `planned → beta` 승격은 실제 제품 vertical slice 이후 리드가 진행한다.
113
+ 이 조사 당시 제품 채택은 미확인이었다. 2026-09-29부터 제품 채택은 관측으로 분리하며,
114
+ 현재 성숙도는 catalog와 [승격 기준](stable-promotion.md)을 따른다.
114
115
 
115
116
  ## TreeSelect 판정
116
117
 
@@ -124,8 +125,9 @@ popup/sheet 표면에 얹으면 된다. 새 recipe나 새 상태 축이 필요
124
125
 
125
126
  ## Web renderer (2026-09-18)
126
127
 
127
- `@hjmds/react/tree`의 `Tree`가 이 계약을 실행한다. catalog는 Web `beta`,
128
- Native `unsupported`다. 제품 채택·보조기기 실측은 아직 없다.
128
+ `@hjmds/react/tree`의 `Tree`가 이 계약을 실행한다. Web hierarchy·keyboard focus·selection과 긴
129
+ label proof를 통과해 2026-09-29 stable로 승격한다. Native는 `unsupported`이며 제품 채택·보조기기
130
+ 실측은 소비 앱 release QA에서 별도로 확인한다.
129
131
 
130
132
  - **판정은 전부 계약이 한다.** 화살표(`getTreeArrowResult`), 상하·Home/End
131
133
  (`getVisibleTreeNavigationTarget`), 타이핑 검색(`getVisibleTreeTypeaheadMatch`),
@@ -138,7 +140,10 @@ Native `unsupported`다. 제품 채택·보조기기 실측은 아직 없다.
138
140
  - **tri-state 체크는 노드 자체에 실린다.** `checkedStates`(=`resolveTreeCheckedStates`
139
141
  결과)를 주면 행이 `aria-checked`로 true/false/mixed를 말한다. 체크박스를 행 안에 넣으면
140
142
  tab stop 규칙이 깨지므로 넣지 않았다.
141
- - 로컬 검증: `test/tree.browser.test.tsx` 6개(깊이·형제 위치 발표, 단일 tab stop과 roving,
142
- 펼침·접힘과 접힌 subtree 건너뛰기, RTL 화살표 반전, disabled의 선택만 차단·타이핑 검색,
143
- tri-state 파생과 enabled leaf만의 cascade)와 `Patterns/Tree`.
144
-
143
+ - 브라우저 검증: `test/tree.browser.test.tsx` 8개. 기존 여섯 동작(깊이·형제 위치 발표,
144
+ 단일 tab stop과 roving, 펼침·접힘과 접힌 subtree 건너뛰기, RTL 화살표 반전,
145
+ disabled의 선택만 차단·타이핑 검색, tri-state 파생과 enabled leaf만의 cascade)에 더해,
146
+ 포커스된 자식에서 부모로 돌아온 뒤 접어도 선택 상태와 포커스가 유지되는지, 320px 폭에서
147
+ 긴 라벨이 줄바꿈되어 트리 바깥으로 넘치지 않는지를 실제 브라우저에서 확인한다.
148
+ 긴 문구 케이스는 환경 행렬에 연결할 수 있도록 `default-render-fixtures.tsx`에도 등록했다.
149
+ 이 테스트는 보조기기 실측이나 제품 채택 근거를 대신하지 않는다.
@@ -63,6 +63,10 @@
63
63
  `error`만 쓴다. `loadingMore`와 `empty`는 목록 페이지네이션 개념이라 한 파일의
64
64
  상태에는 적용되지 않는다.
65
65
 
66
- **검증 화면.** first-party Web·Native renderer와 cancel/retry 상태 테스트는 연결되어
67
- surface는 `beta`다. 실제 전송 lifecycle을 쓰는 제품 vertical slice는 아직 없으므로
68
- `stable` 승격 gate는 닫혀 있다.
66
+ **검증 화면.** Web browser test는 긴 파일명·크기·상태 문구가 좁은 화면에서도 유지되고
67
+ 취소 버튼이 Tab/Enter로 동작하는지 확인한다. Native renderer test는 긴 문구, uploading의
68
+ `busy` 상태, 취소·재시도 action을 확인하지만 하드웨어 키보드나 VoiceOver/TalkBack 동작을
69
+ 증명하지 않는다. HJM은 caller가 전달한 전송 상태를 표시하고 action을 전달한다. 서버 전송,
70
+ 실제 취소, 재시도 lifecycle 검증은 소비 제품이 소유하므로 이 vertical slice의 부재는 HJM
71
+ renderer 승격을 막지 않는다. 2026-09-29 승격 기준 정리에서 adoption/deployment 조건을
72
+ 분리했고, renderer 계약과 실제 제품 흐름을 중복 요구하지 않기로 했다.