@qijenchen/design-system 0.1.0-beta.85 → 0.1.0-beta.87

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 (481) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  50. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  51. package/dist/components/DataTable/data-table-filter-panel.js +3 -4
  52. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  53. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  54. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  55. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  56. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  57. package/dist/components/DataTable/data-table.d.ts +1 -1
  58. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  59. package/dist/components/DataTable/data-table.js +44 -32
  60. package/dist/components/DataTable/data-table.js.map +1 -1
  61. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  62. package/dist/components/DatePicker/date-picker.js +4 -4
  63. package/dist/components/DatePicker/date-picker.js.map +1 -1
  64. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  65. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  66. package/dist/components/DescriptionList/description-list.js +6 -6
  67. package/dist/components/DescriptionList/description-list.js.map +1 -1
  68. package/dist/components/Dialog/dialog.d.ts +2 -2
  69. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  70. package/dist/components/Dialog/dialog.js.map +1 -1
  71. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  72. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  73. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  74. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  75. package/dist/components/Field/field-context.d.ts +16 -10
  76. package/dist/components/Field/field-context.d.ts.map +1 -1
  77. package/dist/components/Field/field-context.js.map +1 -1
  78. package/dist/components/Field/field-types.d.ts +2 -2
  79. package/dist/components/Field/field-types.d.ts.map +1 -1
  80. package/dist/components/Field/field-types.js.map +1 -1
  81. package/dist/components/Field/field-wrapper.d.ts +20 -4
  82. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  83. package/dist/components/Field/field-wrapper.js +30 -31
  84. package/dist/components/Field/field-wrapper.js.map +1 -1
  85. package/dist/components/Field/field.d.ts +1 -1
  86. package/dist/components/Field/field.d.ts.map +1 -1
  87. package/dist/components/Field/field.js +25 -3
  88. package/dist/components/Field/field.js.map +1 -1
  89. package/dist/components/Field/use-form-validation.d.ts +1 -1
  90. package/dist/components/Field/use-form-validation.js.map +1 -1
  91. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  92. package/dist/components/FileItem/file-item.js +2 -5
  93. package/dist/components/FileItem/file-item.js.map +1 -1
  94. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  95. package/dist/components/FileUpload/file-upload.js +5 -1
  96. package/dist/components/FileUpload/file-upload.js.map +1 -1
  97. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  98. package/dist/components/FileViewer/file-viewer.js +2 -1
  99. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  100. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  101. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  102. package/dist/components/HoverCard/hover-card.js +4 -2
  103. package/dist/components/HoverCard/hover-card.js.map +1 -1
  104. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  105. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  106. package/dist/components/InlineEdit/inline-edit.js +104 -62
  107. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  108. package/dist/components/Input/input.d.ts +1 -1
  109. package/dist/components/Input/input.d.ts.map +1 -1
  110. package/dist/components/Input/input.js +6 -6
  111. package/dist/components/Input/input.js.map +1 -1
  112. package/dist/components/LinkInput/link-input.d.ts +5 -5
  113. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  114. package/dist/components/LinkInput/link-input.js +3 -3
  115. package/dist/components/LinkInput/link-input.js.map +1 -1
  116. package/dist/components/Notice/notice.d.ts +17 -1
  117. package/dist/components/Notice/notice.d.ts.map +1 -1
  118. package/dist/components/Notice/notice.js +7 -1
  119. package/dist/components/Notice/notice.js.map +1 -1
  120. package/dist/components/NumberInput/number-input.d.ts +1 -1
  121. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  122. package/dist/components/NumberInput/number-input.js +12 -1
  123. package/dist/components/NumberInput/number-input.js.map +1 -1
  124. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  125. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  126. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  127. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  128. package/dist/components/PeoplePicker/people-picker.js +7 -5
  129. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  130. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  131. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  132. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  133. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  134. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  135. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  136. package/dist/components/RadioGroup/radio-group.js +1 -1
  137. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  138. package/dist/components/Rating/rating.d.ts.map +1 -1
  139. package/dist/components/Rating/rating.js +4 -0
  140. package/dist/components/Rating/rating.js.map +1 -1
  141. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  142. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  143. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  144. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  145. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  146. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  147. package/dist/components/Select/select.d.ts +16 -6
  148. package/dist/components/Select/select.d.ts.map +1 -1
  149. package/dist/components/Select/select.js +17 -5
  150. package/dist/components/Select/select.js.map +1 -1
  151. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  152. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  153. package/dist/components/SelectMenu/select-menu.js +17 -3
  154. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  155. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  156. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  157. package/dist/components/Sheet/sheet.d.ts +2 -2
  158. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  159. package/dist/components/Sheet/sheet.js.map +1 -1
  160. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  161. package/dist/components/Sidebar/sidebar.js +2 -2
  162. package/dist/components/Sidebar/sidebar.js.map +1 -1
  163. package/dist/components/Slider/slider.d.ts.map +1 -1
  164. package/dist/components/Slider/slider.js +6 -3
  165. package/dist/components/Slider/slider.js.map +1 -1
  166. package/dist/components/Steps/steps.d.ts +6 -4
  167. package/dist/components/Steps/steps.d.ts.map +1 -1
  168. package/dist/components/Steps/steps.js +19 -5
  169. package/dist/components/Steps/steps.js.map +1 -1
  170. package/dist/components/Switch/switch.d.ts +4 -4
  171. package/dist/components/Switch/switch.d.ts.map +1 -1
  172. package/dist/components/Switch/switch.js +3 -1
  173. package/dist/components/Switch/switch.js.map +1 -1
  174. package/dist/components/Tabs/tabs.d.ts +1 -1
  175. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  176. package/dist/components/Tabs/tabs.js +73 -23
  177. package/dist/components/Tabs/tabs.js.map +1 -1
  178. package/dist/components/Tag/tag.d.ts +3 -1
  179. package/dist/components/Tag/tag.d.ts.map +1 -1
  180. package/dist/components/Tag/tag.js +2 -2
  181. package/dist/components/Tag/tag.js.map +1 -1
  182. package/dist/components/Textarea/textarea.d.ts +4 -4
  183. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  184. package/dist/components/Textarea/textarea.js +15 -15
  185. package/dist/components/Textarea/textarea.js.map +1 -1
  186. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  187. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  188. package/dist/components/TimePicker/time-picker.js +8 -5
  189. package/dist/components/TimePicker/time-picker.js.map +1 -1
  190. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  191. package/dist/components/Tooltip/tooltip.js +27 -23
  192. package/dist/components/Tooltip/tooltip.js.map +1 -1
  193. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  194. package/dist/components/TreeView/tree-view.js +16 -0
  195. package/dist/components/TreeView/tree-view.js.map +1 -1
  196. package/dist/index.d.ts +7 -7
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +6 -13
  199. package/dist/index.js.map +1 -1
  200. package/dist/lib/drag-visual.d.ts +2 -2
  201. package/dist/lib/drag-visual.js.map +1 -1
  202. package/dist/lib/utils.d.ts +1 -0
  203. package/dist/lib/utils.d.ts.map +1 -1
  204. package/dist/lib/utils.js +21 -1
  205. package/dist/lib/utils.js.map +1 -1
  206. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  207. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  208. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  209. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  210. package/dist/tokens/categorical-color.d.ts +3 -3
  211. package/dist/tokens/categorical-color.d.ts.map +1 -1
  212. package/dist/tokens/categorical-color.js +2 -2
  213. package/dist/tokens/categorical-color.js.map +1 -1
  214. package/ds-canonical/fork/AGENTS.md +213 -0
  215. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  216. package/ds-canonical/fork/codex/hooks.json +16 -0
  217. package/ds-canonical/fork/governance.lock +22 -7
  218. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  219. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  220. package/ds-canonical/fork/manifest.json +10 -1
  221. package/ds-canonical/fork/preamble.md +3 -2
  222. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  223. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  224. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  225. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  226. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  227. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +19 -2
  228. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  229. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  230. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  232. package/ds-canonical/references/certified-surfaces.md +20 -0
  233. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  234. package/ds-canonical/references/principle-dim-map.json +20 -2
  235. package/ds-canonical/references/props-naming.md +2 -1
  236. package/ds-canonical/references/ssot-index.md +2 -2
  237. package/ds-canonical/references/story-baseline-registry.json +2 -2
  238. package/ds-canonical/rules/story-rules.md +1 -1
  239. package/ds-canonical/rules/ui-development.md +2 -1
  240. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  241. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  242. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  243. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  244. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  245. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  246. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  247. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  248. package/ds-story-manifest.json +21 -21
  249. package/llms-full.txt +3 -3
  250. package/llms.txt +1 -1
  251. package/package.json +2 -1
  252. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  253. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  254. package/src/components/Accordion/accordion.spec.md +10 -1
  255. package/src/components/Accordion/accordion.stories.tsx +10 -5
  256. package/src/components/Accordion/accordion.tsx +7 -2
  257. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  258. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  259. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  260. package/src/components/AppShell/app-shell.spec.md +4 -0
  261. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  262. package/src/components/Avatar/avatar.tsx +1 -1
  263. package/src/components/Badge/badge.spec.md +2 -2
  264. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  265. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  266. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  267. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  268. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  269. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  270. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  271. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  272. package/src/components/Button/button-group.tsx +4 -4
  273. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  274. package/src/components/Button/button.principles.stories.tsx +1 -1
  275. package/src/components/Button/button.spec.md +2 -2
  276. package/src/components/Button/button.stories.tsx +22 -28
  277. package/src/components/Button/button.tsx +2 -1
  278. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  279. package/src/components/Calendar/calendar.spec.md +1 -1
  280. package/src/components/Carousel/carousel.spec.md +17 -1
  281. package/src/components/Carousel/carousel.tsx +93 -42
  282. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  283. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  284. package/src/components/Checkbox/checkbox.spec.md +12 -3
  285. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  286. package/src/components/Checkbox/checkbox.tsx +79 -19
  287. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  288. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  289. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  290. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  291. package/src/components/Combobox/combobox.spec.md +6 -2
  292. package/src/components/Combobox/combobox.stories.tsx +9 -36
  293. package/src/components/Combobox/combobox.tsx +42 -27
  294. package/src/components/Command/command.spec.md +3 -3
  295. package/src/components/Command/command.tsx +9 -2
  296. package/src/components/DataTable/cell-registry.tsx +75 -76
  297. package/src/components/DataTable/column-types.ts +4 -17
  298. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  299. package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
  300. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  301. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  302. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  303. package/src/components/DataTable/data-table.css +2 -3
  304. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  305. package/src/components/DataTable/data-table.spec.md +8 -7
  306. package/src/components/DataTable/data-table.stories.tsx +39 -29
  307. package/src/components/DataTable/data-table.tsx +90 -67
  308. package/src/components/DataTable/filter-operators.spec.md +2 -0
  309. package/src/components/DateGrid/date-grid.spec.md +1 -1
  310. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  311. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  312. package/src/components/DatePicker/date-picker.spec.md +10 -9
  313. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  314. package/src/components/DatePicker/date-picker.tsx +13 -13
  315. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  316. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  317. package/src/components/DescriptionList/description-list.spec.md +12 -12
  318. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  319. package/src/components/DescriptionList/description-list.tsx +10 -10
  320. package/src/components/Dialog/dialog.tsx +4 -1
  321. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  322. package/src/components/Empty/empty.spec.md +0 -1
  323. package/src/components/Field/field-context.ts +17 -11
  324. package/src/components/Field/field-controls.spec.md +46 -37
  325. package/src/components/Field/field-types.ts +14 -12
  326. package/src/components/Field/field-wrapper.tsx +59 -43
  327. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  328. package/src/components/Field/field.principles.stories.tsx +5 -28
  329. package/src/components/Field/field.spec.md +5 -4
  330. package/src/components/Field/field.stories.tsx +103 -72
  331. package/src/components/Field/field.tsx +36 -4
  332. package/src/components/Field/form-validation.spec.md +4 -0
  333. package/src/components/Field/use-form-validation.ts +1 -1
  334. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  335. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  336. package/src/components/FileItem/file-item.tsx +10 -8
  337. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  338. package/src/components/FileUpload/file-upload.spec.md +3 -2
  339. package/src/components/FileUpload/file-upload.tsx +5 -1
  340. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  342. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  343. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  344. package/src/components/FileViewer/file-viewer.tsx +3 -2
  345. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  346. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  347. package/src/components/HoverCard/hover-card.spec.md +2 -2
  348. package/src/components/HoverCard/hover-card.tsx +4 -2
  349. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  350. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  351. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  352. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  353. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  354. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  355. package/src/components/Input/input.principles.stories.tsx +3 -3
  356. package/src/components/Input/input.spec.md +4 -4
  357. package/src/components/Input/input.stories.tsx +3 -3
  358. package/src/components/Input/input.tsx +13 -13
  359. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  360. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  361. package/src/components/LinkInput/link-input.spec.md +6 -2
  362. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  363. package/src/components/LinkInput/link-input.tsx +21 -19
  364. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  365. package/src/components/Notice/notice.tsx +8 -2
  366. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  367. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  368. package/src/components/NumberInput/number-input.spec.md +6 -6
  369. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  370. package/src/components/NumberInput/number-input.tsx +17 -5
  371. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  372. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  373. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  374. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  375. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  376. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  377. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  378. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  379. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  380. package/src/components/PeoplePicker/person-display.tsx +3 -3
  381. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  382. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  383. package/src/components/Popover/popover.spec.md +4 -2
  384. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  385. package/src/components/ProfileCard/profile-card.tsx +1 -1
  386. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  387. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  388. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  389. package/src/components/README.md +1 -0
  390. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  391. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  392. package/src/components/RadioGroup/radio-group.tsx +19 -14
  393. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  394. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  395. package/src/components/Rating/rating.spec.md +2 -2
  396. package/src/components/Rating/rating.stories.tsx +4 -18
  397. package/src/components/Rating/rating.tsx +5 -1
  398. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  399. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  400. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  401. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  402. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  403. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  404. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  405. package/src/components/Select/select.principles.stories.tsx +3 -3
  406. package/src/components/Select/select.spec.md +10 -1
  407. package/src/components/Select/select.stories.tsx +41 -27
  408. package/src/components/Select/select.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  410. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  411. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  412. package/src/components/SelectMenu/select-menu.tsx +38 -5
  413. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  414. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  415. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  416. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  417. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  418. package/src/components/Sheet/sheet.tsx +4 -1
  419. package/src/components/Sidebar/sidebar.tsx +1 -1
  420. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  421. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  422. package/src/components/Slider/slider.spec.md +13 -1
  423. package/src/components/Slider/slider.stories.tsx +44 -32
  424. package/src/components/Slider/slider.tsx +13 -4
  425. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  426. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  427. package/src/components/Steps/steps.spec.md +4 -2
  428. package/src/components/Steps/steps.stories.tsx +4 -56
  429. package/src/components/Steps/steps.tsx +31 -7
  430. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  431. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  432. package/src/components/Switch/switch.spec.md +4 -4
  433. package/src/components/Switch/switch.stories.tsx +3 -3
  434. package/src/components/Switch/switch.tsx +16 -10
  435. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  436. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  437. package/src/components/Tabs/tabs.spec.md +5 -2
  438. package/src/components/Tabs/tabs.stories.tsx +36 -44
  439. package/src/components/Tabs/tabs.tsx +101 -36
  440. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  441. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  442. package/src/components/Tag/tag.spec.md +4 -1
  443. package/src/components/Tag/tag.tsx +5 -3
  444. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  445. package/src/components/Textarea/textarea.spec.md +5 -5
  446. package/src/components/Textarea/textarea.tsx +24 -24
  447. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  448. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  449. package/src/components/TimePicker/time-picker.spec.md +6 -5
  450. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  451. package/src/components/TimePicker/time-picker.tsx +24 -14
  452. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  453. package/src/components/Toast/toast.stories.tsx +1 -1
  454. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  455. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  456. package/src/components/Tooltip/tooltip.spec.md +9 -3
  457. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  458. package/src/components/Tooltip/tooltip.tsx +12 -2
  459. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  460. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  461. package/src/components/TreeView/tree-view.spec.md +8 -6
  462. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  463. package/src/components/TreeView/tree-view.tsx +36 -0
  464. package/src/index.ts +13 -10
  465. package/src/lib/drag-visual.ts +2 -2
  466. package/src/lib/utils.ts +19 -0
  467. package/src/patterns/action-bar/action-bar.spec.md +1 -0
  468. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  469. package/src/patterns/element-anatomy/item-anatomy.spec.md +4 -0
  470. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  471. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  472. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  473. package/src/tokens/categorical-color.ts +5 -5
  474. package/src/tokens/color/color.spec.md +4 -4
  475. package/src/tokens/color/primitives.css +9 -2
  476. package/src/tokens/motion/motion.spec.md +6 -7
  477. package/src/tokens/opacity/opacity.spec.md +1 -1
  478. package/src/tokens/orphan-tokens.spec.md +1 -1
  479. package/src/tokens/typography/typography.spec.md +2 -0
  480. package/src/tokens/uiSize/uiSize.css +5 -0
  481. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -7,6 +7,7 @@ import { cva, type VariantProps } from "class-variance-authority"
7
7
  import { cn } from "@/lib/utils"
8
8
  import type { FieldMode, FieldVariant } from "@/design-system/components/Field/field-types"
9
9
  import { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from "@/design-system/components/Field/field-context"
10
+ import { useControllable } from "@/design-system/hooks/use-controllable"
10
11
  import { fieldWrapperStyles } from "@/design-system/components/Field/field-wrapper"
11
12
  import { SelectionItem } from "@/design-system/components/SelectionControl/selection-item"
12
13
  import { BooleanValueIcon } from "@/design-system/components/SelectionControl/boolean-value"
@@ -80,8 +81,13 @@ const checkStrokeWidth: Record<string, number> = { sm: 3, md: 3, lg: 2.5 }
80
81
 
81
82
  // ── Types ───────────────────────────────────────────────────────────────────
82
83
 
84
+ // asChild / children 從公開型別 Omit(2026-07-17 d9i6):Checkbox 有**固定 anatomy** —
85
+ // 內部恆渲染 Indicator(Check / Minus 兩子節點),非 Slot host。若保留 Radix `asChild`,
86
+ // consumer 傳入的元素會被 Radix Slot `React.Children.only` 因多子節點在執行期拋錯(失敗記憶索引
87
+ // 已 codify 此 asChild 多子節點 bug class);`children` 同理會被固定 Indicator 覆蓋。需自訂佈局
88
+ // 請用 `label` / `description` / `icon` / `avatar` 一級 props(內部自動包 SelectionItem)。
83
89
  export interface CheckboxProps
84
- extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
90
+ extends Omit<React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>, 'asChild' | 'children'>,
85
91
  VariantProps<typeof checkboxVariants> {
86
92
  /**
87
93
  * Inline label。提供時 Checkbox 自動透過 SelectionItem 包裝,
@@ -111,7 +117,7 @@ export interface CheckboxProps
111
117
  /**
112
118
  * Field mode(2026-05-05 Phase B3 align):
113
119
  * edit — 一般可互動 checkbox(預設)
114
- * display — **純展示**:渲染 Check / X icon(true=勾 / false=叉,無互動 primitive、無 input chrome);
120
+ * view — **純展示**:渲染 Check / X icon(true=勾 / false=叉,無互動 primitive、無 input chrome);
115
121
  * 對齊 Carbon read-only / DataTable boolean cell 場景。取代既有 BooleanDisplay。
116
122
  * readonly — 同 readOnly prop:checkbox 視覺保留 + 鎖互動 + a11y readonly signal
117
123
  * disabled — 同 disabled prop:降色 + 鎖互動
@@ -143,6 +149,13 @@ const Checkbox = React.forwardRef<
143
149
  mode,
144
150
  // chrome 對 Checkbox 主體無視覺影響(無 input wrapper)— 接收純為 prop 一致性;destructure 防 leak 到 DOM。
145
151
  variant: _chrome,
152
+ // controllable checked triplet(2026-07-17 d26i0):於 wrapper 層取出,交由 useControllable 持有
153
+ // resolved 值,供 edit / view / readonly 三分支共用。原本 view / readonly 分支各自讀 raw prop →
154
+ // uncontrolled(只傳 defaultChecked)在 edit 態 toggle 後切 mode 會丟失目前值(Radix 內部狀態
155
+ // wrapper 讀不到)。移出 props 後 edit 主路徑改由 checked={resolvedChecked} 受控(見下方 rootEl)。
156
+ checked: checkedProp,
157
+ defaultChecked: defaultCheckedProp,
158
+ onCheckedChange,
146
159
  id: idProp,
147
160
  ...props
148
161
  },
@@ -154,7 +167,7 @@ const Checkbox = React.forwardRef<
154
167
 
155
168
  // Field context:Checkbox 單獨塞進 Field(binary toggle)時,忽略自己的 label 讓 FieldLabel 接管
156
169
  // 2026-05-31 #35:hooks(useFieldContext / useContext / useId)必在任何 conditional return 前呼叫(Rules of Hooks)。
157
- // 原 mode='display' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。
170
+ // 原 mode='view' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。
158
171
  //
159
172
  // **例外**:Checkbox 是 CheckboxGroup 的 child 時(multi-select 情境),**每個 checkbox
160
173
  // 的 label 是它自己的選項名**,FieldLabel 只是群組名稱 — 此時 label **必須保留**,
@@ -181,7 +194,7 @@ const Checkbox = React.forwardRef<
181
194
  const generatedId = React.useId()
182
195
  const inputId = idProp ?? (insideGroup ? generatedId : (fieldCtx?.id ?? generatedId))
183
196
 
184
- // 2026-06-08 SSOT cascade:disabled + mode 經 resolver hook(原 raw prop → <Field disabled>/<Field mode="display"> 漏 cascade)
197
+ // 2026-06-08 SSOT cascade:disabled + mode 經 resolver hook(原 raw prop → <Field disabled>/<Field mode="view"> 漏 cascade)
185
198
  const resolvedDisabled = useResolvedFieldDisabled(disabled)
186
199
  const resolvedMode = useResolvedFieldMode({ mode, disabled, readOnly })
187
200
  const effectiveReadOnly = readOnly || resolvedMode === 'readonly'
@@ -192,36 +205,74 @@ const Checkbox = React.forwardRef<
192
205
  // readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)
193
206
  const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'
194
207
 
195
- // 2026-07-04 修:display / readonly-in-Field 分支的裸 span/div 原丟棄剩餘 props
208
+ // 2026-07-04 修:view / readonly-in-Field 分支的裸 span/div 原丟棄剩餘 props
196
209
  // (id/data-*/aria-*)且不轉發 forwardRef ref → consumer 的 aria-label 等靜默失效。
197
- // 抽出 Radix 專屬 non-DOM props,其餘 DOM props 於兩分支 spread 轉發(與 Switch/
198
- // RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。
210
+ // 抽出 Radix 專屬 form props(required/name/value 不可落到裸 span/div),其餘 DOM props 於兩分支
211
+ // spread 轉發(與 Switch/RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。
212
+ // (checked/defaultChecked/onCheckedChange 已於上方 top-level destructure 取出交 useControllable;
213
+ // asChild/children 已從 CheckboxProps 型別 Omit — 固定 anatomy 非 Slot host,見型別註解。)
199
214
  const {
200
- checked: checkedProp,
201
- defaultChecked: defaultCheckedProp,
202
- onCheckedChange: _onCheckedChange,
203
215
  required: _required,
204
216
  name: _name,
205
217
  value: _value,
206
- asChild: _asChild,
207
- children: _children,
208
218
  ...restDomProps
209
219
  } = props
210
220
 
211
- // ── mode='display'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────
221
+ // ── Resolved checked SSOT(controlled / uncontrolled dual-mode,2026-07-17 d26i0)──────────
222
+ // 對齊 Input / Textarea 既有 canonical(field-controls.spec.md「有值判定」:useControllable 內部
223
+ // resolved value + form.reset bridge)。修 view / readonly 分支原各自讀 raw prop 導致「uncontrolled
224
+ // 切 mode 丟失目前值」的 dual-mode 缺口。controlled(傳 checked)時 useControllable 純 passthrough,
225
+ // edit 行為 Δ=0。
226
+ const isControlled = checkedProp !== undefined
227
+ const [resolvedChecked, setResolvedChecked] = useControllable<boolean | 'indeterminate'>({
228
+ value: checkedProp,
229
+ defaultValue: defaultCheckedProp ?? false,
230
+ })
231
+
232
+ // form.reset() bridge(uncontrolled only):wrapper 取得 controllable 主導後,HTML 標準 reset 不發
233
+ // 變更事件 → 手動把 resolvedChecked 歸位 defaultChecked(對齊 input.tsx 同名 bridge)。keyed on
234
+ // resolvedMode:切回 edit 重掛 native Root 時 effect 重跑補掛 listener;view / readonly(Root
235
+ // unmount)時 innerRef 為 null → early return 不掛。
236
+ const innerRef = React.useRef<HTMLButtonElement | null>(null)
237
+ React.useEffect(() => {
238
+ if (isControlled) return
239
+ const form = innerRef.current?.form
240
+ if (!form) return
241
+ const handleReset = () => setResolvedChecked(defaultCheckedProp ?? false)
242
+ form.addEventListener('reset', handleReset)
243
+ return () => form.removeEventListener('reset', handleReset)
244
+ }, [isControlled, resolvedMode, defaultCheckedProp, setResolvedChecked])
245
+ // Merge refs(input.tsx setRef idiom):innerRef 供 reset bridge 取 form,同時轉發 forwardRef ref。
246
+ const setRef = React.useCallback((el: HTMLButtonElement | null) => {
247
+ innerRef.current = el
248
+ if (typeof ref === 'function') ref(el)
249
+ else if (ref) (ref as React.MutableRefObject<HTMLButtonElement | null>).current = el
250
+ }, [ref])
251
+
252
+ // ── mode='view'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────
212
253
  // 純展示模式:無互動 primitive、渲染 Check / X icon(true=勾 / false=叉,中性 foreground 色)。
213
254
  // boolean 值展示符號 SSOT = SelectionControl/boolean-value.tsx(勾/叉 icon + 中性色 + M22 世界級對照)。取代 BooleanDisplay。
214
- if (resolvedMode === 'display') {
215
- const isChecked = checkedProp === true
255
+ if (resolvedMode === 'view') {
256
+ const isChecked = resolvedChecked === true
257
+ // a11y(2026-07-17 d10i2):BooleanValueIcon 帶 aria-hidden → 裸 span 在 a11y tree 無名,
258
+ // 布林值對螢幕閱讀器完全消失。給 view 容器 role="img" + aria-label 承載值語意(對齊 MUI X
259
+ // DataGrid boolean cell 的 icon role/label 世界級做法);consumer 若自帶 aria-label 則優先。
260
+ const viewAriaLabel = (restDomProps as { 'aria-label'?: string })['aria-label'] ?? (isChecked ? '是' : '否')
216
261
  return (
217
- <span {...restDomProps} ref={ref as React.Ref<HTMLSpanElement>} className="inline-flex">
262
+ <span
263
+ {...restDomProps}
264
+ ref={ref as React.Ref<HTMLSpanElement>}
265
+ role="img"
266
+ aria-label={viewAriaLabel}
267
+ className="inline-flex"
268
+ >
218
269
  <BooleanValueIcon checked={isChecked} size={resolvedBoxSize} />
219
270
  </span>
220
271
  )
221
272
  }
222
273
 
223
274
  // ── mode='readonly' in Field(2026-06-12 拍板「灰框 + 勾/叉」;2026-07-09 ✓/— glyph → Check/X icon)─
224
- // Field 內 readonly boolean = readonly 灰框 chrome + display 同款值語言(勾/叉 icon)。
275
+ // Field 內 readonly boolean = readonly 灰框 chrome + view 同款值語言(勾/叉 icon)。
225
276
  // 灰框消費 fieldWrapperStyles 同一 cva = 與 Input readonly 字面同源(SSOT,改一處全動)。
226
277
  // 理由:同一張 readonly 表單裡文字控件有 bg-readonly 灰框鎖定訊號,boolean 保留全彩
227
278
  // 控件會誤導「仍可操作」(世界級 0/4 用原樣鎖互動:Salesforce=✓ 靜態 glyph /
@@ -229,7 +280,7 @@ const Checkbox = React.forwardRef<
229
280
  // Scope:僅 Field 內且無 inline label(FieldLabel 接管 label 的表單欄位場景);
230
281
  // standalone readOnly(settings list / SelectionItem row)維持原樣鎖互動不變。
231
282
  if (effectiveReadOnly && insideField && effectiveLabel == null) {
232
- const isChecked = (checkedProp ?? defaultCheckedProp) === true
283
+ const isChecked = resolvedChecked === true
233
284
  const boxSize = resolvedBoxSize
234
285
  return (
235
286
  <div
@@ -256,8 +307,17 @@ const Checkbox = React.forwardRef<
256
307
  const rootEl = (
257
308
  <CheckboxPrimitive.Root
258
309
  id={inputId}
259
- ref={ref}
310
+ ref={setRef}
260
311
  disabled={effectiveDisabled}
312
+ // controllable checked SSOT(2026-07-17 d26i0):Root 受 wrapper resolvedChecked 主導,
313
+ // onCheckedChange 先同步 wrapper 內部 state 再 forward consumer → uncontrolled(只傳
314
+ // defaultChecked)toggle 後切 mode(view / readonly)仍保留目前值。controlled(傳 checked)
315
+ // 時 useControllable 純 passthrough,edit 行為 Δ=0。
316
+ checked={resolvedChecked}
317
+ onCheckedChange={(next) => {
318
+ setResolvedChecked(next)
319
+ onCheckedChange?.(next)
320
+ }}
261
321
  aria-readonly={effectiveReadOnly || undefined}
262
322
  data-readonly={effectiveReadOnly || undefined}
263
323
  tabIndex={effectiveReadOnly ? -1 : undefined}
@@ -68,7 +68,7 @@ export const Overview: Story = {
68
68
  <table className="text-caption border-collapse">
69
69
  <thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
70
70
  <tbody>
71
- <tr><Td mono>children</Td><Td mono>ReactNode</Td><Td mono>—</Td><Td>anchor trigger element(Popover asChild)</Td></tr>
71
+ <tr><Td mono>children</Td><Td mono>ReactElement</Td><Td mono>—</Td><Td>anchor trigger element(Popover asChild Slot 單 element 契約,2026-07-05 型別收緊)</Td></tr>
72
72
  <tr><Td mono>open / onOpenChange</Td><Td mono>boolean / (o) =&gt; void</Td><Td mono>—</Td><Td>controlled 控制(多步 tour 必用)</Td></tr>
73
73
  <tr><Td mono>defaultOpen</Td><Td mono>boolean</Td><Td mono>—</Td><Td>uncontrolled 初始開啟狀態</Td></tr>
74
74
  <tr><Td mono>kind</Td><Td mono>'tips' | 'new-features' | ReactNode</Td><Td mono>—</Td><Td>有值則渲染 Header(tour-level title);'tips'→「使用技巧」、'new-features'→「新功能介紹」、ReactNode→自訂;multi-step tour 建議傳</Td></tr>
@@ -126,9 +126,9 @@ export const Inspector: Story = {
126
126
  </div>
127
127
  <Coachmark
128
128
  open
129
- image={hasImage ? <MediaGradient from="var(--color-indigo-6)" to="var(--color-purple-6)" icon={Sparkles} label="功能介紹" /> : undefined}
130
- title="試試新功能"
131
- description="這是 Coachmark 的說明文字;多行內容會自動換行並保持 leading 一致。"
129
+ image={hasImage ? <MediaGradient from="var(--color-indigo-6)" to="var(--color-purple-6)" icon={Sparkles} label="AI 續寫" /> : undefined}
130
+ title="讓 AI 幫你續寫草稿"
131
+ description="選取一段文字,AI 會依前後文續寫並保留你的語氣;不滿意可以一鍵重新產生。"
132
132
  step={hasStep ? { current: 2, total: 3 } : undefined}
133
133
  onPrev={hasPrev ? () => {} : undefined}
134
134
  onSkip={hasSkip ? () => {} : undefined}
@@ -137,7 +137,7 @@ export const Inspector: Story = {
137
137
  side="right"
138
138
  align="start"
139
139
  >
140
- <Button variant="primary" size="sm" startIcon={Sparkles}>Anchor</Button>
140
+ <Button variant="primary" size="sm" startIcon={Sparkles}>AI 續寫</Button>
141
141
  </Coachmark>
142
142
  </div>
143
143
  </div>
@@ -158,7 +158,7 @@ export const UsageGuidance: Story = {
158
158
  image={<MediaGradient from="var(--color-indigo-6)" to="var(--color-purple-6)" icon={Bot} label="AI 助理" />}
159
159
  title="試試新的 AI 助理"
160
160
  description="在任何文件中按下 AI 按鈕,讓 Claude 幫你摘要、翻譯或改寫內容。"
161
- onSkip={() => {}}
161
+ isLastStep
162
162
  onNext={() => {}}
163
163
  side="bottom"
164
164
  align="start"
@@ -306,7 +306,7 @@ export const Overview = {
306
306
  <thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
307
307
  <tbody>
308
308
  {[
309
- ['mode', "'edit'|'display'|'readonly'|'disabled'", "'edit'", 'FieldMode 四模式;顯式傳入時永遠最優先,不被 disabled 覆蓋'],
309
+ ['mode', "'edit'|'view'|'readonly'|'disabled'", "'edit'", 'FieldMode 四模式;顯式傳入時永遠最優先,不被 disabled 覆蓋'],
310
310
  ['size', "'sm'|'md'|'lg'", "'md'", '尺寸,與 Button 共用 field-height token'],
311
311
  ['options', 'ComboboxOption[]', '—', '選項列表(extends SelectMenuOption:value / label / icon / avatar / description / disabled / group)'],
312
312
  ['value', 'string[]', '[]', '已選中的值陣列'],
@@ -410,6 +410,7 @@ const InspectorInner = () => {
410
410
  value={value}
411
411
  onChange={setValue}
412
412
  placeholder="選擇分類"
413
+ aria-label="產品分類"
413
414
  className="w-72"
414
415
  />
415
416
  </div>
@@ -551,6 +552,7 @@ export const ColorMatrix = {
551
552
  size="sm"
552
553
  disabled={st === 'disabled'}
553
554
  onChange={() => {}}
555
+ aria-label={`產品分類(${st})`}
554
556
  />
555
557
  <TokenAnnotation colors={st === 'disabled' ? TOKEN_MAP.disabled.default : TOKEN_MAP.edit[st]} />
556
558
  </td>
@@ -567,6 +569,7 @@ export const ColorMatrix = {
567
569
  error={st !== 'disabled'}
568
570
  disabled={st === 'disabled'}
569
571
  onChange={() => {}}
572
+ aria-label={`產品分類(錯誤態、${st})`}
570
573
  />
571
574
  <TokenAnnotation colors={st === 'disabled' ? TOKEN_MAP.disabled.default : ERROR_COLORS[st]} />
572
575
  </td>
@@ -588,10 +591,10 @@ export const ColorMatrix = {
588
591
  <tr key={m}>
589
592
  <Td mono>{m}</Td>
590
593
  <td className="p-3 border-b border-divider align-top min-w-[180px]">
591
- <Combobox mode={m} options={categoryOptions} value={['electronics', 'food']} size="sm" />
594
+ <Combobox mode={m} options={categoryOptions} value={['electronics', 'food']} size="sm" aria-label={`產品分類(${m})`} />
592
595
  </td>
593
596
  <td className="p-3 border-b border-divider align-top min-w-[160px]">
594
- <Combobox mode={m} options={categoryOptions} value={[]} size="sm" />
597
+ <Combobox mode={m} options={categoryOptions} value={[]} size="sm" aria-label={`產品分類(${m}、空值)`} />
595
598
  </td>
596
599
  <td className="p-3 border-b border-divider align-top min-w-[160px]">
597
600
  <TokenAnnotation colors={TOKEN_MAP[m].default} />
@@ -726,7 +729,7 @@ export const SizeMatrix = {
726
729
  <div className="flex flex-col gap-3">
727
730
  {SIZES.map((sz) => (
728
731
  <div key={sz} className="flex items-center gap-3">
729
- <Combobox size={sz} options={categoryOptions} value={['electronics', 'food']} onChange={() => {}} className="w-64" />
732
+ <Combobox size={sz} options={categoryOptions} value={['electronics', 'food']} onChange={() => {}} className="w-64" aria-label={`產品分類(size=${sz})`} />
730
733
  <span className="text-caption text-fg-secondary font-mono">size=&quot;{sz}&quot;</span>
731
734
  </div>
732
735
  ))}
@@ -778,6 +781,7 @@ export const StateBehavior = {
778
781
  options={categoryOptions}
779
782
  value={overflowV}
780
783
  onChange={setOverflowV}
784
+ aria-label="產品分類(單行溢出 +N 範例)"
781
785
  />
782
786
  </div>
783
787
  <div className="flex flex-col gap-1 text-[11px] text-fg-secondary">
@@ -814,6 +818,7 @@ export const StateBehavior = {
814
818
  value={wrapV}
815
819
  onChange={setWrapV}
816
820
  wrap
821
+ aria-label="產品分類(換行模式範例)"
817
822
  />
818
823
  </div>
819
824
  </div>
@@ -846,6 +851,7 @@ export const StateBehavior = {
846
851
  onChange={setClearV}
847
852
  clearable
848
853
  className="w-64"
854
+ aria-label="產品分類(清除全部範例)"
849
855
  />
850
856
  <button
851
857
  type="button"
@@ -872,6 +878,7 @@ export const StateBehavior = {
872
878
  value={dismissV}
873
879
  onChange={setDismissV}
874
880
  className="w-72"
881
+ aria-label="產品分類(個別移除 Tag 範例)"
875
882
  />
876
883
  <button
877
884
  type="button"
@@ -60,10 +60,7 @@ export const UsageGuidance: Story = {
60
60
  <LinkTo kind="Design System/Components/Combobox/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">四模式</span></LinkTo>
61
61
  </li>
62
62
  <li>
63
- <LinkTo kind="Design System/Components/Combobox/展示" name="尺寸與 Button 對齊"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">尺寸與 Button 對齊</span></LinkTo>
64
- </li>
65
- <li>
66
- <LinkTo kind="Design System/Components/Combobox/展示" name="單行 vs 換行"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">單行 vs 換行</span></LinkTo>
63
+ <LinkTo kind="Design System/Components/Combobox/展示" name="三種尺寸"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">尺寸與 Button 對齊</span></LinkTo>
67
64
  </li>
68
65
  <li>
69
66
  <LinkTo kind="Design System/Components/Combobox/展示" name="搜尋"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">搜尋</span></LinkTo>
@@ -81,14 +78,14 @@ export const UsageGuidance: Story = {
81
78
  title="Combobox 的 sweet spot — 多選 + 空間受限 + 選項數 6+"
82
79
  note="Tag / 分類 / 協作成員 / 通知訂閱。使用者快速加選、移除,label 自帶語意不需描述"
83
80
  >
84
- <Combobox options={categoryOptions} value={tags} onChange={setTags} />
81
+ <Combobox options={categoryOptions} value={tags} onChange={setTags} aria-label="商品分類(多選 Tag 範例)" />
85
82
  </Rule>
86
83
 
87
84
  <Rule
88
85
  title="❌ 單選:用 Select"
89
86
  note="Combobox 永遠多選——單選塞進來使用者每次要手動先移除舊 Tag 再選新的,多餘的互動"
90
87
  >
91
- <Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} />
88
+ <Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} aria-label="商品分類(單選反例——應改用 Select)" />
92
89
  <Label warn>↑ 只選一個 electronics → 應該用 Select,一次點擊完成切換</Label>
93
90
  </Rule>
94
91
 
@@ -104,6 +101,7 @@ export const UsageGuidance: Story = {
104
101
  ]}
105
102
  value={['terms']}
106
103
  onChange={() => {}}
104
+ aria-label="同意項目"
107
105
  />
108
106
  <Label warn>↑ 條款勾選是「完整閱讀後同意」→ 用 Checkbox stack 全露內容</Label>
109
107
  </Rule>
@@ -121,6 +119,7 @@ export const UsageGuidance: Story = {
121
119
  ]}
122
120
  value={['eng-fe']}
123
121
  onChange={() => {}}
122
+ aria-label="部門"
124
123
  />
125
124
  <Label warn>↑ 用縮排偽造階層 → 沒有展開收合、不能按父節點全選、破壞資料結構</Label>
126
125
  </Rule>
@@ -141,7 +140,7 @@ export const WrapRule: Story = {
141
140
  title="單行(預設)— Table cell、空間受限的 Form"
142
141
  note="固定高度,與 Input / Select 等欄位並排對齊。多於可見寬度的 Tag 以 +N 指示器代替,hover 可看完整清單"
143
142
  >
144
- <Combobox options={categoryOptions} value={single} onChange={setSingle} />
143
+ <Combobox options={categoryOptions} value={single} onChange={setSingle} aria-label="商品分類(單行溢出範例)" />
145
144
  <Label>↑ 單行:高度固定,超出的 Tag → +N</Label>
146
145
  </Rule>
147
146
 
@@ -149,7 +148,7 @@ export const WrapRule: Story = {
149
148
  title="多行 wrap — 空間充裕的 Form"
150
149
  note="高度隨選中數量展開,每個 Tag 都完整可見。適合填答型表單——使用者一眼看到所有選項,不需 hover 溢出指示器"
151
150
  >
152
- <Combobox wrap options={categoryOptions} value={wrapped} onChange={setWrapped} />
151
+ <Combobox wrap options={categoryOptions} value={wrapped} onChange={setWrapped} aria-label="商品分類(多行 wrap 範例)" />
153
152
  <Label>↑ 多行:完整展開,無溢出</Label>
154
153
  </Rule>
155
154
 
@@ -189,7 +188,7 @@ export const TagOperationRule: Story = {
189
188
  title="Tag 只能被「移除」,不能被「編輯」或「重排」"
190
189
  note="每個 Tag 右側的 X 是唯一被允許的互動——保持 Tag 的心智模型單純:它代表一個已選中的選項,要換就刪了重選"
191
190
  >
192
- <Combobox options={categoryOptions} value={value} onChange={setValue} />
191
+ <Combobox options={categoryOptions} value={value} onChange={setValue} aria-label="商品分類(Tag 移除範例)" />
193
192
  <Label>↑ 點 Tag 的 X 移除;右側 clear all 一次清除;新增從 dropdown 選擇</Label>
194
193
  </Rule>
195
194
 
@@ -205,7 +204,7 @@ export const TagOperationRule: Story = {
205
204
  title="已選中的選項在下拉裡以打勾標示,再點一次即取消"
206
205
  note="桌機(預設)走自建浮層選單:已選項保留在清單中並以打勾呈現,再點一次即移除——避免使用者跨越下拉與 field 才能對照已選狀態。手機 / 觸控裝置改走原生 select,已選項則不重複出現在原生下拉"
207
206
  >
208
- <Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} />
207
+ <Combobox options={categoryOptions} value={['electronics']} onChange={() => {}} aria-label="商品分類(已選項打勾範例)" />
209
208
  <Label>↑ 打開 dropdown,Electronics 仍在清單裡並打勾,可再點一次取消</Label>
210
209
  </Rule>
211
210
  </div>
@@ -223,7 +222,7 @@ export const OverflowRule: Story = {
223
222
  title="+N 指示器是單行模式的必要元件"
224
223
  note="使用者必須知道「還有多少沒看到」——沒有 +N 的單行會誤導使用者以為選項已完整顯示。Hover 可看完整清單"
225
224
  >
226
- <Combobox options={categoryOptions} value={value} onChange={setValue} />
225
+ <Combobox options={categoryOptions} value={value} onChange={setValue} aria-label="商品分類(+N 溢出指示範例)" />
227
226
  <Label>↑ 窄容器內多個 Tag,自動出現 +N</Label>
228
227
  </Rule>
229
228
 
@@ -124,7 +124,7 @@ value 軸 controlled-only;open 軸方向相反 — **uncontrolled-only**:`defaul
124
124
 
125
125
  ## Loading
126
126
 
127
- `loading?: boolean`(forward 給 SelectMenu SSOT,2026-05-15 audit B ):dropdown body 內取代 options 顯 `<Empty icon={<CircularProgress size={48}/>}/>`(消費 既有 empty.spec.md「現有消費者」SelectMenu loading row SSOT)。Trigger 不變,user 隨時可開。對齊 Ant AutoComplete loading idiom。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
127
+ `loading?: boolean`(forward 給 SelectMenu SSOT,2026-05-15 audit B 補;措辭對齊 `select.spec.md`「Loading」2026-07-04 Q3 拍板 — 不清空 stale options):spinner 只在**無可顯示選項時**佔 empty slot 顯 `<Empty icon={<CircularProgress size={48}/>}/>`(cmdk `CommandEmpty` 機制;已有 options 時保留顯示,不取代)。Trigger 不變,user 隨時可開。對齊 MUI Autocomplete「loading 只在無 suggestions 時顯 loadingText」共識(cite 詳 select.spec.md 同段)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
128
128
 
129
129
  ---
130
130
 
@@ -132,7 +132,7 @@ value 軸 controlled-only;open 軸方向相反 — **uncontrolled-only**:`defaul
132
132
 
133
133
  - **Disabled**:Field SSOT own(`Field/field-controls.spec.md`)。trigger / tag dismiss / 搜尋 input 全部 disabled,token 走 M24 state precedence(`text-fg-disabled`);已選 Tag 的 dismiss X 自動隱藏(見「readonly / disabled 的 Tag」段)。
134
134
  - **Loading**:已 codify(見「Loading」段)。
135
- - **Empty(no search results)**:dropdown body 內渲 SelectMenu 預設 `emptyText`「沒有符合的選項」(Combobox 不傳 `emptyText`,走 SelectMenu primitive default)。Combobox 不暴露 `creatable` / `onCreate` prop( SelectMenu primitive 本身支援),故 Combobox consumer 無「建立 "xxx"」row
135
+ - **Empty(no search results)**:dropdown body 內渲 `emptyText`(Combobox 暴露 `emptyText` prop 並 forward 給 SelectMenu;未傳時走 SelectMenu 預設「沒有符合的選項」)。Combobox **暴露 `creatable` / `onCreate` / `createLabel` prop 並 forward 給 SelectMenu**(2026-07-18 user 拍板;搜尋非空且無完全同名既有選項時,dropdown 顯 create row `Plus + createLabel`)——邏輯/顯示/互動 SSOT 住在 SelectMenu(`select-menu.tsx` :271-275 顯隱 / render)。僅 searchable 桌機路徑生效(native mobile 不支援)。對齊 Ant tags / react-select Creatable
136
136
  - **Empty(no value selected)**:multi mode `value=[]` 時 trigger 顯 placeholder(如「請選擇」);empty state 不渲 tag 區。
137
137
  - **Dark mode / density**:走 Field + SelectMenu SSOT 自動 adapt。
138
138
 
@@ -145,6 +145,10 @@ value 軸 controlled-only;open 軸方向相反 — **uncontrolled-only**:`defaul
145
145
  - multi mode 可附 `min` / `max` selected count 限制(consumer 自驗,Combobox 不獨立 own validation rules)
146
146
  - Validation timing:預設 onBlur + onSubmit,onChange 不立即 validate(避免邊選邊紅)
147
147
 
148
+ ## Ref 契約(cross-mode 例外,2026-07-17 user 拍板)
149
+
150
+ Combobox 是 **4-mode field**(edit / view / readonly / disabled),各 mode 渲染**本質不同的 subtree**(edit = trigger + hidden select;view/readonly = `ReadonlyMultiSelect`)。**`ref` 只保證在 edit mode 指向 trigger root(`__triggerRef`)**;view / readonly / disabled mode **不保證穩定 root**(對齊 React「avoid over-exposing DOM nodes in higher-level components」)。需在任意 mode 取穩定 DOM root 的 consumer 應在外層自包一層容器,不依賴 Combobox `ref` 跨 mode 一致。與 T1 RadioGroup / Switch 的跨 mode 缺口採同一哲學(記錄例外,不硬造統一 host)。
151
+
148
152
  ---
149
153
 
150
154
  ## 禁止事項
@@ -26,7 +26,7 @@ const meta: Meta<typeof Combobox> = {
26
26
  export default meta
27
27
  type Story = StoryObj<typeof Combobox>
28
28
 
29
- // @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add display mode card to Modes story only.
29
+ // @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add view mode card to Modes story only.
30
30
  /* ── 四模式 ── */
31
31
  export const Modes: Story = {
32
32
  name: '四模式',
@@ -39,8 +39,8 @@ export const Modes: Story = {
39
39
  <Combobox options={categoryOptions} value={value} onChange={setValue} aria-label="類別(edit mode demo)" />
40
40
  </div>
41
41
  <div>
42
- <h3 className="text-body font-bold text-foreground mb-2">display</h3>
43
- <Combobox mode="display" options={categoryOptions} value={value} aria-label="類別(display mode demo)" />
42
+ <h3 className="text-body font-bold text-foreground mb-2">view</h3>
43
+ <Combobox mode="view" options={categoryOptions} value={value} aria-label="類別(view 模式示範)" />
44
44
  </div>
45
45
  <div>
46
46
  <h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
@@ -61,7 +61,7 @@ export const Modes: Story = {
61
61
 
62
62
  /* ── 尺寸與 Button 對齊 ── */
63
63
  export const SizeAlignment: Story = {
64
- name: '尺寸與 Button 對齊',
64
+ name: '三種尺寸',
65
65
  render: () => {
66
66
  const [sm, setSm] = React.useState(['electronics', 'food', 'lifestyle'])
67
67
  const [md, setMd] = React.useState(['electronics', 'food', 'lifestyle'])
@@ -71,7 +71,7 @@ export const SizeAlignment: Story = {
71
71
  <div className="flex flex-col gap-4">
72
72
  {(['sm', 'md', 'lg'] as const).map(size => (
73
73
  <div key={size} className="flex items-center gap-3">
74
- <Combobox size={size} options={categoryOptions} value={states[size][0]} onChange={states[size][1]} className="max-w-xs" />
74
+ <Combobox size={size} options={categoryOptions} value={states[size][0]} onChange={states[size][1]} className="max-w-xs" aria-label={`商品分類(size=${size})`} />
75
75
  <Button variant="primary" size={size}>送出</Button>
76
76
  <span className="text-caption text-fg-muted">size="{size}"</span>
77
77
  </div>
@@ -81,37 +81,10 @@ export const SizeAlignment: Story = {
81
81
  },
82
82
  }
83
83
 
84
- /* ── 單行 vs 換行 ── */
85
- export const WrapModes: Story = {
86
- name: '單行 vs 換行',
87
- render: () => {
88
- const init = ['electronics', 'food', 'lifestyle', 'clothing', 'furniture']
89
- const [v1, setV1] = React.useState(init)
90
- const [v2, setV2] = React.useState(init)
91
- return (
92
- <div className="flex flex-col gap-6 w-72">
93
- <div>
94
- <h3 className="text-body font-bold text-foreground mb-2">單行(預設)</h3>
95
- <p className="text-caption text-fg-muted mb-3">塞不下的自動收進 +N,hover 顯示隱藏項</p>
96
- <Combobox options={categoryOptions} value={v1} onChange={setV1} />
97
- </div>
98
- <div>
99
- <h3 className="text-body font-bold text-foreground mb-2">單行 readonly</h3>
100
- <Combobox mode="readonly" options={categoryOptions} value={init} />
101
- </div>
102
- <div>
103
- <h3 className="text-body font-bold text-foreground mb-2">換行(wrap)</h3>
104
- <p className="text-caption text-fg-muted mb-3">高度隨內容長,badges 自動換行</p>
105
- <Combobox options={categoryOptions} value={v2} onChange={setV2} wrap />
106
- </div>
107
- <div>
108
- <h3 className="text-body font-bold text-foreground mb-2">換行 readonly</h3>
109
- <Combobox mode="readonly" options={categoryOptions} value={init} wrap />
110
- </div>
111
- </div>
112
- )
113
- },
114
- }
84
+ // @story-trait-rationale: 原 WrapModes(單行 vs 換行)retired 2026-07-17(Dim 24 earn-existence)—
85
+ // 單行/wrap × edit/readonly 矩陣已由 anatomy「狀態行為」(單行溢出 + readonly 溢出 + edit/readonly wrap)
86
+ // 完整覆蓋機制,wrap 選擇原則由 principles「Wrap 模式選擇」(WrapRule)owns。展示層不重演矩陣(三層定位);
87
+ // principles 使用指引頁對應 LinkTo(單行 vs 換行)同步移除。
115
88
 
116
89
  /* ── 搜尋 ── */
117
90
  export const Searchable: Story = {