@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
@@ -68,7 +68,7 @@ const ISSUE_COLUMNS = [
68
68
  *
69
69
  * Per codex Layer B D3(2026-05-20):row-driven Aside trigger 才符合 Linear/Notion/Jira/Airtable
70
70
  * production 真實情境。row 右側 dedicated action button(`Button variant="text" size="xs" iconOnly`
71
- * per data-table.spec L193 canonical)→ click 開 Aside + 被選 issue active visual(pressed prop)。
71
+ * per data-table.spec L153 rowActions canonical)→ click 開 Aside + 被選 issue active visual(pressed prop)。
72
72
  * AppShell header toggle 降級為 secondary show/hide 不是主入口。
73
73
  */
74
74
  function IssuesView({ selectedId, asideOpen, onSelectIssue }: { selectedId?: string; asideOpen: boolean; onSelectIssue: (issue: Issue) => void }) {
@@ -118,7 +118,6 @@ function IssuesView({ selectedId, asideOpen, onSelectIssue }: { selectedId?: str
118
118
  </PopoverTrigger>
119
119
  <PopoverContent align="end" className="w-auto p-0">
120
120
  <DataTableFilterPanel
121
- mode="flat"
122
121
  columns={ISSUE_COLUMNS as any}
123
122
  value={filterTree}
124
123
  onChange={setFilterTree}
@@ -150,7 +149,7 @@ function IssuesView({ selectedId, asideOpen, onSelectIssue }: { selectedId?: str
150
149
  </div>
151
150
  </div>
152
151
  {/* DataTable:naked structure,layoutSpace 規則 1B 父層 mx 對齊 chrome 內容左右邊界。
153
- rowActions:per data-table.spec L193 canonical(Button text xs iconOnly,固定 24px)+
152
+ rowActions:per data-table.spec L153 rowActions canonical(Button text xs iconOnly,固定 24px)+
154
153
  pressed={row.id === selectedId} 顯示當前選中(per codex D3 active visual)。 */}
155
154
  <div className="flex-1 min-h-0 mx-[var(--layout-space-loose)] mb-[var(--layout-space-loose)]">
156
155
  <DataTable
@@ -226,7 +225,7 @@ function IssueDetail({ issue }: { issue: Issue | null }) {
226
225
  <Tag size="sm" color={PRIORITY_COLOR[issue.priority]}>{issue.priority}</Tag>
227
226
  </div>
228
227
  </div>
229
- <DescriptionList direction="horizontal" divided>
228
+ <DescriptionList orientation="horizontal" divided>
230
229
  <DescriptionItem label="Assignee">{issue.assignee}</DescriptionItem>
231
230
  <DescriptionItem label="Due">{issue.due}</DescriptionItem>
232
231
  </DescriptionList>
@@ -374,7 +373,7 @@ export const PrimarySidebarWithTabs: Story = {
374
373
  /**
375
374
  * primary-header mode(GitHub / Gmail / Slack 派)— global header 橫跨頂部 + local header 仍在 main col 頂。
376
375
  *
377
- * @usage-ref: app-shell.spec.md L74(primary-header 2-layer model)
376
+ * @usage-ref: app-shell.spec.md「primary-header = primary-sidebar + 一條 global header」段(2-layer model)
378
377
  * @usage-consumes: ChromeHeader + Sidebar viewportInsetTop + GlobalHeader + PageHeader + IssuesView
379
378
  *
380
379
  * 2026-05-21 v2 per user clarification「primary-header = primary-sidebar + 一條 global header」:
@@ -375,7 +375,7 @@ export const avatarMeta = {
375
375
  // — item-anatomy AVATAR_SIZE 查表 / ProfileCard 40 等),無 discrete tier → 兩欄留空為 intentional 非漏填
376
376
  variants: {},
377
377
  sizes: {},
378
- states: ['default', 'focus-visible', 'disabled'], // 2026-06-11 R2:本身無自有 hover/active(spec L279;hoverCard 互動屬 HoverCard),
378
+ states: ['default', 'focus-visible', 'disabled'], // 2026-06-11 R2:本身無自有 hover/active(spec「StateBehavior 範疇」段;hoverCard 互動屬 HoverCard),
379
379
  tokens: {
380
380
  bg: ['bg-surface-raised'],
381
381
  fg: ['--foreground', '--on-emphasis'],
@@ -379,14 +379,14 @@ Badge 是**計數 / 狀態視覺指示器**,本身**非互動元件**:
379
379
  - Badge 通常依附在互動元件上(Button / Nav Item),那些元件有自己的 state——Badge 隨父層視覺連動,不擁有獨立 state。
380
380
  - 計數變化(`count` 更新)屬資料更新不是 UI state 切換。
381
381
 
382
- 對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix` + `SizeMatrix`。
382
+ 對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix` + `SizeMatrix` + `Accessibility`。
383
383
 
384
384
  ---
385
385
 
386
386
  ## 相關
387
387
 
388
388
  - `../Tag/tag.spec.md` — 分類標籤、狀態標記(Badge vs Tag 的詳細對照在本 spec 定位段落)
389
- - `../Avatar/avatar.spec.md` — `badgeCount` 內部消費 `<Badge variant="critical">`(遵循本 spec);`status` 是 Avatar 自有 presence SVG(非 Badge 系統),兩者可並存,詳該 spec
389
+ - `../Avatar/avatar.spec.md` — `badgeCount` 內部消費 `<Badge variant="critical">`(遵循本 spec);`status` 是 Avatar 自有 presence dot(內部 `span` + inline backgroundColor,非 Badge 系統),兩者可並存,詳該 spec
390
390
  - `../Button/button.spec.md` — iconOnly Button + Badge overlay 通知 icon 的組合模式
391
391
  - `../Chip/chip.spec.md` — 可互動 filter(不是 Badge 的用途)
392
392
  - `../CircularProgress/circular-progress.spec.md` — Loading 狀態指示(取代 Spinner)
@@ -342,19 +342,23 @@ export const StateBehavior: Story = {
342
342
  <Breadcrumb>
343
343
  <BreadcrumbList>
344
344
  <BreadcrumbItem>
345
- <BreadcrumbLink href="#">Link(預設 fg-secondary)</BreadcrumbLink>
345
+ <BreadcrumbLink href="#">團隊空間</BreadcrumbLink>
346
346
  </BreadcrumbItem>
347
347
  <BreadcrumbSeparator />
348
348
  <BreadcrumbItem>
349
- <BreadcrumbLink href="#">Hover 我(→ primary-hover)</BreadcrumbLink>
349
+ <BreadcrumbLink href="#">設計系統</BreadcrumbLink>
350
350
  </BreadcrumbItem>
351
351
  <BreadcrumbSeparator />
352
352
  <BreadcrumbItem>
353
- <BreadcrumbPage>Current Page(foreground, 不可點)</BreadcrumbPage>
353
+ <BreadcrumbPage>元件規格</BreadcrumbPage>
354
354
  </BreadcrumbItem>
355
355
  </BreadcrumbList>
356
356
  </Breadcrumb>
357
357
  </div>
358
+ <p className="text-footnote text-fg-muted mt-3">
359
+ 「團隊空間」「設計系統」為可點連結(預設 fg-secondary,移上去 hover 轉 primary-hover);
360
+ 末項「元件規格」為當前頁(foreground,不可點)。
361
+ </p>
358
362
  </div>
359
363
  </div>
360
364
  ),
@@ -18,7 +18,7 @@ import {
18
18
  DropdownMenuContent,
19
19
  DropdownMenuItem,
20
20
  } from '@/design-system/components/DropdownMenu/dropdown-menu'
21
- import { Tabs, TabsList, TabsTrigger } from '@/design-system/components/Tabs/tabs'
21
+ import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/design-system/components/Tabs/tabs'
22
22
  import { Button } from '@/design-system/components/Button/button'
23
23
 
24
24
  const meta: Meta = {
@@ -159,6 +159,9 @@ export const UsageGuidance: Story = {
159
159
  <TabsTrigger value="customers">顧客</TabsTrigger>
160
160
  <TabsTrigger value="products">產品</TabsTrigger>
161
161
  </TabsList>
162
+ <TabsContent value="orders" className="text-body text-fg-muted mt-2">訂單列表、篩選與批次出貨</TabsContent>
163
+ <TabsContent value="customers" className="text-body text-fg-muted mt-2">顧客名單、分群與生命週期價值</TabsContent>
164
+ <TabsContent value="products" className="text-body text-fg-muted mt-2">商品目錄、庫存與上下架狀態</TabsContent>
162
165
  </Tabs>
163
166
  </div>
164
167
  </Rule>
@@ -190,7 +190,7 @@ export const DeclarativeAutoCollapse: Story = {
190
190
  <Breadcrumb>
191
191
  <BreadcrumbList
192
192
  items={[
193
- { label: 'Long Organization Name', href: '/org' },
193
+ { label: 'Global Platform Infrastructure Group', href: '/org' },
194
194
  { label: 'Product Engineering Team', href: '/team' },
195
195
  { label: 'Design System Component Refactor Sprint 23' },
196
196
  ]}
@@ -46,7 +46,7 @@ export const Overview: Story = {
46
46
  <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
47
47
  </>
48
48
  }
49
- onClear={() => {}}
49
+ onClearSelection={() => {}}
50
50
  />
51
51
  </div>
52
52
  </section>
@@ -87,7 +87,7 @@ export const Overview: Story = {
87
87
  <BulkActionBar
88
88
  selection={Array.from({ length: 50 }, (_, i) => `f-${i}`)}
89
89
  actions={<Button variant="tertiary" size="md" startIcon={Download}>下載</Button>}
90
- onClear={() => {}}
90
+ onClearSelection={() => {}}
91
91
  />
92
92
  </div>
93
93
  </div>
@@ -115,7 +115,7 @@ function SelectionStateDemo() {
115
115
  <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
116
116
  </>
117
117
  }
118
- onClear={() => setCount(0)}
118
+ onClearSelection={() => setCount(0)}
119
119
  />
120
120
  {count === 0 && <span className="text-caption text-fg-muted italic px-3 py-2 inline-block">↑ count=0 → BulkActionBar 不渲染</span>}
121
121
  </div>
@@ -162,7 +162,7 @@ function InspectorInner() {
162
162
  <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
163
163
  </>
164
164
  }
165
- onClear={() => setSelectionCount(0)}
165
+ onClearSelection={() => setSelectionCount(0)}
166
166
  />
167
167
  {selectionCount === 0 && <span className="text-caption text-fg-muted italic px-3 py-2 inline-block">selection=0 → 不渲染</span>}
168
168
  </div>
@@ -196,7 +196,7 @@ export const Accessibility: Story = {
196
196
  <section>
197
197
  <H3>鍵盤(預期 consumer 在 page 層級監聽)</H3>
198
198
  <ul className="list-disc list-inside text-caption text-fg-secondary space-y-1">
199
- <li><kbd>Esc</kbd> → 觸發 <code>onClear()</code>(consumer 在 page-level keydown 監聽)</li>
199
+ <li><kbd>Esc</kbd> → 觸發 <code>onClearSelection()</code>(consumer 在 page-level keydown 監聽)</li>
200
200
  <li>Tab 序:close → actions(count 是純文字 / aria 朗讀對象,非 tab stop)</li>
201
201
  <li>Hint CTA 是 <code>{`<button>`}</code>,鍵盤可達</li>
202
202
  </ul>
@@ -216,7 +216,7 @@ export const Accessibility: Story = {
216
216
  <Button variant="tertiary" size="md" startIcon={Trash2} danger disabled>刪除(無權限)</Button>
217
217
  </>
218
218
  }
219
- onClear={() => {}}
219
+ onClearSelection={() => {}}
220
220
  />
221
221
  </div>
222
222
  </section>
@@ -83,7 +83,7 @@ export const UsageGuidance: Story = {
83
83
  <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
84
84
  </>
85
85
  }
86
- onClear={() => {}}
86
+ onClearSelection={() => {}}
87
87
  />
88
88
  <Label>↑ selection {`>`} 0 浮現,= 0 完全藏</Label>
89
89
  </Rule>
@@ -160,7 +160,7 @@ export const ActionVariantRule: Story = {
160
160
  <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
161
161
  </>
162
162
  }
163
- onClear={() => {}}
163
+ onClearSelection={() => {}}
164
164
  />
165
165
  <Label>↑ tertiary 主 / tertiary danger 破壞性</Label>
166
166
  </Rule>
@@ -177,7 +177,7 @@ export const ActionVariantRule: Story = {
177
177
  <Button variant="primary" size="md" startIcon={Trash2} danger>刪除</Button>
178
178
  </>
179
179
  }
180
- onClear={() => {}}
180
+ onClearSelection={() => {}}
181
181
  />
182
182
  <Label warn>↑ 兩顆都 primary → 視覺重量過高,跟 page Submit 競爭</Label>
183
183
  </Rule>
@@ -211,7 +211,7 @@ export const HintBannerRule: Story = {
211
211
  <BulkActionBar
212
212
  selection={Array.from({ length: 50 }, (_, i) => `f-${i}`)}
213
213
  actions={<Button variant="tertiary" size="md">下載</Button>}
214
- onClear={() => {}}
214
+ onClearSelection={() => {}}
215
215
  />
216
216
  </div>
217
217
  </div>
@@ -222,7 +222,19 @@ export const HintBannerRule: Story = {
222
222
  title="❌ 自刻 hint banner / 用 contrast 底色 div"
223
223
  note="banner 是 Alert 的職責(自帶 a11y role / aria-live / 視覺一致性)。自刻會破壞跟其他 Alert 的視覺一致性,也漏 a11y"
224
224
  >
225
- <Label warn>(範例省略)有 Alert 元件不用是浪費</Label>
225
+ <div className="border border-divider rounded-md overflow-hidden">
226
+ <div className="bg-info-subtle text-info-text px-[var(--layout-space-loose)] py-[var(--layout-space-tight)] text-footnote">
227
+ 已選取本頁全部 50 個。點此選取全部 5370 個項目
228
+ </div>
229
+ <div className="border-t border-divider">
230
+ <BulkActionBar
231
+ selection={Array.from({ length: 50 }, (_, i) => `f-${i}`)}
232
+ actions={<Button variant="tertiary" size="md">下載</Button>}
233
+ onClearSelection={() => {}}
234
+ />
235
+ </div>
236
+ </div>
237
+ <Label warn>↑ 手刻 div 當 banner:無 role=&quot;status&quot; / aria-live,SR 不會朗讀狀態變化;底色跟其他 Alert 不一致;「點此選取」是純文字非可操作連結</Label>
226
238
  </Rule>
227
239
 
228
240
  <Rule
@@ -233,7 +245,7 @@ export const HintBannerRule: Story = {
233
245
  selection={['a', 'b', 'c']}
234
246
  hiddenByFilter={2}
235
247
  actions={<Button variant="tertiary" size="md" startIcon={Archive}>封存</Button>}
236
- onClear={() => {}}
248
+ onClearSelection={() => {}}
237
249
  />
238
250
  <Label>↑ count 文字 inline:「已選 3 項 · 2 個被 filter 隱藏」</Label>
239
251
  </Rule>
@@ -81,9 +81,9 @@ benchmark:
81
81
 
82
82
  ### Slot
83
83
 
84
- - **`actions`**:consumer 提供 **md** Buttons(size rationale 見「Size canonical」);`variant=tertiary`(主)/ `tertiary danger`(destructive)— **不用 primary**( dialog 確認最終 action)
84
+ - **`actions`**:consumer 提供 **md** Buttons(size rationale 見「Size canonical」);**一律 `variant=tertiary`**( destructive — `Trash` 等 icon + label 已辨識危險)— **不用 primary、destructive 不上 danger 紅填色**(2026-07-17 user 拍板:批次刪除鈕點下去是**開確認 dialog**非直接刪,紅色強調留給 dialog 內確認最終不可逆 action;對齊 UX Movement / GitLab Pajamas「紅留給不可逆最終確認」+ button.spec.md「Inline destructive 不用高強調」)
85
85
  - **count 區**:`已選 {N} 項`(內建)+ inline filter hidden status `· {M} 個被 filter 隱藏`(`hiddenByFilter` prop 傳入時)
86
- - **clear**:`<Button iconOnly size=md variant=text dismiss />`(內建,觸發 `onClear`)
86
+ - **clear**:`<Button iconOnly size=md variant=text dismiss />`(內建,觸發 `onClearSelection`)
87
87
 
88
88
  #### Size canonical(2026-05-04 升 SSOT)
89
89
 
@@ -143,7 +143,7 @@ interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement> {
143
143
  /** 已選 ID;length === 0 且無 totalSelected 時自動隱藏(回 null,完整判準見「Extend dataset pattern」) */
144
144
  selection: readonly string[]
145
145
  /** Clear 觸發,user 點 X icon(consumer 在 page-level 監聽 Esc 觸發) */
146
- onClear?: () => void
146
+ onClearSelection?: () => void
147
147
  /** 批次 actions(consumer 提供 md Button,variant=tertiary 或 tertiary+danger,不用 primary) */
148
148
  actions?: React.ReactNode
149
149
  /** Filter 模式:hidden 數量,顯示在 count 區 inline 「已選 {N} 項 · {M} 個被 filter 隱藏」 */
@@ -169,6 +169,16 @@ interface BulkActionBarLabels {
169
169
 
170
170
  **Hint banner(擴 dataset 提示)不在本 API**:由 consumer 用 `<Alert variant="info" placement="fixed">` 配 ReactNode title 帶 inline link 自組,黏在 BulkActionBar 上方。Alert / Notice 的 `title` + `description` 已支援 ReactNode(2026-04-28)。
171
171
 
172
+ ### 批次操作進行中(loading / 防重複提交 / 選取保留)
173
+
174
+ `actions` 由 consumer 注入 ReactNode,**批次操作的非同步生命週期由 consumer 擁有**(BulkActionBar 是 stateless 呈現層,不介入 action 執行):
175
+
176
+ - **Loading**:非同步 action(批次刪除 / 匯出)進行中,對應 action Button 傳 `loading`(既有 API,spinner + 自動 disabled)——不在 bar 內另加全域 spinner
177
+ - **防重複提交**:同一批次操作進行中,consumer 對該 action Button 設 `loading` / `disabled` 阻止連點觸發多次(語義同 `../Field/form-validation.spec.md` double-submit 防護,但 owner 在 consumer 而非 bar)
178
+ - **選取保留**:操作進行中 `selection` 維持不變、bar 持續可見;**成功**後才由 consumer 清空 `selection`(觸發 bar 自動隱藏),**失敗**則保留選取讓 user 重試
179
+
180
+ 對齊 Polaris BulkActions(action `loading` 由 consumer 提供)/ Material DataGrid batch action 慣例。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
181
+
172
182
  ### Extend dataset pattern(totalSelected)
173
183
 
174
184
  「本頁全選 → hint 點擊 → 擴選整個 dataset」2-step 後,consumer 把 `totalSelected` 設為 dataset 真總數,count 區改顯示該值(否則 fallback `selection.length`)——避免 Alert 顯「已選 5370」但 bar 仍顯「已選 50」的不同步(2026-05-13 ship)。對齊 Gmail / Linear / Notion 全選 dataset hint pattern。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
@@ -183,7 +193,7 @@ interface BulkActionBarLabels {
183
193
  - count 文字用 `aria-live="polite"` + `aria-atomic="true"`(selection 變更時 SR 整句重讀「已選 3 項」)
184
194
  - Clear button:`aria-label="清除選取"`
185
195
  - Hint banner 用 `role="status"` + `aria-live="polite"`(state 切換時通知)
186
- - 鍵盤:Esc → `onClear()`(consumer 應監聽 page-level keydown 觸發);Tab 序按 DOM 順序 = clear(X)→ actions(count 是純文字 span,非互動元素 → 不參與 Tab)
196
+ - 鍵盤:Esc → `onClearSelection()`(consumer 應監聽 page-level keydown 觸發);Tab 序按 DOM 順序 = clear(X)→ actions(count 是純文字 span,非互動元素 → 不參與 Tab)
187
197
  - Disabled action(無權限等)用 Button `disabled` + tooltip 解釋,**不藏 action**(避免 user 困惑)
188
198
 
189
199
  ---
@@ -194,7 +204,7 @@ interface BulkActionBarLabels {
194
204
  - **底色**:**無底色 contrast**,跟 page 同色(`bg-canvas` / `bg-surface` 視 placement 繼承)。對齊 Notion / Linear minimalist — 用文字內容切換呈現「mode」,**不**用底色 highlight。**不像 Polaris 那種顯著底色變化** <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
195
205
  - **邊界**:**無外框邊界**(融入 page chrome)— 恆 **`border-top` border-divider 切割 layout**(bar 是 page 結構,不是 floating overlay,不用 box-shadow 製造「浮層」誤導)。top-toolbar 變體為未來項(見「Size canonical」)
196
206
  - **與 table 的關係**:inline composition — bar 接在 DataTable 下方,toolbar 永遠保留(見「Placement」)
197
- - **Action variant**:`tertiary`(主)+ `tertiary danger`(destructive)— **不用 primary**(留給 dialog 確認最終 action)
207
+ - **Action variant**:**一律 `tertiary`**(含 destructive,icon+label 辨識危險)— **不用 primary、不用 danger 紅填色**(紅色強調留給 dialog 內確認最終 action,見「Slot」rationale)
198
208
 
199
209
  ---
200
210
 
@@ -21,13 +21,13 @@ export const Default: Story = {
21
21
  return (
22
22
  <BulkActionBar
23
23
  selection={selection}
24
- onClear={() => setSelection([])}
24
+ onClearSelection={() => setSelection([])}
25
25
  actions={
26
26
  <>
27
27
  <Button variant="tertiary" size="md" startIcon={Archive}>封存</Button>
28
28
  <Button variant="tertiary" size="md" startIcon={TagIcon}>加標籤</Button>
29
29
  <Button variant="tertiary" size="md" startIcon={MoveRight}>移動</Button>
30
- <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
30
+ <Button variant="tertiary" size="md" startIcon={Trash2}>刪除</Button>
31
31
  </>
32
32
  }
33
33
  />
@@ -35,26 +35,10 @@ export const Default: Story = {
35
35
  },
36
36
  }
37
37
 
38
- // Filter 模式:hidden 數量顯示在 count inline
39
- export const WithFilterHidden: Story = {
40
- name: '部分項目被篩選隱藏',
41
- render: () => {
42
- const [selection, setSelection] = useState<string[]>(['issue-1', 'issue-2', 'issue-3'])
43
- return (
44
- <BulkActionBar
45
- selection={selection}
46
- onClear={() => setSelection([])}
47
- hiddenByFilter={2}
48
- actions={
49
- <>
50
- <Button variant="tertiary" size="md" startIcon={Archive}>封存</Button>
51
- <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
52
- </>
53
- }
54
- />
55
- )
56
- },
57
- }
38
+ // @story-trait-rationale: WithFilterHidden(selection=3 + hiddenByFilter=2)retired 2026-07-17 per audit Dim 24 —
39
+ // principles.stories.tsx HintBannerRule 第三 Rule 已用同情境(selection 3 + hiddenByFilter=2)且多教「filter hidden
40
+ // inline 進 count 區、不開 hint banner」規則;展示版無新增約束(earn-existence 2-test 雙 NO)→ retire。
41
+ // hiddenByFilter inline 呈現 canonical home = principles HintBannerRule。
58
42
 
59
43
  // Hint banner via Alert primitive(擴 dataset 提示)— 對齊 ref 圖
60
44
  // hint banner 唯一 trigger condition:本頁全選 + 還有 dataset 沒選到
@@ -108,11 +92,11 @@ export const WithExtendDatasetHint: Story = {
108
92
  <BulkActionBar
109
93
  selection={selection}
110
94
  totalSelected={allSelected ? TOTAL : undefined}
111
- onClear={() => { setSelection([]); setAllSelected(false) }}
95
+ onClearSelection={() => { setSelection([]); setAllSelected(false) }}
112
96
  actions={
113
97
  <>
114
98
  <Button variant="tertiary" size="md" startIcon={Download}>下載</Button>
115
- <Button variant="tertiary" size="md" startIcon={Trash2} danger>刪除</Button>
99
+ <Button variant="tertiary" size="md" startIcon={Trash2}>刪除</Button>
116
100
  </>
117
101
  }
118
102
  />
@@ -41,7 +41,7 @@ export interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement>
41
41
  /** 已選 ID,length === 0 時自動隱藏(回傳 null) */
42
42
  selection: readonly string[]
43
43
  /** Clear 觸發,user 點 X icon 或 Esc(consumer 在 page-level 監聽) */
44
- onClear?: () => void
44
+ onClearSelection?: () => void
45
45
  /** 批次 actions(consumer 提供 md Button,variant=tertiary 或 tertiary+danger;不用 primary) */
46
46
  actions?: React.ReactNode
47
47
  /** Filter 模式:hidden 數量,顯示在 count 區 inline「已選 {N} 項 · {M} 個被 filter 隱藏」 */
@@ -77,7 +77,7 @@ export interface BulkActionBarProps extends React.HTMLAttributes<HTMLDivElement>
77
77
 
78
78
  const BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(
79
79
  function BulkActionBar(
80
- { selection, onClear, actions, hiddenByFilter, totalSelected, labels: labelsOverride, className, ...props },
80
+ { selection, onClearSelection, actions, hiddenByFilter, totalSelected, labels: labelsOverride, className, ...props },
81
81
  ref
82
82
  ) {
83
83
  const labels: BulkActionBarLabels = React.useMemo(
@@ -109,7 +109,7 @@ const BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(
109
109
  {/* X close — md dismiss(2026-05-04 spec update:default placement = footer variant,
110
110
  visual weight 對齊 Dialog footer commitment buttons md;same-row consistency 維持)
111
111
  未來若有 top-toolbar variant(覆蓋 sm-density toolbar)→ 該 variant override sm */}
112
- {onClear && (
112
+ {onClearSelection && (
113
113
  <Button
114
114
  variant="text"
115
115
  size="md"
@@ -117,7 +117,7 @@ const BulkActionBar = React.forwardRef<HTMLDivElement, BulkActionBarProps>(
117
117
  dismiss
118
118
  startIcon={X}
119
119
  aria-label={labels.clear}
120
- onClick={onClear}
120
+ onClick={onClearSelection}
121
121
  />
122
122
  )}
123
123
 
@@ -23,14 +23,14 @@ import { ButtonGroupContext } from './button'
23
23
  * </ButtonGroup>
24
24
  *
25
25
  * // 垂直排列(fullWidth 自動套用)
26
- * <ButtonGroup direction="vertical">
26
+ * <ButtonGroup orientation="vertical">
27
27
  * <Button variant="primary">確認</Button>
28
28
  * <Button variant="tertiary">取消</Button>
29
29
  * </ButtonGroup>
30
30
  */
31
31
  interface ButtonGroupProps extends React.HTMLAttributes<HTMLDivElement> {
32
32
  /** 排列方向,預設 horizontal */
33
- direction?: 'horizontal' | 'vertical'
33
+ orientation?: 'horizontal' | 'vertical'
34
34
  /** 水平對齊,預設 start */
35
35
  align?: 'start' | 'center' | 'end'
36
36
  }
@@ -40,8 +40,8 @@ const BUTTON_GROUP_CTX_VERTICAL = { fullWidth: true } as const
40
40
  const BUTTON_GROUP_CTX_HORIZONTAL = { fullWidth: false } as const
41
41
 
42
42
  const ButtonGroup = React.forwardRef<HTMLDivElement, ButtonGroupProps>(
43
- ({ direction = 'horizontal', align = 'start', className, children, ...props }, ref) => {
44
- const isVertical = direction === 'vertical'
43
+ ({ orientation = 'horizontal', align = 'start', className, children, ...props }, ref) => {
44
+ const isVertical = orientation === 'vertical'
45
45
 
46
46
  return (
47
47
  <ButtonGroupContext.Provider value={isVertical ? BUTTON_GROUP_CTX_VERTICAL : BUTTON_GROUP_CTX_HORIZONTAL}>
@@ -102,6 +102,23 @@ const VARIANT_DESC: Record<VariantKey, string> = {
102
102
  link: '外觀像連結的按鈕,不用於操作列',
103
103
  }
104
104
 
105
+ // variant 名稱只放在左側 mono 標籤欄;按鈕本體用真實動作文案(禁 variant 名當 label)
106
+ const VARIANT_LABEL: Record<VariantKey, string> = {
107
+ primary: '新增任務',
108
+ secondary: '儲存變更',
109
+ tertiary: '取消',
110
+ text: '略過此步',
111
+ link: '查看說明',
112
+ }
113
+
114
+ const DANGER_LABEL: Record<VariantKey, string> = {
115
+ primary: '刪除專案',
116
+ secondary: '移除成員',
117
+ tertiary: '清除紀錄',
118
+ text: '撤銷授權',
119
+ link: '刪除',
120
+ }
121
+
105
122
  /* ═══════════════════════════════════════════════════════════════════════════
106
123
  Shared UI Components
107
124
 
@@ -224,7 +241,8 @@ export const Overview = {
224
241
  <div className="flex flex-col gap-2">
225
242
  {VARIANTS.map((v) => (
226
243
  <div key={v} className="flex items-center gap-4">
227
- <div className="w-28 shrink-0"><Button variant={v} size="sm" startIcon={Plus}>{v}</Button></div>
244
+ <span className="w-16 shrink-0 text-[11px] font-mono text-fg-muted">{v}</span>
245
+ <div className="w-28 shrink-0"><Button variant={v} size="sm" startIcon={Plus}>{VARIANT_LABEL[v]}</Button></div>
228
246
  <span className="text-caption text-fg-secondary">{VARIANT_DESC[v]}</span>
229
247
  </div>
230
248
  ))}
@@ -232,7 +250,8 @@ export const Overview = {
232
250
  <span className="text-[11px] text-fg-muted font-medium">+ danger prop</span>
233
251
  {DANGER_VARIANTS.map((v) => (
234
252
  <div key={v} className="flex items-center gap-4">
235
- <div className="w-28 shrink-0"><Button variant={v} danger size="sm" startIcon={Trash2}>{v}</Button></div>
253
+ <span className="w-16 shrink-0 text-[11px] font-mono text-fg-muted">{v}</span>
254
+ <div className="w-28 shrink-0"><Button variant={v} danger size="sm" startIcon={Trash2}>{DANGER_LABEL[v]}</Button></div>
236
255
  <span className="text-caption text-fg-secondary">
237
256
  {v === 'primary' ? '立即不可逆——點下去就執行' : v === 'secondary' ? '有警示意圖,後面還有確認' : '低強調的危險操作'}
238
257
  </span>
@@ -503,7 +522,7 @@ export const ColorMatrix = {
503
522
  <td className="p-3 border-b border-divider font-mono text-caption font-medium align-top">{v}</td>
504
523
  {STATES.map((st) => (
505
524
  <td key={st} className="p-3 border-b border-divider align-top min-w-[160px]">
506
- <Button variant={v} size="sm" startIcon={Plus} disabled={st === 'disabled'}>{v}</Button>
525
+ <Button variant={v} size="sm" startIcon={Plus} disabled={st === 'disabled'}>{VARIANT_LABEL[v]}</Button>
507
526
  <TokenAnnotation colors={TOKEN_MAP[v][st]} />
508
527
  </td>
509
528
  ))}
@@ -523,7 +542,7 @@ export const ColorMatrix = {
523
542
  <td className="p-3 border-b border-divider font-mono text-caption font-medium align-top">{v} + danger</td>
524
543
  {STATES.map((st) => (
525
544
  <td key={st} className="p-3 border-b border-divider align-top min-w-[160px]">
526
- <Button variant={v} danger size="sm" startIcon={Trash2} disabled={st === 'disabled'}>{v}</Button>
545
+ <Button variant={v} danger size="sm" startIcon={Trash2} disabled={st === 'disabled'}>{DANGER_LABEL[v]}</Button>
527
546
  <TokenAnnotation colors={DANGER_MAP[v]![st]} />
528
547
  </td>
529
548
  ))}
@@ -612,10 +631,10 @@ export const SizeMatrix = {
612
631
  <tr key={v}>
613
632
  <Td mono>{v}</Td>
614
633
  {SIZES.map((sz) => (
615
- <Td key={sz}><Button variant={v} size={sz} startIcon={Plus}>{v}</Button></Td>
634
+ <Td key={sz}><Button variant={v} size={sz} startIcon={Plus}>{VARIANT_LABEL[v]}</Button></Td>
616
635
  ))}
617
636
  {SIZES.map((sz) => (
618
- <Td key={`io-${sz}`}><Button variant={v} size={sz} iconOnly startIcon={Plus} aria-label={v} /></Td>
637
+ <Td key={`io-${sz}`}><Button variant={v} size={sz} iconOnly startIcon={Plus} aria-label={VARIANT_LABEL[v]} /></Td>
619
638
  ))}
620
639
  </tr>
621
640
  ))}
@@ -661,7 +680,7 @@ export const StateBehavior = {
661
680
  <div className="flex flex-wrap gap-3">
662
681
  {VARIANTS.map((v) => (
663
682
  <div key={v} className="flex flex-col items-center gap-1">
664
- <Button variant={v} disabled startIcon={Plus}>{v}</Button>
683
+ <Button variant={v} disabled startIcon={Plus}>{VARIANT_LABEL[v]}</Button>
665
684
  <span className="text-[10px] text-fg-muted">{v}</span>
666
685
  </div>
667
686
  ))}
@@ -351,7 +351,7 @@ export const OrderRule: Story = {
351
351
  note="使用者眼睛最先掃到最上方,最希望被點擊的動作放第一個。所有按鈕撐滿容器寬度"
352
352
  >
353
353
  <div className="w-[200px]">
354
- <ButtonGroup direction="vertical">
354
+ <ButtonGroup orientation="vertical">
355
355
  <Button variant="primary">確認送出</Button>
356
356
  <Button variant="tertiary">取消</Button>
357
357
  </ButtonGroup>
@@ -273,7 +273,7 @@ const ICON_ONLY_BASE = 'aspect-square p-0 min-w-0 gap-0'
273
273
 
274
274
  完整 rationale(包含 2026-04-25 從 padding-formula 派切換的 bug origin)+ 4 家世界級對照 → **SSOT 在 `tokens/uiSize/uiSize.spec.md`「Icon-only 元件的 padding canonical」節**。本 spec 不重複,只 pointer。
275
275
 
276
- **icon-only 按鈕內建自動 tooltip:** 當 `iconOnly` 為 true 時,Button 自動以 `aria-label` 的值渲染 tooltip。開發者不需要額外包 `<Tooltip>`——tooltip 是元件保證的行為,不是開發者「記得要加」的外部組合。
276
+ **icon-only 按鈕內建自動 tooltip:** 當 `iconOnly` 為 true 且非 `asChild` 時,Button 自動以 `aria-label` 的值渲染 tooltip(`asChild` 因 Radix Slot 單 child 限制不包 Tooltip,consumer 需自包)。開發者不需要額外包 `<Tooltip>`——tooltip 是元件保證的行為,不是開發者「記得要加」的外部組合。
277
277
 
278
278
  `aria-label` 是給螢幕閱讀器的,tooltip 是給所有人看的,兩者語意相同,由同一個值驅動。
279
279
 
@@ -434,7 +434,7 @@ N/A(action trigger,無資料層)。
434
434
 
435
435
  ## A11y 預設
436
436
 
437
- **ARIA / Pattern**:預設渲染原生 `<button>`,自動繼承瀏覽器原生按鈕語意(button role / Enter / Space 觸發 / Tab 聚焦),無需額外 ARIA。`asChild` 時改用 Radix `Slot` 把 props 合併到 consumer child element(Slot 為純 prop-merger,a11y 仍由該 child 自負)。icon-only 模式傳入 `aria-label` 描述用途並自動包 Tooltip。`pressed` 定義時自動寫 `aria-pressed` + `data-state`。
437
+ **ARIA / Pattern**:預設渲染原生 `<button>`,自動繼承瀏覽器原生按鈕語意(button role / Enter / Space 觸發 / Tab 聚焦),無需額外 ARIA。`asChild` 時改用 Radix `Slot` 把 props 合併到 consumer child element(Slot 為純 prop-merger,a11y 仍由該 child 自負)。icon-only 模式傳入 `aria-label` 描述用途;**僅在非 `asChild` 時**自動包 Tooltip(`asChild` 因 Radix Slot 單 child 限制不包,consumer 需自管 child 的 `aria-label` 與 Tooltip)。`pressed` 定義時自動寫 `aria-pressed` + `data-state`。
438
438
 
439
439
  **Focus**:鍵盤聚焦時(`focus-visible`)顯示 focus ring(`focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1`,以 box-shadow 實作並 `outline-none`);滑鼠點擊不觸發。Button 為單一互動元件,**不含** focus trap / focus restoration(那是 Dialog / 浮層的概念)。
440
440
 
@@ -24,7 +24,7 @@ const meta: Meta<typeof Button> = {
24
24
  },
25
25
  danger: {
26
26
  control: 'boolean',
27
- description: '套用危險色(紅色)。僅 `primary` / `secondary` / `text` 支援(`tertiary` 視覺與 secondary+danger 重複、`link` 語義矛盾,見 spec 禁止事項)。',
27
+ description: '套用危險色(紅色)。僅 `primary` / `secondary` / `text` 支援(`tertiary` danger compound——會靜默渲染成一般 tertiary、並非等同 secondary+danger;`link` 語義矛盾。見 spec 禁止事項)。',
28
28
  },
29
29
  size: {
30
30
  control: 'select',
@@ -76,11 +76,11 @@ export const Default: Story = {
76
76
  name: '預設',
77
77
  render: () => (
78
78
  <div className="flex flex-wrap items-center gap-3">
79
- <Button variant="primary">主要動作</Button>
80
- <Button variant="secondary">次要動作</Button>
81
- <Button variant="tertiary">第三動作</Button>
82
- <Button variant="text">純文字</Button>
83
- <Button variant="link">連結樣式</Button>
79
+ <Button variant="primary">送出申請</Button>
80
+ <Button variant="secondary">儲存草稿</Button>
81
+ <Button variant="tertiary">取消</Button>
82
+ <Button variant="text">重設表單</Button>
83
+ <Button variant="link">查看填寫說明</Button>
84
84
  </div>
85
85
  ),
86
86
  }
@@ -240,26 +240,20 @@ export const Loading: Story = {
240
240
  <div className="flex flex-col gap-6">
241
241
  {/* 行為對照 */}
242
242
  <div>
243
- <p className="mb-2 text-caption text-fg-muted">行為對照:原始 → loading</p>
244
- <div className="flex flex-col gap-3">
245
- <div className="flex items-center gap-3">
246
- <Button variant="primary" startIcon={Download}>匯出</Button>
247
- <span className="text-caption text-fg-muted">→</span>
248
- <Button variant="primary" startIcon={Download} loading>匯出中</Button>
249
- <span className="text-caption text-fg-muted">startIcon 被 spinner 替換,位置不變</span>
250
- </div>
251
- <div className="flex items-center gap-3">
252
- <Button variant="primary">儲存</Button>
253
- <span className="text-caption text-fg-muted">→</span>
254
- <Button variant="primary" loading>儲存中</Button>
255
- <span className="text-caption text-fg-muted">spinner 出現在文字左側,按鈕略寬</span>
256
- </div>
257
- <div className="flex items-center gap-3">
258
- <Button size="sm" iconOnly startIcon={Download} aria-label="下載" />
259
- <span className="text-caption text-fg-muted">→</span>
260
- <Button size="sm" iconOnly startIcon={Download} loading aria-label="下載中" />
261
- <span className="text-caption text-fg-muted">icon-only:spinner 替換 icon</span>
262
- </div>
243
+ <p className="mb-2 text-caption text-fg-muted">行為對照:操作前與載入中</p>
244
+ <div className="grid grid-cols-[auto_auto_1fr] items-center gap-x-6 gap-y-3">
245
+ <span className="text-caption text-fg-muted">操作前</span>
246
+ <span className="text-caption text-fg-muted">載入中</span>
247
+ <span />
248
+ <Button variant="primary" startIcon={Download}>匯出</Button>
249
+ <Button variant="primary" startIcon={Download} loading>匯出中</Button>
250
+ <span className="text-caption text-fg-muted">startIcon 被 spinner 替換,位置不變</span>
251
+ <Button variant="primary">儲存</Button>
252
+ <Button variant="primary" loading>儲存中</Button>
253
+ <span className="text-caption text-fg-muted">spinner 出現在文字左側,按鈕略寬</span>
254
+ <Button size="sm" iconOnly startIcon={Download} aria-label="下載" />
255
+ <Button size="sm" iconOnly startIcon={Download} loading aria-label="下載中" />
256
+ <span className="text-caption text-fg-muted">icon-only:spinner 替換 icon</span>
263
257
  </div>
264
258
  </div>
265
259
 
@@ -325,8 +319,8 @@ export const HoverFocusState: Story = {
325
319
  tags: ['!autodocs'],
326
320
  render: () => (
327
321
  <div className="flex gap-4">
328
- <Button variant="primary" data-testid="hover-target">Hover 我</Button>
329
- <Button variant="primary" data-testid="focus-target">Focus 我</Button>
322
+ <Button variant="primary" data-testid="hover-target">查看帳單</Button>
323
+ <Button variant="primary" data-testid="focus-target">下載明細</Button>
330
324
  </div>
331
325
  ),
332
326
  play: async ({ canvasElement }) => {