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

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 (622) 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-group.d.ts +47 -0
  53. package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
  54. package/dist/components/DataTable/data-table-filter-group.js +154 -0
  55. package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
  56. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  57. package/dist/components/DataTable/data-table-filter-panel.js +285 -0
  58. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
  59. package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -0
  60. package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
  61. package/dist/components/DataTable/data-table-filter-value-picker.js +187 -0
  62. package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
  63. package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
  64. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  65. package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
  66. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  67. package/dist/components/DataTable/data-table-sort-manager.js +140 -0
  68. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
  69. package/dist/components/DataTable/data-table.d.ts +5 -6
  70. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  71. package/dist/components/DataTable/data-table.js +36 -15
  72. package/dist/components/DataTable/data-table.js.map +1 -1
  73. package/dist/components/DataTable/filter-operators.js +140 -0
  74. package/dist/components/DataTable/filter-operators.js.map +1 -0
  75. package/dist/components/DataTable/filter-tree.js +312 -0
  76. package/dist/components/DataTable/filter-tree.js.map +1 -0
  77. package/dist/components/DataTable/index.d.ts +3 -0
  78. package/dist/components/DataTable/index.d.ts.map +1 -1
  79. package/dist/components/DataTable/index.js +12 -1
  80. package/dist/components/DataTable/index.js.map +1 -1
  81. package/dist/components/DataTable/lib/column-meta.js +25 -0
  82. package/dist/components/DataTable/lib/column-meta.js.map +1 -0
  83. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  84. package/dist/components/DateGrid/date-grid.js +3 -1
  85. package/dist/components/DateGrid/date-grid.js.map +1 -1
  86. package/dist/components/DatePicker/date-picker.d.ts +7 -1
  87. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  88. package/dist/components/DatePicker/date-picker.js +105 -74
  89. package/dist/components/DatePicker/date-picker.js.map +1 -1
  90. package/dist/components/Dialog/dialog.d.ts +20 -3
  91. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  92. package/dist/components/Dialog/dialog.js +38 -20
  93. package/dist/components/Dialog/dialog.js.map +1 -1
  94. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  95. package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
  96. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  97. package/dist/components/Field/field-context.d.ts +45 -5
  98. package/dist/components/Field/field-context.d.ts.map +1 -1
  99. package/dist/components/Field/field-context.js +19 -0
  100. package/dist/components/Field/field-context.js.map +1 -1
  101. package/dist/components/Field/field-edit-keys.d.ts +21 -0
  102. package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
  103. package/dist/components/Field/field-edit-keys.js +19 -0
  104. package/dist/components/Field/field-edit-keys.js.map +1 -0
  105. package/dist/components/Field/field-types.d.ts +20 -1
  106. package/dist/components/Field/field-types.d.ts.map +1 -1
  107. package/dist/components/Field/field-types.js.map +1 -1
  108. package/dist/components/Field/field-wrapper.d.ts +3 -2
  109. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  110. package/dist/components/Field/field-wrapper.js +38 -39
  111. package/dist/components/Field/field-wrapper.js.map +1 -1
  112. package/dist/components/Field/field.d.ts +2 -1
  113. package/dist/components/Field/field.d.ts.map +1 -1
  114. package/dist/components/Field/field.js.map +1 -1
  115. package/dist/components/Field/index.d.ts +1 -0
  116. package/dist/components/Field/index.d.ts.map +1 -1
  117. package/dist/components/Field/index.js +2 -0
  118. package/dist/components/Field/index.js.map +1 -1
  119. package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
  120. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  121. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  122. package/dist/components/FileItem/file-item.js +1 -1
  123. package/dist/components/FileItem/file-item.js.map +1 -1
  124. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  125. package/dist/components/FileUpload/file-upload.js.map +1 -1
  126. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  127. package/dist/components/FileViewer/file-viewer.js +7 -2
  128. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  129. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
  130. package/dist/components/FileViewer/image-renderer.js +22 -1
  131. package/dist/components/FileViewer/image-renderer.js.map +1 -1
  132. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  133. package/dist/components/HoverCard/hover-card.js +5 -3
  134. package/dist/components/HoverCard/hover-card.js.map +1 -1
  135. package/dist/components/InlineEdit/index.d.ts +2 -0
  136. package/dist/components/InlineEdit/index.d.ts.map +1 -0
  137. package/dist/components/InlineEdit/index.js +5 -0
  138. package/dist/components/InlineEdit/index.js.map +1 -0
  139. package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
  140. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
  141. package/dist/components/InlineEdit/inline-edit.js +164 -0
  142. package/dist/components/InlineEdit/inline-edit.js.map +1 -0
  143. package/dist/components/Input/input.d.ts +6 -11
  144. package/dist/components/Input/input.d.ts.map +1 -1
  145. package/dist/components/Input/input.js +43 -13
  146. package/dist/components/Input/input.js.map +1 -1
  147. package/dist/components/LinkInput/link-input.d.ts +2 -2
  148. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  149. package/dist/components/LinkInput/link-input.js +6 -5
  150. package/dist/components/LinkInput/link-input.js.map +1 -1
  151. package/dist/components/Menu/menu-item.d.ts +14 -2
  152. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  153. package/dist/components/Menu/menu-item.js +25 -3
  154. package/dist/components/Menu/menu-item.js.map +1 -1
  155. package/dist/components/NumberInput/number-input.d.ts +3 -3
  156. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  157. package/dist/components/NumberInput/number-input.js +6 -5
  158. package/dist/components/NumberInput/number-input.js.map +1 -1
  159. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  160. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
  161. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  162. package/dist/components/Pagination/pagination.js +1 -1
  163. package/dist/components/Pagination/pagination.js.map +1 -1
  164. package/dist/components/PeoplePicker/index.js +7 -1
  165. package/dist/components/PeoplePicker/index.js.map +1 -1
  166. package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
  167. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  168. package/dist/components/PeoplePicker/people-picker.js +23 -10
  169. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  170. package/dist/components/PeoplePicker/person-display.d.ts +6 -3
  171. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  172. package/dist/components/PeoplePicker/person-display.js +19 -14
  173. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  174. package/dist/components/Popover/popover.d.ts.map +1 -1
  175. package/dist/components/Popover/popover.js +3 -1
  176. package/dist/components/Popover/popover.js.map +1 -1
  177. package/dist/components/ProfileCard/profile-card.d.ts +2 -2
  178. package/dist/components/ProfileCard/profile-card.js +3 -3
  179. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  180. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  181. package/dist/components/RadioGroup/radio-group.js +15 -9
  182. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  183. package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
  184. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  185. package/dist/components/ScrollArea/scroll-area.js +6 -3
  186. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  187. package/dist/components/Select/select.d.ts +46 -5
  188. package/dist/components/Select/select.d.ts.map +1 -1
  189. package/dist/components/Select/select.js +109 -28
  190. package/dist/components/Select/select.js.map +1 -1
  191. package/dist/components/SelectMenu/select-menu.d.ts +3 -1
  192. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  193. package/dist/components/SelectMenu/select-menu.js +8 -1
  194. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  195. package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
  196. package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
  197. package/dist/components/SelectionControl/boolean-value.js +23 -0
  198. package/dist/components/SelectionControl/boolean-value.js.map +1 -0
  199. package/dist/components/SelectionControl/index.d.ts +1 -0
  200. package/dist/components/SelectionControl/index.d.ts.map +1 -1
  201. package/dist/components/SelectionControl/index.js +2 -0
  202. package/dist/components/SelectionControl/index.js.map +1 -1
  203. package/dist/components/Sheet/index.js +2 -1
  204. package/dist/components/Sheet/sheet.d.ts +7 -1
  205. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  206. package/dist/components/Sheet/sheet.js +5 -2
  207. package/dist/components/Sheet/sheet.js.map +1 -1
  208. package/dist/components/Sidebar/sidebar.d.ts +9 -4
  209. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  210. package/dist/components/Sidebar/sidebar.js +8 -10
  211. package/dist/components/Sidebar/sidebar.js.map +1 -1
  212. package/dist/components/Slider/slider.d.ts.map +1 -1
  213. package/dist/components/Slider/slider.js.map +1 -1
  214. package/dist/components/Switch/switch.d.ts +6 -6
  215. package/dist/components/Switch/switch.d.ts.map +1 -1
  216. package/dist/components/Switch/switch.js +3 -2
  217. package/dist/components/Switch/switch.js.map +1 -1
  218. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  219. package/dist/components/Tabs/tabs.js +15 -1
  220. package/dist/components/Tabs/tabs.js.map +1 -1
  221. package/dist/components/Textarea/textarea.d.ts +2 -2
  222. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  223. package/dist/components/Textarea/textarea.js +50 -42
  224. package/dist/components/Textarea/textarea.js.map +1 -1
  225. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  226. package/dist/components/TimePicker/time-columns.js +42 -38
  227. package/dist/components/TimePicker/time-columns.js.map +1 -1
  228. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  229. package/dist/components/TimePicker/time-picker.js +8 -6
  230. package/dist/components/TimePicker/time-picker.js.map +1 -1
  231. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  232. package/dist/components/Tooltip/tooltip.js +7 -5
  233. package/dist/components/Tooltip/tooltip.js.map +1 -1
  234. package/dist/components/TreeView/tree-view.d.ts +56 -1
  235. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  236. package/dist/components/TreeView/tree-view.js +211 -12
  237. package/dist/components/TreeView/tree-view.js.map +1 -1
  238. package/dist/index.d.ts +115 -58
  239. package/dist/index.d.ts.map +1 -1
  240. package/dist/index.js +95 -108
  241. package/dist/index.js.map +1 -1
  242. package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
  243. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  244. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  245. package/dist/tokens/categorical-color.js +15 -0
  246. package/dist/tokens/categorical-color.js.map +1 -1
  247. package/dist/tokens/motion/motion.d.ts +7 -6
  248. package/dist/tokens/motion/motion.d.ts.map +1 -1
  249. package/dist/tokens/motion/motion.js +6 -6
  250. package/dist/tokens/motion/motion.js.map +1 -1
  251. package/dist/tokens/motion/overlay-motion.d.ts +19 -0
  252. package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
  253. package/dist/tokens/motion/overlay-motion.js +9 -0
  254. package/dist/tokens/motion/overlay-motion.js.map +1 -0
  255. package/dist/tokens/uiSize/icon-size.js +5 -0
  256. package/dist/tokens/uiSize/icon-size.js.map +1 -0
  257. package/ds-canonical/fork/governance.lock +31 -19
  258. package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
  259. package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
  260. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
  261. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
  262. package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
  263. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
  264. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
  265. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
  266. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
  267. package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
  268. package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
  269. package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  270. package/ds-canonical/fork/manifest.json +15 -0
  271. package/ds-canonical/fork/preamble.md +20 -18
  272. package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
  273. package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
  274. package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
  275. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
  276. package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
  277. package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
  278. package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
  279. package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
  280. package/ds-canonical/hooks/README.md +1 -1
  281. package/ds-canonical/hooks/block_prototype_imports.py +15 -4
  282. package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
  283. package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
  284. package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
  285. package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
  286. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
  287. package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
  288. package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
  289. package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
  290. package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
  291. package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
  292. package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
  293. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
  294. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
  295. package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
  296. package/ds-canonical/hooks/check_story_determinism.sh +2 -0
  297. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
  298. package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  299. package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
  300. package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
  301. package/ds-canonical/hooks/stop_self_audit.sh +31 -0
  302. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
  303. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
  304. package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
  305. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
  306. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
  307. package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
  308. package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
  309. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
  310. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
  311. package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
  312. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
  313. package/ds-canonical/references/build-ui-canonicals.md +2 -1
  314. package/ds-canonical/references/failure-class-registry.json +145 -0
  315. package/ds-canonical/references/governance-audit-coverage.md +33 -0
  316. package/ds-canonical/references/item-anatomy-recipe.md +2 -2
  317. package/ds-canonical/references/scenario-definition.md +6 -9
  318. package/ds-canonical/references/ssot-consultation.md +2 -2
  319. package/ds-canonical/references/ssot-index.md +5 -4
  320. package/ds-canonical/references/story-baseline-registry.json +8 -2
  321. package/ds-canonical/references/structural-token-retention.md +6 -9
  322. package/ds-canonical/rules/meta-patterns.md +8 -8
  323. package/ds-canonical/rules/self-verify.md +4 -3
  324. package/ds-canonical/rules/story-rules.md +2 -2
  325. package/ds-canonical/rules/ui-development.md +2 -2
  326. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
  327. package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
  328. package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
  329. package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
  330. package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
  331. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  332. package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
  333. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
  334. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
  335. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
  336. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
  337. package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
  338. package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
  339. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
  340. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
  341. package/ds-canonical/skills/governance-health/SKILL.md +1 -1
  342. package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
  343. package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
  344. package/ds-canonical/skills/new-component/SKILL.md +5 -5
  345. package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
  346. package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
  347. package/ds-canonical/skills/propose-options/SKILL.md +3 -3
  348. package/ds-canonical/skills/prototype/SKILL.md +1 -1
  349. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
  350. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
  351. package/ds-canonical/skills/story-writing/SKILL.md +3 -3
  352. package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
  353. package/ds-story-manifest.json +29 -20
  354. package/llms-full.txt +22 -1
  355. package/llms.txt +5 -4
  356. package/package.json +7 -3
  357. package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
  358. package/src/components/Accordion/accordion.stories.tsx +16 -1
  359. package/src/components/Alert/alert.principles.stories.tsx +1 -1
  360. package/src/components/Alert/alert.spec.md +8 -10
  361. package/src/components/Alert/alert.stories.tsx +28 -28
  362. package/src/components/Alert/alert.tsx +1 -1
  363. package/src/components/AppShell/_demo-helpers.tsx +6 -3
  364. package/src/components/AppShell/app-shell.spec.md +4 -4
  365. package/src/components/AppShell/app-shell.tsx +28 -2
  366. package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
  367. package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
  368. package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
  369. package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
  370. package/src/components/Avatar/avatar.spec.md +2 -2
  371. package/src/components/Avatar/avatar.stories.tsx +8 -6
  372. package/src/components/Avatar/avatar.tsx +13 -5
  373. package/src/components/Badge/badge.principles.stories.tsx +1 -1
  374. package/src/components/Badge/badge.spec.md +2 -0
  375. package/src/components/Badge/badge.stories.tsx +4 -2
  376. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
  377. package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
  378. package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
  379. package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
  380. package/src/components/Button/button.principles.stories.tsx +1 -1
  381. package/src/components/Button/button.spec.md +2 -2
  382. package/src/components/Button/button.tsx +18 -3
  383. package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
  384. package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
  385. package/src/components/Calendar/calendar.spec.md +5 -4
  386. package/src/components/Calendar/calendar.stories.tsx +7 -4
  387. package/src/components/Calendar/calendar.tsx +26 -7
  388. package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
  389. package/src/components/Carousel/carousel.spec.md +2 -2
  390. package/src/components/Carousel/carousel.tsx +11 -3
  391. package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
  392. package/src/components/Chart/chart.principles.stories.tsx +1 -1
  393. package/src/components/Chart/chart.stories.tsx +2 -8
  394. package/src/components/Chart/chart.tsx +3 -0
  395. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
  396. package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
  397. package/src/components/Checkbox/checkbox.spec.md +13 -26
  398. package/src/components/Checkbox/checkbox.stories.tsx +11 -8
  399. package/src/components/Checkbox/checkbox.tsx +18 -13
  400. package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
  401. package/src/components/Chip/chip.principles.stories.tsx +1 -1
  402. package/src/components/Chip/chip.spec.md +5 -4
  403. package/src/components/Chip/chip.tsx +5 -1
  404. package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
  405. package/src/components/CircularProgress/circular-progress.spec.md +3 -3
  406. package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
  407. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
  408. package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
  409. package/src/components/Coachmark/coachmark.spec.md +5 -5
  410. package/src/components/Coachmark/coachmark.stories.tsx +3 -1
  411. package/src/components/Coachmark/coachmark.tsx +10 -3
  412. package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
  413. package/src/components/Combobox/combobox.tsx +53 -19
  414. package/src/components/Command/command.anatomy.stories.tsx +2 -2
  415. package/src/components/Command/command.principles.stories.tsx +1 -1
  416. package/src/components/Command/command.stories.tsx +42 -10
  417. package/src/components/DataTable/cell-registry.tsx +86 -63
  418. package/src/components/DataTable/column-types.ts +10 -1
  419. package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
  420. package/src/components/DataTable/data-table-filter-group.tsx +231 -0
  421. package/src/components/DataTable/data-table-filter-panel.tsx +16 -430
  422. package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
  423. package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
  424. package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
  425. package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
  426. package/src/components/DataTable/data-table.spec.md +33 -13
  427. package/src/components/DataTable/data-table.stories.tsx +16 -17
  428. package/src/components/DataTable/data-table.tsx +107 -61
  429. package/src/components/DataTable/filter-operators.spec.md +3 -3
  430. package/src/components/DataTable/index.ts +3 -0
  431. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
  432. package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
  433. package/src/components/DateGrid/date-grid.spec.md +1 -1
  434. package/src/components/DateGrid/date-grid.tsx +3 -1
  435. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
  436. package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
  437. package/src/components/DatePicker/date-picker.spec.md +3 -3
  438. package/src/components/DatePicker/date-picker.stories.tsx +4 -5
  439. package/src/components/DatePicker/date-picker.tsx +99 -45
  440. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
  441. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  442. package/src/components/DescriptionList/description-list.spec.md +3 -3
  443. package/src/components/DescriptionList/description-list.stories.tsx +7 -6
  444. package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
  445. package/src/components/Dialog/dialog.spec.md +9 -0
  446. package/src/components/Dialog/dialog.stories.tsx +66 -5
  447. package/src/components/Dialog/dialog.tsx +60 -25
  448. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
  449. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
  450. package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
  451. package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
  452. package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
  453. package/src/components/Empty/empty.spec.md +2 -2
  454. package/src/components/Field/field-context.ts +69 -5
  455. package/src/components/Field/field-controls.spec.md +62 -8
  456. package/src/components/Field/field-edit-keys.ts +66 -0
  457. package/src/components/Field/field-types.ts +58 -9
  458. package/src/components/Field/field-wrapper.tsx +50 -42
  459. package/src/components/Field/field.anatomy.stories.tsx +9 -6
  460. package/src/components/Field/field.spec.md +1 -1
  461. package/src/components/Field/field.stories.tsx +1 -1
  462. package/src/components/Field/field.tsx +2 -1
  463. package/src/components/Field/form-validation.spec.md +3 -3
  464. package/src/components/Field/index.ts +1 -0
  465. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
  466. package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
  467. package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
  468. package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
  469. package/src/components/FileItem/file-item.spec.md +5 -8
  470. package/src/components/FileItem/file-item.stories.tsx +36 -25
  471. package/src/components/FileItem/file-item.tsx +8 -6
  472. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
  473. package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
  474. package/src/components/FileUpload/file-upload.spec.md +1 -1
  475. package/src/components/FileUpload/file-upload.tsx +1 -1
  476. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
  477. package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
  478. package/src/components/FileViewer/file-viewer.spec.md +30 -12
  479. package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
  480. package/src/components/FileViewer/file-viewer.tsx +12 -4
  481. package/src/components/FileViewer/image-renderer.tsx +35 -7
  482. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
  483. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
  484. package/src/components/HoverCard/hover-card.spec.md +5 -5
  485. package/src/components/HoverCard/hover-card.stories.tsx +16 -16
  486. package/src/components/HoverCard/hover-card.tsx +5 -3
  487. package/src/components/InlineEdit/index.ts +5 -0
  488. package/src/components/InlineEdit/inline-edit.spec.md +149 -0
  489. package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
  490. package/src/components/InlineEdit/inline-edit.tsx +287 -0
  491. package/src/components/Input/input.anatomy.stories.tsx +8 -7
  492. package/src/components/Input/input.principles.stories.tsx +2 -12
  493. package/src/components/Input/input.spec.md +13 -18
  494. package/src/components/Input/input.tsx +69 -22
  495. package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
  496. package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
  497. package/src/components/LinkInput/link-input.tsx +11 -10
  498. package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
  499. package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
  500. package/src/components/Menu/menu-item.spec.md +22 -15
  501. package/src/components/Menu/menu-item.stories.tsx +39 -11
  502. package/src/components/Menu/menu-item.tsx +38 -4
  503. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  504. package/src/components/Notice/notice.spec.md +16 -3
  505. package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
  506. package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
  507. package/src/components/NumberInput/number-input.spec.md +4 -4
  508. package/src/components/NumberInput/number-input.tsx +19 -12
  509. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
  510. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
  511. package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
  512. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
  513. package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
  514. package/src/components/Pagination/pagination.spec.md +1 -1
  515. package/src/components/Pagination/pagination.stories.tsx +2 -6
  516. package/src/components/Pagination/pagination.tsx +1 -1
  517. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
  518. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
  519. package/src/components/PeoplePicker/people-picker.spec.md +6 -6
  520. package/src/components/PeoplePicker/people-picker.tsx +56 -16
  521. package/src/components/PeoplePicker/person-display.tsx +32 -16
  522. package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
  523. package/src/components/Popover/popover.tsx +3 -1
  524. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
  525. package/src/components/ProfileCard/profile-card.spec.md +3 -3
  526. package/src/components/ProfileCard/profile-card.tsx +6 -6
  527. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
  528. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
  529. package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
  530. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
  531. package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
  532. package/src/components/RadioGroup/radio-group.tsx +41 -15
  533. package/src/components/Rating/rating.spec.md +11 -3
  534. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  535. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  536. package/src/components/ScrollArea/scroll-area.spec.md +7 -3
  537. package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
  538. package/src/components/ScrollArea/scroll-area.tsx +17 -4
  539. package/src/components/Select/select.anatomy.stories.tsx +3 -3
  540. package/src/components/Select/select.spec.md +29 -17
  541. package/src/components/Select/select.stories.tsx +33 -0
  542. package/src/components/Select/select.tsx +190 -36
  543. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
  544. package/src/components/SelectMenu/select-menu.spec.md +15 -7
  545. package/src/components/SelectMenu/select-menu.tsx +16 -3
  546. package/src/components/SelectionControl/boolean-value.tsx +39 -0
  547. package/src/components/SelectionControl/index.ts +1 -0
  548. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
  549. package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
  550. package/src/components/SelectionControl/selection-item.spec.md +3 -3
  551. package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
  552. package/src/components/Separator/separator.spec.md +2 -2
  553. package/src/components/Separator/separator.stories.tsx +6 -27
  554. package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
  555. package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
  556. package/src/components/Sheet/sheet.spec.md +2 -2
  557. package/src/components/Sheet/sheet.tsx +9 -5
  558. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
  559. package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
  560. package/src/components/Sidebar/sidebar.spec.md +13 -15
  561. package/src/components/Sidebar/sidebar.stories.tsx +8 -7
  562. package/src/components/Sidebar/sidebar.tsx +37 -25
  563. package/src/components/Skeleton/skeleton.stories.tsx +4 -11
  564. package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
  565. package/src/components/Slider/slider.principles.stories.tsx +2 -2
  566. package/src/components/Slider/slider.spec.md +5 -5
  567. package/src/components/Slider/slider.tsx +3 -1
  568. package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
  569. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  570. package/src/components/Steps/steps.spec.md +1 -1
  571. package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
  572. package/src/components/Switch/switch.principles.stories.tsx +4 -4
  573. package/src/components/Switch/switch.spec.md +8 -8
  574. package/src/components/Switch/switch.stories.tsx +9 -24
  575. package/src/components/Switch/switch.tsx +17 -13
  576. package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
  577. package/src/components/Tabs/tabs.spec.md +1 -1
  578. package/src/components/Tabs/tabs.tsx +21 -1
  579. package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
  580. package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
  581. package/src/components/Textarea/textarea.spec.md +4 -4
  582. package/src/components/Textarea/textarea.tsx +72 -46
  583. package/src/components/TimePicker/time-columns.tsx +6 -2
  584. package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
  585. package/src/components/TimePicker/time-picker.spec.md +3 -3
  586. package/src/components/TimePicker/time-picker.tsx +16 -10
  587. package/src/components/Toast/toast.stories.tsx +7 -4
  588. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
  589. package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
  590. package/src/components/Tooltip/tooltip.spec.md +1 -1
  591. package/src/components/Tooltip/tooltip.stories.tsx +4 -39
  592. package/src/components/Tooltip/tooltip.tsx +8 -6
  593. package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
  594. package/src/components/TreeView/tree-view.spec.md +42 -11
  595. package/src/components/TreeView/tree-view.stories.tsx +1 -0
  596. package/src/components/TreeView/tree-view.tsx +322 -17
  597. package/src/index.ts +588 -60
  598. package/src/patterns/action-bar/action-bar.spec.md +9 -0
  599. package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
  600. package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
  601. package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
  602. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
  603. package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
  604. package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
  605. package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
  606. package/src/styles/tokens.css +3 -0
  607. package/src/tokens/README.md +1 -1
  608. package/src/tokens/color/color.spec.md +4 -4
  609. package/src/tokens/color/color.stories.tsx +3 -3
  610. package/src/tokens/density/density.stories.tsx +16 -3
  611. package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
  612. package/src/tokens/motion/motion.css +33 -21
  613. package/src/tokens/motion/motion.spec.md +32 -15
  614. package/src/tokens/motion/motion.stories.tsx +58 -5
  615. package/src/tokens/motion/motion.ts +7 -6
  616. package/src/tokens/motion/overlay-motion.ts +26 -0
  617. package/src/tokens/orphan-tokens.spec.md +4 -4
  618. package/src/tokens/token-system.spec.md +1 -0
  619. package/src/tokens/uiSize/uiSize.css +1 -1
  620. package/src/tokens/uiSize/uiSize.spec.md +1 -1
  621. package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
  622. package/src/tokens/utility-registry.json +160 -23
@@ -230,6 +230,118 @@ expect_silent "25. P8 nearmiss shadow-[var(--elevation-100)] → silent"
230
230
  run_hook "$PROD_TSX" 'export const C = () => <div className="max-w-[600px] grid-cols-[1fr_2fr]">x</div>'
231
231
  expect_silent "26. P8 nearmiss max-w-[600px]/grid-cols-[...](非色字 shadow)→ silent"
232
232
 
233
+ # ── 手刻 menu-item 可點列(2026-07-10 WM TypeSettingsDialog 左 rail 錨例)──
234
+ # 27. POSITIVE:手刻 button + hover:bg-neutral-hover + bg-neutral-selected 成對 → BLOCK
235
+ run_hook "$PROD_TSX" 'const cls = `flex w-full items-center gap-2 rounded-md hover:bg-neutral-hover ${sel ? "bg-neutral-selected" : ""}`; export const C = () => <button type="button" className={cls}>Task</button>'
236
+ expect_block "27. 手刻 nav row(hover+selected 成對)→ BLOCK"
237
+
238
+ # 28. NEGATIVE:同簽名 token 出現但已消費 <MenuItem>(正道)→ silent
239
+ run_hook "$PROD_TSX" 'export const C = () => <MenuItem size="sm" selected startContent={<Badge/>}>Task</MenuItem> /* hover:bg-neutral-hover bg-neutral-selected */'
240
+ expect_silent "28. 消費 <MenuItem> → silent"
241
+
242
+ # 29. NEGATIVE:只有 hover 無 selected(單純 hover row,非 menu-item family 簽名)→ silent
243
+ run_hook "$PROD_TSX" 'export const C = () => <button className="hover:bg-neutral-hover">row</button>'
244
+ expect_silent "29. 只 hover 無 selected → silent"
245
+
246
+ # 30. NEGATIVE:escape marker → silent
247
+ run_hook "$PROD_TSX" 'export const C = () => <div className="hover:bg-neutral-hover bg-neutral-selected">x</div> // @nav-row-handcraft-ok: calendar cell 非 menu 語義'
248
+ expect_silent "30. @nav-row-handcraft-ok escape → silent"
249
+
250
+ # ── 2026-07-10 批次 A(治理覆蓋 matrix 收官)──
251
+ # 31. C5 POSITIVE:亮色底 + text-white 對比配對違規 → BLOCK
252
+ run_hook "$PROD_TSX" 'export const T = () => <span className="bg-[var(--color-amber-6)] text-white size-4">A</span>'
253
+ expect_block "31. C5 亮色底+text-white 配對 → BLOCK"
254
+
255
+ # 32. C5 NEGATIVE:CAT_SOLID 正道(深字桶自帶 on-emphasis-dark)→ silent
256
+ run_hook "$PROD_TSX" 'export const T = () => <span className={`size-4 ${CAT_SOLID[hue]}`}>A</span>'
257
+ expect_silent "32. C5 消費 CAT_SOLID → silent"
258
+
259
+ # 33. C18 POSITIVE:children 計數括號串接 → BLOCK
260
+ run_hook "$PROD_TSX" 'export const H = () => <span>{group.label} ({items.length})</span>'
261
+ expect_block "33. C18 {label} ({count}) 串接 → BLOCK"
262
+
263
+ # 34. C18 NEGATIVE:aria-label 字串層(attr 非 children)→ silent
264
+ run_hook "$PROD_TSX" 'export const H = () => <span aria-label={`${label} (${count})`}>{label}</span>'
265
+ expect_silent "34. C18 aria-label 括號形 → silent"
266
+
267
+ # 35. C17 POSITIVE:vertical Separator 無 mx → BLOCK
268
+ run_hook "$PROD_TSX" 'export const B = () => <><Button>A</Button><Separator orientation="vertical" className="h-6" /><Button>B</Button></>'
269
+ expect_block "35. C17 vertical Separator 無 mx → BLOCK"
270
+
271
+ # 36. C17 NEGATIVE:h-6 mx-1 canonical → silent
272
+ run_hook "$PROD_TSX" 'export const B = () => <><Button>A</Button><Separator orientation="vertical" className="h-6 mx-1" /><Button>B</Button></>'
273
+ expect_silent "36. C17 h-6 mx-1 canonical → silent"
274
+
275
+ # 37. C20 POSITIVE:手刻 underline 連結字 → BLOCK
276
+ run_hook "$PROD_TSX" 'export const D = () => <span className="text-primary underline">upload</span>'
277
+ expect_block "37. C20 裸 underline 連結 → BLOCK"
278
+
279
+ # 38. C20 NEGATIVE:no-underline(合規移除底線)→ silent
280
+ run_hook "$PROD_TSX" 'export const D = () => <a className="no-underline text-primary">upload</a>'
281
+ expect_silent "38. C20 no-underline → silent"
282
+
283
+ # 39. C10 POSITIVE:spacer 把 Search 推最右 → BLOCK
284
+ run_hook "$PROD_TSX" 'export const T = () => <div><Button>Add</Button><span className="flex-1" /><Input placeholder="Search employees" /></div>'
285
+ expect_block "39. C10 業務 search 被推最右 → BLOCK"
286
+
287
+ # 40. C10 NEGATIVE:search 在業務層(無 spacer 前置)→ silent
288
+ run_hook "$PROD_TSX" 'export const T = () => <div><Button>Add</Button><Input placeholder="Search employees" /><span className="flex-1" /></div>'
289
+ expect_silent "40. C10 search 歸業務層 → silent"
290
+
291
+ # 41. C11 POSITIVE:DialogHeader 手放 X(雙 X)→ BLOCK
292
+ run_hook "$PROD_TSX" 'export const D = () => <DialogHeader><DialogTitle>Edit</DialogTitle><Button iconOnly startIcon={X} aria-label="Close" /></DialogHeader>'
293
+ expect_block "41. C11 DialogHeader 雙 X → BLOCK"
294
+
295
+ # 42. C11 NEGATIVE:header 操作走 actions slot → silent
296
+ run_hook "$PROD_TSX" 'export const D = () => <DialogHeader actions={<Button iconOnly startIcon={X} aria-label="Prev" />}><DialogTitle>Edit</DialogTitle></DialogHeader>'
297
+ expect_silent "42. C11 actions slot → silent"
298
+
299
+ # 43. C12 POSITIVE:Select 硬寬 w-36 → BLOCK
300
+ run_hook "$PROD_TSX" 'export const F = () => <Select className="w-36" options={opts} />'
301
+ expect_block "43. C12 Select 硬寬 w-36 → BLOCK"
302
+
303
+ # 44. C12 NEGATIVE:width="hug" 語義軸 → silent
304
+ run_hook "$PROD_TSX" 'export const F = () => <Select width="hug" options={opts} />'
305
+ expect_silent "44. C12 width=hug → silent"
306
+
307
+ # 45. named-import 除鏽 POSITIVE:無 DS. 前綴的 LinkInput placeholder-only 也要抓 → BLOCK
308
+ run_hook "$PROD_TSX" 'export const L = () => <LinkInput placeholder="https://" />'
309
+ expect_block "45. named-import <LinkInput placeholder-only → BLOCK(除鏽)"
310
+
311
+ # ── C19 兩欄 dialog 共用捲軸(2026-07-10 user 拍板組合 canonical)──
312
+ # 46. POSITIVE:兩欄(border-l)+ 只有 1 個 ScrollArea = 共用捲軸 → BLOCK
313
+ run_hook "$PROD_TSX" 'export const D = () => <DialogBody><ScrollArea><div className="flex"><div>main</div><aside className="border-l">meta</aside></div></ScrollArea></DialogBody>'
314
+ expect_block "46. C19 兩欄共用單一 ScrollArea → BLOCK"
315
+
316
+ # 47. NEGATIVE:各欄自帶 ScrollArea(組合 canonical)→ silent
317
+ run_hook "$PROD_TSX" 'export const D = () => <DialogBody><div className="flex"><ScrollArea>main</ScrollArea><aside className="border-l"><ScrollArea>meta</ScrollArea></aside></div></DialogBody>'
318
+ expect_silent "47. C19 各欄自帶 ScrollArea → silent"
319
+
320
+ # 48. NEGATIVE:escape → silent
321
+ run_hook "$PROD_TSX" 'export const D = () => <DialogBody><div className="flex border-l">x</div></DialogBody> // @two-pane-dialog-ok: 非兩欄,版面裝飾線'
322
+ expect_silent "48. C19 @two-pane-dialog-ok escape → silent"
323
+
324
+ # ── C7 SelectMenu 直用 + C13 手刻 section header(2026-07-10 收官)──
325
+ # 49. C7 POSITIVE:<SelectMenu> 直用 → BLOCK
326
+ run_hook "$PROD_TSX" 'export const M = () => <SelectMenu options={opts} onSelect={pick} />'
327
+ expect_block "49. C7 <SelectMenu> 直用 → BLOCK"
328
+
329
+ # 50. C7 NEGATIVE:<Select>(正道)→ silent
330
+ run_hook "$PROD_TSX" 'export const M = () => <Select options={opts} onChange={pick} />'
331
+ expect_silent "50. C7 <Select> 正道 → silent"
332
+
333
+ # 51. C13 POSITIVE:手刻可收合標題列(Chevron + justify-between + button)→ BLOCK
334
+ run_hook "$PROD_TSX" 'export const H = () => <button onClick={toggle} className="flex w-full items-center justify-between"><span>Description</span><ChevronDown className="size-4" /></button>'
335
+ expect_block "51. C13 手刻可收合標題列 → BLOCK"
336
+
337
+ # 52. C13 NEGATIVE:共用 SectionHeader 元件(正道)→ silent
338
+ run_hook "$PROD_TSX" 'export const H = () => <SectionHeader title="Description" collapsed={c} onToggle={toggle} />'
339
+ expect_silent "52. C13 共用 SectionHeader → silent"
340
+
341
+ # 53. C13 NEGATIVE:escape(非 section 標題語義)→ silent
342
+ run_hook "$PROD_TSX" 'export const P = () => <button onClick={next} className="flex justify-between">next<ChevronRight /></button> // @section-header-ok: 分頁導航非 section 標題'
343
+ expect_silent "53. C13 @section-header-ok escape → silent"
344
+
233
345
  echo ""
234
346
  echo "=== Summary ==="
235
347
  echo "Passed: $PASS / $((PASS + FAIL))"
@@ -161,12 +161,19 @@ expect_pass_silent "N4. DS internal stories → excluded silent"
161
161
  run_hook "Read" "$CONSUMER_STORY" "$CONTENT_VIOLATION"
162
162
  expect_pass_silent "N5. tool=Read → silent"
163
163
 
164
- # N6. over-broad guard A:bare <Dialog>(no DS. namespace prefix)→ silent
164
+ # N6. over-broad guard A:bare <Dialog>(no DS. namespace prefix)from consumer-local import → silent
165
165
  # consumer 用自己的 local Dialog,不是高風險 DS primitive → 不該 fire
166
166
  CONTENT_BARE='import { Dialog } from "./local-dialog";
167
167
  export const Basic = () => <Dialog open>hi</Dialog>;'
168
168
  run_hook "Write" "$CONSUMER_STORY" "$CONTENT_BARE"
169
- expect_pass_silent "N6. bare <Dialog> (no DS. prefix) → silent (over-broad guard)"
169
+ expect_pass_silent "N6. bare <Dialog> (local import) → silent (over-broad guard)"
170
+
171
+ # P5. named-import 除鏽 POSITIVE(2026-07-10):bare <Dialog> 但由 DS package named-import 進來
172
+ # → 是真 DS Dialog(fork 慣用 named import 繞過 <DS.> 前綴)→ 無 marker 必 BLOCK
173
+ CONTENT_NAMED='import { Dialog, Button } from "@qijenchen/design-system";
174
+ export const Basic = () => <Dialog open><Button>ok</Button></Dialog>;'
175
+ run_hook "Write" "$CONSUMER_STORY" "$CONTENT_NAMED"
176
+ expect_block "P5. named-import <Dialog> from DS pkg 無 marker → BLOCK" "CONSUMER-STORY-BASELINE BLOCKER"
170
177
 
171
178
  # N7. over-broad guard B:comment / prose mentioning "Dialog DataTable Sheet" but no JSX usage → silent
172
179
  CONTENT_PROSE='// This story demonstrates a layout. We avoid Dialog and DataTable here.
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+ # test_check_dynamic_tailwind_class.sh — 動態 Tailwind class 哨測試
3
+ # (2026-07-10 補 hook-test-coverage debt;hook 2026-07-09 建,anchor = h-table-row-${size} row 塌)
4
+ set -uo pipefail
5
+ cd "$(dirname "$0")/../../.."
6
+ HOOK=".claude/hooks/check_dynamic_tailwind_class.sh"
7
+ PASS=0; FAIL=0; FAILED_TESTS=""
8
+
9
+ TMP_DIR=$(mktemp -d)
10
+ trap 'rm -rf "$TMP_DIR"' EXIT
11
+ export CLAUDE_PROJECT_DIR="$TMP_DIR"
12
+ mkdir -p "$TMP_DIR/.claude/logs"
13
+
14
+ PROD_TSX="/Users/x/proj/packages/design-system/src/components/DataTable/data-table.tsx"
15
+
16
+ run_hook() {
17
+ local file_path="$1"; local content="$2"
18
+ local payload
19
+ payload=$(jq -n --arg fp "$file_path" --arg c "$content" \
20
+ '{tool_name:"Edit", tool_input:{file_path:$fp, new_string:$c}}')
21
+ STDERR=$(mktemp)
22
+ set +e
23
+ printf '%s' "$payload" | bash "$HOOK" >/dev/null 2>"$STDERR"
24
+ EXIT=$?
25
+ set -e
26
+ STDERR_TEXT=$(cat "$STDERR" 2>/dev/null); rm -f "$STDERR"
27
+ }
28
+
29
+ expect_block() {
30
+ local name="$1"
31
+ if [ "$EXIT" = "2" ]; then echo " PASS $name"; PASS=$((PASS+1))
32
+ else echo " FAIL $name (expected exit=2, got exit=$EXIT)"; FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"; fi
33
+ }
34
+ expect_silent() {
35
+ local name="$1"
36
+ if [ "$EXIT" = "0" ] && [ -z "$STDERR_TEXT" ]; then echo " PASS $name"; PASS=$((PASS+1))
37
+ else echo " FAIL $name (expected silent exit=0, got exit=$EXIT, stderr=${STDERR_TEXT:+non-empty})"; FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"; fi
38
+ }
39
+
40
+ # 1. POSITIVE:病根錨例 h-table-row-${size}(class 名含插值)→ BLOCK
41
+ run_hook "$PROD_TSX" 'const cls = `h-table-row-${size} flex`'
42
+ expect_block "1. h-table-row-\${size} → BLOCK"
43
+
44
+ # 2. POSITIVE:間距 utility gap-${g} → BLOCK
45
+ run_hook "$PROD_TSX" 'const cls = `flex gap-${g}`'
46
+ expect_block "2. gap-\${g} → BLOCK"
47
+
48
+ # 3. NEGATIVE:正解 literal map → silent
49
+ run_hook "$PROD_TSX" "const cls = { sm: 'h-table-row-sm', md: 'h-table-row-md', lg: 'h-table-row-lg' }[size]"
50
+ expect_silent "3. literal class 對照表 → silent"
51
+
52
+ # 4. NEGATIVE:arbitrary value 內插值(是值不是 class 名)→ silent
53
+ run_hook "$PROD_TSX" 'const cls = `h-[calc(100%_-_${offset}px)]`'
54
+ expect_silent "4. h-[calc(\${x})] arbitrary → silent"
55
+
56
+ # 5. NEGATIVE:var() 內插值 → silent
57
+ run_hook "$PROD_TSX" 'const cls = `w-[var(--col-${i})]`'
58
+ expect_silent "5. w-[var(--x-\${i})] → silent"
59
+
60
+ # 6. NEGATIVE:色彩 utility 不在 scope(hook 只鎖尺寸/間距)→ silent
61
+ run_hook "$PROD_TSX" 'const cls = `text-${color}`'
62
+ expect_silent "6. text-\${color}(非尺寸間距)→ silent"
63
+
64
+ # 7. NEGATIVE:escape 註解 → silent
65
+ run_hook "$PROD_TSX" 'const cls = `size-${px}` // @dynamic-tailwind-allow: 傳給 canvas 非 class'
66
+ expect_silent "7. @dynamic-tailwind-allow escape → silent"
67
+
68
+ # 8. NEGATIVE:非 production path(tests/)→ silent
69
+ run_hook "/Users/x/proj/scripts/gen-something.mjs" 'const cls = `h-${x}`'
70
+ expect_silent "8. 非 tsx production path → silent"
71
+
72
+ echo ""
73
+ echo "=== Summary ==="
74
+ echo "Passed: $PASS / $((PASS + FAIL))"
75
+ if [ "$FAIL" -gt 0 ]; then printf "Failed:%b\n" "$FAILED_TESTS"; exit 1; fi
76
+ exit 0
@@ -182,6 +182,30 @@ expect_not_block "N8. empty content → not blocked"
182
182
  run_hook_bypass "Write" "$CONSUMER" "content" "$C_3DISTINCT"
183
183
  expect_not_block "N9. CLAUDE_BYPASS_ESCAPE_MARKER_AUDIT=1 override → not blocked"
184
184
 
185
+ # ── R-series:repo 級累計 ratchet(2026-07-08 WM 戰役 R4)──────────────────────
186
+ # 存量 ≥10(apps/** 全 repo)後,只擋「本次 edit 再新增 marker」;無 marker edit 不 brick。
187
+ mkdir -p "$TMP_DIR/apps/work/src"
188
+ for i in 1 2 3 4 5 6; do
189
+ printf '// @ds-misuse-allow: seeded reason %s\n// @layout-space-magic-ok: seeded reason %sb\n' "$i" "$i" \
190
+ > "$TMP_DIR/apps/work/src/seed$i.tsx"
191
+ done
192
+
193
+ # R1. 存量 12 ≥ cap 10 + 本次新增 1 marker → BLOCK(ratchet)
194
+ run_hook "Write" "/repo/apps/work/src/new.tsx" "content" '<div /> // @ds-misuse-allow: one more'
195
+ expect_block "R1. repo 存量 12 ≥ cap + edit 加 marker → blocked (ratchet)" "ESCAPE-MARKER-REPO-RATCHET"
196
+
197
+ # R2. 存量 12 ≥ cap 但本次 edit 無 marker → not blocked(不因存量 brick 無關 edit)
198
+ run_hook "Write" "/repo/apps/work/src/new.tsx" "content" '<div className="flex" />'
199
+ expect_not_block "R2. repo 存量 ≥ cap 但 edit 無 marker → not blocked"
200
+
201
+ # R3. 存量降到 4 < cap + 本次加 1 marker → not blocked
202
+ rm -f "$TMP_DIR/apps/work/src/seed3.tsx" "$TMP_DIR/apps/work/src/seed4.tsx" \
203
+ "$TMP_DIR/apps/work/src/seed5.tsx" "$TMP_DIR/apps/work/src/seed6.tsx"
204
+ run_hook "Write" "/repo/apps/work/src/new.tsx" "content" '<div /> // @ds-misuse-allow: legit case'
205
+ expect_not_block "R3. repo 存量 4 < cap + edit 加 marker → not blocked"
206
+
207
+ rm -rf "$TMP_DIR/apps"
208
+
185
209
  echo ""
186
210
  echo "=== Summary ==="
187
211
  echo "Passed: $PASS / $((PASS + FAIL))"
@@ -1,11 +1,13 @@
1
1
  #!/bin/bash
2
- # Tests for check_field_family_invariants.sh — merged 4 sub-rules(A.1-A.4)
2
+ # Tests for check_field_family_invariants.sh — merged sub-rules(A.1-A.4 + A.6)
3
3
  #
4
- # Coverage(每 sub-rule pass + block 各 1 case,共 12 case):
4
+ # Coverage(每 sub-rule pass + block 各 1 case):
5
5
  # A.1 naked row-mode propagation:pass / block / allowlist
6
6
  # A.2 FieldControlGroup wrapper child:pass / block / allowlist
7
7
  # A.3 Field state ring SSOT:pass / 3 block(shadow inset / outline / per-control open)
8
8
  # A.4 disabled placeholder color:pass / 1 stderr-warn(exit 0)/ allowlist
9
+ # A.6 空值顯示 SSOT(2026-07-08 半形 hyphen):非 owner import EMPTY_DISPLAY block /
10
+ # owner skip / 全形 em dash block / 半形 pass / allowlist
9
11
  # non-target:non-tsx skip / SSOT host skip(field-wrapper.tsx)
10
12
 
11
13
  set -u
@@ -183,6 +185,29 @@ else
183
185
  FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - A.4.3"
184
186
  fi
185
187
 
188
+ echo ""
189
+ echo "=== A.6 空值顯示 SSOT(2026-07-08 半形 hyphen)==="
190
+
191
+ # 17. 非 owner import EMPTY_DISPLAY → BLOCK(應消費 useFieldEmptyDisplay hook 分流)
192
+ run_hook "/r/packages/design-system/src/components/Bad/bad.tsx" "import { EMPTY_DISPLAY } from '@/design-system/components/Field/field-wrapper'"
193
+ expect_exit "A.6.1 非 owner import EMPTY_DISPLAY → BLOCK" 2 "EMPTY_DISPLAY 直引"
194
+
195
+ # 18. owner field-context.ts import EMPTY_DISPLAY → pass(SSOT owner skip)
196
+ run_hook "/r/packages/design-system/src/components/Field/field-context.ts" "import { EMPTY_DISPLAY } from './field-wrapper'"
197
+ expect_exit "A.6.1 owner field-context.ts import → pass" 0
198
+
199
+ # 19. components tsx hardcode 全形 em dash '—' → BLOCK
200
+ run_hook "/r/packages/design-system/src/components/Bad/bad.tsx" "const cls = value ?? '—'"
201
+ expect_exit "A.6.2 hardcode 全形 em dash → BLOCK" 2 "全形 em dash"
202
+
203
+ # 20. 半形 hyphen '-' → pass(非全形,不觸發)
204
+ run_hook "/r/packages/design-system/src/components/Bad/bad.tsx" "const sep = '-'"
205
+ expect_exit "A.6.2 半形 hyphen → pass" 0
206
+
207
+ # 21. allowlist → pass
208
+ run_hook "/r/packages/design-system/src/components/Bad/bad.tsx" "const cls = value ?? '—' // @empty-display-allow: legacy N/A marker"
209
+ expect_exit "A.6 allowlist → pass" 0
210
+
186
211
  echo ""
187
212
  echo "=== Skip cases ==="
188
213
 
@@ -56,6 +56,18 @@ expect_warn() {
56
56
  fi
57
57
  }
58
58
 
59
+ # #71 soft WARN tier(micro_gap / fraction):exit 0(不 block)+ stderr 含 'soft flag'
60
+ expect_soft_flag() {
61
+ local name="$1"
62
+ if [ "$EXIT" = "0" ] && echo "$STDERR_TEXT" | grep -qF "soft flag"; then
63
+ echo " PASS $name"; PASS=$((PASS+1))
64
+ else
65
+ echo " FAIL $name (expected exit=0 + 'soft flag', got exit=$EXIT)"
66
+ echo " --- stderr ---"; echo "$STDERR_TEXT" | sed 's/^/ /'; echo " --- end ---"
67
+ FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"
68
+ fi
69
+ }
70
+
59
71
  echo "=== check_opacity_token_usage tests ==="
60
72
 
61
73
  # 1. raw opacity-30 → warn
@@ -101,6 +113,33 @@ const b = "opacity-75"
101
113
  '
102
114
  expect_warn "7. multi opacity-N values → warn" "opacity-25"
103
115
 
116
+ # ── #71 micro_gap / fraction soft WARN tier(2026-07-11 接線)──────────────────
117
+ FP71="/repo/packages/design-system/src/components/Calendar/calendar.tsx"
118
+
119
+ # 8. gap-0.5(micro gap)→ soft flag(exit 0,非 block)
120
+ run_hook "$FP71" 'const a = <div className="gap-0.5" />'
121
+ expect_soft_flag "8. gap-0.5 micro gap → soft WARN(非 block)"
122
+
123
+ # 9. w-1/3(registry fraction)→ soft flag(exit 0)
124
+ run_hook "$FP71" 'const a = <div className="w-1/3" />'
125
+ expect_soft_flag "9. w-1/3 registry fraction → soft WARN"
126
+
127
+ # 10. w-1/2(合法,不在 registry 14 條)→ silent(不誤殺)
128
+ run_hook "$FP71" 'const a = <div className="w-1/2" />'
129
+ expect_pass_silent "10. w-1/2(合法留白)→ silent 不誤殺"
130
+
131
+ # 11. gap-2(合法)→ silent
132
+ run_hook "$FP71" 'const a = <div className="gap-2" />'
133
+ expect_pass_silent "11. gap-2(合法)→ silent"
134
+
135
+ # 12. 硬 violation + gap-0.5 → exit 2(hard block 不被 soft tier 弱化)
136
+ run_hook "$FP71" 'const a = <div className="text-muted-foreground gap-0.5" />'
137
+ expect_warn "12. 硬 violation + gap-0.5 → exit 2 block" "shadcn alias"
138
+
139
+ # 13. gap-0.5 + @token-registry-ok escape → silent
140
+ run_hook "$FP71" 'const a = <div className="gap-0.5" /> // @token-registry-ok: skeleton bone'
141
+ expect_pass_silent "13. gap-0.5 + escape → silent"
142
+
104
143
  echo ""
105
144
  echo "=== Summary ==="
106
145
  echo "Passed: $PASS / $((PASS + FAIL))"
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+ # test_check_tabs_content_chrome_body_double_gap.sh — overlay-body layout-space 哨測試
3
+ # (2026-07-10 補 hook-test-coverage debt;hook 2026-07-01 建,anchor = 專案設定 Dialog 雙 tight)
4
+ # 注意:本 hook 是 PostToolUse「讀完整檔」型(防 partial-edit 盲區)→ 測試必寫真實 temp 檔,
5
+ # 且路徑必須匹配 scope regex(packages/design-system/src/ 或 /apps/)。
6
+ set -uo pipefail
7
+ cd "$(dirname "$0")/../../.."
8
+ HOOK=".claude/hooks/check_tabs_content_chrome_body_double_gap.sh"
9
+ PASS=0; FAIL=0; FAILED_TESTS=""
10
+
11
+ TMP_DIR=$(mktemp -d)
12
+ trap 'rm -rf "$TMP_DIR"' EXIT
13
+ export CLAUDE_PROJECT_DIR="$TMP_DIR"
14
+ mkdir -p "$TMP_DIR/.claude/logs"
15
+
16
+ # scope 內的真實 temp 檔路徑(hook 讀 disk)
17
+ DS_DIR="$TMP_DIR/packages/design-system/src/components/Dialog"
18
+ mkdir -p "$DS_DIR"
19
+
20
+ run_hook_file() {
21
+ local file_path="$1"; local content="$2"
22
+ mkdir -p "$(dirname "$file_path")"
23
+ printf '%s' "$content" > "$file_path"
24
+ local payload
25
+ payload=$(jq -n --arg fp "$file_path" --arg c "$content" \
26
+ '{tool_name:"Edit", tool_input:{file_path:$fp, new_string:$c}}')
27
+ STDERR=$(mktemp)
28
+ set +e
29
+ printf '%s' "$payload" | bash "$HOOK" >/dev/null 2>"$STDERR"
30
+ EXIT=$?
31
+ set -e
32
+ STDERR_TEXT=$(cat "$STDERR" 2>/dev/null); rm -f "$STDERR"
33
+ rm -f "$file_path"
34
+ }
35
+
36
+ expect_block() {
37
+ local name="$1"
38
+ if [ "$EXIT" = "2" ]; then echo " PASS $name"; PASS=$((PASS+1))
39
+ else echo " FAIL $name (expected exit=2, got exit=$EXIT)"; FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"; fi
40
+ }
41
+ expect_silent() {
42
+ local name="$1"
43
+ if [ "$EXIT" = "0" ] && [ -z "$STDERR_TEXT" ]; then echo " PASS $name"; PASS=$((PASS+1))
44
+ else echo " FAIL $name (expected silent exit=0, got exit=$EXIT, stderr=${STDERR_TEXT:+non-empty})"; FAIL=$((FAIL+1)); FAILED_TESTS="${FAILED_TESTS}\n - $name"; fi
45
+ }
46
+
47
+ # 1. POSITIVE(Check 1 錨例):chrome body 內 TabsContent 無 mt-0 → 雙重 gap → BLOCK
48
+ run_hook_file "$DS_DIR/case1.stories.tsx" '<DialogBody><Tabs value={t}><TabsContent value="a"><p>內容</p></TabsContent></Tabs></DialogBody>'
49
+ expect_block "1. DialogBody 內 TabsContent 無 mt-0 → BLOCK"
50
+
51
+ # 2. NEGATIVE:TabsContent 帶 mt-0(ownership 轉移給 body)→ silent
52
+ run_hook_file "$DS_DIR/case2.stories.tsx" '<DialogBody><Tabs value={t}><TabsContent value="a" className="mt-0"><p>內容</p></TabsContent></Tabs></DialogBody>'
53
+ expect_silent "2. TabsContent className=mt-0 → silent"
54
+
55
+ # 3. NEGATIVE:TabsContent 不在 chrome body 內(頁面級 Tabs)→ silent
56
+ run_hook_file "$DS_DIR/case3.stories.tsx" '<Tabs value={t}><TabsList>…</TabsList><TabsContent value="a"><p>內容</p></TabsContent></Tabs>'
57
+ expect_silent "3. 頁面級 Tabs(無 chrome body)→ silent"
58
+
59
+ # 4. POSITIVE(Check 3 root 簽名):TabsList 手塞 DialogBody 同檔且無 tabsSlot → BLOCK
60
+ run_hook_file "$DS_DIR/case4.stories.tsx" '<DialogBody><TabsList size="sm"><TabsTrigger value="a">A</TabsTrigger></TabsList><TabsContent value="a" className="mt-0">x</TabsContent></DialogBody>'
61
+ expect_block "4. TabsList 手塞 chrome body 無 tabsSlot → BLOCK(root)"
62
+
63
+ # 5. NEGATIVE:escape 註解 → silent
64
+ run_hook_file "$DS_DIR/case5.stories.tsx" '{/* @tabs-content-gap-ok: 內容層分頁非 dialog chrome */}
65
+ <DialogBody><Tabs value={t}><TabsContent value="a">x</TabsContent></Tabs></DialogBody>'
66
+ expect_silent "5. @tabs-content-gap-ok escape → silent"
67
+
68
+ # 6. NEGATIVE:scope 外路徑(非 DS-src / apps)→ silent
69
+ run_hook_file "$TMP_DIR/docs/example.tsx" '<DialogBody><TabsContent value="a">x</TabsContent></DialogBody>'
70
+ expect_silent "6. scope 外路徑 → silent"
71
+
72
+ echo ""
73
+ echo "=== Summary ==="
74
+ echo "Passed: $PASS / $((PASS + FAIL))"
75
+ if [ "$FAIL" -gt 0 ]; then printf "Failed:%b\n" "$FAILED_TESTS"; exit 1; fi
76
+ exit 0
@@ -45,7 +45,7 @@
45
45
 
46
46
  | 真缺項 | 補的形式 | Commit |
47
47
  |---|---|---|
48
- | #13 i18n 硬寫字串 | `.claude/hooks/check_hardcoded_strings.sh` PostToolUse,flag DS primitive tsx(非 stories)CJK ≥ 3 chars / 英文 sentence-case label;支援 `// i18n-allow: {rationale}` 白名單 | 本次 session |
48
+ | #13 i18n 硬寫字串 | `post_edit_dispatcher.sh → lib/_hardcoded_strings.sh` PostToolUse flag(2026-05-13 由獨立 hook `check_hardcoded_strings.sh` folded 進 dispatcher lib),flag DS primitive tsx(非 stories)CJK ≥ 3 chars / 英文 sentence-case label;支援 `// i18n-allow: {rationale}` 白名單 | 本次 session |
49
49
  | #3 Controlled / Uncontrolled + #12 Form dual-mode | `design-system-audit` Dim 26(新 Group J)— 掃 form + overlay 元件 value/defaultValue / open/defaultOpen / checked/defaultChecked 的 pair 完整性;V1-V4 violation types | 本次 session |
50
50
  | #23 edge case(null / empty / rapid / success) | `/ux-audit` Phase 5 從 3 態 → 5 態 + null-safety + rapid-interaction + edge case corollary | 本次 session |
51
51
 
@@ -18,6 +18,7 @@
18
18
  | 資料表格(含 header / sorting / sticky) | `<table><thead>...</thead><tbody>...</tbody></table>` | `<DataTable columns={...} data={...} />` |
19
19
  | 檔案上傳列表 | `<div>filename</div><ProgressBar /><Paperclip />` | `<FileItem mode="compact" />` or `<FileUpload>` |
20
20
  | 表單欄位(label + control + error) | `<label>...</label><input/><span className="text-error">...</span>` | `<Field><FieldLabel>...<Input />...<FieldError/>` |
21
+ | 表單提交驗證(何時顯錯 / 提交可點性) | 手刻 `useState(showErrors)` + `submitAttempt` 旗標自組顯錯時機 | `useFormValidation`(Field 家族 hook,`intent:'create'` = 提交恆可點、點擊時 validate 顯錯;搭 `<FieldError>`)|
21
22
  | 全頁 / 區域 loading | `<div className="absolute inset-0 flex center"><Spinner /></div>` | `<Empty icon={<CircularProgress />} description="..." />` |
22
23
  | 確認對話框 | raw `<div className="fixed inset-0 bg-black/50">...<button>OK</button>` | `<Dialog>` + `<DialogHeader>` etc |
23
24
  | 分隔線 | `<hr className="..." />` or `<div className="h-px bg-..."/>` | `<Separator />`(必要時)or CSS border(見 separator.spec) |
@@ -60,7 +61,7 @@
60
61
  - 以上都沒命中 → 才可自建,但 **建完要立刻回來加行**(防下一個人又重造輪子)
61
62
  - **本規則同樣適用 story / consumer / exploration code**:不 hand-craft 已有 prop 能做的事(如 Input loading 走 `loading` prop 不自刻 `<div className="relative"><input/><div className="absolute">` / 全頁 loading 走 `<Empty icon={<CircularProgress/>}/>` 不自刻 `absolute inset-0`)。遇缺口**回元件 spec 擴 API**,不自刻繞過 — hand-craft 視覺對齊 bug 上游
62
63
 
63
- 具體 anti-pattern signals → `/design-system-audit` Dim 21;pixel-level 視覺 regression(API 用對但視覺仍跑掉)→ `/visual-audit`(D5)抓(原 memory `project_pending_tasks` 已 retire)。
64
+ 具體 anti-pattern signals → `design-system-audit/references/audit-prompts.md`「L1. 手刻繞 DS canonical」+ Dim 71 consumer 手刻(Pattern 10;現行 Dim 21 已是「連續 item list wrapper gap」,勿誤指);pixel-level 視覺 regression(API 用對但視覺仍跑掉)→ `/visual-audit`(D5)抓(原 memory `project_pending_tasks` 已 retire)。
64
65
 
65
66
  ---
66
67
 
@@ -0,0 +1,145 @@
1
+ {
2
+ "_meta": {
3
+ "invariant": "每類被抓過的 failure class 必須終有 ship 到 consumer 的機械防線(user 2026-07-10 verbatim「建立治理的基本原則」)。status 三態:protected(已有 MECHANICAL_CONSUMER / DS_API_FIXED 防線)/ remediating(必帶 plan 指標)/ judgment(regex 不可判,必帶 auditDim 兜底)。gate = scripts/audit-failure-class-coverage.mjs --check(deep-audit dim 91 chain)。",
4
+ "source": ".claude/logs/failure-class-coverage-matrix.json(2026-07-10 41-agent 對抗 workflow,每 verdict cite 驗證)",
5
+ "addRule": "新 failure class(deep-audit / user 抓 / codex 抓)→ 本 registry 加 row;沒 row 或 status 缺 = gate 紅燈。remediation 落地後把 status 升 protected 並記 landedAt。"
6
+ },
7
+ "classes": [
8
+ {
9
+ "id": "phantom-layout-token",
10
+ "name": "幻覺 layout token / utility",
11
+ "status": "protected",
12
+ "note": "check_layout_space_magic_numbers PHANTOM 白名單(SHIP_AS_IS)+ opacity hook 第 10 類幻覺 state 尾綴(2026-07-10)"
13
+ },
14
+ {
15
+ "id": "handcraft-mini-table",
16
+ "name": "手刻 mini-table(grid-cols 黏死欄寬)",
17
+ "status": "protected",
18
+ "note": "r3 偽表格簽名 + magic-hook grid-cols px(皆 SHIP_AS_IS)"
19
+ },
20
+ {
21
+ "id": "handcraft-menu-item-row",
22
+ "name": "手刻 menu-item 可點列",
23
+ "status": "protected",
24
+ "landedAt": "2026-07-10",
25
+ "note": "根因 MenuItem startContent(beta.84)+ r3 nav-row 簽名(hover+selected 成對)"
26
+ },
27
+ {
28
+ "id": "export-chain-break",
29
+ "name": "export 斷鏈逼手刻(R2)",
30
+ "status": "protected",
31
+ "note": "DS_API_FIXED — barrel generator + preflight --check drift gate;beta.84 發版後 consumer 正式接上"
32
+ },
33
+ {
34
+ "id": "contrast-pair-violation",
35
+ "name": "對比配對違規(亮色底 × text-white)",
36
+ "status": "protected",
37
+ "landedAt": "2026-07-10",
38
+ "note": "r3 C5 簽名 → CAT_SOLID pair"
39
+ },
40
+ {
41
+ "id": "handcraft-form-validation",
42
+ "name": "手刻表單驗證 state",
43
+ "status": "protected",
44
+ "note": "r3 useFormValidation 零消費簽名(SHIP_AS_IS)"
45
+ },
46
+ {
47
+ "id": "selectmenu-direct-use",
48
+ "name": "SelectMenu internal 直用",
49
+ "status": "protected",
50
+ "note": "r3 C7 簽名(<SelectMenu 直用 → BLOCK,escape @selectmenu-direct-ok:;select-menu.spec.md:53 明文禁直用特例)",
51
+ "landedAt": "2026-07-10"
52
+ },
53
+ {
54
+ "id": "handcraft-header-tabs",
55
+ "name": "頁內手刻 header+TabsList(未走 tabsSlot)",
56
+ "status": "judgment",
57
+ "note": "dialog/surface 半邊已有 check_tabs_content_chrome_body_double_gap P0(SHIP_AS_IS);頁內 h2+TabsList 存在合法場景(TypeSettings 內容層分頁 @tabs-content-gap-ok 錨例)= context 判斷,倉促 regex = 誤殺",
58
+ "auditDim": "product-ui-audit + header-canonical.spec.md Rule W4"
59
+ },
60
+ {
61
+ "id": "spacing-tier-semantic",
62
+ "name": "spacing 親疏語義誤用(tier 選錯)",
63
+ "status": "judgment",
64
+ "auditDim": "90(layout-space macro judgment sweep)+ product-ui-audit",
65
+ "note": "合法 token 用錯 tier = context 判斷,regex 不可判;magic/phantom 機械半邊已 protected"
66
+ },
67
+ {
68
+ "id": "search-action-position",
69
+ "name": "業務 search 被推工具層位置",
70
+ "status": "protected",
71
+ "landedAt": "2026-07-10",
72
+ "note": "r3 C10 簽名(spacer+Search Input);業務 vs 工具判定本身 judgment → escape @search-right-ok"
73
+ },
74
+ {
75
+ "id": "dialog-chrome-double-x",
76
+ "name": "dialog chrome 雙 X / header 操作不走 actions",
77
+ "status": "protected",
78
+ "landedAt": "2026-07-10",
79
+ "note": "r3 C11 簽名(DialogHeader 250 字窗)"
80
+ },
81
+ {
82
+ "id": "field-width-misuse",
83
+ "name": "Field 家族硬寬 / hug-fill 語義",
84
+ "status": "protected",
85
+ "landedAt": "2026-07-10",
86
+ "note": "硬寬 w-N 機械(r3 C12);hug vs fill 語義選擇 = judgment 半邊歸 product-ui-audit"
87
+ },
88
+ {
89
+ "id": "handcraft-section-header",
90
+ "name": "手刻可收合 section header",
91
+ "status": "protected",
92
+ "note": "R3-7 拍板 codify 進 item-anatomy.spec.md「可收合 section header 組合 canonical」(組合非元件,隨 npm ship)+ r3 C13 簽名(Chevron+justify-between+可點且無共用元件 → BLOCK)",
93
+ "landedAt": "2026-07-10"
94
+ },
95
+ {
96
+ "id": "avatar-anatomy-misuse",
97
+ "name": "avatar row-context 直用(未走 ItemAvatar/PersonValue 鏈)",
98
+ "status": "judgment",
99
+ "note": "前置已清:PersonValue/PersonDisplay/PersonAvatarTag 2026-07-10 補進 export 面(probe 驗 root barrel 解析)= 正道可 import;「row context 內 raw Avatar」判定 = context 判斷,regex 不可判(Avatar 合法 standalone 場景遍地)",
100
+ "auditDim": "product-ui-audit + item-anatomy.spec.md:178(Prefix 垂直對齊)"
101
+ },
102
+ {
103
+ "id": "datatable-density-structure",
104
+ "name": "DataTable 密度/tree 佔位/inline-create idle 未消費",
105
+ "status": "judgment",
106
+ "note": "tree 佔位半邊 DS_API_FIXED(data-table.tsx sibling-aware,beta.84 生效);size 密度選擇與 idle 列樣式 = context 判斷(嵌入式 vs 主表格),spec 隨 npm ship 供讀",
107
+ "auditDim": "product-ui-audit + data-table.spec.md:71/80(size 密度)+ :360(inline-create idle)"
108
+ },
109
+ {
110
+ "id": "always-edit-cell",
111
+ "name": "恆-edit cell(display 態渲染 edit 控件)",
112
+ "status": "judgment",
113
+ "note": "機械半邊已上:story-baseline-registry antiPattern datatable-always-edit-cell(cell: 直渲 edit 控件 → R8 BLOCK,unless onCellCommit/editable/display);custom cell 元件包裹子集 regex 看不進去 + RoleCell 拍板反例證實 context 判斷 → judgment 兜底",
114
+ "auditDim": "product-ui-audit + data-table.spec.md:373(indicator A 案)"
115
+ },
116
+ {
117
+ "id": "separator-geometry",
118
+ "name": "分隔線幾何(黏按鈕無 mx)",
119
+ "status": "protected",
120
+ "landedAt": "2026-07-10",
121
+ "note": "r3 C17 簽名 + magic-hook divider 行豁免(治理自我打架修正)"
122
+ },
123
+ {
124
+ "id": "count-label-concat",
125
+ "name": "計數括號串接(children 層)",
126
+ "status": "protected",
127
+ "landedAt": "2026-07-10",
128
+ "note": "r3 C18 簽名(children 錨定,aria attr 合法)"
129
+ },
130
+ {
131
+ "id": "two-pane-dialog",
132
+ "name": "兩欄 dialog 版型 canonical 缺席",
133
+ "status": "protected",
134
+ "landedAt": "2026-07-10",
135
+ "note": "user 拍板:組合非元件(對齊 Atlassian/MUI composition verdict)→ overlay-surface.spec.md「兩欄 dialog 組合 canonical」(隨 npm ship)+ r3 C19 簽名(共用捲軸機械攔)"
136
+ },
137
+ {
138
+ "id": "handcraft-link-underline",
139
+ "name": "連結字手刻 underline",
140
+ "status": "protected",
141
+ "landedAt": "2026-07-10",
142
+ "note": "r3 C20 簽名(no-underline / hover:underline 形不誤殺)"
143
+ }
144
+ ]
145
+ }