@qijenchen/design-system 0.1.0-beta.83 → 0.1.0-beta.84

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 (604) hide show
  1. package/CLAUDE.md +8 -8
  2. package/README.md +3 -2
  3. package/dist/components/Alert/alert.js.map +1 -1
  4. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
  5. package/dist/components/AppShell/app-shell.d.ts +1 -1
  6. package/dist/components/AppShell/app-shell.d.ts.map +1 -1
  7. package/dist/components/AppShell/app-shell.js +22 -2
  8. package/dist/components/AppShell/app-shell.js.map +1 -1
  9. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  10. package/dist/components/Avatar/avatar.js +4 -4
  11. package/dist/components/Avatar/avatar.js.map +1 -1
  12. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  13. package/dist/components/Breadcrumb/breadcrumb.js +1 -1
  14. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  15. package/dist/components/Button/button.d.ts +2 -2
  16. package/dist/components/Button/button.d.ts.map +1 -1
  17. package/dist/components/Button/button.js +12 -3
  18. package/dist/components/Button/button.js.map +1 -1
  19. package/dist/components/Calendar/calendar.d.ts +13 -5
  20. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  21. package/dist/components/Calendar/calendar.js +7 -1
  22. package/dist/components/Calendar/calendar.js.map +1 -1
  23. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  24. package/dist/components/Carousel/carousel.js +8 -3
  25. package/dist/components/Carousel/carousel.js.map +1 -1
  26. package/dist/components/Chart/chart.d.ts.map +1 -1
  27. package/dist/components/Chart/chart.js +1 -0
  28. package/dist/components/Chart/chart.js.map +1 -1
  29. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  30. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  31. package/dist/components/Checkbox/checkbox.js +8 -4
  32. package/dist/components/Checkbox/checkbox.js.map +1 -1
  33. package/dist/components/Chip/chip.d.ts +1 -1
  34. package/dist/components/Chip/chip.d.ts.map +1 -1
  35. package/dist/components/Chip/chip.js.map +1 -1
  36. package/dist/components/Coachmark/coachmark.d.ts +10 -3
  37. package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
  38. package/dist/components/Coachmark/coachmark.js.map +1 -1
  39. package/dist/components/Combobox/combobox.d.ts +5 -1
  40. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  41. package/dist/components/Combobox/combobox.js +30 -13
  42. package/dist/components/Combobox/combobox.js.map +1 -1
  43. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  44. package/dist/components/DataTable/cell-registry.js +53 -62
  45. package/dist/components/DataTable/cell-registry.js.map +1 -1
  46. package/dist/components/DataTable/column-types.d.ts +10 -4
  47. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  48. package/dist/components/DataTable/column-types.js.map +1 -1
  49. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +1 -1
  50. package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
  51. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
  52. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  53. package/dist/components/DataTable/data-table-filter-panel.js +607 -0
  54. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
  55. package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
  56. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  57. package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
  58. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  59. package/dist/components/DataTable/data-table-sort-manager.js +140 -0
  60. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
  61. package/dist/components/DataTable/data-table.d.ts +5 -6
  62. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  63. package/dist/components/DataTable/data-table.js +36 -15
  64. package/dist/components/DataTable/data-table.js.map +1 -1
  65. package/dist/components/DataTable/filter-operators.js +140 -0
  66. package/dist/components/DataTable/filter-operators.js.map +1 -0
  67. package/dist/components/DataTable/filter-tree.js +312 -0
  68. package/dist/components/DataTable/filter-tree.js.map +1 -0
  69. package/dist/components/DataTable/index.d.ts +3 -0
  70. package/dist/components/DataTable/index.d.ts.map +1 -1
  71. package/dist/components/DataTable/index.js +12 -1
  72. package/dist/components/DataTable/index.js.map +1 -1
  73. package/dist/components/DataTable/lib/column-meta.js +25 -0
  74. package/dist/components/DataTable/lib/column-meta.js.map +1 -0
  75. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  76. package/dist/components/DateGrid/date-grid.js +3 -1
  77. package/dist/components/DateGrid/date-grid.js.map +1 -1
  78. package/dist/components/DatePicker/date-picker.d.ts +7 -1
  79. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  80. package/dist/components/DatePicker/date-picker.js +105 -74
  81. package/dist/components/DatePicker/date-picker.js.map +1 -1
  82. package/dist/components/Dialog/dialog.d.ts +20 -3
  83. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  84. package/dist/components/Dialog/dialog.js +38 -20
  85. package/dist/components/Dialog/dialog.js.map +1 -1
  86. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  87. package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
  88. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  89. package/dist/components/Field/field-context.d.ts +45 -5
  90. package/dist/components/Field/field-context.d.ts.map +1 -1
  91. package/dist/components/Field/field-context.js +19 -0
  92. package/dist/components/Field/field-context.js.map +1 -1
  93. package/dist/components/Field/field-edit-keys.d.ts +21 -0
  94. package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
  95. package/dist/components/Field/field-edit-keys.js +19 -0
  96. package/dist/components/Field/field-edit-keys.js.map +1 -0
  97. package/dist/components/Field/field-types.d.ts +20 -1
  98. package/dist/components/Field/field-types.d.ts.map +1 -1
  99. package/dist/components/Field/field-types.js.map +1 -1
  100. package/dist/components/Field/field-wrapper.d.ts +3 -2
  101. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  102. package/dist/components/Field/field-wrapper.js +38 -39
  103. package/dist/components/Field/field-wrapper.js.map +1 -1
  104. package/dist/components/Field/field.d.ts +2 -1
  105. package/dist/components/Field/field.d.ts.map +1 -1
  106. package/dist/components/Field/field.js.map +1 -1
  107. package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
  108. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  109. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  110. package/dist/components/FileItem/file-item.js +1 -1
  111. package/dist/components/FileItem/file-item.js.map +1 -1
  112. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  113. package/dist/components/FileUpload/file-upload.js.map +1 -1
  114. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  115. package/dist/components/FileViewer/file-viewer.js +7 -2
  116. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  117. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
  118. package/dist/components/FileViewer/image-renderer.js +22 -1
  119. package/dist/components/FileViewer/image-renderer.js.map +1 -1
  120. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  121. package/dist/components/HoverCard/hover-card.js +5 -3
  122. package/dist/components/HoverCard/hover-card.js.map +1 -1
  123. package/dist/components/InlineEdit/index.d.ts +2 -0
  124. package/dist/components/InlineEdit/index.d.ts.map +1 -0
  125. package/dist/components/InlineEdit/index.js +5 -0
  126. package/dist/components/InlineEdit/index.js.map +1 -0
  127. package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
  128. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
  129. package/dist/components/InlineEdit/inline-edit.js +164 -0
  130. package/dist/components/InlineEdit/inline-edit.js.map +1 -0
  131. package/dist/components/Input/input.d.ts +6 -11
  132. package/dist/components/Input/input.d.ts.map +1 -1
  133. package/dist/components/Input/input.js +43 -13
  134. package/dist/components/Input/input.js.map +1 -1
  135. package/dist/components/LinkInput/link-input.d.ts +2 -2
  136. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  137. package/dist/components/LinkInput/link-input.js +6 -5
  138. package/dist/components/LinkInput/link-input.js.map +1 -1
  139. package/dist/components/Menu/menu-item.d.ts +14 -2
  140. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  141. package/dist/components/Menu/menu-item.js +25 -3
  142. package/dist/components/Menu/menu-item.js.map +1 -1
  143. package/dist/components/NumberInput/number-input.d.ts +3 -3
  144. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  145. package/dist/components/NumberInput/number-input.js +6 -5
  146. package/dist/components/NumberInput/number-input.js.map +1 -1
  147. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  148. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
  149. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  150. package/dist/components/Pagination/pagination.js +1 -1
  151. package/dist/components/Pagination/pagination.js.map +1 -1
  152. package/dist/components/PeoplePicker/index.js +7 -1
  153. package/dist/components/PeoplePicker/index.js.map +1 -1
  154. package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
  155. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  156. package/dist/components/PeoplePicker/people-picker.js +23 -10
  157. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  158. package/dist/components/PeoplePicker/person-display.d.ts +6 -3
  159. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  160. package/dist/components/PeoplePicker/person-display.js +19 -14
  161. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  162. package/dist/components/Popover/popover.d.ts.map +1 -1
  163. package/dist/components/Popover/popover.js +3 -1
  164. package/dist/components/Popover/popover.js.map +1 -1
  165. package/dist/components/ProfileCard/profile-card.d.ts +2 -2
  166. package/dist/components/ProfileCard/profile-card.js +3 -3
  167. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  168. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  169. package/dist/components/RadioGroup/radio-group.js +15 -9
  170. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  171. package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
  172. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  173. package/dist/components/ScrollArea/scroll-area.js +6 -3
  174. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  175. package/dist/components/Select/select.d.ts +46 -5
  176. package/dist/components/Select/select.d.ts.map +1 -1
  177. package/dist/components/Select/select.js +109 -28
  178. package/dist/components/Select/select.js.map +1 -1
  179. package/dist/components/SelectMenu/select-menu.d.ts +3 -1
  180. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  181. package/dist/components/SelectMenu/select-menu.js +8 -1
  182. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  183. package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
  184. package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
  185. package/dist/components/SelectionControl/boolean-value.js +23 -0
  186. package/dist/components/SelectionControl/boolean-value.js.map +1 -0
  187. package/dist/components/SelectionControl/index.d.ts +1 -0
  188. package/dist/components/SelectionControl/index.d.ts.map +1 -1
  189. package/dist/components/SelectionControl/index.js +2 -0
  190. package/dist/components/SelectionControl/index.js.map +1 -1
  191. package/dist/components/Sheet/index.js +2 -1
  192. package/dist/components/Sheet/sheet.d.ts +7 -1
  193. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  194. package/dist/components/Sheet/sheet.js +5 -2
  195. package/dist/components/Sheet/sheet.js.map +1 -1
  196. package/dist/components/Sidebar/sidebar.d.ts +9 -4
  197. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  198. package/dist/components/Sidebar/sidebar.js +8 -10
  199. package/dist/components/Sidebar/sidebar.js.map +1 -1
  200. package/dist/components/Slider/slider.d.ts.map +1 -1
  201. package/dist/components/Slider/slider.js.map +1 -1
  202. package/dist/components/Switch/switch.d.ts +6 -6
  203. package/dist/components/Switch/switch.d.ts.map +1 -1
  204. package/dist/components/Switch/switch.js +3 -2
  205. package/dist/components/Switch/switch.js.map +1 -1
  206. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  207. package/dist/components/Tabs/tabs.js +15 -1
  208. package/dist/components/Tabs/tabs.js.map +1 -1
  209. package/dist/components/Textarea/textarea.d.ts +2 -2
  210. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  211. package/dist/components/Textarea/textarea.js +50 -42
  212. package/dist/components/Textarea/textarea.js.map +1 -1
  213. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  214. package/dist/components/TimePicker/time-columns.js +42 -38
  215. package/dist/components/TimePicker/time-columns.js.map +1 -1
  216. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  217. package/dist/components/TimePicker/time-picker.js +8 -6
  218. package/dist/components/TimePicker/time-picker.js.map +1 -1
  219. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  220. package/dist/components/Tooltip/tooltip.js +7 -5
  221. package/dist/components/Tooltip/tooltip.js.map +1 -1
  222. package/dist/components/TreeView/tree-view.d.ts +56 -1
  223. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  224. package/dist/components/TreeView/tree-view.js +211 -12
  225. package/dist/components/TreeView/tree-view.js.map +1 -1
  226. package/dist/index.d.ts +115 -58
  227. package/dist/index.d.ts.map +1 -1
  228. package/dist/index.js +93 -108
  229. package/dist/index.js.map +1 -1
  230. package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
  231. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  232. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  233. package/dist/tokens/categorical-color.js +15 -0
  234. package/dist/tokens/categorical-color.js.map +1 -1
  235. package/dist/tokens/motion/motion.d.ts +7 -6
  236. package/dist/tokens/motion/motion.d.ts.map +1 -1
  237. package/dist/tokens/motion/motion.js +6 -6
  238. package/dist/tokens/motion/motion.js.map +1 -1
  239. package/dist/tokens/motion/overlay-motion.d.ts +19 -0
  240. package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
  241. package/dist/tokens/motion/overlay-motion.js +9 -0
  242. package/dist/tokens/motion/overlay-motion.js.map +1 -0
  243. package/dist/tokens/uiSize/icon-size.js +5 -0
  244. package/dist/tokens/uiSize/icon-size.js.map +1 -0
  245. package/ds-canonical/fork/governance.lock +31 -19
  246. package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
  247. package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
  248. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
  249. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
  250. package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
  251. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
  252. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
  253. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
  254. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
  255. package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
  256. package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
  257. package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  258. package/ds-canonical/fork/manifest.json +15 -0
  259. package/ds-canonical/fork/preamble.md +20 -18
  260. package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
  261. package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
  262. package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
  263. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
  264. package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
  265. package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
  266. package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
  267. package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
  268. package/ds-canonical/hooks/README.md +1 -1
  269. package/ds-canonical/hooks/block_prototype_imports.py +15 -4
  270. package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
  271. package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
  272. package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
  273. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
  274. package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
  275. package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
  276. package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
  277. package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
  278. package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
  279. package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
  280. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
  281. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
  282. package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
  283. package/ds-canonical/hooks/check_story_determinism.sh +2 -0
  284. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
  285. package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  286. package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
  287. package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
  288. package/ds-canonical/hooks/stop_self_audit.sh +31 -0
  289. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
  290. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
  291. package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
  292. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
  293. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
  294. package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
  295. package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
  296. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
  297. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
  298. package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
  299. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
  300. package/ds-canonical/references/build-ui-canonicals.md +2 -1
  301. package/ds-canonical/references/failure-class-registry.json +145 -0
  302. package/ds-canonical/references/governance-audit-coverage.md +33 -0
  303. package/ds-canonical/references/item-anatomy-recipe.md +2 -2
  304. package/ds-canonical/references/scenario-definition.md +6 -9
  305. package/ds-canonical/references/ssot-consultation.md +2 -2
  306. package/ds-canonical/references/ssot-index.md +5 -4
  307. package/ds-canonical/references/story-baseline-registry.json +8 -2
  308. package/ds-canonical/references/structural-token-retention.md +6 -9
  309. package/ds-canonical/rules/meta-patterns.md +8 -8
  310. package/ds-canonical/rules/self-verify.md +4 -3
  311. package/ds-canonical/rules/story-rules.md +2 -2
  312. package/ds-canonical/rules/ui-development.md +2 -2
  313. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
  314. package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
  315. package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
  316. package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
  317. package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
  318. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  319. package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
  320. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
  321. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
  322. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
  323. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
  324. package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
  325. package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
  326. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
  327. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
  328. package/ds-canonical/skills/governance-health/SKILL.md +1 -1
  329. package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
  330. package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
  331. package/ds-canonical/skills/new-component/SKILL.md +5 -5
  332. package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
  333. package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
  334. package/ds-canonical/skills/propose-options/SKILL.md +3 -3
  335. package/ds-canonical/skills/prototype/SKILL.md +1 -1
  336. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
  337. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
  338. package/ds-canonical/skills/story-writing/SKILL.md +3 -3
  339. package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
  340. package/ds-story-manifest.json +29 -20
  341. package/llms-full.txt +22 -1
  342. package/llms.txt +5 -4
  343. package/package.json +7 -3
  344. package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
  345. package/src/components/Accordion/accordion.stories.tsx +16 -1
  346. package/src/components/Alert/alert.principles.stories.tsx +1 -1
  347. package/src/components/Alert/alert.spec.md +8 -10
  348. package/src/components/Alert/alert.stories.tsx +28 -28
  349. package/src/components/Alert/alert.tsx +1 -1
  350. package/src/components/AppShell/_demo-helpers.tsx +6 -3
  351. package/src/components/AppShell/app-shell.spec.md +4 -4
  352. package/src/components/AppShell/app-shell.tsx +28 -2
  353. package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
  354. package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
  355. package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
  356. package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
  357. package/src/components/Avatar/avatar.spec.md +2 -2
  358. package/src/components/Avatar/avatar.stories.tsx +8 -6
  359. package/src/components/Avatar/avatar.tsx +13 -5
  360. package/src/components/Badge/badge.principles.stories.tsx +1 -1
  361. package/src/components/Badge/badge.spec.md +2 -0
  362. package/src/components/Badge/badge.stories.tsx +4 -2
  363. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
  364. package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
  365. package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
  366. package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
  367. package/src/components/Button/button.principles.stories.tsx +1 -1
  368. package/src/components/Button/button.spec.md +2 -2
  369. package/src/components/Button/button.tsx +18 -3
  370. package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
  371. package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
  372. package/src/components/Calendar/calendar.spec.md +5 -4
  373. package/src/components/Calendar/calendar.stories.tsx +7 -4
  374. package/src/components/Calendar/calendar.tsx +26 -7
  375. package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
  376. package/src/components/Carousel/carousel.spec.md +2 -2
  377. package/src/components/Carousel/carousel.tsx +11 -3
  378. package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
  379. package/src/components/Chart/chart.principles.stories.tsx +1 -1
  380. package/src/components/Chart/chart.stories.tsx +2 -8
  381. package/src/components/Chart/chart.tsx +3 -0
  382. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
  383. package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
  384. package/src/components/Checkbox/checkbox.spec.md +11 -26
  385. package/src/components/Checkbox/checkbox.stories.tsx +11 -8
  386. package/src/components/Checkbox/checkbox.tsx +18 -13
  387. package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
  388. package/src/components/Chip/chip.principles.stories.tsx +1 -1
  389. package/src/components/Chip/chip.spec.md +5 -4
  390. package/src/components/Chip/chip.tsx +5 -1
  391. package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
  392. package/src/components/CircularProgress/circular-progress.spec.md +3 -3
  393. package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
  394. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
  395. package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
  396. package/src/components/Coachmark/coachmark.spec.md +5 -5
  397. package/src/components/Coachmark/coachmark.stories.tsx +3 -1
  398. package/src/components/Coachmark/coachmark.tsx +10 -3
  399. package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
  400. package/src/components/Combobox/combobox.tsx +53 -19
  401. package/src/components/Command/command.anatomy.stories.tsx +2 -2
  402. package/src/components/Command/command.principles.stories.tsx +1 -1
  403. package/src/components/Command/command.stories.tsx +42 -10
  404. package/src/components/DataTable/cell-registry.tsx +86 -63
  405. package/src/components/DataTable/column-types.ts +10 -1
  406. package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
  407. package/src/components/DataTable/data-table-filter-panel.tsx +4 -1
  408. package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
  409. package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
  410. package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
  411. package/src/components/DataTable/data-table.spec.md +32 -12
  412. package/src/components/DataTable/data-table.stories.tsx +16 -17
  413. package/src/components/DataTable/data-table.tsx +103 -60
  414. package/src/components/DataTable/index.ts +3 -0
  415. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
  416. package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
  417. package/src/components/DateGrid/date-grid.spec.md +1 -1
  418. package/src/components/DateGrid/date-grid.tsx +3 -1
  419. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
  420. package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
  421. package/src/components/DatePicker/date-picker.spec.md +3 -3
  422. package/src/components/DatePicker/date-picker.stories.tsx +4 -5
  423. package/src/components/DatePicker/date-picker.tsx +99 -45
  424. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
  425. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  426. package/src/components/DescriptionList/description-list.spec.md +3 -3
  427. package/src/components/DescriptionList/description-list.stories.tsx +7 -6
  428. package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
  429. package/src/components/Dialog/dialog.spec.md +9 -0
  430. package/src/components/Dialog/dialog.stories.tsx +66 -5
  431. package/src/components/Dialog/dialog.tsx +60 -25
  432. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
  433. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
  434. package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
  435. package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
  436. package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
  437. package/src/components/Empty/empty.spec.md +2 -2
  438. package/src/components/Field/field-context.ts +69 -5
  439. package/src/components/Field/field-controls.spec.md +62 -8
  440. package/src/components/Field/field-edit-keys.ts +66 -0
  441. package/src/components/Field/field-types.ts +58 -9
  442. package/src/components/Field/field-wrapper.tsx +50 -42
  443. package/src/components/Field/field.anatomy.stories.tsx +9 -6
  444. package/src/components/Field/field.spec.md +1 -1
  445. package/src/components/Field/field.stories.tsx +1 -1
  446. package/src/components/Field/field.tsx +2 -1
  447. package/src/components/Field/form-validation.spec.md +3 -3
  448. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
  449. package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
  450. package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
  451. package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
  452. package/src/components/FileItem/file-item.spec.md +5 -8
  453. package/src/components/FileItem/file-item.stories.tsx +36 -25
  454. package/src/components/FileItem/file-item.tsx +8 -6
  455. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
  456. package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
  457. package/src/components/FileUpload/file-upload.spec.md +1 -1
  458. package/src/components/FileUpload/file-upload.tsx +1 -1
  459. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
  460. package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
  461. package/src/components/FileViewer/file-viewer.spec.md +30 -12
  462. package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
  463. package/src/components/FileViewer/file-viewer.tsx +12 -4
  464. package/src/components/FileViewer/image-renderer.tsx +35 -7
  465. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
  466. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
  467. package/src/components/HoverCard/hover-card.spec.md +5 -5
  468. package/src/components/HoverCard/hover-card.stories.tsx +16 -16
  469. package/src/components/HoverCard/hover-card.tsx +5 -3
  470. package/src/components/InlineEdit/index.ts +5 -0
  471. package/src/components/InlineEdit/inline-edit.spec.md +149 -0
  472. package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
  473. package/src/components/InlineEdit/inline-edit.tsx +287 -0
  474. package/src/components/Input/input.anatomy.stories.tsx +8 -7
  475. package/src/components/Input/input.principles.stories.tsx +2 -12
  476. package/src/components/Input/input.spec.md +13 -18
  477. package/src/components/Input/input.tsx +69 -22
  478. package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
  479. package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
  480. package/src/components/LinkInput/link-input.tsx +11 -10
  481. package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
  482. package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
  483. package/src/components/Menu/menu-item.spec.md +22 -15
  484. package/src/components/Menu/menu-item.stories.tsx +39 -11
  485. package/src/components/Menu/menu-item.tsx +38 -4
  486. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  487. package/src/components/Notice/notice.spec.md +16 -3
  488. package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
  489. package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
  490. package/src/components/NumberInput/number-input.spec.md +4 -4
  491. package/src/components/NumberInput/number-input.tsx +19 -12
  492. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
  493. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
  494. package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
  495. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
  496. package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
  497. package/src/components/Pagination/pagination.spec.md +1 -1
  498. package/src/components/Pagination/pagination.stories.tsx +2 -6
  499. package/src/components/Pagination/pagination.tsx +1 -1
  500. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
  501. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
  502. package/src/components/PeoplePicker/people-picker.spec.md +6 -6
  503. package/src/components/PeoplePicker/people-picker.tsx +56 -16
  504. package/src/components/PeoplePicker/person-display.tsx +32 -16
  505. package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
  506. package/src/components/Popover/popover.tsx +3 -1
  507. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
  508. package/src/components/ProfileCard/profile-card.spec.md +3 -3
  509. package/src/components/ProfileCard/profile-card.tsx +6 -6
  510. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
  511. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
  512. package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
  513. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
  514. package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
  515. package/src/components/RadioGroup/radio-group.tsx +41 -15
  516. package/src/components/Rating/rating.spec.md +11 -3
  517. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  518. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  519. package/src/components/ScrollArea/scroll-area.spec.md +7 -3
  520. package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
  521. package/src/components/ScrollArea/scroll-area.tsx +17 -4
  522. package/src/components/Select/select.anatomy.stories.tsx +3 -3
  523. package/src/components/Select/select.spec.md +27 -17
  524. package/src/components/Select/select.stories.tsx +33 -0
  525. package/src/components/Select/select.tsx +190 -36
  526. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
  527. package/src/components/SelectMenu/select-menu.spec.md +15 -7
  528. package/src/components/SelectMenu/select-menu.tsx +16 -3
  529. package/src/components/SelectionControl/boolean-value.tsx +39 -0
  530. package/src/components/SelectionControl/index.ts +1 -0
  531. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
  532. package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
  533. package/src/components/SelectionControl/selection-item.spec.md +3 -3
  534. package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
  535. package/src/components/Separator/separator.spec.md +2 -2
  536. package/src/components/Separator/separator.stories.tsx +6 -27
  537. package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
  538. package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
  539. package/src/components/Sheet/sheet.spec.md +2 -2
  540. package/src/components/Sheet/sheet.tsx +9 -5
  541. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
  542. package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
  543. package/src/components/Sidebar/sidebar.spec.md +13 -15
  544. package/src/components/Sidebar/sidebar.stories.tsx +8 -7
  545. package/src/components/Sidebar/sidebar.tsx +37 -25
  546. package/src/components/Skeleton/skeleton.stories.tsx +4 -11
  547. package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
  548. package/src/components/Slider/slider.principles.stories.tsx +2 -2
  549. package/src/components/Slider/slider.spec.md +5 -5
  550. package/src/components/Slider/slider.tsx +3 -1
  551. package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
  552. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  553. package/src/components/Steps/steps.spec.md +1 -1
  554. package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
  555. package/src/components/Switch/switch.principles.stories.tsx +4 -4
  556. package/src/components/Switch/switch.spec.md +8 -8
  557. package/src/components/Switch/switch.stories.tsx +9 -24
  558. package/src/components/Switch/switch.tsx +17 -13
  559. package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
  560. package/src/components/Tabs/tabs.spec.md +1 -1
  561. package/src/components/Tabs/tabs.tsx +21 -1
  562. package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
  563. package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
  564. package/src/components/Textarea/textarea.spec.md +4 -4
  565. package/src/components/Textarea/textarea.tsx +72 -46
  566. package/src/components/TimePicker/time-columns.tsx +6 -2
  567. package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
  568. package/src/components/TimePicker/time-picker.spec.md +3 -3
  569. package/src/components/TimePicker/time-picker.tsx +16 -10
  570. package/src/components/Toast/toast.stories.tsx +7 -4
  571. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
  572. package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
  573. package/src/components/Tooltip/tooltip.spec.md +1 -1
  574. package/src/components/Tooltip/tooltip.stories.tsx +4 -39
  575. package/src/components/Tooltip/tooltip.tsx +8 -6
  576. package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
  577. package/src/components/TreeView/tree-view.spec.md +42 -11
  578. package/src/components/TreeView/tree-view.stories.tsx +1 -0
  579. package/src/components/TreeView/tree-view.tsx +322 -17
  580. package/src/index.ts +584 -60
  581. package/src/patterns/action-bar/action-bar.spec.md +9 -0
  582. package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
  583. package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
  584. package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
  585. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
  586. package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
  587. package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
  588. package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
  589. package/src/styles/tokens.css +3 -0
  590. package/src/tokens/README.md +1 -1
  591. package/src/tokens/color/color.spec.md +3 -3
  592. package/src/tokens/color/color.stories.tsx +3 -3
  593. package/src/tokens/density/density.stories.tsx +16 -3
  594. package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
  595. package/src/tokens/motion/motion.css +33 -21
  596. package/src/tokens/motion/motion.spec.md +32 -15
  597. package/src/tokens/motion/motion.stories.tsx +58 -5
  598. package/src/tokens/motion/motion.ts +7 -6
  599. package/src/tokens/motion/overlay-motion.ts +26 -0
  600. package/src/tokens/orphan-tokens.spec.md +4 -4
  601. package/src/tokens/token-system.spec.md +1 -0
  602. package/src/tokens/uiSize/uiSize.spec.md +1 -1
  603. package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
  604. package/src/tokens/utility-registry.json +160 -23
@@ -35,8 +35,11 @@ const Label = ({ children, warn }: { children: React.ReactNode; warn?: boolean }
35
35
  <p className={`text-footnote leading-normal ${warn ? 'text-error font-medium' : 'text-fg-muted'}`}>{children}</p>
36
36
  )
37
37
 
38
+ /* 2026-07-14 Dim 90 修:Action Bar 無 production container,本檔 toolbar frame 是主要參考
39
+ 實作 — 水平內距原本 px-4 / px-3 hardcode(不隨 layout density 縮放且三處不一致),統一改
40
+ chrome 水平內距 canonical `px-[var(--layout-space-loose)]`(對齊 chrome-header.tsx 同 token)。 */
38
41
  const ToolbarFrame = ({ title, children }: { title: string; children: React.ReactNode }) => (
39
- <div className="flex items-center justify-between w-full px-4 min-h-[52px] border border-border rounded-lg bg-surface">
42
+ <div className="flex items-center justify-between w-full px-[var(--layout-space-loose)] min-h-[52px] border border-border rounded-lg bg-surface">
40
43
  <span className="text-body font-bold text-foreground shrink-0 mr-4">{title}</span>
41
44
  {children}
42
45
  </div>
@@ -317,7 +320,7 @@ export const Dividers: Story = {
317
320
  </ButtonGroup>
318
321
  </ToolbarFrame>
319
322
  <Label>靠右對齊 — 有框業務操作接無框工具操作,視覺差異已足夠,不加分隔線</Label>
320
- <div className="flex items-center w-full px-4 h-[52px] border border-border rounded-lg bg-surface">
323
+ <div className="flex items-center w-full px-[var(--layout-space-loose)] h-[52px] border border-border rounded-lg bg-surface">
321
324
  <ButtonGroup>
322
325
  <Button variant="primary" size="sm" startIcon={Plus}>新增</Button>
323
326
  <Button variant="tertiary" size="sm" startIcon={Download}>匯出</Button>
@@ -421,7 +424,7 @@ export const Overflow: Story = {
421
424
  title="群組溢出(例外)— 各群組各自管理,只在合併選單會讓使用者困惑時才用"
422
425
  note="當多個群組的低頻操作領域差異大到「放進同一個選單使用者會搞不清這是哪個群組的」時,才讓各群組各自管理溢出。每個群組溢出的右側必須加分隔線(群組溢出邊界)。以 Rich Text Editor 為例:文字格式、插入元素、歷史操作三個群組功能差異極大,合併選單語意混亂"
423
426
  >
424
- <div className="flex items-center w-full px-3 h-[52px] border border-border rounded-lg bg-surface">
427
+ <div className="flex items-center w-full px-[var(--layout-space-loose)] h-[52px] border border-border rounded-lg bg-surface">
425
428
  <ButtonGroup>
426
429
  {/* 群組 A:文字格式 + 溢出 */}
427
430
  <Button variant="text" size="sm" iconOnly startIcon={Bold} aria-label="粗體" />
@@ -27,6 +27,8 @@
27
27
  | focus-visible | `outline: 2px solid var(--ring)` | — |
28
28
  | 宿主 disabled | 不渲染 inline action | — |
29
29
 
30
+ **Loading(明文 N/A)**:inline action **無 loading 態**——icon 級靶子沒有空間承載 spinner 且換渲會位移幾何,故不設 `aria-busy` / spinner surface。async 動作(row approve / retry / API delete)兩條路:(a) 觸發後由宿主層呈現 in-flight 結果(row pending 樣式 / Toast / optimistic update);(b) 需要使用者可感知的進行中狀態 → **升級為 `<Button loading>`**(Button spec「loading」段:CircularProgress + 自動 disabled + `aria-busy`),不用 inline action。double-trigger 防護由 consumer handler 冪等 / 重入 guard 承擔(對齊 `form-validation.spec.md`「Double-submit 防護」)。
31
+
30
32
  **Overlay trigger canonical**(2026-04-29 訂 / 2026-05-02 改 / 2026-05-05 prop 化):trigger 透過 `asChild` 作 DropdownMenu / Popover / Tooltip / HoverCard trigger 時,Radix 自動 set `data-state="open"`,**trigger 維持 host hover 樣式**直到浮層關閉。對齊**狀態極簡派**(shadcn / Radix Themes / Material — 不另開 4th token);避免 state 增生 + 跨 host(neutral / colored)規則同步。
31
33
 
32
34
  **2026-05-05 修正:overlay vs in-place 語意分離**。`Radix Collapsible.Trigger` 也 emit 同 `data-state="open"`,但語意完全不同(展開內容**接在下方非 floating**,user 不需追溯)。原 `ItemInlineActionButton` 將規則**無條件**套用於所有 `data-state=open`,造成 Sidebar collapsible group label 的 chevron 展開時殘留 hover bg(2026-05-05 user reported)。修正:`ItemInlineActionButton` 加 `overlayTrigger?: boolean` prop,**default `false`**。consumer 顯式宣告:
@@ -173,6 +173,8 @@ rg 'grid-cols-\[[0-9]+px_1fr\]' packages/design-system/src -g '*.tsx'
173
173
  - **Size variants**: sm / md / lg 跟 `--field-height-*` family 一致
174
174
  - **Icon 尺寸控制**: 用 `ICON_SIZE` 常數 `{ sm: 16, md: 16, lg: 20 }` 對齊 `--field-height-*`,並**透過 `size` prop 直接傳給 Lucide icon**(不要用 CSS selector 如 `[&>svg]:size-4`——當 icon 被包在 `h-[1lh]` wrapper 裡時,`>` 直接子選擇器失效,Lucide 會 fallback 到 24px 預設)。MenuItem / TreeView / SidebarMenuButton 都這樣做,新元件照抄
175
175
  - **Row header(分組標題)**: 用 `MenuItem header={true}` 模式,`font-medium text-fg-muted pointer-events-none` + 與 items **完全相同**的 row geometry(同 px / 同 py / 同 text size)
176
+ - **Row header 計數 suffix**(2026-07-08 WM 戰役 codify,user 拍板):分組標題帶總數時 = **標題靠左、純數字靠右**(space-between,即 suffix slot 位置 `ml-auto`)。數字規格走既有 suffix value canonical(下方 metadata 表「fg-muted、字體大小與 label 相同」)+ `font-normal` + `tabular-nums`;count = 0 不渲染。**禁**把 count 串進 label 字串相鄰放(「Unstarted (2)」— 6 家世界級無一家括號串接:Primer CounterLabel / Ant Badge / Atlassian Badge 皆結構化 slot);字串層(aria-label / 純文字匯出)可用括號形。互動導覽元素(tab / segmented / sidebar item)的計數仍走 `badge` slot(tabs.spec.md「badge 傳達計數」),不適用本條。
177
+ - **可收合 section header 組合 canonical**(2026-07-08 R3-7 拍板 + 2026-07-10 codify 進 DS;**組合非元件** — SectionHeader 留產品客製,但 layout 全消費本 canonical):(1) chevron = **title 後的 suffix inline action**(非 prefix、非獨立按鈕群);(2) 可選 description 與 title 間距用 `--item-gap-label-desc-*` token;(3) endSlot(操作鈕)只有 title 一行時垂直置中;(4) 同構標題列 ≥ 2 份必抽共用元件(WM `SectionHeader.tsx` 錨例 — Description / Attachments / Child work items 三份同構收斂)。手刻簽名(Chevron + justify-between + 可點且無共用元件)由 consumer 防線攔(escape `@section-header-ok:`)。
176
178
 
177
179
  ### Prefix 垂直對齊:`items-start` + `h-[1lh]` wrapper(**永遠這樣**,不要做例外)
178
180
 
@@ -427,7 +429,14 @@ MenuItem 承載 Switch 時,**整列 row 的 click = toggle 這個 control**(不
427
429
  ```tsx
428
430
  // ✅ Canonical:row click 與 suffix Switch 同步 toggle(row 可點擊、Switch 視覺反映狀態)
429
431
  // (DropdownMenuItem 無任意 suffix slot——trailing 互動 control 用 MenuItem endContent)
430
- <MenuItem endContent={<Switch checked={dark} tabIndex={-1} aria-hidden />} onClick={() => setDark(!dark)}>
432
+ // row = 唯一 ARIA owner:role="menuitemcheckbox" + aria-checked AT 感知 on/off
433
+ //(Switch aria-hidden 後,沒有這兩個屬性 toggle 狀態對 SR 完全隱形)
434
+ <MenuItem
435
+ role="menuitemcheckbox"
436
+ aria-checked={dark}
437
+ endContent={<Switch checked={dark} tabIndex={-1} aria-hidden />}
438
+ onClick={() => setDark(!dark)}
439
+ >
431
440
  Dark mode
432
441
  </MenuItem>
433
442
 
@@ -438,7 +447,7 @@ MenuItem 承載 Switch 時,**整列 row 的 click = toggle 這個 control**(不
438
447
  </MenuItem>
439
448
  ```
440
449
 
441
- **Switch 實作細節**:放 suffix 時 Switch 應 `tabIndex={-1}` + `aria-hidden`(或去掉自己的 click handler),讓 **row 成為唯一互動靶子**、Switch 純視覺反映狀態。Radix `DropdownMenuCheckboxItem` 的 Checkbox 就是這模式(checkmark 是視覺,整列是 trigger)。Switch 類比採用同樣規則。
450
+ **Switch 實作細節**:放 suffix 時 Switch 應 `tabIndex={-1}` + `aria-hidden`(或去掉自己的 click handler),讓 **row 成為唯一互動靶子**、Switch 純視覺反映狀態。**同時 row 必須自己宣告可感知的 checked state**——`role="menuitemcheckbox"`(或 `"switch"`)+ `aria-checked`;Switch 被 aria-hidden 後,漏宣告 = toggle 狀態對 screen reader 完全隱形。Radix `DropdownMenuCheckboxItem` 就是這模式(checkmark 純視覺,整列 row 帶 role=menuitemcheckbox + aria-checked)。Switch 類比採用同樣規則。
442
451
 
443
452
  **何時用 suffix Switch vs Field horizontal**:
444
453
 
@@ -538,7 +547,7 @@ Apple Mail / Gmail / iOS Settings / Material 3 / Atlassian DSP / Polaris Resourc
538
547
 
539
548
  **關鍵**:consumer 可以自由選擇「小 avatar + description」——那是完全合法的組合,此時 avatar inline 對齊第一行 label,description 從第二行自然往下。沒有「有 desc 就必須用 block 尺寸」的規則。此自由度屬裸 `<ItemAvatar>` 組合;MenuItem 的 AvatarData API 不暴露此選擇(自動推導,見上 scope 註)。
540
549
 
541
- **程式化規則**(scope:**row context only** — Sidebar / SelectMenu / TreeView / Combobox / Menu 等 row primitive 子樹內):consumer **必須**用 `<ItemAvatar>` / `<ItemIcon>` helper 元件,**禁止** `import { AVATAR_SIZE }` 手動查表,更**禁止**硬寫 `<Avatar size={N} />`。
550
+ **Helper 程式化封裝 + review 防線**(scope:**row context only** — Sidebar / SelectMenu / TreeView / Combobox / Menu 等 row primitive 子樹內):consumer **必須**用 `<ItemAvatar>` / `<ItemIcon>` helper 元件(helper 自動查 `RowSizeContext` 對表 = 程式化封裝),**禁止** `import { AVATAR_SIZE }` 手動查表,更**禁止**硬寫 `<Avatar size={N} />`(兩條禁令現無機械 hook 閘,靠 review 防線把關)。
542
551
 
543
552
  **Scope 例外:Chrome header 不是 row context**(per `header-canonical.spec.md` 4.5):chrome header 有自己的 spec-level avatar canonical = 24px(density-fixed / row-size-fixed),用 raw `<Avatar size={24}>` + `--chrome-header-avatar-size` CSS token。Chrome header avatar 不參與 row anatomy 對齊機制(無 sm/md/lg row size lookup 需求)。詳 `header-canonical.spec.md` 4.5「Chrome header avatar SSOT」段。
544
553
 
@@ -829,8 +838,8 @@ World-class benchmark(6 家 DS):
829
838
  (2026-05-31 重構後依 mode/size 選對應後綴變體 `--item-gap-label-desc-<reading|scanning>[-lg]`,bare token 已不存在;見上方「兩種閱讀模式」SSOT 段。)
830
839
 
831
840
  **Enforcement**:
832
- - Hook `check_item_content_primitive.sh`(2026-04-23)P1 warn:component .tsx 出現硬寫 `mt-0.5` / `gap-0.5` 提示改 token / primitive
833
- - Consumer 刻意 hard-code 加 `// @item-gap-exempt: <reason>` 豁免 + rationale 在 spec
841
+ - Hook `check_item_content_primitive.sh`(2026-04-23) retired(→ `.claude/hooks/retired/`,無現役 write-time 機械閘);硬寫 `mt-0.5` / `gap-0.5` 現靠 audit-time 掃描 + mindset #2(優先消費既有 token / primitive)把關
842
+ - Consumer 刻意 hard-code 加 `// @item-gap-exempt: <reason>` 豁免 + rationale 在 spec(marker 現無 hook 消費者,保留作 review 註記)
834
843
 
835
844
  **兩種模式的唯一差異是行高。** Description 在所有模式都降一級字體——label 是要辨識的目標,description 是補充,尺寸差有助快速區分。
836
845
 
@@ -15,12 +15,14 @@ import { Avatar, type AvatarData } from '@/design-system/components/Avatar/avata
15
15
  import { ProfileCard, ProfileCardDefaultActions } from '@/design-system/components/ProfileCard/profile-card'
16
16
 
17
17
  /** Person avatar hover canonical helper — avatar.spec.md DS-wide rule:
18
- * profile-card.spec.md 重要資訊 canonical(status / statusMessage / fields 皆必含) */
18
+ * profile-card.spec.md 重要資訊 canonical(status / statusMessage / fields 皆必含)
19
+ * 真實人像(2026-07-08 sweep):固定 u= key 保 determinism(對齊 avatar.stories.tsx pravatar 慣例)*/
20
+ const avatarSrc = (name: string, px = 96) => `https://i.pravatar.cc/${px}?u=${name.toLowerCase().replace(/\s+/g, '-')}`
19
21
  const personHover = (name: string, subtitle?: string) => (
20
22
  <ProfileCard
21
23
  name={name}
22
24
  subtitle={subtitle ?? 'Design|D-0042|EMP-1001'}
23
- avatar={{ alt: name }}
25
+ avatar={{ src: avatarSrc(name), alt: name }}
24
26
  status="online"
25
27
  statusMessage="Out of Office: Back on Monday!"
26
28
  actions={<ProfileCardDefaultActions />}
@@ -1034,10 +1036,10 @@ export const AlignmentThreshold = {
1034
1036
 
1035
1037
  {/* Live example */}
1036
1038
  <MenuFrame width={360}>
1037
- <MenuItem size="md" avatar={{ alt: "Alice", color: "indigo" as const, hoverCard: personHover("Alice Chen", "Design team lead") }} description="Design team lead">
1039
+ <MenuItem size="md" avatar={{ src: avatarSrc("Alice Chen", 64), alt: "Alice", color: "indigo" as const, hoverCard: personHover("Alice Chen", "Design team lead") }} description="Design team lead">
1038
1040
  Alice Chen
1039
1041
  </MenuItem>
1040
- <MenuItem size="md" avatar={{ alt: "Bob", color: "yellow" as const, hoverCard: personHover("Bob Wang", "Backend engineer") }} description="Backend engineer">
1042
+ <MenuItem size="md" avatar={{ src: avatarSrc("Bob Wang", 64), alt: "Bob", color: "yellow" as const, hoverCard: personHover("Bob Wang", "Backend engineer") }} description="Backend engineer">
1041
1043
  Bob Wang
1042
1044
  </MenuItem>
1043
1045
  </MenuFrame>
@@ -77,15 +77,16 @@ export const ICON_SIZE: Record<RowSize, number> = {
77
77
  * - **block**(有 description,avatar 跨越 label + desc 兩行)→ 對齊文字塊中心
78
78
  * sm: 32, md: 32, lg: 40
79
79
  *
80
- * **用法**:所有 row primitive 的 consumer(包含 `asChild` pattern 的 Sidebar / Tree
81
- * consumer)**必須**從本 module import 這個常數,**不可硬寫 `size={24}`**。
82
- * 硬寫會讓 sm 變體的 avatar 尺寸錯誤、跟 ICON_SIZE 對齊規則脫鉤。
80
+ * **用法**:row context 的 consumer(包含 `asChild` pattern 的 Sidebar / Tree
81
+ * consumer)**必須**用 `<ItemAvatar>` / `<ItemIcon>` helper 元件(自動查
82
+ * RowSizeContext 對表),**禁止** `import { AVATAR_SIZE }` 手動查表、**不可硬寫
83
+ * `size={24}`** — 硬寫會讓 sm 變體的 avatar 尺寸錯誤、跟 ICON_SIZE 對齊規則脫鉤。
84
+ * 詳 item-anatomy.spec.md「Helper 程式化封裝 + review 防線」段。
83
85
  *
84
86
  * ```tsx
85
- * import { AVATAR_SIZE } from "@/design-system/patterns/element-anatomy/item-anatomy"
87
+ * import { ItemAvatar } from "@/design-system/patterns/element-anatomy/item-anatomy"
86
88
  *
87
- * const { size } = useSidebar() // RowSize
88
- * <Avatar size={AVATAR_SIZE.inline[size]} />
89
+ * <ItemAvatar alt="Alan" color="blue" /> // 自動查 AVATAR_SIZE.inline[rowSize]
89
90
  * ```
90
91
  *
91
92
  * Canonical 消費者:MenuItem 直接 import 本檔 `AVATAR_SIZE`(menu-item.tsx,消費 .block/.inline;re-export 已完成,MenuItem 無內部查表)。
@@ -30,6 +30,7 @@ benchmark:
30
30
  **何時不用(when NOT to use)— 最常見誤判**:
31
31
  - ❌ **chrome 與 overlay 搞混**:看 surface 本身是常駐 chrome 還是浮層,不看視覺像不像。**邊界案例**:Sidebar 內彈出的 flyout / popover header = **overlay → SurfaceHeader**,不因為它長在 sidebar 裡就當 chrome。
32
32
  - ❌ 純內容區小標題(section heading)→ 用 typography(`text-h6` 等),不是 header primitive
33
+ - ❌ **Dialog / 浮層內「不可關閉的 side pane」標題**(如 detail dialog 右欄 metadata 欄的「General info」)→ 走 typography,不消費 header primitive。**判準一句話:「這個 pane 能不能自己被關掉」**(2026-07-08 user 拍板 codify)—— **可獨立 dismiss**(自帶 close、自帶 ScrollArea、旁有等高 chrome 需對齊,如 FileViewer InfoPanel:I 鍵 + close X)→ `<ChromeHeader>`;**不可關閉** = pane 標題只是 content 的一部分 → 純 typography,間距跟著 layoutSpace 原則走(不 flush、無 border-b、隨內容捲動)。反例先例:DatePicker TimePickerSidePanel 同層級 caption 不消費 header primitive(date-picker.spec.md「TimePickerSidePanel header 下方無 divider」段)。外部對照:Carbon SidePanel(https://github.com/carbon-design-system/ibm-products/blob/main/packages/ibm-products-styles/src/components/SidePanel/_side-panel.scss)/ Material side sheet(https://github.com/material-components/material-components-android/blob/master/docs/components/SideSheet.md)皆「有 close affordance 才有正式 header + divider」;Jira issue view 右欄僅輕量 group heading。
33
34
  - ❌ 列表 row / menu item → 走 `item-anatomy`,不是 header
34
35
  - ❌ 卡片內標題列 → Card 自己的 header 區,不套本 pattern
35
36
 
@@ -233,10 +234,10 @@ ChromeHeader / SurfaceHeader 新增 `tabsSlot?: ReactNode` prop。提供時自
233
234
 
234
235
  ### Layer 1 — Token shared
235
236
 
236
- 兩家族 consume 同組 CSS variable(機械對齊):
237
- - `--chrome-header-height`(uiSize.css:55,103)
238
- - `--layout-space-loose` / `--layout-space-tight`
239
- - `--divider-color`
237
+ 兩家族連動 token 清單(各 token 標注實際消費者;非全部兩家族交集):
238
+ - `--chrome-header-height`(uiSize.css:55,103)— B 家族 tsx 直接消費(chrome-header.tsx);A 家族不直接消費,靠 padding 算式對齊(24 + 2×tight = 48;等式由 overlay-surface.tsx anatomy 註解 + `lib/_tab_lg_chrome_header_equal.sh` W3 assert 守)
239
+ - `--layout-space-loose`(兩家族 px)/ `--layout-space-tight`(僅 A 家族 py;B 家族 fixed-height 無 py)
240
+ - `--divider`(semantic.css:333;兩家族經 `border-divider` utility 消費)
240
241
  - `--tab-height-sm` / `--tab-height-lg`(uiSize.css:41-43 md default + 99-101 lg-density override)
241
242
  - `--field-height-sm`(button sm 透過 button family 連動)
242
243
 
@@ -361,7 +361,7 @@ const CHROME_UNBOUNDED_SLOT =
361
361
 
362
362
  **禁止**:`w-[640px]` 單獨用(❌ 斷鏈)/ `flex flex-col h-full` 無 `min-h-0`(❌ flex item 不 shrink,scroll 失效)。
363
363
 
364
- **DS-wide consumer 必檢點**:`grep '<PopoverContent\|<HoverCardContent\|<DialogContent\|<SheetContent'` 內第一層 wrapper 是否含 `flex flex-col h-full`(若該 panel 用 SurfaceBody)。Hook `check_pattern_invariants.sh` C.1(原 `check_overlay_panel_scroll_chain.sh` 已 folded;2026-05-31 infra-audit 修 dangling ref)機械化攔截。
364
+ **DS-wide consumer 必檢點**:`grep '<PopoverContent\|<HoverCardContent\|<DialogContent\|<SheetContent'` 內第一層 wrapper 是否含 `flex flex-col h-full`(若該 panel 用 SurfaceBody)。Hook `check_pattern_invariants.sh` C.1(原 `check_overlay_panel_scroll_chain.sh` 已 folded;2026-05-31 infra-audit 修 dangling ref)write-time 機械化警示(P1 WARN stderr,僅掃本次 edit fragment 不 block);DS-wide 全掃(上述 grep 必檢點)走 audit。
365
365
 
366
366
  ---
367
367
 
@@ -381,6 +381,27 @@ const CHROME_UNBOUNDED_SLOT =
381
381
 
382
382
  ---
383
383
 
384
+ ## 兩欄 dialog 組合 canonical(2026-07-10 user 拍板:組合,不做元件)
385
+
386
+ 「左內容 + 右 metadata」兩欄 dialog(工作項詳情類)**是產品層組合,不收進 DS 元件**——對齊
387
+ Atlassian(modal-dialog 無宣告式兩欄 API,官方以 composition 範例示範)與 MUI(Dialog 無 split
388
+ API,欄由 layout primitive 組)。DS 只 codify 組合鐵律(違規簽名由 consumer 防線
389
+ `check_consumer_app_invariants.sh` r3 機械攔):
390
+
391
+ 1. **各欄自帶 `<ScrollArea>` 獨立捲動**——禁兩欄共用單一 ScrollArea / 共用一條捲軸(每欄
392
+ 套上方「Body overflow canonical」模板,padding 進 viewport 內層 div)。
393
+ 2. **divider = 右欄(`<aside>`)自持 `border-l border-divider`,貫穿 body 頂到底**——非獨立
394
+ div、非只切半高。
395
+ 3. **欄底 footer(如 comment composer)釘在所屬欄內**(欄內 `SurfaceFooter` chrome),
396
+ 非 dialog 全寬 footer——對齊 Atlassian 官方兩欄範例把 ModalFooter 巢狀進左欄。
397
+ 4. **header 維持全寬**,分欄從 body 才開始。
398
+
399
+ **Archetype**(照抄結構,禁憑記憶手刻):WM `WorkItemDetailDialog.tsx`(產品實證,2026-07-08
400
+ 拍板落地)/ DS 內部同構先例 `file-viewer.tsx` InfoPanel(`<aside class="w-80 shrink-0 flex-col
401
+ border-l border-divider">`)/ Atlassian `modal-dialog/examples/101-full-height-illustration.tsx`
402
+ (per-column `flex:1 + minHeight:0 + overflow auto`)。完整研究引文 →
403
+ `.claude/planning/2026-07-10-dialog-split-body-proposal.md`(元件化提案被 user 否決的紀錄)。
404
+
384
405
  ## 不屬本 primitive 的職責
385
406
 
386
407
  - **Close 按鈕渲染**:由 consumer(Dialog / Sheet / Popover)自己包 `<Button iconOnly dismiss>` 在 Header 內,綁各自 Radix Close primitive。SurfaceHeader 本身不渲染 close,避免 pattern 與 consumer 的職責耦合。
@@ -25,6 +25,9 @@
25
25
 
26
26
  ═══════════════════════════════════════════════════════════════════════ */
27
27
 
28
+ /* Overlay 進出場動畫 utilities(tw-animate-css;7 浮層消費)*/
29
+ @import "tw-animate-css";
30
+
28
31
  @import './../tokens/color/primitives.css';
29
32
  @import './../tokens/color/semantic.css';
30
33
  @import './../tokens/typography/typography.css';
@@ -26,7 +26,7 @@
26
26
  |---|---|---|
27
27
  | `color/` / `typography/` / `radius/` / `elevation/` / `opacity/` / `layoutSpace/` / `density/` | **Public** — consumer-layer(`src/app` / `src/explorations`)直接消費 | UI 開發者寫 `text-body` / `bg-primary` / `--layout-space-loose` 等 |
28
28
  | `uiSize/`(`--field-height-*` / `--tab-height-*` / `--table-row-*` / `--tree-indent-*`)| **Internal primitive** — DS 內部 component 消費,consumer 不直接用 | Button / Input / Tabs / DataTable / TreeView 等 primitive 內部消費;consumer 用 `<Button size="sm">` 不用 `h-[var(--field-height-sm)]` |
29
- | `motion/`(`--hover-delay-*`)| **Internal primitive** — DS overlay 元件內部消費,consumer 不直接用 | Tooltip / HoverCard / Avatar / OverflowIndicator 的 hover open / close delay;consumer 用元件預設,不直接讀 token |
29
+ | `motion/`(`--motion-delay-*`)| **Internal primitive** — DS overlay 元件內部消費,consumer 不直接用 | Tooltip / HoverCard / Avatar / OverflowIndicator 的 hover open / close delay;consumer 用元件預設,不直接讀 token |
30
30
 
31
31
  **Internal token 規則**(`uiSize/` / `motion/` 適用):
32
32
  - **不必補 Storybook stories**(consumer 不直接看;審查 grep 結果:`src/app` + `src/explorations` 0 個檔案直接消費 uiSize token,2026-05-17 verified)
@@ -113,12 +113,12 @@ disabled 元件內的所有子元素必須呈現 disabled 狀態:
113
113
 
114
114
  ### 兩種 disabled 策略:何時用哪個
115
115
 
116
- 系統有**兩種** disabled 視覺處理方式,判準是「**顏色是否是 semantic state 的唯一視覺載體**」:
116
+ 系統有**兩種** disabled 視覺處理方式,判準是「**顏色是否是 semantic state 的主視覺載體**」:
117
117
 
118
118
  | 策略 | 何時用 | 消費者 | 做法 |
119
119
  |---|---|---|---|
120
120
  | **灰階 token swap** | State 由形狀 / 位置 / icon / 文字 等**非顏色載體**承載,顏色只是美學 | Button、Checkbox、Input、Slider、Tag | 每個元素換到 disabled 對應的灰階 token(`bg-disabled` / `text-fg-disabled` / `bg-border` 等) |
121
- | **`opacity-disabled`** | State **完全只靠顏色區分**(形狀在 on/off 之間沒有差異),灰階化會丟失 state 辨識 | **Switch** | Root 層套 `opacity-disabled`,保留原有顏色身分,透過透明度均勻降級 |
121
+ | **`opacity-disabled`** | State **主要靠顏色區分**(殘餘線索如 thumb 位移 / 小 icon 在灰階低對比下太弱),灰階化會使 state 辨識大幅下降 | **Switch** | Root 層套 `opacity-disabled`,保留原有顏色身分,透過透明度均勻降級 |
122
122
 
123
123
  **具體判準(寫新元件時問自己)**:
124
124
  1. 在 disabled 狀態下,使用者需要辨識的 state 資訊是什麼?
@@ -229,7 +229,7 @@ Icon 色彩 canonical 的 SSOT 住 `patterns/element-anatomy/item-anatomy.spec.m
229
229
  | 底色 | 文字色 | 原因 |
230
230
  |------|--------|------|
231
231
  | `bg-warning`(yellow-6,滿版) | `text-on-emphasis-dark`(`black-a85`,深色) | 黃色亮度高,白字對比不足,必須用深色(通用亮底深字 token,非 warning 專屬;定義見下「`--on-emphasis` / `--on-emphasis-dark` 配對」段) |
232
- | `bg-warning-subtle`(淡黃) | `text-[yellow-7]`(step-7) | subtle 底色夠淺,深一階的黃色文字可辨識(見「文字色 Step 原則」) |
232
+ | `bg-warning-subtle`(淡黃) | `text-warning-text`(semantic,= `--color-yellow-7` step-7) | subtle 底色夠淺,深一階的黃色文字可辨識(見「文字色 Step 原則」);Notice / Alert code 消費的即是此 semantic utility,不硬寫 primitive 色名 |
233
233
 
234
234
  ### Indicator — Notification
235
235
 
@@ -8,7 +8,7 @@ const meta: Meta = {
8
8
  docs: {
9
9
  description: {
10
10
  component: `
11
- 色彩 token 系統。元件只使用語義 token,不直接引用原始色票。
11
+ 色彩 token 系統。互動 / 狀態語意一律使用語義 token;categorical 靜態多色場景(Tag / Avatar / Calendar event)依 spec 直接消費 primitive 色票(見 color.spec.md「消費規則」)。
12
12
 
13
13
  完整規則:\`packages/design-system/src/tokens/color/color.spec.md\`
14
14
  `,
@@ -85,7 +85,7 @@ export const Primitives: Story = {
85
85
  docs: {
86
86
  description: {
87
87
  story:
88
- '原始色票(Layer 1)。元件**不得直接使用**,一律透過語義 token。\n\n' +
88
+ '原始色票(Layer 1)。互動 / 狀態語意**不得直接使用** primitive,一律透過語義 token;例外:Tag / Avatar / Calendar 等 categorical 多色區分場景直接消費 primitive(color.spec.md「消費規則」)。\n\n' +
89
89
  '**已映射為語義 token 的色相:** blue → primary、deep-orange → error + notification、green → success、yellow → warning\n\n' +
90
90
  '**其餘色相(orange、amber、lime、turquoise、indigo、purple、magenta、red)** 保留給 data visualization、categorization tag、avatar 等需要多色區分的場景。',
91
91
  },
@@ -223,7 +223,7 @@ export const Semantic: Story = {
223
223
  docs: {
224
224
  description: {
225
225
  story:
226
- 'Primary = 互動入口(按鈕、連結)。Info = 系統狀態(in-progress、active)。subtle 為淡底填充,用於 tag、banner、checked 背景。',
226
+ 'Primary = 互動入口(按鈕、連結)。Info = 系統狀態(in-progress、active)。subtle 為淡底填充,用於 badge、banner、checked 背景(Tag 的多色淡底走 categorical primitive step-1,非 semantic subtle,見「原始色票」)。',
227
227
  },
228
228
  },
229
229
  },
@@ -1,4 +1,5 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react'
2
+ import { Button } from '@/design-system/components/Button/button'
2
3
 
3
4
  const meta: Meta = {
4
5
  title: 'Design System/Tokens/Density',
@@ -178,7 +179,7 @@ export const LayoutSpace: Story = {
178
179
  parameters: {
179
180
  docs: {
180
181
  description: {
181
- story: '版面間距 token。用於頁面側邊、header 內距、底部留白。',
182
+ story: '版面間距 token。用於頁面側邊、header 內距、內容到 action buttons 的結論留白。',
182
183
  },
183
184
  },
184
185
  },
@@ -187,7 +188,10 @@ export const LayoutSpace: Story = {
187
188
  <ColHeader cols={LS_COLS} />
188
189
  <TokenRow attr="data-layout-space" cols={LS_COLS} token="--layout-space-loose" md="16px" lg="24px" desc="頁面側邊、內容區外層" isSolid={false} />
189
190
  <TokenRow attr="data-layout-space" cols={LS_COLS} token="--layout-space-tight" md="12px" lg="16px" desc="Header 上下內距" isSolid={false} />
190
- <TokenRow attr="data-layout-space" cols={LS_COLS} token="--layout-space-bottom" md="48px" lg="48px" desc="頁面底部留白" isSolid={false} />
191
+ {/* 2026-07-14 audit Dim 68:bottom 通用「頁面底部留白」— layoutSpace.spec.md 定義為
192
+ 「結論留白:內容到 action buttons(commitment 前視覺暫停)」;無 action 的容器底依
193
+ bounded / unbounded / element 用 loose / 0 / tight(spec 規則 4)*/}
194
+ <TokenRow attr="data-layout-space" cols={LS_COLS} token="--layout-space-bottom" md="48px" lg="48px" desc="內容 → action buttons 結論留白" isSolid={false} />
191
195
  </div>
192
196
  ),
193
197
  }
@@ -223,9 +227,18 @@ export const PageLayout: Story = {
223
227
  ))}
224
228
  </div>
225
229
  </div>
230
+ {/* 2026-07-14 audit Dim 68:bottom 是「內容 → action buttons」結論留白(layoutSpace.spec.md
231
+ 規則 4 line 1)— 原 demo 把它畫成無 action 的通用頁尾 band = 教錯用法。補 action row
232
+ 讓 48px 留白真的落在 content 與 commitment 之間。 */}
226
233
  <div style={{ height: 'var(--layout-space-bottom)', borderTop: '1px dashed var(--border)' }}
227
234
  className="flex items-center justify-center">
228
- <span className="text-caption text-fg-muted">bottom space</span>
235
+ <span className="text-caption text-fg-muted">bottom 48 — 內容 → action 結論留白</span>
236
+ </div>
237
+ <div
238
+ className="flex justify-end"
239
+ style={{ padding: `0 var(--layout-space-loose) var(--layout-space-tight)` }}
240
+ >
241
+ <Button variant="primary">儲存變更</Button>
229
242
  </div>
230
243
  </div>
231
244
  )
@@ -2,7 +2,7 @@
2
2
 
3
3
  # LayoutSpace 設計原則
4
4
 
5
- Layout Space 定義頁面與容器的巨觀間距 token,隨 density 自動縮放(透過 `data-density` 或 `data-layout-space`)。
5
+ Layout Space 定義頁面與容器的巨觀間距 token,隨 density 自動縮放(透過 `data-density` 或 `data-layout-space`)。另 **co-locate 一組 item 級 micro token** `--item-gap-label-desc-*`(label ↔ description 2px gap,概念 owner = `patterns/element-anatomy`,見下「Co-located:item-gap tokens」)
6
6
 
7
7
  ## Token 表
8
8
 
@@ -12,6 +12,8 @@ Layout Space 定義頁面與容器的巨觀間距 token,隨 density 自動縮放
12
12
  | `--layout-space-tight` | 12px | 16px | 緊湊間距:Header → element、functional 交互的元素之間 |
13
13
  | `--layout-space-bottom` | 48px | 48px | 結論留白:內容到 action buttons(commitment 前視覺暫停)|
14
14
 
15
+ **Co-located:item-gap tokens** — `layoutSpace.css` 另定義 `--item-gap-label-desc-{reading,reading-lg,scanning,scanning-lg}`(皆 2px):**非**巨觀 layout token,是 item 內 label ↔ description 的 typography-mode-aware micro gap;設計 SSOT 在 `item-anatomy.spec.md`「Label ↔ Desc 間距」段,本檔只是 CSS 住所。修改值 / 加 mode → 走 item-anatomy spec。
16
+
15
17
  **為什麼 bottom 不隨 density 變**:48px 是「結論前的留白」— content 到 action buttons 的視覺暫停。跟 density 無關(不論 compact 或 comfortable,使用者都需要「commitment 前」的節奏)。
16
18
 
17
19
  ---
@@ -1,30 +1,42 @@
1
1
  /**
2
- * Motion tokens — hover delay tier system.
2
+ * Motion tokens — 統一 `--motion-*` family(2026-07-11 unify + 加進出場動畫 token)。
3
3
  *
4
- * 2026-05-18 ship per user 拍板 #3A(3-tier hover delay token + 確保命名世界級)。
4
+ * Naming convention(對齊 token-system.spec.md 規則 1 family-scoped + Material `md-sys-motion-*`
5
+ * / Polaris `p-motion-*` / Carbon motion 三家 namespace 共識):
6
+ * --motion-<measurement>-<variant>
7
+ * grep `--motion-` 即抓齊全 motion family。
5
8
  *
6
- * Naming convention:
7
- * --hover-delay-{tier}
9
+ * ── 2 個 sub-measurement family ──
8
10
  *
9
- * Tier semantics 對齊 world-class consensus(see motion.spec.md「世界級對照」段):
10
- * - plain passive hint | Tooltip 文字提示 | 500ms | Material 3 / Apple HIG / shadcn-Radix default 主流共識
11
- * - rich rich preview | HoverCard / ProfileCard | 700ms | 含 fetch / multi-section,避免列表掃視誤觸發
12
- * - close universal exit| 全部關閉延遲 | 200ms | UX research consensus accidental-hover 容錯
11
+ * (A) delay(何時開/關 hover open/close 延遲;Radix delayDuration/openDelay/closeDelay 吃 JS 鏡像)
12
+ * - plain 500ms Tooltip 純文字提示(被動 hint,對齊 Material 3 / Apple HIG / shadcn-Radix 主流)
13
+ * - rich 700ms → HoverCard / ProfileCard 內容預覽(含 fetch,避免列表掃視誤觸發)
14
+ * - close 200ms overlay 關閉延遲(close open UX 共識,user 誤滑出可回來)
15
+ * (2026-05-18/20 user 拍板 #3A;原名 `--hover-delay-*`,2026-07-11 統一前綴為 `--motion-delay-*`)
13
16
  *
14
- * 2026-05-20 user 拍板「太快很容易干擾人」+ B 選項(plain 500 / rich 700):
15
- * - plain 200 → 500ms:對齊 Material 3 plain tooltip 500ms + Apple HIG ~500ms + shadcn-Radix default 500ms
16
- * 主流共識(MUI 100ms / Ant 100ms 是 fast-tier 例外);200ms 偏快會打擾滑過列表的 user
17
- * - rich 300 700ms:HoverCard fetch + multi-section(ProfileCard avatar / actions),
18
- * user「真停留」才觸發;300ms 列表掃視易觸發 N 次 fetch
19
- * - close 200ms 維持:close delay open delay UX 共識(user 誤滑出可回來)
20
- *
21
- * Rationale 命名:不用 component name(`tooltip` 太特定)、不用純數字(`delay-200` 用值不用語意)
22
- * 不用孤立縮寫(`hd-fast` 跨人不可讀)。`plain` / `rich` / `close` 對齊 Material rich-tooltip 公開文件 +
23
- * DS 既有 `compact / rich` mode 詞彙一致(per `# 命名與語言一致性` 命名 3 test)
17
+ * (B) 進出場動畫(fade/zoom/slide duration / easing / 幾何 — CSS 驅動,由 tw-animate-css 消費)
18
+ * 全部世界級實證(見 motion.spec.md「世界級對照」+ planning/2026-07-11-overlay-motion-tokens.md):
19
+ * - duration-overlay 150ms:輕量浮層(Tooltip/Popover/HoverCard/DropdownMenu)
20
+ * Material short3 / Carbon moderate-01 / Polaris 150 / tw-animate-css 預設 **四家一致**。
21
+ * - duration-surface 250ms:模態面板(Dialog/Sheet/FileViewer,面積大位移遠 慢一階)。
22
+ * Material medium1 / Polaris 250 / Carbon moderate-02(240)
23
+ * - easing-enter cubic-bezier(0,0,0,1):進場減速(Material standard-decelerate,企業級中性沉穩)。
24
+ * - easing-exit cubic-bezier(0.3,0,1,1):出場加速(Material standard-accelerate)
25
+ * - enter-distance 0.5rem(8px):slide 位移,沿用現行 slide-*-2 = shadcn/Radix canonical。
26
+ * - enter-scale 0.95:zoom scale,沿用現行 zoom-95 = shadcn default
24
27
  */
25
28
 
26
29
  :root {
27
- --hover-delay-plain: 500ms;
28
- --hover-delay-rich: 700ms;
29
- --hover-delay-close: 200ms;
30
+ /* (A) delay */
31
+ --motion-delay-plain: 500ms;
32
+ --motion-delay-rich: 700ms;
33
+ --motion-delay-close: 200ms;
34
+
35
+ /* (B) 進出場動畫 */
36
+ --motion-duration-overlay: 150ms;
37
+ --motion-duration-surface: 250ms;
38
+ --motion-easing-enter: cubic-bezier(0, 0, 0, 1);
39
+ --motion-easing-exit: cubic-bezier(0.3, 0, 1, 1);
40
+ --motion-enter-distance: 0.5rem;
41
+ --motion-enter-scale: 0.95;
30
42
  }
@@ -23,15 +23,15 @@ benchmark:
23
23
 
24
24
  Hover delay token 是「hover 觸發 → 延遲 N ms → overlay 顯示」的延遲時間(對齊 token 名 `delay` 術語)。**目的不是動畫長度,是「user 真的想看」過濾器** — 短暫滑過不該觸發 expensive overlay(ProfileCard fetch 資料 / Tooltip 視覺擾動)。
25
25
 
26
- **Scope 邊界**:本 token 系統僅管 hover open / close 延遲;overlay 開啟後的 fetch loading 視覺(skeleton / 留空)屬各 consumer 元件 spec(HoverCard / ProfileCard),不在 motion token scope。
26
+ **Scope**:motion token 統一在 `--motion-*` 前綴下,兩個 sub-family:(A)**delay**(hover 開/關延遲,見下)(B)**進出場動畫**(overlay fade/zoom/slide duration/easing/幾何,見「進出場動畫 token」段)。overlay 開啟後的 fetch loading 視覺(skeleton / 留空)屬各 consumer 元件 spec,不在 motion token scope。
27
27
 
28
28
  ## 三層 tier 系統
29
29
 
30
30
  | Token | 值 | 用於 | 為何 |
31
31
  |---|---|---|---|
32
- | `--hover-delay-plain` | `500ms` | Tooltip 純文字提示 | 被動 hint,需 user「真停留」才觸發,避免滑過列表時 N 次視覺擾動。對齊 Material 3 plain tooltip 500ms / Apple HIG ~500ms / shadcn-Radix default 500ms 主流共識 | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
33
- | `--hover-delay-rich` | `700ms` | HoverCard / ProfileCard 內容預覽 | 含 avatar / fields / actions 的 rich content(可能含 fetch)。User 必須「真的想看」才停留 700ms,避免列表掃視時誤觸發 N 個 fetch waterfall |
34
- | `--hover-delay-close` | `200ms` | 所有 overlay 關閉 | Mouse leave 後給 200ms 緩衝(user 可能誤滑出再回來)。對齊 UX 共識「close delay ≤ open delay」+ 既有 Avatar `closeDelay={200}` 值 |
32
+ | `--motion-delay-plain` | `500ms` | Tooltip 純文字提示 | 被動 hint,需 user「真停留」才觸發,避免滑過列表時 N 次視覺擾動。對齊 Material 3 plain tooltip 500ms / Apple HIG ~500ms / shadcn-Radix default 500ms 主流共識 | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
33
+ | `--motion-delay-rich` | `700ms` | HoverCard / ProfileCard 內容預覽 | 含 avatar / fields / actions 的 rich content(可能含 fetch)。User 必須「真的想看」才停留 700ms,避免列表掃視時誤觸發 N 個 fetch waterfall |
34
+ | `--motion-delay-close` | `200ms` | 所有 overlay 關閉 | Mouse leave 後給 200ms 緩衝(user 可能誤滑出再回來)。對齊 UX 共識「close delay ≤ open delay」+ 既有 Avatar `closeDelay={200}` 值 |
35
35
 
36
36
  ## 為何不用單一值 / 為何不沿用過去 200ms
37
37
 
@@ -45,11 +45,11 @@ Hover delay token 是「hover 觸發 → 延遲 N ms → overlay 顯示」的延
45
45
 
46
46
  | 場景 | 用哪 token | 為何 |
47
47
  |---|---|---|
48
- | Icon-only Button → 顯示文字提示 | `--hover-delay-plain` | 純文字輔助 |
49
- | Avatar / Username → 顯示完整人物卡 | `--hover-delay-rich` | 含 fetch + multi-section content |
50
- | OverflowIndicator → 顯示隱藏列表 | `--hover-delay-plain` | 純列表展開,無 fetch |
51
- | Tag / Chip → 顯示說明 | `--hover-delay-plain` | 純文字 |
52
- | 任何 overlay 關閉延遲 | `--hover-delay-close` | universal |
48
+ | Icon-only Button → 顯示文字提示 | `--motion-delay-plain` | 純文字輔助 |
49
+ | Avatar / Username → 顯示完整人物卡 | `--motion-delay-rich` | 含 fetch + multi-section content |
50
+ | OverflowIndicator → 顯示隱藏列表 | `--motion-delay-plain` | 純列表展開,無 fetch |
51
+ | Tag / Chip → 顯示說明 | `--motion-delay-plain` | 純文字 |
52
+ | 任何 overlay 關閉延遲 | `--motion-delay-close` | universal |
53
53
  | Click-triggered Popover / Dialog | — | N/A,click 不適用 hover delay |
54
54
  | Tooltip 鍵盤 focus 觸發 | — | N/A,直接顯示(對齊 WAI-ARIA APG) |
55
55
 
@@ -61,18 +61,18 @@ Hover delay token 是「hover 觸發 → 延遲 N ms → overlay 顯示」的延
61
61
 
62
62
  ### Anti-pattern 避免命名
63
63
 
64
- - ❌ `--hover-delay-tooltip` / `--hover-delay-hovercard` — 元件名綁定 → 新元件(Popover variant)用哪個?
64
+ - ❌ `--motion-delay-tooltip` / `--motion-delay-hovercard` — 元件名綁定 → 新元件(Popover variant)用哪個?
65
65
  - ❌ `--delay-200` / `--delay-300` — 用值不用語意 → 改值要 rename
66
66
  - ❌ `--motion-hover-fast` / `--motion-hover-slow` — fast/slow 在 hover 語境語意模糊(對 user 來說「fast」應該是 instant?)
67
67
  - ❌ `--hover-time` / `--mouseover-pause` — 自創縮寫,跨人不可讀
68
68
 
69
69
  ## 消費者
70
70
 
71
- - `components/Avatar/avatar.tsx` — HoverCard openDelay / closeDelay 消費 `HOVER_DELAY_RICH_MS` / `HOVER_DELAY_CLOSE_MS`(原硬寫 300/200,migrate 到 token)
72
- - `components/HoverCard/hover-card.tsx` — Root 預設 `openDelay`=`--hover-delay-rich` / `closeDelay`=`--hover-delay-close`(Radix HoverCard 無 Provider;2026-06-11 落地,原宣稱與 code 脫鉤)
73
- - `components/Tooltip/tooltip.tsx` — Radix Provider 預設 delayDuration override 為 `--hover-delay-plain`
74
- - `components/ProfileCard/profile-card.tsx`(consumer of HoverCard)— 繼承 `--hover-delay-rich`
75
- - `components/OverflowIndicator/overflow-indicator.tsx`(consumer)— 用 `--hover-delay-plain`
71
+ - `components/Avatar/avatar.tsx` — HoverCard openDelay / closeDelay 消費 `MOTION_DELAY_RICH_MS` / `MOTION_DELAY_CLOSE_MS`(原硬寫 300/200,migrate 到 token)
72
+ - `components/HoverCard/hover-card.tsx` — Root 預設 `openDelay`=`--motion-delay-rich` / `closeDelay`=`--motion-delay-close`(Radix HoverCard 無 Provider;2026-06-11 落地,原宣稱與 code 脫鉤)
73
+ - `components/Tooltip/tooltip.tsx` — Radix Provider 預設 delayDuration override 為 `--motion-delay-plain`
74
+ - `components/ProfileCard/profile-card.tsx`(consumer of HoverCard)— 繼承 `--motion-delay-rich`
75
+ - `components/OverflowIndicator/overflow-indicator.tsx`(consumer)— 用 `--motion-delay-plain`
76
76
  - 任何 future overlay hover consumer 必 import 此 token(per M17 SSOT 必可傳播)
77
77
 
78
78
  ## 世界級對照
@@ -103,3 +103,20 @@ Hover delay token 是「hover 觸發 → 延遲 N ms → overlay 顯示」的延
103
103
  > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
104
104
 
105
105
  - `hover-card.spec.md`
106
+
107
+ ## 進出場動畫 token(2026-07-11 加,user 拍板)
108
+
109
+ Overlay(Tooltip/Popover/HoverCard/DropdownMenu/Dialog/Sheet/FileViewer)的 fade/zoom/slide 進出場動畫,值統一 token 化(原各元件硬寫 zoom-95/slide-2/duration-300 = M17 假 SSOT)。由 tw-animate-css(Tailwind v4,= shadcn 官方機制)的 `--tw-duration`/`--tw-ease` 變數綁定;共用 SSOT = `overlay-motion.ts`(overlayMotion/surfaceMotion)。
110
+
111
+ | Token | 值 | 用於 | 世界級對照 |
112
+ |---|---|---|---|
113
+ | `--motion-duration-overlay` | `150ms` | 輕量浮層(Tooltip/Popover/HoverCard/DropdownMenu) | Material short3 / Carbon moderate-01 / Polaris 150 / tw-animate-css 預設 **四家一致** |
114
+ | `--motion-duration-surface` | `250ms` | 模態面板(Dialog/Sheet/FileViewer,面積大位移遠→慢一階) | Material medium1 / Polaris 250 / Carbon moderate-02(240) |
115
+ | `--motion-easing-enter` | `cubic-bezier(0,0,0,1)` | 進場(減速,快起平滑落定) | Material standard-decelerate(企業級中性沉穩) |
116
+ | `--motion-easing-exit` | `cubic-bezier(0.3,0,1,1)` | 出場(加速) | Material standard-accelerate |
117
+ | `--motion-enter-distance` | `0.5rem`(8px) | slide 位移 | shadcn/Radix canonical(= 現行 slide-*-2) |
118
+ | `--motion-enter-scale` | `0.95` | zoom scale | shadcn default(= 現行 zoom-95) |
119
+
120
+ **幾何原型分層(正當差異,不強行抹平)**:輕量 popup = fade+zoom+slide-side(8px);模態置中 = fade+zoom+slide-center(Dialog/FileViewer);邊緣抽屜 = slide-edge 100%、正當無 zoom(Sheet)。統一的是**時長/曲線/reduced-motion 守衛**(motion-reduce:animate-none 全 7 浮層),非幾何原型(對齊 Material standard-vs-emphasized / Carbon productive-vs-expressive tier 分層)。
121
+
122
+ **a11y**:prefers-reduced-motion 下 `motion-reduce:animate-none` 全 7 浮層統一關進出場動畫(overlay-motion SSOT 保證,無漏)。