@qijenchen/design-system 0.1.0-beta.145 → 0.1.0-beta.147

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 (576) hide show
  1. package/dist/components/Accordion/accordion.d.ts +1 -1
  2. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  3. package/dist/components/Accordion/accordion.js +8 -3
  4. package/dist/components/Accordion/accordion.js.map +1 -1
  5. package/dist/components/AccountMenu/account-menu.d.ts.map +1 -1
  6. package/dist/components/AccountMenu/account-menu.js.map +1 -1
  7. package/dist/components/AgentPanel/agent-panel-fab.d.ts +7 -1
  8. package/dist/components/AgentPanel/agent-panel-fab.d.ts.map +1 -1
  9. package/dist/components/AgentPanel/agent-panel-fab.js +36 -14
  10. package/dist/components/AgentPanel/agent-panel-fab.js.map +1 -1
  11. package/dist/components/AgentPanel/agent-panel-logo.d.ts +3 -3
  12. package/dist/components/AgentPanel/agent-panel-logo.js.map +1 -1
  13. package/dist/components/AgentPanel/agent-panel.d.ts +1 -1
  14. package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -1
  15. package/dist/components/AgentPanel/agent-panel.js +28 -22
  16. package/dist/components/AgentPanel/agent-panel.js.map +1 -1
  17. package/dist/components/AppShell/app-shell.d.ts +1 -1
  18. package/dist/components/AppShell/app-shell.js +1 -1
  19. package/dist/components/AppShell/app-shell.js.map +1 -1
  20. package/dist/components/Avatar/avatar.d.ts +95 -1
  21. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  22. package/dist/components/Avatar/avatar.js +106 -15
  23. package/dist/components/Avatar/avatar.js.map +1 -1
  24. package/dist/components/Avatar/index.js +14 -2
  25. package/dist/components/Breadcrumb/breadcrumb.d.ts +4 -2
  26. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  27. package/dist/components/Breadcrumb/breadcrumb.js +2 -2
  28. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  29. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  30. package/dist/components/BulkActionBar/bulk-action-bar.js +27 -2
  31. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  32. package/dist/components/Button/button.d.ts +2 -2
  33. package/dist/components/Button/button.d.ts.map +1 -1
  34. package/dist/components/Button/button.js +118 -22
  35. package/dist/components/Button/button.js.map +1 -1
  36. package/dist/components/Calendar/calendar.d.ts +34 -10
  37. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  38. package/dist/components/Calendar/calendar.js +210 -36
  39. package/dist/components/Calendar/calendar.js.map +1 -1
  40. package/dist/components/Carousel/carousel.d.ts +1 -1
  41. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  42. package/dist/components/Carousel/carousel.js +3 -2
  43. package/dist/components/Carousel/carousel.js.map +1 -1
  44. package/dist/components/Chart/chart.d.ts +1 -0
  45. package/dist/components/Chart/chart.d.ts.map +1 -1
  46. package/dist/components/Chart/chart.js +8 -0
  47. package/dist/components/Chart/chart.js.map +1 -1
  48. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  49. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  50. package/dist/components/Checkbox/checkbox.js +10 -2
  51. package/dist/components/Checkbox/checkbox.js.map +1 -1
  52. package/dist/components/Chip/chip.d.ts +1 -1
  53. package/dist/components/Chip/chip.d.ts.map +1 -1
  54. package/dist/components/Chip/chip.js +4 -2
  55. package/dist/components/Chip/chip.js.map +1 -1
  56. package/dist/components/Combobox/combobox.d.ts +1 -1
  57. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  58. package/dist/components/Combobox/combobox.js +37 -11
  59. package/dist/components/Combobox/combobox.js.map +1 -1
  60. package/dist/components/Command/command.d.ts +1 -1
  61. package/dist/components/Command/command.d.ts.map +1 -1
  62. package/dist/components/Command/command.js +106 -8
  63. package/dist/components/Command/command.js.map +1 -1
  64. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  65. package/dist/components/DataTable/cell-registry.js +3 -2
  66. package/dist/components/DataTable/cell-registry.js.map +1 -1
  67. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  68. package/dist/components/DataTable/data-table-column-visibility-panel.js +24 -24
  69. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  70. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -1
  71. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  72. package/dist/components/DataTable/data-table-interaction-layer.js +3 -4
  73. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  74. package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -1
  75. package/dist/components/DataTable/data-table-sort-manager.js +20 -20
  76. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  77. package/dist/components/DataTable/data-table.d.ts +8 -5
  78. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  79. package/dist/components/DataTable/data-table.js +197 -71
  80. package/dist/components/DataTable/data-table.js.map +1 -1
  81. package/dist/components/DateGrid/date-grid.d.ts +1 -1
  82. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  83. package/dist/components/DateGrid/date-grid.js +358 -225
  84. package/dist/components/DateGrid/date-grid.js.map +1 -1
  85. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  86. package/dist/components/DatePicker/date-picker.js +16 -1
  87. package/dist/components/DatePicker/date-picker.js.map +1 -1
  88. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  89. package/dist/components/Dialog/dialog.js +55 -43
  90. package/dist/components/Dialog/dialog.js.map +1 -1
  91. package/dist/components/DropdownMenu/dropdown-menu-keyboard.d.ts +86 -0
  92. package/dist/components/DropdownMenu/dropdown-menu-keyboard.d.ts.map +1 -0
  93. package/dist/components/DropdownMenu/dropdown-menu-keyboard.js +172 -0
  94. package/dist/components/DropdownMenu/dropdown-menu-keyboard.js.map +1 -0
  95. package/dist/components/DropdownMenu/dropdown-menu.d.ts +6 -1
  96. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  97. package/dist/components/DropdownMenu/dropdown-menu.js +50 -39
  98. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  99. package/dist/components/Field/field-context.d.ts +4 -0
  100. package/dist/components/Field/field-context.d.ts.map +1 -1
  101. package/dist/components/Field/field-context.js +1 -2
  102. package/dist/components/Field/field-context.js.map +1 -1
  103. package/dist/components/Field/field-edit-keys.d.ts +8 -0
  104. package/dist/components/Field/field-edit-keys.d.ts.map +1 -1
  105. package/dist/components/Field/field-edit-keys.js +3 -0
  106. package/dist/components/Field/field-edit-keys.js.map +1 -1
  107. package/dist/components/Field/field-wrapper.d.ts +18 -1
  108. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  109. package/dist/components/Field/field-wrapper.js +39 -10
  110. package/dist/components/Field/field-wrapper.js.map +1 -1
  111. package/dist/components/Field/field.d.ts +3 -2
  112. package/dist/components/Field/field.d.ts.map +1 -1
  113. package/dist/components/Field/field.js +2 -1
  114. package/dist/components/Field/field.js.map +1 -1
  115. package/dist/components/FileItem/file-item.d.ts +26 -2
  116. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  117. package/dist/components/FileItem/file-item.js +82 -25
  118. package/dist/components/FileItem/file-item.js.map +1 -1
  119. package/dist/components/FileItem/index.js +4 -2
  120. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  121. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  122. package/dist/components/FileUpload/file-upload.js +132 -55
  123. package/dist/components/FileUpload/file-upload.js.map +1 -1
  124. package/dist/components/FileViewer/file-viewer.d.ts +1 -1
  125. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  126. package/dist/components/FileViewer/file-viewer.js +9 -4
  127. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  128. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  129. package/dist/components/InlineEdit/inline-edit.js +1 -1
  130. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  131. package/dist/components/Input/input.d.ts.map +1 -1
  132. package/dist/components/Input/input.js +6 -1
  133. package/dist/components/Input/input.js.map +1 -1
  134. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  135. package/dist/components/LinkInput/link-input.js +20 -4
  136. package/dist/components/LinkInput/link-input.js.map +1 -1
  137. package/dist/components/Notice/notice.js +1 -1
  138. package/dist/components/Notice/notice.js.map +1 -1
  139. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  140. package/dist/components/NumberInput/number-input.js +6 -1
  141. package/dist/components/NumberInput/number-input.js.map +1 -1
  142. package/dist/components/OverflowIndicator/index.js +2 -1
  143. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +19 -1
  144. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  145. package/dist/components/OverflowIndicator/overflow-indicator.js +47 -27
  146. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  147. package/dist/components/Pagination/pagination.d.ts +1 -1
  148. package/dist/components/Pagination/pagination.js +1 -1
  149. package/dist/components/Pagination/pagination.js.map +1 -1
  150. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +7 -6
  151. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -1
  152. package/dist/components/PeoplePicker/avatar-stack-overflow.js +6 -7
  153. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  154. package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -1
  155. package/dist/components/PeoplePicker/people-picker-helpers.js +1 -1
  156. package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -1
  157. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  158. package/dist/components/PeoplePicker/people-picker.js +2 -2
  159. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  160. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  161. package/dist/components/PeoplePicker/person-display.js +26 -28
  162. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  163. package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
  164. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  165. package/dist/components/RadioGroup/radio-group.d.ts +1 -1
  166. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  167. package/dist/components/RadioGroup/radio-group.js +10 -4
  168. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  169. package/dist/components/Rating/rating.d.ts +28 -6
  170. package/dist/components/Rating/rating.d.ts.map +1 -1
  171. package/dist/components/Rating/rating.js +97 -80
  172. package/dist/components/Rating/rating.js.map +1 -1
  173. package/dist/components/ScrollArea/scroll-area.d.ts +1 -1
  174. package/dist/components/ScrollArea/scroll-area.js +1 -1
  175. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  176. package/dist/components/SegmentedControl/segmented-control.d.ts +1 -1
  177. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  178. package/dist/components/SegmentedControl/segmented-control.js +3 -2
  179. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  180. package/dist/components/Select/select.d.ts.map +1 -1
  181. package/dist/components/Select/select.js +15 -8
  182. package/dist/components/Select/select.js.map +1 -1
  183. package/dist/components/SelectMenu/index.js +2 -1
  184. package/dist/components/SelectMenu/index.js.map +1 -1
  185. package/dist/components/SelectMenu/select-menu-keyboard.d.ts +59 -0
  186. package/dist/components/SelectMenu/select-menu-keyboard.d.ts.map +1 -0
  187. package/dist/components/SelectMenu/select-menu-keyboard.js +107 -0
  188. package/dist/components/SelectMenu/select-menu-keyboard.js.map +1 -0
  189. package/dist/components/SelectMenu/select-menu.d.ts +1 -22
  190. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  191. package/dist/components/SelectMenu/select-menu.js +18 -34
  192. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  193. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
  194. package/dist/components/SelectionControl/selection-item.js +1 -0
  195. package/dist/components/SelectionControl/selection-item.js.map +1 -1
  196. package/dist/components/Sidebar/sidebar.d.ts +7 -9
  197. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  198. package/dist/components/Sidebar/sidebar.js +171 -50
  199. package/dist/components/Sidebar/sidebar.js.map +1 -1
  200. package/dist/components/Slider/slider.d.ts +1 -1
  201. package/dist/components/Slider/slider.d.ts.map +1 -1
  202. package/dist/components/Slider/slider.js +9 -4
  203. package/dist/components/Slider/slider.js.map +1 -1
  204. package/dist/components/Steps/steps.d.ts.map +1 -1
  205. package/dist/components/Steps/steps.js +54 -26
  206. package/dist/components/Steps/steps.js.map +1 -1
  207. package/dist/components/Switch/switch.d.ts +1 -1
  208. package/dist/components/Switch/switch.d.ts.map +1 -1
  209. package/dist/components/Switch/switch.js +7 -2
  210. package/dist/components/Switch/switch.js.map +1 -1
  211. package/dist/components/Tabs/tabs.d.ts +1 -1
  212. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  213. package/dist/components/Tabs/tabs.js +39 -4
  214. package/dist/components/Tabs/tabs.js.map +1 -1
  215. package/dist/components/Tag/tag.d.ts +1 -1
  216. package/dist/components/Tag/tag.d.ts.map +1 -1
  217. package/dist/components/Tag/tag.js +3 -2
  218. package/dist/components/Tag/tag.js.map +1 -1
  219. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  220. package/dist/components/Textarea/textarea.js +8 -2
  221. package/dist/components/Textarea/textarea.js.map +1 -1
  222. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  223. package/dist/components/TimePicker/time-columns.js +8 -4
  224. package/dist/components/TimePicker/time-columns.js.map +1 -1
  225. package/dist/components/TimePicker/time-picker.d.ts +1 -1
  226. package/dist/components/TimePicker/time-picker.js +1 -1
  227. package/dist/components/TimePicker/time-picker.js.map +1 -1
  228. package/dist/components/TreeView/tree-view.d.ts +9 -5
  229. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  230. package/dist/components/TreeView/tree-view.js +266 -214
  231. package/dist/components/TreeView/tree-view.js.map +1 -1
  232. package/dist/hooks/use-input-modality.d.ts +12 -17
  233. package/dist/hooks/use-input-modality.d.ts.map +1 -1
  234. package/dist/hooks/use-input-modality.js +4 -34
  235. package/dist/hooks/use-input-modality.js.map +1 -1
  236. package/dist/hooks/use-overflow-items.d.ts.map +1 -1
  237. package/dist/hooks/use-overflow-items.js +2 -0
  238. package/dist/hooks/use-overflow-items.js.map +1 -1
  239. package/dist/hooks/use-truncated.d.ts.map +1 -1
  240. package/dist/hooks/use-truncated.js.map +1 -1
  241. package/dist/index.d.ts +3 -0
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +23 -3
  244. package/dist/index.js.map +1 -1
  245. package/dist/lib/drag-announcements.d.ts +32 -0
  246. package/dist/lib/drag-announcements.d.ts.map +1 -1
  247. package/dist/lib/drag-announcements.js +39 -1
  248. package/dist/lib/drag-announcements.js.map +1 -1
  249. package/dist/lib/focus-after-trigger.d.ts +45 -0
  250. package/dist/lib/focus-after-trigger.d.ts.map +1 -0
  251. package/dist/lib/focus-after-trigger.js +66 -0
  252. package/dist/lib/focus-after-trigger.js.map +1 -0
  253. package/dist/lib/overlay-coexistence.js +1 -1
  254. package/dist/lib/roving-list-keyboard.d.ts +208 -0
  255. package/dist/lib/roving-list-keyboard.d.ts.map +1 -0
  256. package/dist/lib/roving-list-keyboard.js +174 -0
  257. package/dist/lib/roving-list-keyboard.js.map +1 -0
  258. package/dist/lib/utils.d.ts.map +1 -1
  259. package/dist/lib/utils.js +6 -1
  260. package/dist/lib/utils.js.map +1 -1
  261. package/dist/patterns/element-anatomy/item-anatomy.d.ts +4 -4
  262. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  263. package/dist/patterns/element-anatomy/item-anatomy.js +14 -4
  264. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  265. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -1
  266. package/dist/patterns/horizontal-overflow/horizontal-overflow.js +25 -0
  267. package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -1
  268. package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
  269. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
  270. package/dist/tokens/categorical-color.d.ts +6 -1
  271. package/dist/tokens/categorical-color.d.ts.map +1 -1
  272. package/dist/tokens/categorical-color.js.map +1 -1
  273. package/dist/tokens/uiSize/icon-size.d.ts +1 -1
  274. package/dist/tokens/uiSize/stack-gap.d.ts +18 -0
  275. package/dist/tokens/uiSize/stack-gap.d.ts.map +1 -0
  276. package/dist/tokens/uiSize/stack-gap.js +5 -0
  277. package/dist/tokens/uiSize/stack-gap.js.map +1 -0
  278. package/ds-canonical/fork/codex/agents/skills/performance-audit/SKILL.md +1 -1
  279. package/ds-canonical/fork/codex/hooks.json +1 -1
  280. package/ds-canonical/fork/consumer/lock.json +17 -14
  281. package/ds-canonical/fork/consumer/managed-files/423729840acdd43c812f17c245b871716c6b60f76e4d3e94864d0e34a815bf8d.blob +9 -0
  282. package/ds-canonical/fork/consumer/managed-files/46f10bc55cdfdf834d0749eebff42ea0bb8576f361b36d2b6ba1851354c50150.blob +47 -9
  283. package/ds-canonical/fork/consumer/managed-files/5a0d134a2645114c8caac20458070b00a7f0fd55b3e8805b7325cb4cf52fa15e.blob +110 -0
  284. package/ds-canonical/fork/consumer/managed-files/5af0a46760af338d51fd0f7950675f8e97f7d2f09386b8818fcd7a58e6654e75.blob +790 -0
  285. package/ds-canonical/fork/consumer/managed-files/68bfcddff9c4a16388c248cd34fb66163e9e64b3d809a48ef3984f6ae4ff6d12.blob +211 -0
  286. package/ds-canonical/fork/consumer/managed-files/7eb6cc60abfdabaf6617c336058fad1454ccde08889295767bfd9b7fd153cc6e.blob +45 -6
  287. package/ds-canonical/fork/consumer/managed-files/92e4828cdcb96ff0d01daa16f6885f24045a8e72820665650f2a1890dc3a446c.blob +42 -2
  288. package/ds-canonical/fork/consumer/managed-files/ab072e7f2eca51f0e18a5e18c4b333260ee5d219a12cc6df5bb2d683f0b2734d.blob +27 -1
  289. package/ds-canonical/fork/consumer/managed-files/e71c65f45c6af7ce12b6b3c0d8028f185da5b719e2050c9b2a6b243d41ae4878.blob +62 -14
  290. package/ds-canonical/fork/governance.lock +41 -17
  291. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +16 -4
  292. package/ds-canonical/fork/hooks/check_consumer_code_quality.sh +3 -1
  293. package/ds-canonical/fork/hooks/check_pattern_invariants.sh +13 -9
  294. package/ds-canonical/fork/launchers/settings-hooks.json +1 -1
  295. package/ds-canonical/fork/manifest.json +17 -11
  296. package/ds-canonical/fork/providers/claude/skills/performance-audit/SKILL.md +1 -1
  297. package/ds-canonical/fork/providers/codex/hook-config.json +1 -1
  298. package/ds-canonical/fork/providers/codex/skills/performance-audit/SKILL.md +1 -1
  299. package/ds-canonical/fork/skills/performance-audit/SKILL.md +1 -1
  300. package/ds-canonical/hooks/check_consumer_app_invariants.sh +16 -4
  301. package/ds-canonical/hooks/check_consumer_code_quality.sh +3 -1
  302. package/ds-canonical/hooks/check_datatable_invariants.sh +4 -1
  303. package/ds-canonical/hooks/check_pattern_invariants.sh +13 -9
  304. package/ds-canonical/hooks/check_plugin_fork_health.sh +8 -1
  305. package/ds-canonical/hooks/check_propose_discipline.sh +8 -1
  306. package/ds-canonical/hooks/check_storybook_addon_packaging.sh +8 -1
  307. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +64 -2
  308. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +5 -2
  309. package/ds-canonical/hooks/registrations.json +12 -7
  310. package/ds-canonical/hooks/session_start_governance_check.sh +16 -0
  311. package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +25 -0
  312. package/ds-canonical/hooks/tests/test_check_consumer_code_quality.sh +4 -0
  313. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +14 -0
  314. package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +24 -0
  315. package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +32 -0
  316. package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +59 -0
  317. package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +32 -1
  318. package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +21 -0
  319. package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +21 -0
  320. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +97 -0
  321. package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +49 -0
  322. package/ds-canonical/references/README.md +12 -6
  323. package/ds-canonical/references/drag-canonical.md +3 -1
  324. package/ds-canonical/references/focus-canonical.md +26 -13
  325. package/ds-canonical/references/governance-audit-coverage.md +1 -1
  326. package/ds-canonical/references/hit-area-canonical.md +361 -0
  327. package/ds-canonical/references/item-anatomy-recipe.md +4 -2
  328. package/ds-canonical/references/keyboard-model-canonical.md +559 -0
  329. package/ds-canonical/rules/meta-patterns.md +4 -4
  330. package/ds-canonical/rules/self-verify.md +4 -4
  331. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1 -1
  332. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +96 -0
  333. package/ds-canonical/skills/knowledge-prune/SKILL.md +4 -1
  334. package/ds-canonical/skills/performance-audit/SKILL.md +1 -1
  335. package/ds-story-manifest.json +19 -7
  336. package/llms-full.txt +2 -2
  337. package/llms.txt +2 -2
  338. package/package.json +3 -1
  339. package/src/components/Accordion/accordion.anatomy.stories.tsx +3 -3
  340. package/src/components/Accordion/accordion.spec.md +1 -1
  341. package/src/components/Accordion/accordion.tsx +8 -3
  342. package/src/components/AccountMenu/account-menu.spec.md +2 -3
  343. package/src/components/AccountMenu/account-menu.tsx +0 -1
  344. package/src/components/AgentPanel/agent-decision-card.spec.md +88 -0
  345. package/src/components/AgentPanel/agent-panel-fab.spec.md +151 -0
  346. package/src/components/AgentPanel/agent-panel-fab.tsx +67 -24
  347. package/src/components/AgentPanel/agent-panel-logo.spec.md +87 -0
  348. package/src/components/AgentPanel/agent-panel-logo.tsx +3 -3
  349. package/src/components/AgentPanel/agent-panel.anatomy.stories.tsx +1 -1
  350. package/src/components/AgentPanel/agent-panel.principles.stories.tsx +1 -1
  351. package/src/components/AgentPanel/agent-panel.spec.md +30 -275
  352. package/src/components/AgentPanel/agent-panel.stories.tsx +113 -8
  353. package/src/components/AgentPanel/agent-panel.tsx +59 -22
  354. package/src/components/Alert/alert.anatomy.stories.tsx +1 -1
  355. package/src/components/AppShell/app-shell.tsx +1 -1
  356. package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +10 -15
  357. package/src/components/Avatar/avatar.anatomy.stories.tsx +23 -26
  358. package/src/components/Avatar/avatar.principles.stories.tsx +10 -10
  359. package/src/components/Avatar/avatar.spec.md +45 -6
  360. package/src/components/Avatar/avatar.stories.tsx +8 -8
  361. package/src/components/Avatar/avatar.tsx +227 -21
  362. package/src/components/Badge/badge.anatomy.stories.tsx +16 -21
  363. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +3 -3
  364. package/src/components/Breadcrumb/breadcrumb.spec.md +3 -3
  365. package/src/components/Breadcrumb/breadcrumb.tsx +5 -3
  366. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +1 -1
  367. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +1 -1
  368. package/src/components/BulkActionBar/bulk-action-bar.spec.md +1 -0
  369. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +57 -2
  370. package/src/components/BulkActionBar/bulk-action-bar.tsx +32 -2
  371. package/src/components/Button/button.anatomy.stories.tsx +174 -33
  372. package/src/components/Button/button.spec.md +23 -8
  373. package/src/components/Button/button.tsx +116 -21
  374. package/src/components/Calendar/calendar.anatomy.stories.tsx +34 -11
  375. package/src/components/Calendar/calendar.principles.stories.tsx +44 -1
  376. package/src/components/Calendar/calendar.spec.md +97 -20
  377. package/src/components/Calendar/calendar.stories.tsx +101 -4
  378. package/src/components/Calendar/calendar.tsx +379 -74
  379. package/src/components/Carousel/carousel.anatomy.stories.tsx +16 -17
  380. package/src/components/Carousel/carousel.spec.md +48 -2
  381. package/src/components/Carousel/carousel.tsx +9 -3
  382. package/src/components/Chart/chart.anatomy.stories.tsx +7 -5
  383. package/src/components/Chart/chart.spec.md +32 -7
  384. package/src/components/Chart/chart.tsx +9 -0
  385. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +21 -28
  386. package/src/components/Checkbox/checkbox.spec.md +4 -2
  387. package/src/components/Checkbox/checkbox.tsx +10 -2
  388. package/src/components/Chip/chip.anatomy.stories.tsx +1 -1
  389. package/src/components/Chip/chip.spec.md +2 -1
  390. package/src/components/Chip/chip.tsx +4 -2
  391. package/src/components/Combobox/combobox.anatomy.stories.tsx +30 -37
  392. package/src/components/Combobox/combobox.spec.md +11 -3
  393. package/src/components/Combobox/combobox.tsx +43 -12
  394. package/src/components/Command/command.spec.md +11 -0
  395. package/src/components/Command/command.tsx +143 -10
  396. package/src/components/DataTable/cell-registry.tsx +5 -1
  397. package/src/components/DataTable/data-table-column-visibility-panel.tsx +5 -6
  398. package/src/components/DataTable/data-table-interaction-layer.tsx +27 -14
  399. package/src/components/DataTable/data-table-known-defects.spec.md +72 -0
  400. package/src/components/DataTable/data-table-scroll-performance.spec.md +295 -0
  401. package/src/components/DataTable/data-table-sort-manager.tsx +5 -6
  402. package/src/components/DataTable/data-table.anatomy.stories.tsx +1 -1
  403. package/src/components/DataTable/data-table.css +64 -0
  404. package/src/components/DataTable/data-table.spec.md +70 -346
  405. package/src/components/DataTable/data-table.stories.tsx +56 -9
  406. package/src/components/DataTable/data-table.tsx +392 -103
  407. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +2 -2
  408. package/src/components/DateGrid/date-grid.spec.md +163 -1
  409. package/src/components/DateGrid/date-grid.tsx +270 -7
  410. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +18 -27
  411. package/src/components/DatePicker/date-picker.spec.md +6 -2
  412. package/src/components/DatePicker/date-picker.tsx +20 -1
  413. package/src/components/Dialog/dialog.spec.md +6 -2
  414. package/src/components/Dialog/dialog.stories.tsx +18 -9
  415. package/src/components/Dialog/dialog.tsx +83 -48
  416. package/src/components/DropdownMenu/dropdown-menu-keyboard.ts +255 -0
  417. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +32 -33
  418. package/src/components/DropdownMenu/dropdown-menu.spec.md +18 -5
  419. package/src/components/DropdownMenu/dropdown-menu.stories.tsx +58 -1
  420. package/src/components/DropdownMenu/dropdown-menu.tsx +70 -33
  421. package/src/components/Empty/empty.spec.md +1 -2
  422. package/src/components/Field/field-context.ts +9 -4
  423. package/src/components/Field/field-controls.spec.md +5 -2
  424. package/src/components/Field/field-edit-keys.ts +12 -0
  425. package/src/components/Field/field-wrapper.tsx +76 -10
  426. package/src/components/Field/field.anatomy.stories.tsx +1 -1
  427. package/src/components/Field/field.spec.md +11 -6
  428. package/src/components/Field/field.stories.tsx +24 -1
  429. package/src/components/Field/field.tsx +10 -4
  430. package/src/components/FileItem/file-item.anatomy.stories.tsx +20 -10
  431. package/src/components/FileItem/file-item.principles.stories.tsx +14 -7
  432. package/src/components/FileItem/file-item.spec.md +50 -48
  433. package/src/components/FileItem/file-item.stories.tsx +41 -28
  434. package/src/components/FileItem/file-item.tsx +184 -50
  435. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +11 -15
  436. package/src/components/FileUpload/file-upload.spec.md +27 -1
  437. package/src/components/FileUpload/file-upload.stories.tsx +33 -0
  438. package/src/components/FileUpload/file-upload.tsx +173 -43
  439. package/src/components/FileViewer/file-viewer.tsx +9 -4
  440. package/src/components/HoverCard/hover-card.stories.tsx +2 -2
  441. package/src/components/InlineEdit/inline-edit.spec.md +2 -0
  442. package/src/components/InlineEdit/inline-edit.tsx +8 -3
  443. package/src/components/Input/input.anatomy.stories.tsx +23 -31
  444. package/src/components/Input/input.spec.md +11 -0
  445. package/src/components/Input/input.tsx +6 -1
  446. package/src/components/LinkInput/link-input.anatomy.stories.tsx +18 -21
  447. package/src/components/LinkInput/link-input.principles.stories.tsx +4 -4
  448. package/src/components/LinkInput/link-input.spec.md +12 -1
  449. package/src/components/LinkInput/link-input.tsx +37 -4
  450. package/src/components/Menu/menu-item.anatomy.stories.tsx +50 -56
  451. package/src/components/Menu/menu-item.spec.md +1 -1
  452. package/src/components/Menu/menu-item.stories.tsx +48 -42
  453. package/src/components/Notice/notice.anatomy.stories.tsx +8 -16
  454. package/src/components/Notice/notice.spec.md +1 -1
  455. package/src/components/Notice/notice.tsx +1 -1
  456. package/src/components/NumberInput/number-input.anatomy.stories.tsx +21 -28
  457. package/src/components/NumberInput/number-input.spec.md +2 -0
  458. package/src/components/NumberInput/number-input.tsx +8 -1
  459. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +28 -48
  460. package/src/components/OverflowIndicator/overflow-indicator.spec.md +13 -1
  461. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +12 -9
  462. package/src/components/OverflowIndicator/overflow-indicator.tsx +32 -12
  463. package/src/components/Pagination/pagination.spec.md +1 -0
  464. package/src/components/Pagination/pagination.tsx +1 -1
  465. package/src/components/PeoplePicker/avatar-stack-overflow.ts +14 -13
  466. package/src/components/PeoplePicker/people-picker-helpers.ts +5 -2
  467. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +1 -1
  468. package/src/components/PeoplePicker/people-picker.spec.md +4 -2
  469. package/src/components/PeoplePicker/people-picker.tsx +1 -4
  470. package/src/components/PeoplePicker/person-display.tsx +45 -28
  471. package/src/components/Popover/popover.anatomy.stories.tsx +1 -1
  472. package/src/components/Popover/popover.principles.stories.tsx +3 -12
  473. package/src/components/Popover/popover.spec.md +7 -3
  474. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  475. package/src/components/ProfileCard/profile-card.spec.md +1 -1
  476. package/src/components/ProfileCard/profile-card.tsx +0 -3
  477. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +11 -21
  478. package/src/components/ProgressBar/progress-bar.spec.md +1 -1
  479. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +17 -24
  480. package/src/components/RadioGroup/radio-group.spec.md +1 -1
  481. package/src/components/RadioGroup/radio-group.tsx +22 -4
  482. package/src/components/Rating/rating.anatomy.stories.tsx +131 -124
  483. package/src/components/Rating/rating.principles.stories.tsx +69 -43
  484. package/src/components/Rating/rating.spec.md +142 -63
  485. package/src/components/Rating/rating.stories.tsx +11 -15
  486. package/src/components/Rating/rating.tsx +131 -117
  487. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  488. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +6 -3
  489. package/src/components/ScrollArea/scroll-area.spec.md +3 -1
  490. package/src/components/ScrollArea/scroll-area.stories.tsx +5 -2
  491. package/src/components/ScrollArea/scroll-area.tsx +1 -1
  492. package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +1 -1
  493. package/src/components/SegmentedControl/segmented-control.spec.md +2 -2
  494. package/src/components/SegmentedControl/segmented-control.tsx +3 -2
  495. package/src/components/Select/select.anatomy.stories.tsx +26 -35
  496. package/src/components/Select/select.spec.md +4 -3
  497. package/src/components/Select/select.tsx +11 -4
  498. package/src/components/SelectMenu/select-menu-keyboard.ts +218 -0
  499. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +6 -17
  500. package/src/components/SelectMenu/select-menu.spec.md +12 -4
  501. package/src/components/SelectMenu/select-menu.tsx +21 -56
  502. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +9 -33
  503. package/src/components/SelectionControl/selection-item.spec.md +2 -2
  504. package/src/components/SelectionControl/selection-item.tsx +3 -1
  505. package/src/components/Separator/separator.stories.tsx +4 -4
  506. package/src/components/Sheet/sheet.principles.stories.tsx +31 -13
  507. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +1 -1
  508. package/src/components/Sidebar/sidebar.spec.md +73 -6
  509. package/src/components/Sidebar/sidebar.stories.tsx +82 -4
  510. package/src/components/Sidebar/sidebar.tsx +281 -64
  511. package/src/components/Skeleton/skeleton.spec.md +1 -1
  512. package/src/components/Slider/slider.anatomy.stories.tsx +1 -1
  513. package/src/components/Slider/slider.spec.md +6 -5
  514. package/src/components/Slider/slider.tsx +13 -8
  515. package/src/components/Steps/steps-state-visuals.spec.md +157 -0
  516. package/src/components/Steps/steps.anatomy.stories.tsx +1 -0
  517. package/src/components/Steps/steps.spec.md +59 -142
  518. package/src/components/Steps/steps.stories.tsx +1 -1
  519. package/src/components/Steps/steps.tsx +125 -33
  520. package/src/components/Switch/switch.spec.md +3 -3
  521. package/src/components/Switch/switch.tsx +6 -1
  522. package/src/components/Tabs/tabs.spec.md +5 -1
  523. package/src/components/Tabs/tabs.tsx +42 -3
  524. package/src/components/Tag/tag.anatomy.stories.tsx +24 -28
  525. package/src/components/Tag/tag.spec.md +10 -11
  526. package/src/components/Tag/tag.tsx +3 -3
  527. package/src/components/Textarea/textarea.tsx +7 -1
  528. package/src/components/TimePicker/time-columns.tsx +9 -4
  529. package/src/components/TimePicker/time-picker.spec.md +4 -1
  530. package/src/components/TimePicker/time-picker.tsx +1 -1
  531. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +6 -15
  532. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -16
  533. package/src/components/Tooltip/tooltip.spec.md +2 -1
  534. package/src/components/TreeView/tree-view.anatomy.stories.tsx +35 -13
  535. package/src/components/TreeView/tree-view.spec.md +67 -38
  536. package/src/components/TreeView/tree-view.stories.tsx +221 -12
  537. package/src/components/TreeView/tree-view.tsx +463 -356
  538. package/src/hooks/use-input-modality.ts +17 -46
  539. package/src/hooks/use-overflow-items.ts +4 -0
  540. package/src/hooks/use-truncated.ts +3 -2
  541. package/src/index.ts +17 -0
  542. package/src/lib/README.md +2 -0
  543. package/src/lib/drag-announcements.ts +78 -0
  544. package/src/lib/focus-after-trigger.ts +102 -0
  545. package/src/lib/roving-list-keyboard.ts +400 -0
  546. package/src/lib/utils.ts +5 -0
  547. package/src/patterns/action-bar/action-bar.spec.md +2 -0
  548. package/src/patterns/element-anatomy/inline-action.spec.md +16 -12
  549. package/src/patterns/element-anatomy/item-anatomy.spec.md +98 -6
  550. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +75 -70
  551. package/src/patterns/element-anatomy/item-anatomy.tsx +17 -6
  552. package/src/patterns/element-anatomy/truncated-text.spec.md +1 -0
  553. package/src/patterns/header-canonical/header-canonical.spec.md +3 -2
  554. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +2 -0
  555. package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +36 -0
  556. package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +28 -0
  557. package/src/patterns/overlay-surface/overlay-chrome-sizing.spec.md +180 -0
  558. package/src/patterns/overlay-surface/overlay-surface.spec.md +8 -162
  559. package/src/patterns/overlay-surface/overlay-surface.tsx +5 -3
  560. package/src/patterns/resize-handle/resize-handle.spec.md +3 -3
  561. package/src/styles/base.css +1 -1
  562. package/src/tokens/categorical-color.ts +6 -1
  563. package/src/tokens/color/color.spec.md +91 -24
  564. package/src/tokens/color/color.stories.tsx +50 -2
  565. package/src/tokens/color/primitives.css +41 -38
  566. package/src/tokens/color/semantic.css +105 -36
  567. package/src/tokens/layoutSpace/layoutSpace.spec.md +2 -0
  568. package/src/tokens/motion/motion.spec.md +31 -8
  569. package/src/tokens/orphan-tokens.spec.md +1 -1
  570. package/src/tokens/uiSize/icon-size.ts +1 -1
  571. package/src/tokens/uiSize/stack-gap.ts +17 -0
  572. package/src/tokens/uiSize/uiSize.css +12 -0
  573. package/src/tokens/uiSize/uiSize.spec.md +17 -16
  574. package/src/tokens/uiSize/uiSize.stories.tsx +1 -1
  575. package/dist/node_modules/aria-hidden/dist/es2015/index.js +0 -147
  576. package/dist/node_modules/aria-hidden/dist/es2015/index.js.map +0 -1
@@ -0,0 +1,157 @@
1
+ # Steps 狀態視覺設計原則(indicator / 焦點外環 / label / connector 的 state 疊加;獨立 SSOT)
2
+
3
+ > **本 spec 是 Steps 狀態視覺的獨立 SSOT**(2026-09-27 從 `steps.spec.md` 抽出「State」「自動推導」「Focus marker — Outer ring」「Label 色彩」「Connector 路徑色」五段,避免單一 spec 過長(530 行 > 500 硬上限,待辦總帳 N19);內容零改動,只加本檔頭、檔尾指標,與一處回指 `steps.spec.md` 的路徑)。定位 / Size / Linear vs Non-linear / Expansion / Orientation / API / A11y 仍住 `./steps.spec.md`;「指示點不是命中目標」講的是命中區、不是狀態,也留在 `steps.spec.md`。程式碼對應 `steps.tsx`(`computeState` / `resolveRingColor` / `getOuterRingStyle`)。
4
+ >
5
+ > **Layout Family**:同 `steps.spec.md`(`patterns/element-anatomy/item-anatomy.spec.md` Family 2 List item 的消費者);本檔不另立 family。
6
+
7
+ ## State(Content state,跟 Focus 正交)
8
+
9
+ | State | 視覺 | 觸發 |
10
+ |---|---|---|
11
+ | `upcoming` | 灰底(inline `background: var(--muted)`)+ 灰字(`text-fg-disabled`)| 未走到 |
12
+ | `current` | 藍底(`bg-info`)+ 白字數字 | step === `value` 且不在 completedValues / errorValues |
13
+ | `completed` | 藍底(`bg-info`)+ 白色 ✓ | step 在 `completedValues` 內 |
14
+ | `reachable` | 藍底(`bg-info`)+ 白字數字(僅 linear;sm 為空心環)| linear 下「下一個未完成」step(非 current / completed / error),可點 |
15
+ | `error` | 紅底(`bg-error`)+ 白色 ✕ | step 在 `errorValues` 內(或單項 `state="error"` override)|
16
+
17
+ ### Sm size 的 state 視覺
18
+
19
+ sm 沒有 icon 空間,用色塊表達:
20
+ - `upcoming` → 灰實心點(`bg-fg-disabled`)
21
+ - `current`(linear)→ 藍色**空心**環(`border: 2px solid var(--info-hover)`);non-linear current 走灰實心點(`bg-fg-disabled`)。`reachable` 也是空心環
22
+ - `completed` → 藍實心點(`bg-info`)
23
+ - `error` → 紅實心點(`bg-error`)
24
+
25
+ ### 自動推導(順序即優先級,對齊 `computeState`)
26
+
27
+ **Consumer 不手寫每個 step 的 state**。State 由 Steps root 的 props 依下列順序推導(`steps.tsx` `computeState`):
28
+
29
+ ```
30
+ per-item state override(escape hatch) → 直接採用
31
+ step 在 errorValues → error(優先於 completed;交集一律 error)
32
+ step 在 completedValues → completed
33
+ step === value → current(linear / non-linear 都成立)
34
+ linear && step 在 reachable(completed ∪ 首個未完成)→ reachable
35
+ 其他 → upcoming
36
+ ```
37
+
38
+ **關鍵**:`value` 命中的 step 在兩種模式下 content state 都是 `current`,但 **filled 藍的「正在做」視覺只屬於 linear**。非 linear 的 current 渲染中性 `bg-secondary` + `foreground` 數字(見「Non-linear 被選中 ≠ filled 藍」),focus 由 outline 外環表達,**不會**出現 filled 藍。
39
+
40
+ ### 為什麼非 linear 的 current 不渲染 filled 藍
41
+
42
+ 非 linear 模式讓使用者跳著點 step(例如設定頁、教學目錄),value 的語意是「使用者在看哪一步」,**不是**「使用者在做哪一步」。如果非 linear 也渲染 filled 藍,會造成:
43
+
44
+ - 使用者點 upcoming step 想預覽 → step 立刻變 filled 藍,像是「標記為正在做」
45
+ - 跟 mental model「我只是在看,這步還沒做」衝突
46
+ - completedValues 沒有變化,前一個 filled 藍 step 突然不見
47
+
48
+ 正確做法:focus 視覺跟「進度視覺」完全解耦——focus 透過 outline 外環表達,filled 藍由 linear / completedValues 決定。filled「正在做」視覺是 linear 的概念。
49
+
50
+ Per-item `state="error"` prop 存在但是 **escape hatch**,僅用在 inline JSX 想直接宣告錯誤的罕見場景;一般情況用 `errorValues` array 統一管理,不要混用。
51
+
52
+ ---
53
+
54
+ ## Focus marker — Outer ring(outline + offset,bounding box 永遠不變)
55
+
56
+ **`value` 指向的 step,透過「outline 外圈環」視覺表達 focus**。
57
+
58
+ ### Outer ring 的關鍵設計
59
+
60
+ - **Bounding box 固定**:focus 外環以 outline 表達,不改變 indicator 的 bounding box——focused / non-focused 佔用完全相同的寬高(md=24px,lg=32px,sm=24px 排版盒)
61
+ - **透明間隙 + 外環**:`outline` 2px、`outline-offset` 2px —— indicator 與環之間那 2px 是**透明**的,露出底下真正的背景,形成「indicator 外有一圈帶間隙的環」;數值見 steps.tsx `getOuterRingStyle`(`RING_GAP_PX` / `RING_WIDTH_PX`),與全 DS 焦點框(`styles/base.css` `:focus-visible` 的 `outline: 2px solid var(--ring); outline-offset: 2px`)同一組粗細與間隙。outline 不改變 bounding box,因此不會推動連接線或文字。
62
+ - **Ring 色由 state 決定**:`error` → `--error-hover`;non-linear `current` → `--border-hover`;其餘(含 linear current / completed / upcoming / reachable)→ `--info-hover`
63
+
64
+ ### State × Focus 視覺矩陣(md/lg)
65
+
66
+ filled 底色與內容色**完全由 content state 決定,不因 focused 改變**;focused 只額外疊一圈 outline 外環。
67
+
68
+ | State | 底色 + 內容(focused / non-focused 相同) | Focused 額外疊加 |
69
+ |---|---|---|
70
+ | upcoming(linear)| `bg-muted` + `fg-disabled` 數字 | `--info-hover` 外環 |
71
+ | upcoming(non-linear)| `bg-secondary` + `foreground` 數字 | `--info-hover` 外環 |
72
+ | current(linear)| `bg-info` + white 數字 | `--info-hover` 外環 |
73
+ | current(non-linear)| `bg-secondary` + `foreground` 數字 | `--border-hover` 外環 |
74
+ | completed | `bg-info` + white ✓ | `--info-hover` 外環 |
75
+ | error | `bg-error` + white ✕ | `--error-hover` 外環 |
76
+
77
+ > **linear vs non-linear upcoming 底色刻意不同**:linear upcoming 用 `bg-muted` + `fg-disabled`(灰、弱字 = 「還到不了/鎖住」);non-linear upcoming 用 `bg-secondary` + `foreground`(中性、可讀 = 「可導覽但非當前」)。因為 non-linear 模式所有 step 都可點(reachable),upcoming 不該呈現 linear 那種「鎖住」的 muted 感。
78
+ >
79
+ > **為何 upcoming 用 `--muted`(locked surface)而非 `--bg-disabled`(互動元件 disabled)**:indicator 是 `aria-hidden` 狀態圖示(非互動 control),填色是「狀態色盤」不是「互動元件背景」;linear upcoming 恰是不可點(`isClickable`=false、無 `role=button`)的 locked 狀態。世界級 source-verified(2026-06-01 M26 benchmark):Atlassian Progress Tracker `unvisited`(`--ds-background-neutral-bold`)≠ `disabled`(`--ds-background-disabled`)為兩個獨立 status;Carbon `incomplete`(`$border-subtle`)≠ `disabled`(`$icon-disabled`);Ant Steps `wait` 用 `colorFillContent`/`colorTextLabel` 刻意避開 `colorTextDisabled`。4/5 家以 neutral/locked 語義處理 upcoming。元件真正的 disabled(`disabled` prop)走 `opacity-disabled` 疊加(保留狀態色不換 token)。
80
+
81
+ **注意 linear mode 的 current 永遠 focused**,所以 linear mode 下 current step 永遠帶外環(底色仍是 filled 藍,只是多疊一圈 ring)。
82
+
83
+ ### Sm 尺寸的 focus 處理
84
+
85
+ sm 的 8px dot 用同一套 `getOuterRingStyle` outline 外環在 dot 外圍繞圈——**但仍在 24px 的 indicator 排版盒內**,所以 bounding 不變。(那個盒是欄寬,不是命中區;見 `steps.spec.md`「指示點不是命中目標」。)
86
+
87
+ ### 為什麼 bounding 不變這麼重要
88
+
89
+ 連結線幾何依賴 indicator 的邊緣位置。如果 focus 改變 bounding box,連結線的起點/終點會跟著變,造成「focused step 的連結線比別的短一點點」的視覺不齊感。**outline 外環不佔 layout**——focus 狀態變化時外部幾何完全不變——連結線可以用統一公式,自然一致。
90
+
91
+ ### 為什麼外環與圓之間要有一圈間隙
92
+
93
+ 直接在 filled circle 外貼一圈同色 ring 會讀成「雙圈」很醜;環與 indicator 之間隔一圈 2px 的間隙,視覺乾淨且各 state 都清楚。
94
+
95
+ **間隙必須是透明的,不可以用某個底色「畫」出來**(2026-09-26 修,待辦總帳 N48 / L14)。2026-09-25 以前的寫法是兩層 box-shadow:內層用 `var(--surface)` 實心畫一圈假裝間隙,外層再疊環色。`--surface` 在淺色是不透明白,看起來沒事;在深色是白 8% 半透明,底下那層環色透上來 —— 實測(storybook 非線性「總覽」)淺色 圓 #0065EA / 間隙 #FFFFFF / 外環 #2F85FE,深色 圓 #1982FF / 間隙 **#58A5FF**(應為頁面底 #0A0A0A)/ 外環 #4A9DFF,深色整顆看起來是一個大藍圓,兩主題長得不一樣(user 09-25 原話:「另外我發現圖一的總覽的藍色外圈為何在深色模式看起來跟在亮色模式看起來不一致的設計語言?」)。而且就算換成不透明色,Steps 放在卡片、對話框、側欄裡時,那個顏色也不會剛好等於底下的背景。
96
+
97
+ 現行寫法是 `outline` + `outline-offset`:offset 那一圈本來就不畫任何東西,露出的永遠是真正的背景,兩主題、任何容器都同一個長相 ——與全 DS 焦點框(`../../ds-canonical/references/focus-canonical.md`「框怎麼畫」;`styles/base.css` `:focus-visible`)同一種畫法。
98
+
99
+ ### Non-linear 被選中 ≠ filled 藍(關鍵規則)
100
+
101
+ 非 linear 模式使用者點 upcoming step 瀏覽時,step 的 content state 變為 `current`(`computeState` 對 value 命中者一律回 current),但渲染**刻意中性**。視覺上會是(md/lg):
102
+ - 底色:`bg-secondary`(**刻意不同於 linear upcoming 的 `bg-muted`**——non-linear 所有 step 都可點,不該像 linear upcoming 那樣呈現「鎖住/還到不了」的 muted 灰;secondary 傳達「可導覽但非當前」)
103
+ - 數字:`foreground`(可讀,非 disabled 弱字——呼應 step 可達)
104
+ - 外環:`--border-hover` outline 外環(focus marker,表達「你在看這一步」;`resolveRingColor` 對 non-linear current)
105
+
106
+ **不會**出現 linear current 的 filled 藍——這對齊使用者 mental model「我只是在看,這步還沒做」。non-linear current 與 upcoming 同為 `bg-secondary` 底,被選中(focused)的 step 以 `--border-hover` 外環標示。sm 尺寸的 dot 在 non-linear current 仍用 `fg-disabled` 灰點(8px dot 最小化呈現)。
107
+
108
+ **Ring 不是 selection marker**。Steps 不是 SelectMenu / DropdownMenu 這類 selection control;ring 是 focus marker 單一語意。`patterns/element-anatomy/item-anatomy.spec.md`「選擇 / 狀態視覺規則」規則 B 指出的 `bg-neutral-selected`、radio 圓圈等 selection 視覺**都不適用 Steps**——Steps 用 outline 外環表達「you are here」,不是「你選中了這個」。
109
+
110
+ ---
111
+
112
+ ## Label 色彩(error state 例外)
113
+
114
+ Label 色彩優先順序:
115
+
116
+ ```
117
+ disabled > error > focused > default
118
+ ```
119
+
120
+ - `disabled` → `text-fg-disabled`(最優先,覆蓋所有其他狀態)
121
+ - `error` → **`text-error-text`**(error state 時 label 變紅,跟 indicator 的紅 ✕ 協調表達「這步出錯」)
122
+ - `focused`(非 disabled 非 error)→ `text-foreground`(使用者當前在看這步,加強)
123
+ - `default` → `text-fg-secondary`(一般狀態)
124
+
125
+ ### 為什麼 error label 要跟 indicator 同色
126
+
127
+ Steps 的 step 本身是「狀態載體」,跟 Field 的「label 只是欄位名,error 靠 help text 表達」不同。Steps 的 label 在視覺上屬於 indicator 的延伸資訊,兩者應該一起講故事:紅 ✕ indicator + 紅 label 形成一致的 error visual language,讓使用者一眼看出這步出了什麼錯(description 不變色,見下段)。
128
+
129
+ 這跟 `components/Field/field.spec.md`「樣式規範」的 FieldLabel foreground 原則不衝突——那是 Field 家族的規則(edit / readonly / disabled 三態的欄位容器)。Steps 是**進度指示器**不是**輸入容器**,label 色彩跟著 step state 走是正確做法。
130
+
131
+ ### Description 沒有 error 變色
132
+
133
+ Description 在 error state 下維持 `text-fg-secondary`(跟其他 state 一樣)。理由:
134
+ 1. Error 的「為什麼出錯」訊息該放在 `<StepContent>` 內(可以用 `text-error-text` 寫錯誤詳情),description 只是輔助說明
135
+ 2. 太多紅字會造成視覺壓迫,三層紅(indicator + label + description + content)過多
136
+ 3. 保留 description 為 secondary 給 consumer 一個「寫冷靜說明」的空間
137
+
138
+ ---
139
+
140
+ ## Connector 路徑色
141
+
142
+ 連接 `stepA → stepB` 的 connector:**當且僅當 stepA 是 completed 時,該 connector 為藍色**(`bg-info`),其他一律灰(`bg-border`)。connector 是一條 `w-px`(vertical)/ `h-px`(horizontal)的有底色 div line,故用 `bg-*` 而非 `border-*`。
143
+
144
+ ### 為什麼藍色只跟 completedValues 走,不跟 value 走
145
+
146
+ 藍色代表「實際走過的進度路徑」,必須跟 `completedValues` 一對一對應,才能跟 step 本身的底色邏輯保持一致。非線性模式下:
147
+
148
+ - 使用者把 `value` 跳到中間未完成的 step 5
149
+ - step 1-4 仍為 upcoming(灰底)
150
+ - 若藍色延伸到 step 5 前面,會產生「藍線連灰 step」的矛盾視覺
151
+ - 正確做法:藍色 connector 跟 step 的 bg 同步,都只在 completed 區段出現
152
+
153
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
154
+
155
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
156
+
157
+ - `steps.spec.md`
@@ -405,6 +405,7 @@ export const StateBehavior: Story = {
405
405
  <li>`error` 優先於 `completed`——同一 step 若同時在 completedValues + errorValues,一律渲染 error(紅底 X)。</li>
406
406
  <li>Focus ring 顏色自動切換:current 走 `--info-hover`(linear=false 時走 `--border-hover`)、error 走 `--error-hover`。</li>
407
407
  <li>upcoming step 不可點(linear)或 reachable 判定為 false 時 cursor:not-allowed,鍵盤 Tab 跳過。</li>
408
+ <li>預設展開模式(follow-active)下,current 那一步點了不會發生任何事 → 不是按鈕、鍵盤 Tab 跳過、游標是一般箭頭(它不是被禁止,只是「你就在這裡」);multiple 模式下點它會收合 / 展開內容,照舊可點(steps.spec.md「目前那一步可不可以點」)。</li>
408
409
  <li>sm size(8px dot)無 indicator icon——太小畫不出 check / X;大 tier(md/lg)才有 icon 反饋。</li>
409
410
  </ul>
410
411
  </div>
@@ -5,7 +5,7 @@ variants: {}
5
5
  sizes:
6
6
  sm:
7
7
  px: 8
8
- when: "Sidebar / 緊湊 onboarding;indicator 8px dot(hit area 24px),無內部 icon。對齊 INDICATOR_SIZE.sm + INDICATOR_ICON_SIZE.sm=0(steps.tsx:18-28)"
8
+ when: "Sidebar / 緊湊 onboarding;indicator 8px dot(外面 24px 是排版盒,不是命中區),無內部 icon。對齊 INDICATOR_SIZE.sm + INDICATOR_ICON_SIZE.sm=0(steps.tsx:20-30)"
9
9
  world-class: ["Ant Design Steps small", "MUI Stepper compact"]
10
10
  md:
11
11
  px: 24
@@ -80,7 +80,7 @@ Steps 是 `patterns/element-anatomy/item-anatomy.spec.md` 的 row primitive **co
80
80
  - **預設文字色**:`text-fg-secondary`;`value` 指向的 step(focused)為 `text-foreground`
81
81
  - **Icon tier**:`INDICATOR_ICON_SIZE = { sm: 0, md: 16, lg: 20 }`(sm 為純圓點無內部 icon,見 size table)
82
82
  - **Description 永遠可選**,任何 size 都不強制
83
- - **Hit area 地板**:可點擊的 indicator 至少 `field-height-xs`(24px),不足者用透明 padding 撐開
83
+ - **Indicator 欄寬**:sm 的 8px 圓點放在 24px 排版盒裡(與 md 的 24px 圓同寬;lg 圓本身 32px,`steps.tsx` `INDICATOR_BOX_WIDTH`);這個盒不是命中區 —— 可點的是整列 header(見本檔「指示點不是命中目標」)
84
84
 
85
85
  ---
86
86
 
@@ -137,7 +137,7 @@ indicator 圓形 flex items-center 居中
137
137
 
138
138
  | Size | Indicator 直徑 | 內部 icon | 內部數字字體 | Label 字體 | Description 字體 |
139
139
  |---|---|---|---|---|---|
140
- | `sm` | 8px dot(hit area 24px)| 純圓點,不放數字/icon | — | `text-body` (14px) | `text-caption` (12px) |
140
+ | `sm` | 8px dot(排版盒 24px)| 純圓點,不放數字/icon | — | `text-body` (14px) | `text-caption` (12px) |
141
141
  | `md` | 24px circle | 16px | `text-body` (14px) | `text-body` (14px) | `text-caption` (12px) |
142
142
  | `lg` | 32px circle | 20px | `text-body-lg` (16px) | `text-body-lg` (16px) | `text-body` (14px) |
143
143
 
@@ -150,7 +150,7 @@ indicator 圓形 flex items-center 居中
150
150
  **`sm`(小點)**
151
151
  - ✅ 用在 sidebar 內 nested 流程、緊湊空間、次要進度指示
152
152
  - ❌ 步驟需要 icon 或要使用者明確數到「第幾步」時不用(sm 沒有數字/icon,辨識度不足)
153
- - sm 的 indicator 視覺只有 8px,但 hit area 撐到 24px(`field-height-xs` 地板),可點擊時不違反互動元件最小尺寸規則
153
+ - sm 的圓點視覺是 8px,外面那個 24×24 是**排版盒**(sm 的 indicator 欄因此與 md 同為 24px;lg 為 32px),`steps.tsx:43` 常數名即 `INDICATOR_BOX_WIDTH`(`SM_INDICATOR_BOX` 在 `:41`)。它掛在 `aria-hidden` 的裝飾 span 上,**不是任何東西的命中區** —— 可點的是整列 header,所以這裡沒有「視覺小、命中大」這回事,也不需要拿最小尺寸規則來背書(見本檔「指示點不是命中目標」)
154
154
 
155
155
  **`md`(預設)**
156
156
  - ✅ 絕大多數場景:checkout、註冊、設定精靈
@@ -166,147 +166,36 @@ indicator 圓形 flex items-center 居中
166
166
 
167
167
  ---
168
168
 
169
- ## State(Content state,跟 Focus 正交)
169
+ ## State(Content state,跟 Focus 正交)→ `steps-state-visuals.spec.md`(2026-09-27 抽出,獨立 SSOT)
170
170
 
171
- | State | 視覺 | 觸發 |
172
- |---|---|---|
173
- | `upcoming` | 灰底(inline `background: var(--muted)`)+ 灰字(`text-fg-disabled`)| 未走到 |
174
- | `current` | 藍底(`bg-info`)+ 白字數字 | step === `value` 且不在 completedValues / errorValues |
175
- | `completed` | 藍底(`bg-info`)+ 白色 ✓ | step 在 `completedValues` 內 |
176
- | `reachable` | 藍底(`bg-info`)+ 白字數字(僅 linear;sm 為空心環)| linear 下「下一個未完成」step(非 current / completed / error),可點 |
177
- | `error` | 紅底(`bg-error`)+ 白色 ✕ | step 在 `errorValues` 內(或單項 `state="error"` override)|
178
-
179
- ### Sm size 的 state 視覺
180
-
181
- sm 沒有 icon 空間,用色塊表達:
182
- - `upcoming` → 灰實心點(`bg-fg-disabled`)
183
- - `current`(linear)→ 藍色**空心**環(`border: 2px solid var(--info-hover)`);non-linear current 走灰實心點(`bg-fg-disabled`)。`reachable` 也是空心環
184
- - `completed` → 藍實心點(`bg-info`)
185
- - `error` → 紅實心點(`bg-error`)
186
-
187
- ### 自動推導(順序即優先級,對齊 `computeState`)
188
-
189
- **Consumer 不手寫每個 step 的 state**。State 由 Steps root 的 props 依下列順序推導(`steps.tsx` `computeState`):
190
-
191
- ```
192
- per-item state override(escape hatch) → 直接採用
193
- step 在 errorValues → error(優先於 completed;交集一律 error)
194
- step 在 completedValues → completed
195
- step === value → current(linear / non-linear 都成立)
196
- linear && step 在 reachable(completed ∪ 首個未完成)→ reachable
197
- 其他 → upcoming
198
- ```
199
-
200
- **關鍵**:`value` 命中的 step 在兩種模式下 content state 都是 `current`,但 **filled 藍的「正在做」視覺只屬於 linear**。非 linear 的 current 渲染中性 `bg-secondary` + `foreground` 數字(見「Non-linear 被選中 ≠ filled 藍」),focus 由 box-shadow 外環表達,**不會**出現 filled 藍。
201
-
202
- ### 為什麼非 linear 的 current 不渲染 filled 藍
203
-
204
- 非 linear 模式讓使用者跳著點 step(例如設定頁、教學目錄),value 的語意是「使用者在看哪一步」,**不是**「使用者在做哪一步」。如果非 linear 也渲染 filled 藍,會造成:
205
-
206
- - 使用者點 upcoming step 想預覽 → step 立刻變 filled 藍,像是「標記為正在做」
207
- - 跟 mental model「我只是在看,這步還沒做」衝突
208
- - completedValues 沒有變化,前一個 filled 藍 step 突然不見
209
-
210
- 正確做法:focus 視覺跟「進度視覺」完全解耦——focus 透過 box-shadow 外環表達,filled 藍由 linear / completedValues 決定。filled「正在做」視覺是 linear 的概念。
211
-
212
- Per-item `state="error"` prop 存在但是 **escape hatch**,僅用在 inline JSX 想直接宣告錯誤的罕見場景;一般情況用 `errorValues` array 統一管理,不要混用。
213
-
214
- ---
215
-
216
- ## Focus marker — Outer ring(box-shadow,bounding box 永遠不變)
217
-
218
- **`value` 指向的 step,透過「box-shadow 外圈環」視覺表達 focus**。
219
-
220
- ### Outer ring 的關鍵設計
221
-
222
- - **Bounding box 固定**:focus 外環以 box-shadow 表達,不改變 indicator 的 bounding box——focused / non-focused 佔用完全相同的寬高(md=24px,lg=32px,sm=24px hit area)
223
- - **Surface gap + ring 兩層外環**:內圈先用 surface 色拉開一段 gap,外圈再疊 ring 色,形成「indicator 外有一圈帶間隙的環」——精確 gap / ring 寬度與 box-shadow 值見 steps.tsx `getOuterRingShadow`。兩層 shadow 不改變 bounding box,因此不會推動連接線或文字。
224
- - **Ring 色由 state 決定**:`error` → `--error-hover`;non-linear `current` → `--border-hover`;其餘(含 linear current / completed / upcoming / reachable)→ `--info-hover`
225
-
226
- ### State × Focus 視覺矩陣(md/lg)
227
-
228
- filled 底色與內容色**完全由 content state 決定,不因 focused 改變**;focused 只額外疊一圈 box-shadow 外環。
229
-
230
- | State | 底色 + 內容(focused / non-focused 相同) | Focused 額外疊加 |
231
- |---|---|---|
232
- | upcoming(linear)| `bg-muted` + `fg-disabled` 數字 | `--info-hover` 外環 |
233
- | upcoming(non-linear)| `bg-secondary` + `foreground` 數字 | `--info-hover` 外環 |
234
- | current(linear)| `bg-info` + white 數字 | `--info-hover` 外環 |
235
- | current(non-linear)| `bg-secondary` + `foreground` 數字 | `--border-hover` 外環 |
236
- | completed | `bg-info` + white ✓ | `--info-hover` 外環 |
237
- | error | `bg-error` + white ✕ | `--error-hover` 外環 |
238
-
239
- > **linear vs non-linear upcoming 底色刻意不同**:linear upcoming 用 `bg-muted` + `fg-disabled`(灰、弱字 = 「還到不了/鎖住」);non-linear upcoming 用 `bg-secondary` + `foreground`(中性、可讀 = 「可導覽但非當前」)。因為 non-linear 模式所有 step 都可點(reachable),upcoming 不該呈現 linear 那種「鎖住」的 muted 感。
240
- >
241
- > **為何 upcoming 用 `--muted`(locked surface)而非 `--bg-disabled`(互動元件 disabled)**:indicator 是 `aria-hidden` 狀態圖示(非互動 control),填色是「狀態色盤」不是「互動元件背景」;linear upcoming 恰是不可點(`isClickable`=false、無 `role=button`)的 locked 狀態。世界級 source-verified(2026-06-01 M26 benchmark):Atlassian Progress Tracker `unvisited`(`--ds-background-neutral-bold`)≠ `disabled`(`--ds-background-disabled`)為兩個獨立 status;Carbon `incomplete`(`$border-subtle`)≠ `disabled`(`$icon-disabled`);Ant Steps `wait` 用 `colorFillContent`/`colorTextLabel` 刻意避開 `colorTextDisabled`。4/5 家以 neutral/locked 語義處理 upcoming。元件真正的 disabled(`disabled` prop)走 `opacity-disabled` 疊加(保留狀態色不換 token)。
242
-
243
- **注意 linear mode 的 current 永遠 focused**,所以 linear mode 下 current step 永遠帶外環(底色仍是 filled 藍,只是多疊一圈 ring)。
244
-
245
- ### Sm 尺寸的 focus 處理
246
-
247
- sm 的 8px dot 用同一套 `getOuterRingShadow` box-shadow halo 在 dot 外圍繞圈——**但仍在 24px hit area 內**,所以 bounding 不變。
248
-
249
- ### 為什麼 bounding 不變這麼重要
250
-
251
- 連結線幾何依賴 indicator 的邊緣位置。如果 focus 改變 bounding box,連結線的起點/終點會跟著變,造成「focused step 的連結線比別的短一點點」的視覺不齊感。**box-shadow 外環不佔 layout**——focus 狀態變化時外部幾何完全不變——連結線可以用統一公式,自然一致。
171
+ 狀態表(upcoming / current / completed / reachable / error)、sm 的 state 視覺、自動推導順序(`computeState`)、非 linear 的 current 為何不 filled 藍、焦點外環(outline + offset、State × Focus 視覺矩陣、間隙為何必須透明、Non-linear 被選中 ≠ filled 藍)、Label 色彩優先序、Connector 路徑色 —— 整段住在 `./steps-state-visuals.spec.md`;本檔只留這個指標。下一小節講的是命中區、不是狀態,留在本檔。
252
172
 
253
- ### 為什麼用 surface-gap 而非單純貼邊 ring
173
+ ### 指示點不是命中目標 —— 命中區 = 整列 header(2026-09-24 逐案裁定)
254
174
 
255
- 直接在 filled circle 外貼一圈同色 ring 會讀成「雙圈」很醜;先用 `var(--surface)` 拉一圈 2px gap 再疊 ring,讓環跟 indicator 之間有底色間隙,視覺乾淨且各 state 都清楚(對齊 shadcn `ring-offset` / Polaris focus indicator surface-gap canonical)。
175
+ **可點的是整列 header,不是那顆點。** 圓點掛在 `aria-hidden` 的裝飾 `<span>` 上(`steps.tsx:775-778`),
176
+ 真正帶 `role="button"` / `tabIndex` / `onClick` / `onKeyDown` 的是 `StepItemHeader`(`steps.tsx:526-534`)。
177
+ 指標落在圓點上時,收到事件的一樣是那一列 —— 圓點只是列裡的一個子元素。
256
178
 
257
- ### Non-linear 被選中 ≠ filled 藍(關鍵規則)
179
+ **所以這裡沒有任何外擴**,跨元件契約(`../../ds-canonical/references/hit-area-canonical.md`
180
+ 「懸停回饋的形狀 ≡ 命中區」)要禁的是「在元素之外長出一圈吃指標的東西」,本元件不存在這種東西:
181
+ 命中區就是 header 自己的盒,一個 `-inset` / `hitSlop` / 透明 border 都沒有。
182
+ header 沒有懸停底色,所以依同一份契約的退化條款,判準回到**可視形狀本身**(那一列的內容),兩者同一個盒。
258
183
 
259
- 非 linear 模式使用者點 upcoming step 瀏覽時,step 的 content state 變為 `current`(`computeState` 對 value 命中者一律回 current),但渲染**刻意中性**。視覺上會是(md/lg):
260
- - 底色:`bg-secondary`(**刻意不同於 linear upcoming 的 `bg-muted`**——non-linear 所有 step 都可點,不該像 linear upcoming 那樣呈現「鎖住/還到不了」的 muted 灰;secondary 傳達「可導覽但非當前」)
261
- - 數字:`foreground`(可讀,非 disabled 弱字——呼應 step 可達)
262
- - 外環:`--border-hover` box-shadow ring(focus marker,表達「你在看這一步」;`resolveRingColor` 對 non-linear current)
184
+ **sm 的 8px 圓點外面那個 24×24 的盒是排版欄寬,不是命中區。** 它讓 sm 的 indicator 欄與 md 同為 24px(lg 為 32px)、同一列表內各步的
185
+ label 起點對齊(`INDICATOR_BOX_WIDTH`,`steps.tsx:43-47`)。這個常數 2026-09-24 之前叫 `SM_HIT_AREA`,
186
+ 已正名為 `SM_INDICATOR_BOX` —— 舊名字會讓人以為「視覺 8 / 命中 24」是一條刻意的外擴,於是跑去
187
+ hit-area-canonical 找例外理由,但根本沒有外擴這回事。
263
188
 
264
- **不會**出現 linear current 的 filled 藍——這對齊使用者 mental model「我只是在看,這步還沒做」。non-linear current 與 upcoming 同為 `bg-secondary` 底,被選中(focused)的 step 以 `--border-hover` 外環標示。sm 尺寸的 dot 在 non-linear current 仍用 `fg-disabled` 灰點(8px dot 最小化呈現)。
189
+ **實測(2026-09-24,`elementFromPoint` 逐點掃描,storybook 設計規格--尺寸對照表)**:
265
190
 
266
- **Ring 不是 selection marker**。Steps 不是 SelectMenu / DropdownMenu 這類 selection control;ring 是 focus marker 單一語意。`patterns/element-anatomy/item-anatomy.spec.md`「選擇 / 狀態視覺規則」規則 B 指出的 `bg-neutral-selected`、radio 圓圈等 selection 視覺**都不適用 Steps**——Steps 用 box-shadow 外環表達「you are here」,不是「你選中了這個」。
267
-
268
- ---
269
-
270
- ## Label 色彩(error state 例外)
271
-
272
- Label 色彩優先順序:
273
-
274
- ```
275
- disabled > error > focused > default
276
- ```
277
-
278
- - `disabled` → `text-fg-disabled`(最優先,覆蓋所有其他狀態)
279
- - `error` → **`text-error-text`**(error state 時 label 變紅,跟 indicator 的紅 ✕ 協調表達「這步出錯」)
280
- - `focused`(非 disabled 非 error)→ `text-foreground`(使用者當前在看這步,加強)
281
- - `default` → `text-fg-secondary`(一般狀態)
282
-
283
- ### 為什麼 error label 要跟 indicator 同色
284
-
285
- Steps 的 step 本身是「狀態載體」,跟 Field 的「label 只是欄位名,error 靠 help text 表達」不同。Steps 的 label 在視覺上屬於 indicator 的延伸資訊,兩者應該一起講故事:紅 ✕ indicator + 紅 label 形成一致的 error visual language,讓使用者一眼看出這步出了什麼錯(description 不變色,見下段)。
286
-
287
- 這跟 `components/Field/field.spec.md`「樣式規範」的 FieldLabel foreground 原則不衝突——那是 Field 家族的規則(edit / readonly / disabled 三態的欄位容器)。Steps 是**進度指示器**不是**輸入容器**,label 色彩跟著 step state 走是正確做法。
288
-
289
- ### Description 沒有 error 變色
290
-
291
- Description 在 error state 下維持 `text-fg-secondary`(跟其他 state 一樣)。理由:
292
- 1. Error 的「為什麼出錯」訊息該放在 `<StepContent>` 內(可以用 `text-error-text` 寫錯誤詳情),description 只是輔助說明
293
- 2. 太多紅字會造成視覺壓迫,三層紅(indicator + label + description + content)過多
294
- 3. 保留 description 為 secondary 給 consumer 一個「寫冷靜說明」的空間
295
-
296
- ---
297
-
298
- ## Connector 路徑色
299
-
300
- 連接 `stepA → stepB` 的 connector:**當且僅當 stepA 是 completed 時,該 connector 為藍色**(`bg-info`),其他一律灰(`bg-border`)。connector 是一條 `w-px`(vertical)/ `h-px`(horizontal)的有底色 div line,故用 `bg-*` 而非 `border-*`。
301
-
302
- ### 為什麼藍色只跟 completedValues 走,不跟 value 走
303
-
304
- 藍色代表「實際走過的進度路徑」,必須跟 `completedValues` 一對一對應,才能跟 step 本身的底色邏輯保持一致。非線性模式下:
191
+ | 量的東西 | 結果 |
192
+ |---|---|
193
+ | 24×24 裝飾盒的 `aria-hidden` | `true`;內含 8×8 的點 |
194
+ | 指標打在點的正中心,收到的是誰 | **`role="button"` 的整列 header**(不是那顆點) |
195
+ | 整列 header 的盒 | 1214×18.2 @ (33,121.1) —— 命中就是這個盒 |
196
+ | header 的懸停底色 | `rgba(0,0,0,0)`(hover 前後都是)→ 無懸停回饋,判準回到可視形狀 |
197
+ | 對照組 | 沒有 `role="button"` 祖先的那些 step(不可點的列),同一個點打下去收到的是裝飾 `span` 自己、沒有任何處理器 —— 證明這支探針分得出「可點」與「不可點」 |
305
198
 
306
- - 使用者把 `value` 跳到中間未完成的 step 5
307
- - step 1-4 仍為 upcoming(灰底)
308
- - 若藍色延伸到 step 5 前面,會產生「藍線連灰 step」的矛盾視覺
309
- - 正確做法:藍色 connector 跟 step 的 bg 同步,都只在 completed 區段出現
310
199
 
311
200
  ---
312
201
 
@@ -317,6 +206,10 @@ Description 在 error state 下維持 `text-fg-secondary`(跟其他 state 一樣
317
206
  | `linear=true`(預設) | 可點:`completed` / `current` / `error` / `reachable`(下一個未完成)。**不可點**:`upcoming`(尚未解鎖)。 |
318
207
  | `linear=false` | 所有非 `disabled` 的 step 都可點。適合 setting wizard、教學目錄等「步驟之間無強依賴」的場景。 |
319
208
 
209
+ 兩種模式共同的例外:**預設展開模式(`follow-active`)下 `value` 指到的那一步不可點** —— 見下方「Expansion」的「目前那一步可不可以點」。
210
+
211
+ 不可點分兩種,游標不同(`steps.tsx` `isLocked` / `isClickable`):**鎖住**(`disabled`、linear 的 `upcoming`)= 禁止游標 `cursor-not-allowed`;**你就在這裡**(上述目前那一步)= 一般箭頭,它沒有被禁止,只是點了不會發生任何事。兩種都沒有 `role="button"`、不進 Tab 序;差別在焦點框:鎖住的步不可聚焦(`outline-none`),目前那一步保留 `tabIndex=-1`、焦點框照畫(理由見「Expansion」的「目前那一步可不可以點」)。
212
+
320
213
  ### 點擊 completed step 的行為
321
214
 
322
215
  `linear=true` 下使用者點 completed step:
@@ -336,6 +229,18 @@ Description 在 error state 下維持 `text-fg-secondary`(跟其他 state 一樣
336
229
  | `follow-active`(預設) | 只有 `value` 指向的 step 渲染 `<StepContent>`。value 切換時 content 跟著切。其他 step 即使寫了 `<StepContent>` 也不顯示。 |
337
230
  | `multiple` | 每個 step 獨立管理展開狀態,**可同時展開多個**。點 step header 永遠先更新 `value`(focus),並額外切換該 step 的展開。`defaultExpanded` 接 `"all" \| "none" \| string[]`,預設 `"none"`。 |
338
231
 
232
+ ### 目前那一步可不可以點(2026-09-26,待辦總帳 N44)
233
+
234
+ | 模式 | 點 `value` 指到的那一步會發生什麼 | 所以 |
235
+ |---|---|---|
236
+ | `follow-active`(預設) | 什麼都不會發生:`onValueChange` 收到同一個值,展開又綁在 `value` 上(實測點了 DOM 0 變化) | **不可點**:不是按鈕、不進 Tab 序、一般箭頭游標(不是手形、也不是禁止符號) |
237
+ | `multiple` | 收合 / 展開它自己的內容(`aria-expanded` true ↔ false) | 可點,照舊是按鈕 |
238
+
239
+ 2026-09-25 以前兩種模式都把它做成按鈕,預設模式因此出現「手形游標 + 可以 Tab 停上去,按下去卻沒有任何反應」。判準就是本元件自己的鍵盤規則「Tab — focus 每個 **clickable** step」:點了不會發生事的東西不是 clickable。
240
+
241
+ **它仍保留 `tabIndex=-1`**(不進 Tab 序,但能持有焦點):鍵盤使用者在某一步按 Enter / Space 跳過去時,焦點所在的那一列正好變成「目前那一步」;若它同時變成完全不可聚焦,瀏覽器依 HTML 的 focus fixup 會把焦點丟回頁首,下一個 Tab 得從頭來。`-1` 讓焦點留在原地、Tab / Shift+Tab 照常往前後走,焦點框照全域 `:focus-visible` 畫(用滑鼠點過去不會出現框)。
242
+ 世界級對照:[Atlassian progress-tracker `stage.js#L69-L73`](https://cdn.jsdelivr.net/npm/@atlaskit/progress-tracker@11.4.4/dist/es2019/internal/stage.js)(只有 `status === 'visited'` 的步才渲染成連結,目前那一步不是連結 → 不是停靠點);[Carbon `ProgressIndicator.tsx#L315-L323`](https://github.com/carbon-design-system/carbon/blob/v11.117.0/packages/react/src/components/ProgressIndicator/ProgressIndicator.tsx#L315-L323)(目前那一步 `onClick={!current ? onClick : undefined}`、加 `--unclickable`,樣式 [`_progress-indicator.scss#L228-L231`](https://github.com/carbon-design-system/carbon/blob/v11.117.0/packages/styles/scss/components/progress-indicator/_progress-indicator.scss#L228-L231) `cursor: default`,但仍 `tabIndex={0}`);[Ant Design `steps/style/index.ts#L183-L185`](https://github.com/ant-design/ant-design/blob/6.6.5/components/steps/style/index.ts#L183-L185)(手形游標只給 `[role='button']:not(-active)`,目前那一步是一般箭頭)。三家一致的是「目前那一步不給手形游標」;Tab 停不停,Atlassian 不停、Carbon / Ant 仍停 —— 本 DS 取不停,理由是上面那條本元件自己的鍵盤規則(停上去按 Enter / Space 沒有任何事可做)。
243
+
339
244
  ### 為什麼 `all` 隸屬於 `multiple`
340
245
 
341
246
  `all`(全部展開)跟 `none`(全部收合)**本質上都是「使用者可以同時展開多個」的行為**——差別只在初始狀態。把它們並列在同一個 mode 下、用 `defaultExpanded` 決定初始狀態,是比「三個平行 enum 值」更乾淨的結構。`follow-active` 則是完全不同的 mental model(展開狀態綁定 `value`,使用者不能獨立切換),所以拆成獨立 mode。
@@ -355,6 +260,17 @@ Description 在 error state 下維持 `text-fg-secondary`(跟其他 state 一樣
355
260
  | `vertical`(預設) | 上 → 下 | 垂直線,穿過 description / content | indicator 右側 | 支援 |
356
261
  | `horizontal` | 左 → 右 | 水平線 | indicator 右側(同行) | 不支援(忽略) |
357
262
 
263
+ **可點範圍 = 整列 header,兩種排列都包含描述**(2026-09-26,待辦總帳 N51):垂直版的描述本來就在 header 裡;水平版的描述在連接線下方另起一列,2026-09-25 以前那一列放在 header 外面 —— 滑到描述上游標不是手形、點了也不會跳到那一步(實測 4/4)。現在水平版 header 是直向兩列(第一列 indicator + label + connector,第二列描述),描述一樣點得到;描述那一列的行高照舊(`leading-normal`,= 搬家前從 li 根繼承的值),畫面不變。
264
+
265
+ ### Connector 幾何(2026-09-29,待辦總帳 N52;user 09-26 裁「兩者都是」= 規格沒定義 + bug)
266
+
267
+ - **線寬 1px,x = 指示欄中心**(垂直)/ y = label 第一行中線(水平)。
268
+ - **圓到線的縫兩端各 8px**,兩端對稱。一手區間:MUI `StepLabel` vertical `padding: '8px 0'`(每側 8;[StepLabel.js#L65-L68](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/StepLabel/StepLabel.js#L65-L68))、Ant `marginXXS × 1.5` = 6([steps/style/vertical.ts#L25-L29](https://github.com/ant-design/ant-design/blob/5.27.4/components/steps/style/vertical.ts#L25-L29))、Chakra `--steps-gutter = spacing.3` = 12([recipes/steps.ts#L15](https://github.com/chakra-ui/chakra-ui/blob/main/packages/react/src/theme/recipes/steps.ts#L15));DS 取 8 = 區間正中,與列內 prefix / suffix 的 `gap-2` 同一個數。
269
+ - **線最短 24px,長度不隨說明文字有無變動**。唯一一手明文地板:MUI `StepConnector` vertical `minHeight: 24`([StepConnector.js#L50](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/StepConnector/StepConnector.js#L50));Ant / Chakra 沒有地板(線是列高的餘數,無說明時 Ant 32px 圓只剩 ≈ 4px),Carbon 是另一種模型(1px 線貼左緣全高連續)。24 也等於本元件的步間距 `pb-6`,可讀成「線至少一個步間距」。
270
+ - **落地**:非末項垂直 `li` 的最小高度 = 圓 + 兩端縫 + 線地板(sm 48 / md 64 / lg 72;`steps.tsx` `verticalItemMinHeight`);有說明時列自然更高、不受影響。水平線的最短寬吃同一個 24(先前 `min-w-4` 16px 沒入規格;同元件同概念只准一個地板)。
271
+ - **為什麼是根層修**:線長原本 = li 高 − 2r − 16(餘數),沒有說明時 md 只剩 2.2px、lg 是 0 —— 違反上方「對齊不變量」:指示欄節奏是元件本體,不得隨說明有無變動。
272
+ - **閘**:`scripts/steps-connector-geometry-invariant.mjs`(量三尺寸無說明的垂直線高 ≥ 24、兩端縫 = 8;selftest 用修法前的實測 2.2 / 0 當對照組必紅)。
273
+
358
274
  **何時用 horizontal**:步驟 ≤ 5、重視「進度條」感、水平空間充足、不需要 per-step content 區。
359
275
  **何時用 vertical**:步驟 > 5、需要 description 或 content、行動裝置、主流程精靈。
360
276
 
@@ -436,7 +352,7 @@ Item-level **內容狀態色彩**(completed / current / upcoming / error indicat
436
352
  - **Loading(async step state fetch)**:Steps primitive 為 sync render,async data fetch 應由 consumer 在外層 Skeleton 取代整個 Steps;Steps 內部不獨立 own loading prop,**也無 per-step loading state**(content state 集合不含 loading)— 單一步驟 async 進行中即 current,進度細節由 consumer 在 `StepContent` 內呈現。
437
353
  - **Empty(0 steps)**:無任何 `<StepItem>` children 時無進度可呈現;consumer 應條件性不渲 Steps 或渲 `<Empty>` 替代,不渲空 Steps container。
438
354
  - **Single step / `value` 指向第一步**:合法初始狀態,第一個 step 渲染 current,後續依推導為 reachable / upcoming。
439
- - **Error state(`errorValues`)**:由元件層級 own — 對應 step indicator 切 error token、label 切 `text-error-text`(見「Label 色彩」);connector **不**變色,仍按「Connector 路徑色」規則(前一步 completed 才藍,否則灰);後續 step 仍 upcoming。
355
+ - **Error state(`errorValues`)**:由元件層級 own — 對應 step indicator 切 error token、label 切 `text-error-text`(見 `steps-state-visuals.spec.md`「Label 色彩」);connector **不**變色,仍按 `steps-state-visuals.spec.md`「Connector 路徑色」規則(前一步 completed 才藍,否則灰);後續 step 仍 upcoming。
440
356
  - **Dark mode**:走 semantic token + Primary token 自動 adapt。
441
357
  - **Density**:Step indicator 32px 對齊 `AVATAR_SIZE.block.sm/md`,connector 細線跨 density 不變(進度視覺對 density 不敏感)。
442
358
 
@@ -444,7 +360,7 @@ Item-level **內容狀態色彩**(completed / current / upcoming / error indicat
444
360
 
445
361
  ## 相關
446
362
 
447
- - `../../patterns/element-anatomy/item-anatomy.spec.md` — Row primitive 繼承規則(字體 / icon tier / hit area 地板)
363
+ - `../../patterns/element-anatomy/item-anatomy.spec.md` — Row primitive 繼承規則(字體 / icon tier / 列高)
448
364
  - `../Tabs/tabs.spec.md` — 平行視圖切換(非進度場景)
449
365
  - `../Breadcrumb/breadcrumb.spec.md` — 位置路徑(非進度場景)
450
366
  - `../RadioGroup/radio-group.spec.md` — 選值(非進度場景)
@@ -459,12 +375,12 @@ Item-level **內容狀態色彩**(completed / current / upcoming / error indicat
459
375
 
460
376
  - **root `aria-label`**:consumer 透過 `<Steps aria-label="註冊流程進度">` 提供(透傳到 `<ol>`),命名此流程。對齊 Angular Material「stepper 必須有 label」。
461
377
  - **sr-only 狀態文字**:每個 step header 含 visually-hidden `<span>`「第 N 步,共 M 步,{已完成 / 進行中 / 錯誤 / 未開始}」——indicator 是 `aria-hidden` 純視覺,故 sr-only 是螢幕報讀器**唯一**狀態來源(對齊 Carbon `--assistive-text` 慣例)。
462
- - **展開狀態 ARIA**(2026-07-05 D4 加):垂直模式 step 含 `<StepContent>` 時,clickable header(`role="button"`)輸出 `aria-expanded`(反映 content 展開狀態;`multiple` toggle 與 `follow-active` 皆同步),並在 content 實際渲染(展開)時以 `aria-controls` 指向 content 區(收合時 content 不在 DOM,不輸出避免 dangling reference)——對齊 WAI-ARIA disclosure pattern trigger 最低要求。chevron 維持 `aria-hidden` 純視覺。
463
- - **StepContent 內的 consumer-owned scroll region**:Steps 不替任意 children 猜測捲動語意。consumer 若在 StepContent 放 `overflow-x-auto` / `overflow-y-auto`,實際會 overflow 的 wrapper 必須是鍵盤可達的具名區域(`tabIndex={0}` + `role="region"` + `aria-label`)並使用 DS inset focus ring(`focus-visible:outline-2 outline-offset-[-2px] outline-ring`)。tab stop 必須落在真正控制 `scrollLeft` / `scrollTop` 的 wrapper,不可放在內層 `<pre>`。展示層 `MultipleExpansion` 以 play assertion 驗證該節點確實 overflow、可聚焦。
378
+ - **展開狀態 ARIA**(2026-07-05 D4 加):垂直模式 step 含 `<StepContent>` 時,clickable header(`role="button"`)輸出 `aria-expanded`(反映 content 展開狀態;`multiple` toggle 與 `follow-active` 皆同步;`follow-active` 下目前那一步不是按鈕、沒有 `aria-expanded`,它的內容恆展開 —— 見「Expansion」的「目前那一步可不可以點」),並在 content 實際渲染(展開)時以 `aria-controls` 指向 content 區(收合時 content 不在 DOM,不輸出避免 dangling reference)——對齊 WAI-ARIA disclosure pattern trigger 最低要求。chevron 維持 `aria-hidden` 純視覺。
379
+ - **StepContent 內的 consumer-owned scroll region**:Steps 不替任意 children 猜測捲動語意。consumer 若在 StepContent 放 `overflow-x-auto` / `overflow-y-auto`,實際會 overflow 的 wrapper 必須是鍵盤可達的具名區域(`tabIndex={0}` + `role="region"` + `aria-label`)並使用 DS 內描邊焦點框(`focus-visible:focus-ring-inset`)。tab stop 必須落在真正控制 `scrollLeft` / `scrollTop` 的 wrapper,不可放在內層 `<pre>`。展示層 `MultipleExpansion` 以 play assertion 驗證該節點確實 overflow、可聚焦。
464
380
 
465
381
  **Keyboard 行為**(Carbon 模型 — sequential Tab,非 tablist roving):
466
382
 
467
- - Tab — focus 每個 clickable step(各自 tab stop)
383
+ - Tab — focus 每個 clickable step(各自 tab stop);鎖住的步與預設展開模式下的目前那一步不是 clickable,不停(見「Expansion」的「目前那一步可不可以點」)
468
384
  - Enter / Space — navigate to step(`role=button` 元素必同時支援)
469
385
  - **不提供方向鍵 roving**:採 native button sequential Tab(對齊 Carbon ProgressIndicator);MUI / Angular Material 的「tablist + 方向鍵 roving」是另一派世界級做法,本 DS 不採(避免把 `role=button` 改寫成 `role=tab` 的語義改動)。
470
386
 
@@ -480,3 +396,4 @@ Item-level **內容狀態色彩**(completed / current / upcoming / error indicat
480
396
  - `item-anatomy.spec.md`
481
397
  - `pagination.spec.md`
482
398
  - `progress-bar.spec.md`
399
+ - `steps-state-visuals.spec.md`
@@ -268,7 +268,7 @@ export const MultipleExpansion: Story = {
268
268
  tabIndex={0}
269
269
  role="region"
270
270
  aria-label="Steps 元件匯入範例程式碼"
271
- className="max-w-full overflow-x-auto rounded-md bg-muted focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring"
271
+ className="max-w-full overflow-x-auto rounded-md bg-muted focus-visible:focus-ring-inset"
272
272
  >
273
273
  <pre className="text-caption p-3 whitespace-pre w-max">
274
274
  {"import { Steps } from '@/design-system/components/Steps/steps'"}