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

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 (477) 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 +11 -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 +7 -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 +9 -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/Field/field-context.ts +17 -11
  323. package/src/components/Field/field-controls.spec.md +44 -37
  324. package/src/components/Field/field-types.ts +14 -12
  325. package/src/components/Field/field-wrapper.tsx +59 -43
  326. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  327. package/src/components/Field/field.principles.stories.tsx +5 -28
  328. package/src/components/Field/field.spec.md +4 -4
  329. package/src/components/Field/field.stories.tsx +103 -72
  330. package/src/components/Field/field.tsx +36 -4
  331. package/src/components/Field/form-validation.spec.md +2 -0
  332. package/src/components/Field/use-form-validation.ts +1 -1
  333. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  334. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  335. package/src/components/FileItem/file-item.tsx +10 -8
  336. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  337. package/src/components/FileUpload/file-upload.spec.md +3 -2
  338. package/src/components/FileUpload/file-upload.tsx +5 -1
  339. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  340. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  342. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  343. package/src/components/FileViewer/file-viewer.tsx +3 -2
  344. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  345. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  346. package/src/components/HoverCard/hover-card.spec.md +2 -2
  347. package/src/components/HoverCard/hover-card.tsx +4 -2
  348. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  349. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  350. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  351. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  352. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  353. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  354. package/src/components/Input/input.principles.stories.tsx +3 -3
  355. package/src/components/Input/input.spec.md +4 -4
  356. package/src/components/Input/input.stories.tsx +3 -3
  357. package/src/components/Input/input.tsx +13 -13
  358. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  359. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  360. package/src/components/LinkInput/link-input.spec.md +6 -2
  361. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  362. package/src/components/LinkInput/link-input.tsx +21 -19
  363. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  364. package/src/components/Notice/notice.tsx +8 -2
  365. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  366. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  367. package/src/components/NumberInput/number-input.spec.md +6 -6
  368. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  369. package/src/components/NumberInput/number-input.tsx +17 -5
  370. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  371. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  372. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  373. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  374. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  375. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  376. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  377. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  378. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  379. package/src/components/PeoplePicker/person-display.tsx +3 -3
  380. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  381. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  382. package/src/components/Popover/popover.spec.md +4 -2
  383. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  384. package/src/components/ProfileCard/profile-card.tsx +1 -1
  385. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  386. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  387. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  388. package/src/components/README.md +1 -0
  389. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  390. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  391. package/src/components/RadioGroup/radio-group.tsx +19 -14
  392. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  393. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  394. package/src/components/Rating/rating.spec.md +2 -2
  395. package/src/components/Rating/rating.stories.tsx +4 -18
  396. package/src/components/Rating/rating.tsx +5 -1
  397. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  398. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  399. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  400. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  401. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  402. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  403. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  404. package/src/components/Select/select.principles.stories.tsx +3 -3
  405. package/src/components/Select/select.spec.md +9 -1
  406. package/src/components/Select/select.stories.tsx +41 -27
  407. package/src/components/Select/select.tsx +44 -26
  408. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  410. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  411. package/src/components/SelectMenu/select-menu.tsx +38 -5
  412. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  413. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  414. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  415. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  416. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  417. package/src/components/Sheet/sheet.tsx +4 -1
  418. package/src/components/Sidebar/sidebar.tsx +1 -1
  419. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  420. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  421. package/src/components/Slider/slider.spec.md +13 -1
  422. package/src/components/Slider/slider.stories.tsx +44 -32
  423. package/src/components/Slider/slider.tsx +13 -4
  424. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  425. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  426. package/src/components/Steps/steps.spec.md +4 -2
  427. package/src/components/Steps/steps.stories.tsx +4 -56
  428. package/src/components/Steps/steps.tsx +31 -7
  429. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  430. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  431. package/src/components/Switch/switch.spec.md +4 -4
  432. package/src/components/Switch/switch.stories.tsx +3 -3
  433. package/src/components/Switch/switch.tsx +16 -10
  434. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  435. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  436. package/src/components/Tabs/tabs.spec.md +5 -2
  437. package/src/components/Tabs/tabs.stories.tsx +36 -44
  438. package/src/components/Tabs/tabs.tsx +101 -36
  439. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  440. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  441. package/src/components/Tag/tag.spec.md +3 -1
  442. package/src/components/Tag/tag.tsx +5 -3
  443. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  444. package/src/components/Textarea/textarea.spec.md +5 -5
  445. package/src/components/Textarea/textarea.tsx +24 -24
  446. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  447. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  448. package/src/components/TimePicker/time-picker.spec.md +6 -5
  449. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  450. package/src/components/TimePicker/time-picker.tsx +24 -14
  451. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  452. package/src/components/Toast/toast.stories.tsx +1 -1
  453. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  454. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  455. package/src/components/Tooltip/tooltip.spec.md +9 -3
  456. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  457. package/src/components/Tooltip/tooltip.tsx +12 -2
  458. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  459. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  460. package/src/components/TreeView/tree-view.spec.md +8 -6
  461. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  462. package/src/components/TreeView/tree-view.tsx +36 -0
  463. package/src/index.ts +13 -10
  464. package/src/lib/drag-visual.ts +2 -2
  465. package/src/lib/utils.ts +19 -0
  466. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  467. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  468. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  469. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  470. package/src/tokens/categorical-color.ts +5 -5
  471. package/src/tokens/color/color.spec.md +4 -4
  472. package/src/tokens/color/primitives.css +9 -2
  473. package/src/tokens/opacity/opacity.spec.md +1 -1
  474. package/src/tokens/orphan-tokens.spec.md +1 -1
  475. package/src/tokens/typography/typography.spec.md +2 -0
  476. package/src/tokens/uiSize/uiSize.css +5 -0
  477. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -1,4 +1,5 @@
1
1
  // @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
2
+ // @overlay-open-skip: 本檔為 usage-guidance(設計原則)story——每個 Rule 卡片以「關閉的 trigger 按鈕」並排比較 Popover / Dialog / DropdownMenu / Tooltip 何時用;全部 defaultOpen 會讓多個 portal 疊在一起、視覺全毀。overlay 開啟狀態的視覺覆蓋由 popover.stories.tsx(展示)+ popover.anatomy.stories.tsx(Inspector defaultOpen)負責。
2
3
  import React from 'react'
3
4
  import LinkTo from '@storybook/addon-links/react'
4
5
  import type { Meta, StoryObj } from '@storybook/react'
@@ -217,7 +218,8 @@ export const UsageGuidance: Story = {
217
218
  <PopoverTrigger asChild>
218
219
  <Button variant="tertiary" size="sm" startIcon={Filter}>篩選</Button>
219
220
  </PopoverTrigger>
220
- <PopoverContent align="start">
221
+ {/* naked popover(無 PopoverTitle)→ 自傳 aria-label 讓 role="dialog" 有 accessible name(popover.spec.md A11y) */}
222
+ <PopoverContent align="start" aria-label="篩選任務">
221
223
  <PopoverBody>
222
224
  <CheckboxGroup>
223
225
  <Checkbox defaultChecked label="我的任務" />
@@ -255,33 +257,52 @@ export const VisualAlignmentRule: Story = {
255
257
  title="Popover 與 Dialog 共用 overlay-surface 視覺語言"
256
258
  note="bg-surface-raised / border-border / rounded-lg / elevation-200 完全一致。Header / Body / Footer 內 padding 來自 overlay-surface pattern 主檔(px-loose py-tight)。差異:(1) Popover 是 non-modal 無 overlay 遮罩,(2) Popover 鎖 layout-space=md(header 精簡);Dialog 不鎖 layout-space,全繼承 page(md page → 16 / lg page → 24)。兩者 ui-size 都繼承 page"
257
259
  >
258
- <Popover>
259
- <PopoverTrigger asChild>
260
- <Button variant="tertiary">Popover</Button>
261
- </PopoverTrigger>
262
- <PopoverContent align="start">
263
- <PopoverHeader><PopoverTitle>Header</PopoverTitle></PopoverHeader>
264
- <PopoverBody><p className="text-body">Body 區域</p></PopoverBody>
265
- <PopoverFooter>
266
- <Button variant="tertiary" size="sm">取消</Button>
267
- <Button variant="primary" size="sm">套用</Button>
268
- </PopoverFooter>
269
- </PopoverContent>
270
- </Popover>
271
- <Dialog>
272
- <DialogTrigger asChild>
273
- <Button variant="tertiary">Dialog</Button>
274
- </DialogTrigger>
275
- <DialogContent autoHeight maxWidth="360px">
276
- <DialogHeader><DialogTitle>Header</DialogTitle></DialogHeader>
277
- <DialogBody><p className="text-body">Body 區域</p></DialogBody>
278
- <DialogFooter>
279
- <Button variant="tertiary">取消</Button>
280
- <Button variant="primary">套用</Button>
281
- </DialogFooter>
282
- </DialogContent>
283
- </Dialog>
284
- <Label>↑ 兩個浮層視覺語言一致,consumer 切換不會產生視覺斷層</Label>
260
+ {/* @overlay-open-skip:視覺語言比較卡片——同一「顯示欄位」內容分別以 Popover / Dialog 呈現,證明 chrome 視覺完全一致;trigger 刻意關閉並排(見檔頭 escape),開啟態覆蓋於展示 / anatomy */}
261
+ <div className="flex flex-col items-start gap-2">
262
+ <Popover>
263
+ <PopoverTrigger asChild>
264
+ <Button variant="tertiary">顯示欄位</Button>
265
+ </PopoverTrigger>
266
+ <PopoverContent align="start">
267
+ <PopoverHeader><PopoverTitle>顯示欄位</PopoverTitle></PopoverHeader>
268
+ <PopoverBody>
269
+ <CheckboxGroup>
270
+ <Checkbox defaultChecked label="狀態" />
271
+ <Checkbox defaultChecked label="負責人" />
272
+ <Checkbox label="到期日" />
273
+ </CheckboxGroup>
274
+ </PopoverBody>
275
+ <PopoverFooter>
276
+ <Button variant="tertiary" size="sm">重設</Button>
277
+ <Button variant="primary" size="sm">套用</Button>
278
+ </PopoverFooter>
279
+ </PopoverContent>
280
+ </Popover>
281
+ <Label>↑ 同一內容以 Popover 呈現(non-modal 輕量浮層)</Label>
282
+ </div>
283
+ <div className="flex flex-col items-start gap-2">
284
+ <Dialog>
285
+ <DialogTrigger asChild>
286
+ <Button variant="tertiary">顯示欄位</Button>
287
+ </DialogTrigger>
288
+ <DialogContent autoHeight maxWidth="360px">
289
+ <DialogHeader><DialogTitle>顯示欄位</DialogTitle></DialogHeader>
290
+ <DialogBody>
291
+ <CheckboxGroup>
292
+ <Checkbox defaultChecked label="狀態" />
293
+ <Checkbox defaultChecked label="負責人" />
294
+ <Checkbox label="到期日" />
295
+ </CheckboxGroup>
296
+ </DialogBody>
297
+ <DialogFooter>
298
+ <Button variant="tertiary">重設</Button>
299
+ <Button variant="primary">套用</Button>
300
+ </DialogFooter>
301
+ </DialogContent>
302
+ </Dialog>
303
+ <Label>↑ 同一內容以 Dialog 呈現(modal 阻斷背景)</Label>
304
+ </div>
305
+ <Label>↑ 容器不同、chrome 視覺語言完全一致,consumer 切換不會產生視覺斷層</Label>
285
306
  </Rule>
286
307
 
287
308
  <Rule
@@ -152,11 +152,13 @@ canonical 判斷:「使用者 click 單項是否立即改變系統狀態?」是
152
152
 
153
153
  ## 邊界案例
154
154
 
155
- - **極長內容**:PopoverContent 設 `max-h-[var(--radix-popover-content-available-height)]`(popover.tsx:69),body 包 `<PopoverBody>`(SurfaceBody `flex-1 min-h-0 overflow-y-auto`)→ viewport 太小時 header / footer 留在視窗內、body 內捲。中間 wrapper 必 forward flex chain,詳 `../../patterns/overlay-surface/overlay-surface.spec.md`「Viewport-aware scroll chain invariant」。
155
+ - **極長內容**:PopoverContent 設 `max-h-[var(--radix-popover-content-available-height)]`(popover.tsx:103),body 包 `<PopoverBody>`(SurfaceBody `flex-1 min-h-0 overflow-y-auto`)→ viewport 太小時 header / footer 留在視窗內、body 內捲。中間 wrapper 必 forward flex chain,詳 `../../patterns/overlay-surface/overlay-surface.spec.md`「Viewport-aware scroll chain invariant」。
156
156
  - **Viewport 邊緣**:`collisionPadding = 8` 自動推開(見「Viewport 邊距 canonical」)。
157
157
  - **嵌套 Popover**:禁止(見「禁止事項」)。
158
158
  - **Dark mode**:殼走 semantic token 自動 adapt(見 `color.spec.md`)。
159
159
  - **Density**:layout-space 鎖 `md`(header / footer padding 精簡);ui-size 繼承 page(見「定位」段)。
160
+ - **空內容 / loading / error / validation ownership**:Popover shell **不擁有**這些狀態——由 `PopoverBody` 內的 consumer 內容層負責:空狀態放 `<Empty>`、載入放 `<Skeleton>`、錯誤放 `<Alert>`、表單驗證放 `<Field>` 的 `FieldError`。structural pattern 的職責邊界 SSOT 見 `../../patterns/overlay-surface/overlay-surface.spec.md` SurfaceBody「邊界」段(loading / error / empty 屬 consumer 內容層)。
161
+ - **disabled ownership**:Popover 容器無 disabled 態;trigger 的 disabled 由 trigger 元件自管(`<Button disabled>`),content 內控件各自的 disabled 由該控件負責(對應 `StateBehavior` story「職責邊界」段)。
160
162
 
161
163
  ---
162
164
 
@@ -164,7 +166,7 @@ canonical 判斷:「使用者 click 單項是否立即改變系統狀態?」是
164
166
 
165
167
  焦點 / 鍵盤 / ARIA 行為分兩層——**DS 覆寫**(改 Radix 預設)與 **Radix 內建**(沿用):
166
168
 
167
- - **開啟焦點(DS 覆寫)**:DS 以 `onOpenAutoFocus` 覆寫 Radix 預設 autofocus(見 `popover.tsx` `handlePopoverOpenAutoFocus`),開啟時把焦點落在 body 第一個可互動元素。Radix 預設會先 focus 右上 close X,DS 覆寫以避免觸發 tooltip leak(對齊 Material / Polaris「open 時 focus 落首個有意義控制」)。**注意**:若移除此 default handler,行為會回退成 Radix 預設 focus close X
169
+ - **開啟焦點(DS 覆寫)**:DS 以 `onOpenAutoFocus` 覆寫 Radix 預設 autofocus(見 `popover.tsx` `handlePopoverOpenAutoFocus`),開啟時把焦點落在 body 第一個**表單控件**(`input` / `textarea` / `select` / `button`,排除右上 close X);查無表單控件時退回 footer 按鈕,再無則落在 content 容器(`role="dialog"`)本身。Radix 預設會先 focus 右上 close X,DS 覆寫以避免觸發 tooltip leak(對齊 Material / Polaris「open 時 focus 落首個有意義控制」;selector 與 `dialog.tsx handleOpenAutoFocus` 同一套 DS canonical)。**注意**:(1) 若移除此 default handler,行為會回退成 Radix 預設 focus close X;(2) selector 只認表單控件——body 若只含 `a[href]` / `[tabindex]` / `contenteditable` 類可聚焦內容,焦點會落在 content 容器而非該內容,consumer 需自傳 `onOpenAutoFocus` 指定要聚焦的元素 <!-- @benchmark-unverified: Material / Polaris focus-on-open pattern per frontmatter benchmark list; DS canonical selector = dialog.tsx handleOpenAutoFocus -->
168
170
  - **關閉返回(Radix 內建)**:關閉時 focus return to trigger
169
171
  - **Esc 關閉(Radix 內建)**:按 Esc 自動關閉並返回焦點
170
172
  - **Focus trap(Radix 內建,僅 modal)**:`modal={true}` 時焦點鎖在 content 內
@@ -205,7 +205,7 @@ export const SectionMatrix: Story = {
205
205
  <div className="flex flex-col gap-10">
206
206
  <div>
207
207
  <H3>Minimal — profile header + View more</H3>
208
- <Desc>最小形式:avatar + name + subtitle + **View more**(hover context 必含,見 spec「View more canonical」)。@mention hover 場景 user 點 View more 跳完整 profile。</Desc>
208
+ <Desc>最小形式:avatar + name + subtitle + **View more**(hover context 必含 — canonical owner 見 avatar.spec.mdonViewMore 為 hover context 必含」段;顯示條件見本元件 spec「View More」節)。@mention hover 場景 user 點 View more 跳完整 profile。</Desc>
209
209
  <div className="border border-dashed border-divider rounded-md p-4 inline-block">
210
210
  <ProfileCard name="Alice Wang" subtitle="Frontend Engineer" onViewMore={() => {}} />
211
211
  </div>
@@ -24,7 +24,7 @@ import { ItemContent } from '@/design-system/patterns/element-anatomy/item-anato
24
24
  * 跨 consumer(avatar.principles / profile-card.stories / future product code)應該用
25
25
  * 同一組預設,避免每個範例各自發明 action 組合,讓 reader 誤以為 action 會隨情境自動變。
26
26
  *
27
- * ── 使用方式(hover context 必含 onViewMore,見 profile-card.spec.md 「View more」節)──
27
+ * ── 使用方式(hover context 必含 onViewMore — canonical owner 見 avatar.spec.md「onViewMore 為 hover context 必含」段;顯示條件見 profile-card.spec.md「View More」節)──
28
28
  * <ProfileCard name="..." actions={<ProfileCardDefaultActions />} onViewMore={...} />
29
29
  *
30
30
  * ── 何時要換成自訂 action ──
@@ -91,7 +91,7 @@ export const Overview = {
91
91
  {STATUSES.map((s) => (
92
92
  <div key={s} className="flex items-center gap-4">
93
93
  <div className="w-28 shrink-0">
94
- <ProgressBar value={s === 'success' ? 100 : s === 'error' ? 60 : 45} status={s} />
94
+ <ProgressBar value={s === 'success' ? 100 : s === 'error' ? 60 : 45} status={s} aria-label={`${s} 狀態範例`} />
95
95
  </div>
96
96
  <span className="font-mono text-caption w-20 text-fg-secondary">{s}</span>
97
97
  <span className="text-caption text-fg-secondary">{STATUS_TOKEN[s].desc}</span>
@@ -193,6 +193,7 @@ const InspectorInner = () => {
193
193
  type="range" min={0} max={100} value={value}
194
194
  onChange={(e) => setValue(Number(e.target.value))}
195
195
  className="w-[240px]"
196
+ aria-label="調整進度值"
196
197
  />
197
198
  <span className="text-[11px] font-mono text-fg-secondary tabular-nums w-10">{value}%</span>
198
199
  </div>
@@ -203,7 +204,7 @@ const InspectorInner = () => {
203
204
  {/* Left: preview */}
204
205
  <div className="flex flex-col gap-5 min-w-[360px]">
205
206
  <div className="px-6 py-10 rounded-lg bg-canvas border border-divider">
206
- <ProgressBar value={value} status={status} affix={affixNode} />
207
+ <ProgressBar value={value} status={status} affix={affixNode} aria-label="即時預覽進度" />
207
208
  </div>
208
209
 
209
210
  {/* Blueprint:顯示 track 高度 + fill 寬度 */}
@@ -317,7 +318,7 @@ export const ColorMatrix = {
317
318
  <Td mono>{s}</Td>
318
319
  <Td>
319
320
  <div className="w-[180px]">
320
- <ProgressBar value={s === 'success' ? 100 : 60} status={s} />
321
+ <ProgressBar value={s === 'success' ? 100 : 60} status={s} aria-label={`${s} 狀態色彩範例`} />
321
322
  </div>
322
323
  </Td>
323
324
  <Td><TokenCell token="--secondary" /></Td>
@@ -336,9 +337,9 @@ export const ColorMatrix = {
336
337
  <div className="flex flex-col gap-3">
337
338
  <span className="text-caption font-medium text-fg-secondary">含 affix 預覽</span>
338
339
  <div className="flex flex-col gap-3 max-w-[420px]">
339
- <ProgressBar value={42} status="inProgress" affix="value" />
340
- <ProgressBar value={100} status="success" affix="status-icon" />
341
- <ProgressBar value={68} status="error" affix="status-icon" />
340
+ <ProgressBar value={42} status="inProgress" affix="value" aria-label="進行中含百分比範例" />
341
+ <ProgressBar value={100} status="success" affix="status-icon" aria-label="完成含狀態圖示範例" />
342
+ <ProgressBar value={68} status="error" affix="status-icon" aria-label="失敗含狀態圖示範例" />
342
343
  </div>
343
344
  </div>
344
345
  </div>
@@ -368,7 +369,7 @@ export const AffixBehavior = {
368
369
  配額使用率、下載進度等需要精確數字時使用。
369
370
  </p>
370
371
  <div className="w-[360px]">
371
- <ProgressBar value={45} status="inProgress" affix="value" />
372
+ <ProgressBar value={45} status="inProgress" affix="value" aria-label="含百分比的進度範例" />
372
373
  </div>
373
374
  </div>
374
375
 
@@ -381,9 +382,9 @@ export const AffixBehavior = {
381
382
  inProgress → 無 icon(inProgress 非終態)。
382
383
  </p>
383
384
  <div className="flex flex-col gap-2 w-[360px]">
384
- <ProgressBar value={100} status="success" affix="status-icon" />
385
- <ProgressBar value={72} status="error" affix="status-icon" />
386
- <ProgressBar value={50} status="inProgress" affix="status-icon" />
385
+ <ProgressBar value={100} status="success" affix="status-icon" aria-label="完成狀態範例" />
386
+ <ProgressBar value={72} status="error" affix="status-icon" aria-label="失敗狀態範例" />
387
+ <ProgressBar value={50} status="inProgress" affix="status-icon" aria-label="進行中狀態範例" />
387
388
  <span className="text-footnote text-fg-muted">↑ inProgress 傳 status-icon 時不渲染 icon,且因無 affix 內容而 collapse 成純 bar(無 wrapper、無 gap,與不傳 affix 等價)</span>
388
389
  </div>
389
390
  </div>
@@ -398,7 +399,7 @@ export const AffixBehavior = {
398
399
  <ProgressBar
399
400
  value={42}
400
401
  status="inProgress"
401
-
402
+ aria-label="可取消的進度範例"
402
403
  affix={
403
404
  <Button variant="text" size="xs" iconOnly startIcon={X} aria-label="取消上傳" />
404
405
  }
@@ -406,7 +407,7 @@ export const AffixBehavior = {
406
407
  <ProgressBar
407
408
  value={66}
408
409
  status="inProgress"
409
-
410
+ aria-label="含資料量的進度範例"
410
411
  affix={<span className="text-caption text-fg-muted tabular-nums shrink-0">1.3 / 2.0 MB</span>}
411
412
  />
412
413
  </div>
@@ -419,7 +420,7 @@ export const AffixBehavior = {
419
420
  不包 wrapper,ProgressBar 本身就是整個元件。適合 FileItem 的 compact mode(上方已有檔名文字)。
420
421
  </p>
421
422
  <div className="w-[360px]">
422
- <ProgressBar value={55} status="inProgress" />
423
+ <ProgressBar value={55} status="inProgress" aria-label="純 bar 進度範例" />
423
424
  </div>
424
425
  </div>
425
426
  </div>
@@ -7,6 +7,7 @@ import LinkTo from '@storybook/addon-links/react'
7
7
  import { Paperclip, X, FileText, Table as TableIcon } from 'lucide-react'
8
8
  import { ProgressBar } from './progress-bar'
9
9
  import { CircularProgress } from '@/design-system/components/CircularProgress/circular-progress'
10
+ import { FileItem } from '@/design-system/components/FileItem/file-item'
10
11
  import { Button } from '@/design-system/components/Button/button'
11
12
 
12
13
  const meta: Meta = {
@@ -105,31 +106,15 @@ export const UsageGuidance: Story = {
105
106
  note="每個檔案一條 ProgressBar 已足夠表達整體狀態(使用者自然從完成數量推算),再加一條總 bar 會造成視覺重複與同步邏輯漂移。Dropbox / Google Drive 都只顯示每檔 bar。"
106
107
  >
107
108
  <Frame width={480}>
108
- <div className="flex flex-col gap-3">
109
- <div>
110
- <div className="flex items-center gap-2 mb-1">
111
- <Paperclip size={16} className="text-fg-muted" />
112
- <span className="text-body flex-1 truncate">會議記錄_0418.docx</span>
113
- </div>
114
- <ProgressBar value={100} status="success" affix="status-icon" />
115
- </div>
116
- <div>
117
- <div className="flex items-center gap-2 mb-1">
118
- <Paperclip size={16} className="text-fg-muted" />
119
- <span className="text-body flex-1 truncate">簡報素材.zip</span>
120
- </div>
121
- <ProgressBar value={62} status="inProgress" affix="value" />
122
- </div>
123
- <div>
124
- <div className="flex items-center gap-2 mb-1">
125
- <Paperclip size={16} className="text-fg-muted" />
126
- <span className="text-body flex-1 truncate">截圖.png</span>
127
- </div>
128
- <ProgressBar value={0} status="inProgress" />
129
- </div>
109
+ {/* 上傳列表載體 = FileItem(compact list gap-1 canonical;內部消費 ProgressBar)—
110
+ 不手組 Paperclip + 檔名 + ProgressBar(見下方「檔案上傳 UI → 用 FileItem」rule) */}
111
+ <div className="flex flex-col gap-1">
112
+ <FileItem mode="compact" name="會議記錄_0418.docx" status="completed" />
113
+ <FileItem mode="compact" name="簡報素材.zip" status="uploading" progress={62} />
114
+ <FileItem mode="compact" name="截圖.png" status="uploading" progress={0} />
130
115
  </div>
131
116
  </Frame>
132
- <Label>✅ 每檔一條,整體進度由使用者自然感知(1 檔完成、2 檔進行中)</Label>
117
+ <Label>✅ 每檔一條(FileItem 內建),整體進度由使用者自然感知(1 檔完成、2 檔進行中)</Label>
133
118
  </Rule>
134
119
 
135
120
  <Rule
@@ -37,6 +37,7 @@ const SectionDesc = ({ children }: { children: React.ReactNode }) => (
37
37
  // ── Default(基本範例) ──────────────────────────────────────────────────
38
38
 
39
39
  export const Default: Story = {
40
+ name: '預設',
40
41
  args: { value: 45, status: 'inProgress', affix: 'value' },
41
42
  render: (args) => (
42
43
  <div className="w-[360px]">
@@ -64,7 +65,7 @@ export const BatchTask: Story = {
64
65
  <span className="text-body-lg font-medium flex-1">匯入客戶名單</span>
65
66
  <span className="text-caption text-fg-muted tabular-nums">812 / 1,250 筆</span>
66
67
  </div>
67
- <ProgressBar value={65} status="inProgress" affix="value" />
68
+ <ProgressBar value={65} status="inProgress" affix="value" aria-label="匯入客戶名單進度" />
68
69
  <p className="text-footnote text-fg-muted">
69
70
  處理中,請勿關閉此視窗。預計剩餘 28 秒。
70
71
  </p>
@@ -107,7 +108,12 @@ const quotaColumns: ColumnDef<QuotaRow>[] = [
107
108
  header: '配額使用率',
108
109
  meta: { width: 240 },
109
110
  cell: ({ row }) => (
110
- <ProgressBar value={row.original.quota} status={row.original.status} affix="value" />
111
+ <ProgressBar
112
+ value={row.original.quota}
113
+ status={row.original.status}
114
+ affix="value"
115
+ aria-label={`${row.original.name} 配額使用率`}
116
+ />
111
117
  ),
112
118
  },
113
119
  ]
@@ -22,6 +22,7 @@
22
22
  - `Checkbox/` — `checkbox.tsx` + `checkbox-group.tsx`(2026-04-21 CheckboxGroup merge 自 separate folder,對齊 standalone + group 世界級慣例)+ `boolean-display.tsx`(table cell 顯示)
23
23
  - `Menu/` — `menu-item.tsx`(家族預留位)
24
24
  - `SelectionControl/` — `selection-item.tsx`(Checkbox/Radio 共享的 row layout primitive home)
25
+ - `PeoplePicker/` — `people-picker.tsx` + `person-display.tsx`(`PersonDisplay` / `MultiPersonDisplay` / `PersonAvatarTag`)+ `avatar-stack-overflow.ts` + `people-picker-helpers.ts`。**compound rationale**:全部共享 `PersonValue` 資料模型 + avatar 視覺規則,且 picker↔display 雙向消費(edit 選人 / view 渲染已選)。`PersonDisplay` 為**唯一現存 cross-component view primitive**(可脫離 picker 用於 DataTable cell / detail panel,見 `Field/field-controls.spec.md`「唯一現存 cross-component view primitive」),經 `PeoplePicker` root barrel + subpath 一併公開——與 `Checkbox/boolean-display.tsx`(table-cell 顯示 co-located)同型共居先例
25
26
 
26
27
  **判斷 compound vs 單獨 folder**:
27
28
  - 元件能**獨立 lifecycle / 獨立使用** → 各自獨立 folder(Button / Input / Select)
@@ -169,9 +169,14 @@ export const Overview = {
169
169
  <div className="flex flex-col gap-2 items-start">
170
170
  <span className="text-[11px] text-fg-muted font-medium">搭配 SelectionItem</span>
171
171
  <div className="inline-flex items-center border-2 border-dashed border-primary/30 rounded-md px-3 py-2.5 gap-2">
172
- {[{ name: 'control', color: 'info' }, { name: 'control', color: 'success' }, { name: 'control', color: 'magenta' }].map((s) => (
173
- <span key={s.name} className="rounded px-2 py-1 text-[11px] font-mono border border-dashed"
174
- style={{ borderColor: `var(--${s.color})`, backgroundColor: `var(--${s.color}-subtle)`, color: `var(--${s.color})` }}>{s.name}</span>
172
+ {/* magenta primitive(無 --magenta semantic token)→ 顯式 --color-magenta-{6,1,7}(ProgressBar 同款修法) */}
173
+ {[
174
+ { name: 'control', border: 'var(--info)', bg: 'var(--info-subtle)', text: 'var(--info)' },
175
+ { name: 'control', border: 'var(--success)', bg: 'var(--success-subtle)', text: 'var(--success)' },
176
+ { name: 'control', border: 'var(--color-magenta-6)', bg: 'var(--color-magenta-1)', text: 'var(--color-magenta-7)' },
177
+ ].map((s, i) => (
178
+ <span key={i} className="rounded px-2 py-1 text-[11px] font-mono border border-dashed"
179
+ style={{ borderColor: s.border, backgroundColor: s.bg, color: s.text }}>{s.name}</span>
175
180
  ))}
176
181
  </div>
177
182
  <span className="text-[10px] text-fg-muted font-mono">flex items-start gap-2 · control 在一行文字高度的容器內置中</span>
@@ -15,7 +15,7 @@ type Story = StoryObj<typeof RadioGroupItem>
15
15
  // 「何時用」明文禁止裸用)→ 收斂為公開 <RadioGroupItem value label description>(自動 wire SelectionItem
16
16
  // + id/htmlFor),與同元件 principles / anatomy 層一致 — 三層 story 一律示範公開 API。
17
17
 
18
- // @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with display card.
18
+ // @story-trait-rationale: pre-existing trait gaps tracked separately; this PR scope = add Modes story with view card.
19
19
  /* ── 四模式 ── */
20
20
  export const Modes: Story = {
21
21
  name: '四模式',
@@ -30,8 +30,8 @@ export const Modes: Story = {
30
30
  </RadioGroup>
31
31
  </div>
32
32
  <div>
33
- <h3 className="text-body font-bold text-foreground mb-2">display</h3>
34
- <RadioGroup mode="display" value="yearly" aria-label="付款方案(display mode demo)">
33
+ <h3 className="text-body font-bold text-foreground mb-2">view</h3>
34
+ <RadioGroup mode="view" value="yearly" aria-label="付款方案(view 模式示範)">
35
35
  <RadioGroupItem value="monthly" label="月付方案" />
36
36
  <RadioGroupItem value="yearly" label="年付方案" description="每年 $2,990,省下兩個月" />
37
37
  <RadioGroupItem value="lifetime" label="終身方案" />
@@ -13,21 +13,24 @@ import type { AvatarData } from "@/design-system/components/Avatar/avatar"
13
13
  import { fieldWrapperStyles } from "@/design-system/components/Field/field-wrapper"
14
14
  import { useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'
15
15
 
16
- // ── RadioGroup display mode ─────────────────────────────────────────────────
17
- // RadioGroup mode='display' 時:Group 不渲染 Radix primitive(無 radio 視覺),
16
+ // ── RadioGroup view mode ────────────────────────────────────────────────────
17
+ // RadioGroup mode='view' 時:Group 不渲染 Radix primitive(無 radio 視覺),
18
18
  // 改由 RadioGroup 本體 walk props.children,找 control.value === selectedValue 的
19
19
  // SelectionItem,把它的 label 渲染為單一純文字 span(其他選項不顯示)。
20
20
  // 對齊 Carbon read-only single-select(只顯示 selected 內容)+ Airtable / Notion read-only。
21
- // 實作在 RadioGroup forwardRef 內(見下方 mode === 'display' 分支)。
21
+ // 實作在 RadioGroup forwardRef 內(見下方 mode === 'view' 分支)。
22
22
 
23
23
  // ── RadioGroup ──────────────────────────────────────────────────────────────
24
24
 
25
25
  export interface RadioGroupProps
26
- extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {
26
+ // asChild Omit(2026-07-18 決策2):RadioGroup 恆持有多個 radio item → <Root asChild>
27
+ // Radix Slot React.Children.only crash;view/readonly 模式更直接渲染固定 <div> 忽略之。
28
+ // children 保留(edit 容器內容 + view/readonly 走訪選中 label,見 body cast @line ~105)。
29
+ extends Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>, 'asChild'> {
27
30
  /**
28
31
  * Field mode(2026-05-05 Phase B3 align):
29
32
  * edit — 一般可互動 RadioGroup(預設)
30
- * display — **純展示**:不渲染 Radix Root / 任何 radio 視覺;RadioGroup 本體 walk
33
+ * view — **純展示**:不渲染 Radix Root / 任何 radio 視覺;RadioGroup 本體 walk
31
34
  * children,僅 control.value === group.value 那筆把 label 渲染為純文字 span。
32
35
  * 對齊 Carbon read-only / DataTable single-select cell read mode。
33
36
  * readonly — standalone:ReadonlyContext 傳 items 鎖互動保留視覺;Field 內:灰框 + 選中項 label(不渲染 radio 群組)
@@ -50,7 +53,7 @@ const RadioGroupReadonlyContext = React.createContext(false)
50
53
  // 對齊本檔 RadioGroupReadonlyContext 既有模式 + spec「Disabled」邊界案例(Group-level disabled 視覺繼承 SelectionItem SSOT text-fg-disabled)。
51
54
  const RadioGroupDisabledContext = React.createContext(false)
52
55
 
53
- // walk children 找 control.value === selectedValue 的 SelectionItem label(display / readonly-in-Field 共用)
56
+ // walk children 找 control.value === selectedValue 的 SelectionItem label(view / readonly-in-Field 共用)
54
57
  function findSelectedRadioLabel(children: React.ReactNode, selectedValue: string | undefined): React.ReactNode {
55
58
  let selectedLabel: React.ReactNode = null
56
59
  React.Children.forEach(children, (child) => {
@@ -83,12 +86,12 @@ const RadioGroup = React.forwardRef<
83
86
  const fieldCtx = useFieldContext()
84
87
  // readonly 灰框 size:走 SSOT resolver(RadioGroup 無 size prop → ctx > 'md')
85
88
  const resolvedBoxSize = useResolvedFieldSize(undefined, 'md') as 'sm' | 'md' | 'lg'
86
- // mode='display' — 純展示 selected option 的 label,不渲染任何 radio control 視覺。
89
+ // mode='view' — 純展示 selected option 的 label,不渲染任何 radio control 視覺。
87
90
  // 對齊 Carbon read-only single-select(只顯示 selected 內容)+ Airtable / Notion read-only。
88
91
  // 實作:walk children 找 control.value === selectedValue 的 SelectionItem,render label plain text。
89
92
  // (不用 context dispatch 給 RadioGroupItem — SelectionItem layout wrapper 仍會渲染所有 item label)
90
- // 2026-07-04 修:display / readonly-in-Field 分支的 <div> 原丟棄剩餘 props(id/data-*/aria-*)
91
- // 且不轉發 forwardRef ref → 自家 radio-group.stories.tsx display demo 傳的 aria-label 都靜默失效。
93
+ // 2026-07-04 修:view / readonly-in-Field 分支的 <div> 原丟棄剩餘 props(id/data-*/aria-*)
94
+ // 且不轉發 forwardRef ref → 自家 radio-group.stories.tsx view demo 傳的 aria-label 都靜默失效。
92
95
  // 抽出 Radix 專屬 non-DOM props,其餘 DOM props 於兩分支 spread 轉發(與 Checkbox/Switch 同修);
93
96
  // edit 主路徑不受影響(Root 仍 spread 完整 props)。
94
97
  const {
@@ -104,7 +107,7 @@ const RadioGroup = React.forwardRef<
104
107
  ...restDomProps
105
108
  } = props as RadioGroupProps & { asChild?: boolean }
106
109
 
107
- if (resolvedMode === 'display') {
110
+ if (resolvedMode === 'view') {
108
111
  const selectedValue = (value ?? defaultValue) as string | undefined
109
112
  if (!selectedValue) {
110
113
  return <div {...restDomProps} ref={ref as React.Ref<HTMLDivElement>} role="group" className={cn('grid', className)}><span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span></div>
@@ -223,7 +226,9 @@ const dotSize: Record<string, number> = { sm: 8, md: 8, lg: 10 }
223
226
  type RadioItemPrimitiveProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
224
227
 
225
228
  export interface RadioGroupItemProps
226
- extends RadioItemPrimitiveProps,
229
+ // asChild / children Omit(2026-07-18 決策2):item 固定渲染 Indicator dot(<Circle/>)—
230
+ // children 被固定 Indicator 靜默覆蓋,asChild 破壞 radio 結構。對齊 Checkbox 收窄。label 走 `label` prop。
231
+ extends Omit<RadioItemPrimitiveProps, 'asChild' | 'children'>,
227
232
  VariantProps<typeof radioItemVariants> {
228
233
  /**
229
234
  * Inline label。提供時 RadioGroupItem 自動透過 SelectionItem 包裝,
@@ -273,9 +278,9 @@ const RadioGroupItem = React.forwardRef<
273
278
  const sizeKey = size ?? 'md'
274
279
  const dotPx = dotSize[sizeKey]
275
280
 
276
- // 注意:RadioGroup mode='display' 的純文字渲染由 RadioGroup 本體 walk-children 處理
277
- // (見上方 RadioGroup forwardRef 的 mode === 'display' 分支),RadioGroupItem 在 display
278
- // mode 下不會被獨立 render,故此處無 display 分支。
281
+ // 注意:RadioGroup mode='view' 的純文字渲染由 RadioGroup 本體 walk-children 處理
282
+ // (見上方 RadioGroup forwardRef 的 mode === 'view' 分支),RadioGroupItem 在 view
283
+ // mode 下不會被獨立 render,故此處無 view 分支。
279
284
 
280
285
  // 注意:Radio 的 label 語意與 Checkbox/Switch 不同——
281
286
  // Checkbox/Switch 的 label 就是該 control 的唯一 label(被 Field context 接管),
@@ -188,7 +188,7 @@ const InspectorInner = () => {
188
188
  precision={precision}
189
189
  readOnly={readOnly}
190
190
  disabled={disabled}
191
- aria-label={readOnly ? `平均評分 ${value} 星,共 5 星` : undefined}
191
+ aria-label={readOnly ? `平均評分 ${value} 星,共 5 星` : `為這次體驗評分,目前 ${value} 星,共 5 星`}
192
192
  />
193
193
  </div>
194
194
  <div className="text-caption text-fg-muted font-mono">
@@ -76,8 +76,8 @@ export const UsageGuidance: Story = {
76
76
  {/* 何時不用 / 替代元件 — 原 WhenNotToUse */}
77
77
  <div>
78
78
  <Rule
79
- title="❌ readOnly 不加 aria-label"
80
- note="純視覺的星星螢幕閱讀器讀不出「4.7 分」。readOnly Rating aria-label 必填,描述「幾星、共幾星、幾則評論」。"
79
+ title="❌ standalone readOnly 不給可存取名稱"
80
+ note="純視覺的星星螢幕閱讀器讀不出「4.7 分」。standalone readOnly Rating 必須有可存取名稱——傳 aria-label 描述目前分數與滿分(如「平均評分 4.5 星,共 5 星」);包在 Field 內時由 aria-labelledby 自動指向 FieldLabel,免傳 aria-label。評論數只在畫面確實顯示時才加進描述。"
81
81
  >
82
82
  <div className="flex flex-col gap-2 w-[320px] p-4 border border-border rounded-md">
83
83
  <Rating value={4.5} readOnly precision="half" size="md" aria-label="平均評分 4.5 星,共 5 星" />
@@ -260,7 +260,7 @@ export const YellowStarConvention: Story = {
260
260
  <div>
261
261
  <Rule
262
262
  title="黃星 = 世界級 convention,破壞 = 破壞使用者直覺"
263
- note="Amazon / Yelp / Google Reviews / Shopify / Airbnb / TripAdvisor 全部用黃星。使用者的視覺記憶已經把「黃星 = 評分」綁定——換成品牌 primary 色(藍 / / 紫)會讓使用者多花一瞬間「這是什麼?」。這一瞬間就是設計 bug。"
263
+ note=" / 金色星是星級評分最通用的視覺慣例——Amazon 商品評分、Google 地點評分都用金黃星,使用者的視覺記憶早已把「黃星 = 評分」綁定。換成品牌 primary 色(藍 / / 紫)會讓使用者多花一瞬間「這是什麼?」,這一瞬間就是設計 bug。(少數平台改用自家色:Yelp 紅星、Tripadvisor 綠色圓點 bubble——但黃 / 金星仍是跨平台最通用的星級評分色。)"
264
264
  >
265
265
  <div className="flex flex-col gap-2">
266
266
  <Rating value={4.5} readOnly precision="half" size="lg" aria-label="標準黃星" />
@@ -36,7 +36,7 @@ Rating 是**離散 1–5 分評分元件**——使用者對商品、服務、
36
36
 
37
37
  | 情境 | 改用 | 原因 |
38
38
  |------|------|------|
39
- | 純資訊標記(「熱門」「Beta」「新品」)| `Badge` | Rating 是量化 1–5 分,不是分類標籤 |
39
+ | 純資訊標記(「熱門」「Beta」「新品」)| `Tag` | Rating 是量化 1–5 分,不是分類標籤;文字分類標記走 Tag(Badge 僅 count/dot 兩模式,無文字承載) |
40
40
  | 非 1–5 的連續數值(音量、亮度、價格範圍)| `Slider` | Rating 是離散 tier,Slider 是連續值 |
41
41
  | 二元喜歡 / 不喜歡(thumbs up/down、like)| `Switch` 或自組 icon button | Like 是 binary,Rating 是 graded 1–5 |
42
42
  | 多維度評比(服務 / 品質 / 速度 各 5 分)| 自組多個 Rating 縱向排列 | 單一 Rating 只表達單一維度 |
@@ -210,7 +210,7 @@ Star icon 渲染時明確設 `stroke="none"`(Lucide Star 預設 `stroke="current
210
210
  ## 相關
211
211
 
212
212
  - **`Slider`** — 連續數值選擇(0–100、音量、亮度、價格區間)。Rating vs Slider 分界:離散 tier = Rating,連續值 = Slider
213
- - **`Badge`** — 靜態分類標記(「熱門」「Beta」「NEW」)。Rating 是量化,Badge 是分類
213
+ - **`Tag`** — 靜態文字分類標記(「熱門」「Beta」「NEW」)。Rating 是量化,Tag 是文字分類(Badge 僅 count/dot,不承載文字)
214
214
  - **`Switch`** — 二元 on/off。Rating 是 graded,Switch 是 binary
215
215
  - **`Button iconOnly + pressed={liked}`** — 愛心 / like 的正確實作
216
216
  - **Color token 例外** — `color.spec.md`「共用 `--warning` 色相但語境不同」段落
@@ -113,21 +113,7 @@ export const InField: Story = {
113
113
  }
114
114
 
115
115
  /* @story-trait-rationale: AllSizes retired per F migration 2026-05-15 — anatomy.stories.tsx SizeMatrix auto-compile owns size showcase。 */
116
- /* ── 停用狀態 ── */
117
- export const Disabled: Story = {
118
- name: '停用狀態',
119
- render: () => (
120
- <div className="flex flex-col gap-4 w-[420px]">
121
- <p className="text-caption text-fg-muted">
122
- 評分期限已過的舊訂單,Rating 顯示使用者當初給的分數但無法再修改。
123
- </p>
124
- <div className="flex items-center gap-3 p-3 border border-border rounded-md bg-surface">
125
- <div className="flex-1">
126
- <div className="text-body font-medium">訂單 #A-2025-11-03</div>
127
- <div className="text-caption text-fg-muted mt-[var(--item-gap-label-desc-scanning)]">評分期限已過</div>
128
- </div>
129
- <Rating value={4} disabled aria-label="此訂單已完成評分 4 星,無法修改" />
130
- </div>
131
- </div>
132
- ),
133
- }
116
+ // @story-trait-rationale: Disabled retired per audit Dim 24 —
117
+ // disabled 覆蓋已由 anatomy.stories.tsx StateBehavior disabled live case
118
+ // (value=4 disabled)owns;對齊 Checkbox / Switch / RadioGroup 同 Family
119
+ // 已 retire 的獨立 Disabled story,不重複展示同一 state。
@@ -12,7 +12,7 @@ import { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useRes
12
12
  *
13
13
  * ── 使用情境 ──
14
14
  * - review / feedback:商品評分 / 服務評分(可編輯 + 唯讀兩種)
15
- * - display:已提交評分的唯讀呈現(商品清單星等)
15
+ * - view:已提交評分的唯讀呈現(商品清單星等)
16
16
  *
17
17
  * ── 視覺 ──
18
18
  * 填色用 `var(--warning)`(yellow-6,世界級黃星 convention;與 warning 語意共用色相
@@ -112,6 +112,10 @@ const Rating = React.forwardRef<HTMLDivElement, RatingProps>(
112
112
  // - Standalone(無 Field context) → default `xs`(24px,對齊 Avatar / Tag sm / iOS HIG standalone)
113
113
  // consumer 可傳 size 顯式 override。世界級對照:Material Rating standalone 24dp、
114
114
  // Ant Rate in Form 跟 Form.itemSize,standalone 24px。
115
+ // 2026-07-18 決策4:max dev-warn(spec canonical ≤7;維持 number 型別不收窄,對齊 MUI Rating.max)。
116
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production' && (max > 7 || max < 1 || Math.round(max) !== max)) {
117
+ console.warn(`[DS] Rating max ${max} 超出 canonical 範圍 1-7(或非整數)。建議 ≤7 顆星(對齊世界級 review-stars)。`)
118
+ }
115
119
  const fieldCtx = useFieldContext() // 保留:aria-labelledby 用 fieldCtx.labelId
116
120
  // 2026-06-08 SSOT:<Field disabled> cascade(原 isInteractive 只看 local disabled prop)
117
121
  const disabled = useResolvedFieldDisabled(disabledProp)
@@ -255,7 +255,7 @@ export const SolvesDataTableBug: Story = {
255
255
 
256
256
  <Rule
257
257
  title="解法 — ScrollArea overlay 捲軸,跨 OS 一致不吃寬度"
258
- note="同一份表格,改用 ScrollArea 包起來、額外渲染 horizontal ScrollBar。macOS 與 Windows 呈現完全一致,右側 Status 欄不被裁切。這是 DataTable 遷移到 ScrollArea 的主要動機。"
258
+ note="同一份表格,改用 ScrollArea 包起來、額外渲染 horizontal ScrollBar。macOS 與 Windows 呈現完全一致,右側 Status 欄不被裁切。此組合限外層包 height='auto' 表格的 demo 場景;DataTable 中央捲動區本體走 native overflow-x-auto(pinned column 結構需求,見 scroll-area.spec.md「何時用」例外 + data-table.spec.md「捲軸 canonical」)。"
259
259
  >
260
260
  <div className="w-[560px]">
261
261
  <ScrollArea className="border border-success/40 rounded-md bg-surface">
@@ -132,7 +132,7 @@ Radix Viewport 內建 wrapper `min-width:100%; display:table`——這是**水
132
132
 
133
133
  ## 相關
134
134
 
135
- - `../DataTable/data-table.spec.md` — 主要 consumer(橫向捲動跑版問題的解法來源)
135
+ - `../DataTable/data-table.spec.md` — 歷史動機來源(橫向捲動跑版問題),**非 consumer**:DataTable 中央捲動區走 native `overflow-x-auto`(0 import,見上方「何時用」例外 +「捲軸 canonical」節)
136
136
  - `../Sheet/sheet.spec.md` — body 捲動
137
137
  - `../Dialog/dialog.spec.md` — body 捲動
138
138
  - `../Sidebar/sidebar.spec.md` — nav 長列表捲動
@@ -20,7 +20,8 @@ import { cn } from '@/lib/utils'
20
20
  * 捲動時浮現(hover / scroll 自動顯示)。
21
21
  *
22
22
  * ── 何時用 ──
23
- * - DataTable 橫向捲動(水平跑版最明顯場景)
23
+ * - 寬內容橫向捲動(寬表格類 demo / 程式碼區塊;例外:DataTable 中央捲動區走 native
24
+ * overflow-x-auto + scrollLeft 同步,不用 ScrollArea — 見 scroll-area.spec.md「何時用」)
24
25
  * - Sheet / Dialog 垂直內容捲動(body 太長)
25
26
  * - Sidebar nav 長列表
26
27
  * - 任何「內容可能溢出容器」且「跨 OS 視覺必須一致」的場景
@@ -33,7 +34,9 @@ import { cn } from '@/lib/utils'
33
34
 
34
35
  const ScrollArea = React.forwardRef<
35
36
  React.ElementRef<typeof ScrollAreaPrimitive.Root>,
36
- React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root> & {
37
+ // asChild Omit(2026-07-18 決策2):Root 恆渲染固定三子節點(Viewport + ScrollBar + Corner)
38
+ // → <Root asChild> Radix Slot React.Children.only crash。children 保留(路由進固定 Viewport)。
39
+ Omit<React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>, 'asChild'> & {
37
40
  /** 2026-07-08(WM 戰役 R2):Radix Viewport 內建 wrapper `display:table; min-width:100%`
38
41
  * 讓垂直捲動容器內的 flex 多欄佈局以 max-content 佈局、突破 100% 寬(WM 兩欄 dialog
39
42
  * 右欄被裁 33px 實證)。垂直捲動場景 opt-in 此 prop 中和為 block/w-full(水平捲動