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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (492) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-group.d.ts +47 -0
  50. package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
  51. package/dist/components/DataTable/data-table-filter-group.js +154 -0
  52. package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
  53. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  54. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  55. package/dist/components/DataTable/data-table-filter-panel.js +5 -328
  56. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  57. package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -0
  58. package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
  59. package/dist/components/DataTable/data-table-filter-value-picker.js +187 -0
  60. package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
  61. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  62. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  63. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  64. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  65. package/dist/components/DataTable/data-table.d.ts +1 -1
  66. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  67. package/dist/components/DataTable/data-table.js +44 -32
  68. package/dist/components/DataTable/data-table.js.map +1 -1
  69. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  70. package/dist/components/DatePicker/date-picker.js +4 -4
  71. package/dist/components/DatePicker/date-picker.js.map +1 -1
  72. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  73. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  74. package/dist/components/DescriptionList/description-list.js +6 -6
  75. package/dist/components/DescriptionList/description-list.js.map +1 -1
  76. package/dist/components/Dialog/dialog.d.ts +2 -2
  77. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  78. package/dist/components/Dialog/dialog.js.map +1 -1
  79. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  80. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  81. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  82. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  83. package/dist/components/Field/field-context.d.ts +16 -10
  84. package/dist/components/Field/field-context.d.ts.map +1 -1
  85. package/dist/components/Field/field-context.js.map +1 -1
  86. package/dist/components/Field/field-types.d.ts +2 -2
  87. package/dist/components/Field/field-types.d.ts.map +1 -1
  88. package/dist/components/Field/field-types.js.map +1 -1
  89. package/dist/components/Field/field-wrapper.d.ts +20 -4
  90. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  91. package/dist/components/Field/field-wrapper.js +30 -31
  92. package/dist/components/Field/field-wrapper.js.map +1 -1
  93. package/dist/components/Field/field.d.ts +1 -1
  94. package/dist/components/Field/field.d.ts.map +1 -1
  95. package/dist/components/Field/field.js +25 -3
  96. package/dist/components/Field/field.js.map +1 -1
  97. package/dist/components/Field/index.d.ts +1 -0
  98. package/dist/components/Field/index.d.ts.map +1 -1
  99. package/dist/components/Field/index.js +2 -0
  100. package/dist/components/Field/index.js.map +1 -1
  101. package/dist/components/Field/use-form-validation.d.ts +1 -1
  102. package/dist/components/Field/use-form-validation.js.map +1 -1
  103. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  104. package/dist/components/FileItem/file-item.js +2 -5
  105. package/dist/components/FileItem/file-item.js.map +1 -1
  106. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  107. package/dist/components/FileUpload/file-upload.js +5 -1
  108. package/dist/components/FileUpload/file-upload.js.map +1 -1
  109. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  110. package/dist/components/FileViewer/file-viewer.js +2 -1
  111. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  112. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  113. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  114. package/dist/components/HoverCard/hover-card.js +4 -2
  115. package/dist/components/HoverCard/hover-card.js.map +1 -1
  116. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  117. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  118. package/dist/components/InlineEdit/inline-edit.js +104 -62
  119. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  120. package/dist/components/Input/input.d.ts +1 -1
  121. package/dist/components/Input/input.d.ts.map +1 -1
  122. package/dist/components/Input/input.js +6 -6
  123. package/dist/components/Input/input.js.map +1 -1
  124. package/dist/components/LinkInput/link-input.d.ts +5 -5
  125. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  126. package/dist/components/LinkInput/link-input.js +3 -3
  127. package/dist/components/LinkInput/link-input.js.map +1 -1
  128. package/dist/components/Notice/notice.d.ts +17 -1
  129. package/dist/components/Notice/notice.d.ts.map +1 -1
  130. package/dist/components/Notice/notice.js +7 -1
  131. package/dist/components/Notice/notice.js.map +1 -1
  132. package/dist/components/NumberInput/number-input.d.ts +1 -1
  133. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  134. package/dist/components/NumberInput/number-input.js +12 -1
  135. package/dist/components/NumberInput/number-input.js.map +1 -1
  136. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  137. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  138. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  139. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  140. package/dist/components/PeoplePicker/people-picker.js +7 -5
  141. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  142. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  143. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  144. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  145. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  146. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  147. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  148. package/dist/components/RadioGroup/radio-group.js +1 -1
  149. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  150. package/dist/components/Rating/rating.d.ts.map +1 -1
  151. package/dist/components/Rating/rating.js +4 -0
  152. package/dist/components/Rating/rating.js.map +1 -1
  153. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  154. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  155. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  156. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  157. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  158. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  159. package/dist/components/Select/select.d.ts +16 -6
  160. package/dist/components/Select/select.d.ts.map +1 -1
  161. package/dist/components/Select/select.js +17 -5
  162. package/dist/components/Select/select.js.map +1 -1
  163. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  164. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  165. package/dist/components/SelectMenu/select-menu.js +17 -3
  166. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  167. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  168. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  169. package/dist/components/Sheet/sheet.d.ts +2 -2
  170. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  171. package/dist/components/Sheet/sheet.js.map +1 -1
  172. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  173. package/dist/components/Sidebar/sidebar.js +2 -2
  174. package/dist/components/Sidebar/sidebar.js.map +1 -1
  175. package/dist/components/Slider/slider.d.ts.map +1 -1
  176. package/dist/components/Slider/slider.js +6 -3
  177. package/dist/components/Slider/slider.js.map +1 -1
  178. package/dist/components/Steps/steps.d.ts +6 -4
  179. package/dist/components/Steps/steps.d.ts.map +1 -1
  180. package/dist/components/Steps/steps.js +19 -5
  181. package/dist/components/Steps/steps.js.map +1 -1
  182. package/dist/components/Switch/switch.d.ts +4 -4
  183. package/dist/components/Switch/switch.d.ts.map +1 -1
  184. package/dist/components/Switch/switch.js +3 -1
  185. package/dist/components/Switch/switch.js.map +1 -1
  186. package/dist/components/Tabs/tabs.d.ts +1 -1
  187. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  188. package/dist/components/Tabs/tabs.js +73 -23
  189. package/dist/components/Tabs/tabs.js.map +1 -1
  190. package/dist/components/Tag/tag.d.ts +3 -1
  191. package/dist/components/Tag/tag.d.ts.map +1 -1
  192. package/dist/components/Tag/tag.js +2 -2
  193. package/dist/components/Tag/tag.js.map +1 -1
  194. package/dist/components/Textarea/textarea.d.ts +4 -4
  195. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  196. package/dist/components/Textarea/textarea.js +15 -15
  197. package/dist/components/Textarea/textarea.js.map +1 -1
  198. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  199. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  200. package/dist/components/TimePicker/time-picker.js +8 -5
  201. package/dist/components/TimePicker/time-picker.js.map +1 -1
  202. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  203. package/dist/components/Tooltip/tooltip.js +27 -23
  204. package/dist/components/Tooltip/tooltip.js.map +1 -1
  205. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  206. package/dist/components/TreeView/tree-view.js +16 -0
  207. package/dist/components/TreeView/tree-view.js.map +1 -1
  208. package/dist/index.d.ts +7 -7
  209. package/dist/index.d.ts.map +1 -1
  210. package/dist/index.js +6 -11
  211. package/dist/lib/drag-visual.d.ts +2 -2
  212. package/dist/lib/drag-visual.js.map +1 -1
  213. package/dist/lib/utils.d.ts +1 -0
  214. package/dist/lib/utils.d.ts.map +1 -1
  215. package/dist/lib/utils.js +21 -1
  216. package/dist/lib/utils.js.map +1 -1
  217. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  218. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  219. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  220. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  221. package/dist/tokens/categorical-color.d.ts +3 -3
  222. package/dist/tokens/categorical-color.d.ts.map +1 -1
  223. package/dist/tokens/categorical-color.js +2 -2
  224. package/dist/tokens/categorical-color.js.map +1 -1
  225. package/ds-canonical/fork/AGENTS.md +213 -0
  226. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  227. package/ds-canonical/fork/codex/hooks.json +16 -0
  228. package/ds-canonical/fork/governance.lock +22 -7
  229. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  230. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/fork/manifest.json +10 -1
  232. package/ds-canonical/fork/preamble.md +3 -2
  233. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  234. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  235. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  236. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  237. package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
  238. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  239. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
  240. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  241. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  242. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  243. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  244. package/ds-canonical/references/certified-surfaces.md +20 -0
  245. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  246. package/ds-canonical/references/principle-dim-map.json +20 -2
  247. package/ds-canonical/references/props-naming.md +2 -1
  248. package/ds-canonical/references/ssot-index.md +2 -2
  249. package/ds-canonical/references/story-baseline-registry.json +2 -2
  250. package/ds-canonical/rules/story-rules.md +1 -1
  251. package/ds-canonical/rules/ui-development.md +2 -1
  252. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  253. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  254. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  255. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  256. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  257. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  258. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  259. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  260. package/ds-story-manifest.json +21 -21
  261. package/llms-full.txt +3 -3
  262. package/llms.txt +1 -1
  263. package/package.json +2 -1
  264. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  265. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  266. package/src/components/Accordion/accordion.spec.md +10 -1
  267. package/src/components/Accordion/accordion.stories.tsx +10 -5
  268. package/src/components/Accordion/accordion.tsx +7 -2
  269. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  270. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  271. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  272. package/src/components/AppShell/app-shell.spec.md +4 -0
  273. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  274. package/src/components/Avatar/avatar.tsx +1 -1
  275. package/src/components/Badge/badge.spec.md +2 -2
  276. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  277. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  278. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  279. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  280. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  281. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  282. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  283. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  284. package/src/components/Button/button-group.tsx +4 -4
  285. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  286. package/src/components/Button/button.principles.stories.tsx +1 -1
  287. package/src/components/Button/button.spec.md +2 -2
  288. package/src/components/Button/button.stories.tsx +22 -28
  289. package/src/components/Button/button.tsx +2 -1
  290. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  291. package/src/components/Calendar/calendar.spec.md +1 -1
  292. package/src/components/Carousel/carousel.spec.md +17 -1
  293. package/src/components/Carousel/carousel.tsx +93 -42
  294. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  295. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  296. package/src/components/Checkbox/checkbox.spec.md +14 -3
  297. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  298. package/src/components/Checkbox/checkbox.tsx +79 -19
  299. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  300. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  301. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  302. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  303. package/src/components/Combobox/combobox.spec.md +6 -2
  304. package/src/components/Combobox/combobox.stories.tsx +9 -36
  305. package/src/components/Combobox/combobox.tsx +42 -27
  306. package/src/components/Command/command.spec.md +3 -3
  307. package/src/components/Command/command.tsx +9 -2
  308. package/src/components/DataTable/cell-registry.tsx +75 -76
  309. package/src/components/DataTable/column-types.ts +4 -17
  310. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  311. package/src/components/DataTable/data-table-filter-group.tsx +231 -0
  312. package/src/components/DataTable/data-table-filter-panel.tsx +19 -436
  313. package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
  314. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  315. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  316. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  317. package/src/components/DataTable/data-table.css +2 -3
  318. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  319. package/src/components/DataTable/data-table.spec.md +8 -8
  320. package/src/components/DataTable/data-table.stories.tsx +39 -29
  321. package/src/components/DataTable/data-table.tsx +94 -68
  322. package/src/components/DataTable/filter-operators.spec.md +5 -3
  323. package/src/components/DateGrid/date-grid.spec.md +1 -1
  324. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  325. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  326. package/src/components/DatePicker/date-picker.spec.md +9 -9
  327. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  328. package/src/components/DatePicker/date-picker.tsx +13 -13
  329. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  330. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  331. package/src/components/DescriptionList/description-list.spec.md +12 -12
  332. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  333. package/src/components/DescriptionList/description-list.tsx +10 -10
  334. package/src/components/Dialog/dialog.tsx +4 -1
  335. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  336. package/src/components/Field/field-context.ts +17 -11
  337. package/src/components/Field/field-controls.spec.md +44 -37
  338. package/src/components/Field/field-types.ts +14 -12
  339. package/src/components/Field/field-wrapper.tsx +59 -43
  340. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  341. package/src/components/Field/field.principles.stories.tsx +5 -28
  342. package/src/components/Field/field.spec.md +4 -4
  343. package/src/components/Field/field.stories.tsx +103 -72
  344. package/src/components/Field/field.tsx +36 -4
  345. package/src/components/Field/form-validation.spec.md +2 -0
  346. package/src/components/Field/index.ts +1 -0
  347. package/src/components/Field/use-form-validation.ts +1 -1
  348. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  349. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  350. package/src/components/FileItem/file-item.tsx +10 -8
  351. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  352. package/src/components/FileUpload/file-upload.spec.md +3 -2
  353. package/src/components/FileUpload/file-upload.tsx +5 -1
  354. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  355. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  356. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  357. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  358. package/src/components/FileViewer/file-viewer.tsx +3 -2
  359. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  360. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  361. package/src/components/HoverCard/hover-card.spec.md +2 -2
  362. package/src/components/HoverCard/hover-card.tsx +4 -2
  363. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  364. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  365. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  366. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  367. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  368. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  369. package/src/components/Input/input.principles.stories.tsx +3 -3
  370. package/src/components/Input/input.spec.md +4 -4
  371. package/src/components/Input/input.stories.tsx +3 -3
  372. package/src/components/Input/input.tsx +13 -13
  373. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  374. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  375. package/src/components/LinkInput/link-input.spec.md +6 -2
  376. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  377. package/src/components/LinkInput/link-input.tsx +21 -19
  378. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  379. package/src/components/Notice/notice.tsx +8 -2
  380. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  381. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  382. package/src/components/NumberInput/number-input.spec.md +6 -6
  383. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  384. package/src/components/NumberInput/number-input.tsx +17 -5
  385. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  386. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  387. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  388. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  389. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  390. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  391. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  392. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  393. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  394. package/src/components/PeoplePicker/person-display.tsx +3 -3
  395. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  396. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  397. package/src/components/Popover/popover.spec.md +4 -2
  398. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  399. package/src/components/ProfileCard/profile-card.tsx +1 -1
  400. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  401. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  402. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  403. package/src/components/README.md +1 -0
  404. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  405. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  406. package/src/components/RadioGroup/radio-group.tsx +19 -14
  407. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  408. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  409. package/src/components/Rating/rating.spec.md +2 -2
  410. package/src/components/Rating/rating.stories.tsx +4 -18
  411. package/src/components/Rating/rating.tsx +5 -1
  412. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  413. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  414. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  415. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  416. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  417. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  418. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  419. package/src/components/Select/select.principles.stories.tsx +3 -3
  420. package/src/components/Select/select.spec.md +11 -1
  421. package/src/components/Select/select.stories.tsx +41 -27
  422. package/src/components/Select/select.tsx +44 -26
  423. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  424. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  425. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  426. package/src/components/SelectMenu/select-menu.tsx +38 -5
  427. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  428. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  429. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  430. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  431. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  432. package/src/components/Sheet/sheet.tsx +4 -1
  433. package/src/components/Sidebar/sidebar.tsx +1 -1
  434. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  435. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  436. package/src/components/Slider/slider.spec.md +13 -1
  437. package/src/components/Slider/slider.stories.tsx +44 -32
  438. package/src/components/Slider/slider.tsx +13 -4
  439. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  440. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  441. package/src/components/Steps/steps.spec.md +4 -2
  442. package/src/components/Steps/steps.stories.tsx +4 -56
  443. package/src/components/Steps/steps.tsx +31 -7
  444. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  445. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  446. package/src/components/Switch/switch.spec.md +4 -4
  447. package/src/components/Switch/switch.stories.tsx +3 -3
  448. package/src/components/Switch/switch.tsx +16 -10
  449. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  450. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  451. package/src/components/Tabs/tabs.spec.md +5 -2
  452. package/src/components/Tabs/tabs.stories.tsx +36 -44
  453. package/src/components/Tabs/tabs.tsx +101 -36
  454. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  455. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  456. package/src/components/Tag/tag.spec.md +3 -1
  457. package/src/components/Tag/tag.tsx +5 -3
  458. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  459. package/src/components/Textarea/textarea.spec.md +5 -5
  460. package/src/components/Textarea/textarea.tsx +24 -24
  461. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  462. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  463. package/src/components/TimePicker/time-picker.spec.md +6 -5
  464. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  465. package/src/components/TimePicker/time-picker.tsx +24 -14
  466. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  467. package/src/components/Toast/toast.stories.tsx +1 -1
  468. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  469. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  470. package/src/components/Tooltip/tooltip.spec.md +9 -3
  471. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  472. package/src/components/Tooltip/tooltip.tsx +12 -2
  473. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  474. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  475. package/src/components/TreeView/tree-view.spec.md +8 -6
  476. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  477. package/src/components/TreeView/tree-view.tsx +36 -0
  478. package/src/index.ts +16 -9
  479. package/src/lib/drag-visual.ts +2 -2
  480. package/src/lib/utils.ts +19 -0
  481. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  482. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  483. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  484. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  485. package/src/tokens/categorical-color.ts +5 -5
  486. package/src/tokens/color/color.spec.md +5 -5
  487. package/src/tokens/color/primitives.css +9 -2
  488. package/src/tokens/opacity/opacity.spec.md +1 -1
  489. package/src/tokens/orphan-tokens.spec.md +1 -1
  490. package/src/tokens/typography/typography.spec.md +2 -0
  491. package/src/tokens/uiSize/uiSize.css +6 -1
  492. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -65,7 +65,7 @@ declare module '@tanstack/react-table' {
65
65
  wrap?: boolean
66
66
  /**
67
67
  * Max visible lines before ellipsis(2026-05-14 I9 per codex verdict + user 拍板)。
68
- * Only effective when `autoRowHeight + wrap=true`。Display 用 `line-clamp-N`,edit textarea
68
+ * Only effective when `autoRowHeight + wrap=true`。view 用 `line-clamp-N`,edit textarea
69
69
  * 高度 match clamp。對齊 Notion 「Truncate」row toggle / AG Grid `cellClassRules` 上限 row height。
70
70
  * Default = undefined(無 clamp,完整 wrap)。
71
71
  */
@@ -162,22 +162,9 @@ declare module '@tanstack/react-table' {
162
162
  * Esc cancel / blur or Enter commit。Commit 觸發 `onCellCommit`。
163
163
  */
164
164
  editable?: boolean | ((row: TData) => boolean)
165
- /**
166
- * Inline disabled state(2026-05-13 Stream C Cluster B Q3 ship,per codex Q3 verdict):
167
- * cell 不可操作 state(orthogonal to editable readonly)。
168
- * - `true`:cell 永遠 disabled
169
- * - `false` / undef(default):cell normal
170
- * - `(row) => boolean`:per-row 動態(e.g. row.archived 或 row.locked 才 disabled)
171
- *
172
- * 視覺(per `color.spec.md` `--bg-disabled` component-state token):
173
- * - TD 外殼:`bg-disabled` + `cursor-not-allowed` + 抑制 hover ring
174
- * - Cell content(Field family):`mode='disabled'` → 各 Field type 內部走具體 disabled token
175
- * - edit entry 抑制:disabled cell 點擊不進 edit(對齊 `editable && !disabled` invariant)
176
- *
177
- * 跟 `editable=false` 區分:editable=false = readonly(可看不可編);disabled = 不可操作 state。
178
- * 對齊 MUI X `isCellEditable` + cellClassName / AG Grid `cellClassRules` / Notion locked properties。
179
- */
180
- disabled?: boolean | ((row: TData) => boolean)
165
+ // 2026-07-16 round16:cell `disabled` 已廢除。世界級 grid(MUI X isCellEditable / AG Grid editable /
166
+ // Handsontable readOnly)皆無 disabled cell 鎖定用 `editable:(row)=>false`(可看不可編、不灰化),
167
+ // 非 disabled 灰化態。原 `disabled?: boolean | ((row)=>boolean)` + bg-disabled TD 灰化全移除(全庫 0 消費)。
181
168
  /**
182
169
  * Locked column — column reorder 不可拖,Notion 「primary column」 pattern。
183
170
  * 對齊 SKU / ID 等不可移欄位。
@@ -27,8 +27,7 @@ import { Eye, EyeOff, Lock, GripVertical, Search, RotateCcw, X as XIcon } from '
27
27
  import { Button } from '@/design-system/components/Button/button'
28
28
  import { ButtonDivider } from '@/design-system/components/Button/button-group'
29
29
  import { Input } from '@/design-system/components/Input/input'
30
- import { ScrollArea } from '@/design-system/components/ScrollArea/scroll-area'
31
- import { PopoverHeader, PopoverFooter, PopoverTitle, PopoverClose } from '@/design-system/components/Popover/popover'
30
+ import { PopoverHeader, PopoverBody, PopoverFooter, PopoverTitle, PopoverClose } from '@/design-system/components/Popover/popover'
32
31
  import { ItemPrefix, ItemLabel, ItemInlineActionButton, ROW_PADDING_BY_SIZE } from '@/design-system/patterns/element-anatomy/item-anatomy'
33
32
  import { cn } from '@/lib/utils'
34
33
  import { DndContext, closestCenter, type DragEndEvent } from '@dnd-kit/core'
@@ -130,8 +129,19 @@ export function DataTableColumnVisibilityPanel({
130
129
  onColumnOrderChange!(next)
131
130
  }
132
131
 
132
+ // 2026-07-18 決策16 錯誤史(明記以免再犯):原本這個 panel 是 Fragment + fixed `ScrollArea max-h-72`,
133
+ // 與 sibling FilterPanel/SortManager(root-div + viewport-aware SurfaceBody)不一致。我給過**兩個都錯**
134
+ // 的辯護理由 —— (1)「PopoverHeader 用 -mx 負邊距、包 root 會破壞」= 錯(SurfaceHeader 用正 px-loose+border-b,
135
+ // 無 -mx);(2)「sibling 自刻 header 不用 primitive」= 錯(三 panel 皆消費 SurfaceHeader/PopoverHeader primitive)。
136
+ // 真正差異只是 body/scroll 策略。multi-agent SSOT consistency 稽核定案:**是 drift,該統一**(fixed 288px cap
137
+ // 在高螢幕多欄下劣於 sibling 的 viewport-adaptive;且是唯一不能當 template 複製的 panel)。故下方已改成 canonical shape。
133
138
  return (
134
- <>
139
+ // 決策16 定案(2026-07-18,SSOT consistency 稽核後):對齊 sibling FilterPanel/SortManager 的
140
+ // overlay-surface canonical shape —— root `<div flex flex-col h-full min-h-0>`(M25 viewport-aware
141
+ // scroll chain)+ viewport-adaptive `PopoverBody`(取代原 fixed `ScrollArea max-h-72`)。三個
142
+ // DataTable state-panel 收斂成同一形狀,body 隨視窗高度自適應(高螢幕多欄不再硬卡 288px)。
143
+ // 寬度仍由 consumer 的 `<PopoverContent w-72>` 提供(panel root w-full 撐滿)。
144
+ <div className="flex flex-col h-full min-h-0 w-full">
135
145
  <PopoverHeader hideClose>
136
146
  <div className="flex items-center gap-1 w-full min-w-0">
137
147
  <PopoverTitle className="flex-1">欄位顯示</PopoverTitle>
@@ -151,17 +161,20 @@ export function DataTableColumnVisibilityPanel({
151
161
  </div>
152
162
  </PopoverHeader>
153
163
  {searchable && (
154
- <div className="px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)]">
164
+ <div className="shrink-0 px-[var(--layout-space-loose)] pt-[var(--layout-space-tight)]">
155
165
  <Input
156
166
  size="md"
157
167
  placeholder="搜尋欄位…"
168
+ aria-label="搜尋欄位"
158
169
  value={search}
159
170
  onChange={(e) => setSearch(e.target.value)}
160
171
  startIcon={Search}
161
172
  />
162
173
  </div>
163
174
  )}
164
- <ScrollArea className="max-h-72">
175
+ {/* viewport-adaptive body(List-as-region idiom:PopoverBody !px-0 !py-0 撤 chrome padding,
176
+ 內層 py-2 給垂直呼吸、row 自帶 px-loose 水平 padding)。取代原 fixed ScrollArea max-h-72。 */}
177
+ <PopoverBody className="!px-0 !py-0">
165
178
  <div className="py-2 flex flex-col" style={{ '--item-prefix-slot': '16px' } as React.CSSProperties}>
166
179
  {dndEnabled ? (
167
180
  <DndContext collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
@@ -196,13 +209,13 @@ export function DataTableColumnVisibilityPanel({
196
209
  ))
197
210
  )}
198
211
  </div>
199
- </ScrollArea>
212
+ </PopoverBody>
200
213
  <PopoverFooter className="justify-start">
201
214
  <Button variant="tertiary" size="sm" onClick={handleBulkToggle}>
202
215
  {allVisible ? '全部隱藏' : '顯示全部'}
203
216
  </Button>
204
217
  </PopoverFooter>
205
- </>
218
+ </div>
206
219
  )
207
220
  }
208
221
 
@@ -0,0 +1,231 @@
1
+ // @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved(2026-07-14 自 data-table-filter-panel.tsx 拆檔搬移,原檔級 escape 隨段落帶入)。
2
+ // @internal — DS-internal 單元(filter row / nested-group renderer + 共用 column/operator
3
+ // helpers;GroupBlock 為 nested-group renderer,FilterRow / ConjunctionLabel 為其 row 構件、
4
+ // flat mode 共用。只被 data-table-filter-panel.tsx 消費);不隨 index.ts re-export 進 npm public surface。
5
+ // ────────────────────────────── 消費的 SSOT ──────────────────────────────
6
+ // - FieldControlGroup:field + op + value border-collapse 接合(field-control-group.spec.md;
7
+ // FilterValuePicker 為 direct child,className forward 不開 wrapper div — 2026-05-04 #2 fix)
8
+ // - Button(variant="text" iconOnly)row meta trash / Select(size="sm")conjunction・field・op
9
+ // (data-table.spec.md「四、UI canonical」:trash = form-control row text Button;A6 conjunction)
10
+ // - Width tokens:--data-table-filter-field-width / --data-table-filter-op-width(uiSize.css SSOT,
11
+ // 2026-05-23 Phase A.4 Decision 2)
12
+ // - Operator SSOT:./filter-operators.ts OPERATOR_REGISTRY(禁 hardcode op 字串)
13
+ // - Group container 灰底 bg-muted:color.spec.md L651-654 靜態低重要 surface semantic(2026-05-09 Q3 A)
14
+ // 設計規則:./filter-operators.spec.md + ./data-table.spec.md「進階篩選」段
15
+
16
+ import { Plus, Trash2 } from 'lucide-react'
17
+ import { Button } from '@/design-system/components/Button/button'
18
+ import { Select, type SelectOption } from '@/design-system/components/Select/select'
19
+ import { FieldControlGroup } from '@/design-system/components/FieldControlGroup/field-control-group'
20
+ import type { ColumnType } from './column-types'
21
+ import {
22
+ OPERATOR_REGISTRY,
23
+ DEFAULT_OPERATOR,
24
+ getOperatorSpec,
25
+ getValueShape,
26
+ type ValueShape,
27
+ } from './filter-operators'
28
+ import type { Conjunction, FilterCondition, FilterGroup } from './filter-tree'
29
+ import { FilterValuePicker } from './data-table-filter-value-picker'
30
+
31
+ // ── Shared internal types + operator helpers(panel orchestration 也消費)────
32
+
33
+ export interface FilterColumn {
34
+ id: string
35
+ label: string
36
+ type: ColumnType
37
+ options?: Array<{ value: string; label: string }>
38
+ /** People pool for person/multiPerson filter picker(對齊 cell-registry meta.people SSOT)*/
39
+ people?: Array<{ name: string; avatarUrl?: string; description?: string }>
40
+ includeTime?: boolean
41
+ }
42
+
43
+ function getOperatorOptions(type?: ColumnType): SelectOption[] {
44
+ const registry = type && OPERATOR_REGISTRY[type] ? OPERATOR_REGISTRY[type] : OPERATOR_REGISTRY.string
45
+ return registry.map((op) => ({ value: op.op, label: op.label }))
46
+ }
47
+
48
+ export function getDefaultOperator(type?: ColumnType): string {
49
+ return (type && DEFAULT_OPERATOR[type]) || DEFAULT_OPERATOR.string
50
+ }
51
+
52
+ // Q6(2026-07-04):date 欄位把比對精度寫進 condition(includeTime=true → ms,否則 day)。
53
+ // 'time' 欄暫不寫(值非完整日期,truncate 語意不成立;見 filter-operators.spec v3 time 註)。
54
+ export const datePrecisionOf = (col: FilterColumn | undefined): 'day' | 'ms' | undefined =>
55
+ col?.type === 'date' ? (col.includeTime ? 'ms' : 'day') : undefined
56
+
57
+ // ── ConjunctionLabel ───────────────────────────────────────────────────
58
+
59
+ const CONJ_OPTIONS: SelectOption[] = [
60
+ { value: 'and', label: 'And' },
61
+ { value: 'or', label: 'Or' },
62
+ ]
63
+
64
+ function ConjunctionLabel({
65
+ index, conjunction, onChange,
66
+ }: { index: number; conjunction: Conjunction; onChange: (c: Conjunction) => void }) {
67
+ // index === 0:首 row 顯示靜態「Where」label
68
+ // index === 1:**唯一可改**的 AND/OR Select(連動整 group conjunction)
69
+ // index ≥ 2:被連動的 row,read-only 顯示當前 conjunction 文字(同 Where 視覺,A6 canonical)
70
+ // 對齊 Airtable / Notion / Linear 共識 @benchmark-unverified(non-OSS)
71
+ // px-[var(--field-px)] 對齊 Field 內部 padding 12px(Q13)
72
+ if (index === 0) {
73
+ return <div className="w-20 shrink-0 text-body text-fg-muted px-[var(--field-px)] self-center">Where</div>
74
+ }
75
+ if (index >= 2) {
76
+ const label = conjunction === 'and' ? 'And' : 'Or'
77
+ return <div className="w-20 shrink-0 text-body text-fg-muted px-[var(--field-px)] self-center">{label}</div>
78
+ }
79
+ // index === 1:可切換的 AND/OR Select
80
+ // minRows={2} — And/Or 2 選項,顯式縮 menu 高度避免 reserve 3 row 空白(Q5)
81
+ return (
82
+ <div className="w-20 shrink-0">
83
+ <Select
84
+ size="sm"
85
+ options={CONJ_OPTIONS}
86
+ value={conjunction}
87
+ onChange={(v) => onChange(v as Conjunction)}
88
+ minRows={2}
89
+ aria-label="連接詞 — 同 group 共用"
90
+ />
91
+ </div>
92
+ )
93
+ }
94
+
95
+ // ── FilterRow(flat 用 + group 內共用) ──────────────────────────────
96
+
97
+ export function FilterRow({
98
+ index, condition, conjunction, filterableColumns, fieldOptions,
99
+ onChangeConjunction, onChangeField, onChangeOp, onChangeValue, onRemove,
100
+ }: {
101
+ index: number
102
+ condition: FilterCondition
103
+ conjunction: Conjunction
104
+ filterableColumns: FilterColumn[]
105
+ fieldOptions: SelectOption[]
106
+ onChangeConjunction: (c: Conjunction) => void
107
+ onChangeField: (v: string) => void
108
+ onChangeOp: (v: string) => void
109
+ onChangeValue: (v: unknown) => void
110
+ onRemove: () => void
111
+ }) {
112
+ const colInfo = filterableColumns.find((c) => c.id === condition.field)
113
+ const operatorOptions = getOperatorOptions(colInfo?.type)
114
+ const hasField = !!condition.field
115
+ const opSpec = colInfo ? getOperatorSpec(colInfo.type, condition.op) : null
116
+ const valueShape: ValueShape | null = colInfo && opSpec
117
+ ? getValueShape(opSpec, colInfo.type, colInfo.includeTime)
118
+ : null
119
+ // op 'is_set' / 'is_not_set' 等 shape='none' → 無 value cell,op 自動 expand 填剩餘寬
120
+ // 對齊 Notion / Airtable / Linear filter row 行為
121
+ // 注意:valueShape=null(初始無 field 選)時仍 render value cell(disabled placeholder)— 只 'none' 才 fold
122
+ const hasValueCell = valueShape !== 'none'
123
+
124
+ // FieldControlGroup 接合 field + op + value 視覺(2026-05-04 E refactor + 多輪 fix):
125
+ // - border collapse 取代 3 顆獨立 Select 並排,對齊 Airtable / Linear / Notion filter row idiom
126
+ // - ConjunctionLabel + Trash 在 group 外層(meta actions,不屬 control 一體)
127
+ // - **#5 fix**:row 內水平 gap = `gap-2` (8px),layoutSpace 規則 5 緊密相關
128
+ // - **#9 fix**:cell 用 `min-w-[]`(field 160 / op 120),value flex-1 min-w-0,讓 long label 可撐寬
129
+ // - **#2 fix**:FilterValuePicker 直接是 FieldControlGroup direct child(無 wrapper div),CSS variants 命中正確
130
+ return (
131
+ <div className="flex items-center gap-2">
132
+ <ConjunctionLabel index={index} conjunction={conjunction} onChange={onChangeConjunction} />
133
+ {/* **#9 fix(2026-05-04 v4)**:Field controls trigger `w-full` override 外 className,改用 Tailwind `!`
134
+ important 強制 override(`!w-[160px]` / `!w-[120px]`),value 用 `!flex-1 !min-w-0`。
135
+ Select 元件本身沒 destructure `style` prop 所以 inline style flex-basis 行不通,只能用 className。 */}
136
+ <FieldControlGroup block className="flex-1 min-w-0">
137
+ {/* 2026-05-23 Phase A.4 Decision 2:`!w-[160px]` / `!w-[120px]` → tokens
138
+ `--data-table-filter-field-width` / `--data-table-filter-op-width`(SSOT in uiSize.css)
139
+ Behavior preserved 完好如初:flat + nested 同 width(token 是 design constant) */}
140
+ <Select
141
+ className="!w-[var(--data-table-filter-field-width)] flex-shrink-0"
142
+ size="sm"
143
+ options={fieldOptions}
144
+ value={condition.field}
145
+ onChange={onChangeField}
146
+ placeholder="選擇欄位"
147
+ aria-label="篩選欄位"
148
+ />
149
+ <Select
150
+ className={hasValueCell ? '!w-[var(--data-table-filter-op-width)] flex-shrink-0' : '!flex-1 !min-w-0'}
151
+ size="sm"
152
+ options={operatorOptions}
153
+ value={condition.op}
154
+ onChange={onChangeOp}
155
+ disabled={!hasField}
156
+ placeholder="運算子"
157
+ aria-label="篩選運算子"
158
+ />
159
+ {hasValueCell && (
160
+ <FilterValuePicker
161
+ shape={valueShape}
162
+ value={condition.value}
163
+ onChange={onChangeValue}
164
+ colInfo={colInfo}
165
+ disabled={!hasField}
166
+ ariaLabel={colInfo ? `${colInfo.label} 篩選值` : '篩選值'}
167
+ className="!flex-1 !min-w-0"
168
+ />
169
+ )}
170
+ </FieldControlGroup>
171
+ {/* Trash 用 text Button — filter row 是 form-control row,Field 同高對齊(28 md) */}
172
+ <Button variant="text" size="sm" iconOnly startIcon={Trash2} aria-label="刪除" onClick={onRemove} />
173
+ </div>
174
+ )
175
+ }
176
+
177
+ // ── GroupBlock(nested 用) ────────────────────────────────────────────
178
+
179
+ export function GroupBlock({
180
+ index, group, rootConjunction, filterableColumns, fieldOptions,
181
+ onChangeRootConjunction, onChangeGroupConjunction,
182
+ onChangeCondition, onRemoveCondition, onAddCondition, onRemoveGroup,
183
+ }: {
184
+ index: number
185
+ group: FilterGroup
186
+ rootConjunction: Conjunction
187
+ filterableColumns: FilterColumn[]
188
+ fieldOptions: SelectOption[]
189
+ onChangeRootConjunction: (c: Conjunction) => void
190
+ onChangeGroupConjunction: (c: Conjunction) => void
191
+ onChangeCondition: (condId: string, patch: Partial<FilterCondition>) => void
192
+ onRemoveCondition: (condId: string) => void
193
+ onAddCondition: () => void
194
+ onRemoveGroup: () => void
195
+ }) {
196
+ return (
197
+ <div className="flex items-start gap-2">
198
+ <div className="pt-2">
199
+ <ConjunctionLabel index={index} conjunction={rootConjunction} onChange={onChangeRootConjunction} />
200
+ </div>
201
+ {/* Group container 灰底 — `bg-muted`(`--muted` neutral-2,user 2026-05-09 拍板 Q3 A)。對齊 color.spec.md L651-654 「table header / tab / code block / skeleton」靜態低重要 surface semantic */}
202
+ <div className="flex-1 min-w-0 rounded-md bg-muted p-2 flex flex-col gap-2">
203
+ {group.children.map((cond, cIdx) => (
204
+ <FilterRow
205
+ key={cond.id}
206
+ index={cIdx}
207
+ condition={cond}
208
+ conjunction={group.conjunction}
209
+ filterableColumns={filterableColumns}
210
+ fieldOptions={fieldOptions}
211
+ onChangeConjunction={onChangeGroupConjunction}
212
+ onChangeField={(v) => {
213
+ const newCol = filterableColumns.find((c) => c.id === v)
214
+ onChangeCondition(cond.id, { field: v, op: getDefaultOperator(newCol?.type), value: '', datePrecision: datePrecisionOf(newCol) })
215
+ }}
216
+ onChangeOp={(v) => onChangeCondition(cond.id, { op: v, value: '' })}
217
+ onChangeValue={(v) => onChangeCondition(cond.id, { value: v })}
218
+ onRemove={() => onRemoveCondition(cond.id)}
219
+ />
220
+ ))}
221
+ {/* Q9 — text variant 對齊 inline 派 + 視覺輕量 */}
222
+ <div className="flex items-center justify-between">
223
+ <Button variant="text" size="sm" startIcon={Plus} onClick={onAddCondition}>加入巢狀篩選</Button>
224
+ {group.children.length === 0 && (
225
+ <Button variant="text" size="sm" startIcon={Trash2} danger onClick={onRemoveGroup}>移除空群組</Button>
226
+ )}
227
+ </div>
228
+ </div>
229
+ </div>
230
+ )
231
+ }