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

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 (481) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  50. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  51. package/dist/components/DataTable/data-table-filter-panel.js +3 -4
  52. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  53. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  54. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  55. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  56. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  57. package/dist/components/DataTable/data-table.d.ts +1 -1
  58. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  59. package/dist/components/DataTable/data-table.js +44 -32
  60. package/dist/components/DataTable/data-table.js.map +1 -1
  61. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  62. package/dist/components/DatePicker/date-picker.js +4 -4
  63. package/dist/components/DatePicker/date-picker.js.map +1 -1
  64. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  65. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  66. package/dist/components/DescriptionList/description-list.js +6 -6
  67. package/dist/components/DescriptionList/description-list.js.map +1 -1
  68. package/dist/components/Dialog/dialog.d.ts +2 -2
  69. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  70. package/dist/components/Dialog/dialog.js.map +1 -1
  71. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  72. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  73. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  74. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  75. package/dist/components/Field/field-context.d.ts +16 -10
  76. package/dist/components/Field/field-context.d.ts.map +1 -1
  77. package/dist/components/Field/field-context.js.map +1 -1
  78. package/dist/components/Field/field-types.d.ts +2 -2
  79. package/dist/components/Field/field-types.d.ts.map +1 -1
  80. package/dist/components/Field/field-types.js.map +1 -1
  81. package/dist/components/Field/field-wrapper.d.ts +20 -4
  82. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  83. package/dist/components/Field/field-wrapper.js +30 -31
  84. package/dist/components/Field/field-wrapper.js.map +1 -1
  85. package/dist/components/Field/field.d.ts +1 -1
  86. package/dist/components/Field/field.d.ts.map +1 -1
  87. package/dist/components/Field/field.js +25 -3
  88. package/dist/components/Field/field.js.map +1 -1
  89. package/dist/components/Field/use-form-validation.d.ts +1 -1
  90. package/dist/components/Field/use-form-validation.js.map +1 -1
  91. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  92. package/dist/components/FileItem/file-item.js +2 -5
  93. package/dist/components/FileItem/file-item.js.map +1 -1
  94. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  95. package/dist/components/FileUpload/file-upload.js +5 -1
  96. package/dist/components/FileUpload/file-upload.js.map +1 -1
  97. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  98. package/dist/components/FileViewer/file-viewer.js +2 -1
  99. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  100. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  101. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  102. package/dist/components/HoverCard/hover-card.js +4 -2
  103. package/dist/components/HoverCard/hover-card.js.map +1 -1
  104. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  105. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  106. package/dist/components/InlineEdit/inline-edit.js +104 -62
  107. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  108. package/dist/components/Input/input.d.ts +1 -1
  109. package/dist/components/Input/input.d.ts.map +1 -1
  110. package/dist/components/Input/input.js +6 -6
  111. package/dist/components/Input/input.js.map +1 -1
  112. package/dist/components/LinkInput/link-input.d.ts +5 -5
  113. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  114. package/dist/components/LinkInput/link-input.js +3 -3
  115. package/dist/components/LinkInput/link-input.js.map +1 -1
  116. package/dist/components/Notice/notice.d.ts +17 -1
  117. package/dist/components/Notice/notice.d.ts.map +1 -1
  118. package/dist/components/Notice/notice.js +7 -1
  119. package/dist/components/Notice/notice.js.map +1 -1
  120. package/dist/components/NumberInput/number-input.d.ts +1 -1
  121. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  122. package/dist/components/NumberInput/number-input.js +12 -1
  123. package/dist/components/NumberInput/number-input.js.map +1 -1
  124. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  125. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  126. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  127. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  128. package/dist/components/PeoplePicker/people-picker.js +7 -5
  129. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  130. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  131. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  132. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  133. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  134. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  135. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  136. package/dist/components/RadioGroup/radio-group.js +1 -1
  137. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  138. package/dist/components/Rating/rating.d.ts.map +1 -1
  139. package/dist/components/Rating/rating.js +4 -0
  140. package/dist/components/Rating/rating.js.map +1 -1
  141. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  142. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  143. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  144. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  145. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  146. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  147. package/dist/components/Select/select.d.ts +16 -6
  148. package/dist/components/Select/select.d.ts.map +1 -1
  149. package/dist/components/Select/select.js +17 -5
  150. package/dist/components/Select/select.js.map +1 -1
  151. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  152. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  153. package/dist/components/SelectMenu/select-menu.js +17 -3
  154. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  155. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  156. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  157. package/dist/components/Sheet/sheet.d.ts +2 -2
  158. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  159. package/dist/components/Sheet/sheet.js.map +1 -1
  160. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  161. package/dist/components/Sidebar/sidebar.js +2 -2
  162. package/dist/components/Sidebar/sidebar.js.map +1 -1
  163. package/dist/components/Slider/slider.d.ts.map +1 -1
  164. package/dist/components/Slider/slider.js +6 -3
  165. package/dist/components/Slider/slider.js.map +1 -1
  166. package/dist/components/Steps/steps.d.ts +6 -4
  167. package/dist/components/Steps/steps.d.ts.map +1 -1
  168. package/dist/components/Steps/steps.js +19 -5
  169. package/dist/components/Steps/steps.js.map +1 -1
  170. package/dist/components/Switch/switch.d.ts +4 -4
  171. package/dist/components/Switch/switch.d.ts.map +1 -1
  172. package/dist/components/Switch/switch.js +3 -1
  173. package/dist/components/Switch/switch.js.map +1 -1
  174. package/dist/components/Tabs/tabs.d.ts +1 -1
  175. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  176. package/dist/components/Tabs/tabs.js +73 -23
  177. package/dist/components/Tabs/tabs.js.map +1 -1
  178. package/dist/components/Tag/tag.d.ts +3 -1
  179. package/dist/components/Tag/tag.d.ts.map +1 -1
  180. package/dist/components/Tag/tag.js +2 -2
  181. package/dist/components/Tag/tag.js.map +1 -1
  182. package/dist/components/Textarea/textarea.d.ts +4 -4
  183. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  184. package/dist/components/Textarea/textarea.js +15 -15
  185. package/dist/components/Textarea/textarea.js.map +1 -1
  186. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  187. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  188. package/dist/components/TimePicker/time-picker.js +8 -5
  189. package/dist/components/TimePicker/time-picker.js.map +1 -1
  190. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  191. package/dist/components/Tooltip/tooltip.js +27 -23
  192. package/dist/components/Tooltip/tooltip.js.map +1 -1
  193. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  194. package/dist/components/TreeView/tree-view.js +16 -0
  195. package/dist/components/TreeView/tree-view.js.map +1 -1
  196. package/dist/index.d.ts +7 -7
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +6 -13
  199. package/dist/index.js.map +1 -1
  200. package/dist/lib/drag-visual.d.ts +2 -2
  201. package/dist/lib/drag-visual.js.map +1 -1
  202. package/dist/lib/utils.d.ts +1 -0
  203. package/dist/lib/utils.d.ts.map +1 -1
  204. package/dist/lib/utils.js +21 -1
  205. package/dist/lib/utils.js.map +1 -1
  206. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  207. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  208. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  209. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  210. package/dist/tokens/categorical-color.d.ts +3 -3
  211. package/dist/tokens/categorical-color.d.ts.map +1 -1
  212. package/dist/tokens/categorical-color.js +2 -2
  213. package/dist/tokens/categorical-color.js.map +1 -1
  214. package/ds-canonical/fork/AGENTS.md +213 -0
  215. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  216. package/ds-canonical/fork/codex/hooks.json +16 -0
  217. package/ds-canonical/fork/governance.lock +22 -7
  218. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  219. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  220. package/ds-canonical/fork/manifest.json +10 -1
  221. package/ds-canonical/fork/preamble.md +3 -2
  222. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  223. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  224. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  225. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  226. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  227. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +19 -2
  228. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  229. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  230. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  232. package/ds-canonical/references/certified-surfaces.md +20 -0
  233. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  234. package/ds-canonical/references/principle-dim-map.json +20 -2
  235. package/ds-canonical/references/props-naming.md +2 -1
  236. package/ds-canonical/references/ssot-index.md +2 -2
  237. package/ds-canonical/references/story-baseline-registry.json +2 -2
  238. package/ds-canonical/rules/story-rules.md +1 -1
  239. package/ds-canonical/rules/ui-development.md +2 -1
  240. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  241. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  242. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  243. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  244. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  245. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  246. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  247. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  248. package/ds-story-manifest.json +21 -21
  249. package/llms-full.txt +3 -3
  250. package/llms.txt +1 -1
  251. package/package.json +2 -1
  252. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  253. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  254. package/src/components/Accordion/accordion.spec.md +10 -1
  255. package/src/components/Accordion/accordion.stories.tsx +10 -5
  256. package/src/components/Accordion/accordion.tsx +7 -2
  257. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  258. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  259. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  260. package/src/components/AppShell/app-shell.spec.md +4 -0
  261. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  262. package/src/components/Avatar/avatar.tsx +1 -1
  263. package/src/components/Badge/badge.spec.md +2 -2
  264. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  265. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  266. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  267. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  268. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  269. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  270. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  271. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  272. package/src/components/Button/button-group.tsx +4 -4
  273. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  274. package/src/components/Button/button.principles.stories.tsx +1 -1
  275. package/src/components/Button/button.spec.md +2 -2
  276. package/src/components/Button/button.stories.tsx +22 -28
  277. package/src/components/Button/button.tsx +2 -1
  278. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  279. package/src/components/Calendar/calendar.spec.md +1 -1
  280. package/src/components/Carousel/carousel.spec.md +17 -1
  281. package/src/components/Carousel/carousel.tsx +93 -42
  282. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  283. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  284. package/src/components/Checkbox/checkbox.spec.md +12 -3
  285. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  286. package/src/components/Checkbox/checkbox.tsx +79 -19
  287. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  288. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  289. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  290. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  291. package/src/components/Combobox/combobox.spec.md +6 -2
  292. package/src/components/Combobox/combobox.stories.tsx +9 -36
  293. package/src/components/Combobox/combobox.tsx +42 -27
  294. package/src/components/Command/command.spec.md +3 -3
  295. package/src/components/Command/command.tsx +9 -2
  296. package/src/components/DataTable/cell-registry.tsx +75 -76
  297. package/src/components/DataTable/column-types.ts +4 -17
  298. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  299. package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
  300. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  301. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  302. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  303. package/src/components/DataTable/data-table.css +2 -3
  304. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  305. package/src/components/DataTable/data-table.spec.md +8 -7
  306. package/src/components/DataTable/data-table.stories.tsx +39 -29
  307. package/src/components/DataTable/data-table.tsx +90 -67
  308. package/src/components/DataTable/filter-operators.spec.md +2 -0
  309. package/src/components/DateGrid/date-grid.spec.md +1 -1
  310. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  311. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  312. package/src/components/DatePicker/date-picker.spec.md +10 -9
  313. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  314. package/src/components/DatePicker/date-picker.tsx +13 -13
  315. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  316. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  317. package/src/components/DescriptionList/description-list.spec.md +12 -12
  318. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  319. package/src/components/DescriptionList/description-list.tsx +10 -10
  320. package/src/components/Dialog/dialog.tsx +4 -1
  321. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  322. package/src/components/Empty/empty.spec.md +0 -1
  323. package/src/components/Field/field-context.ts +17 -11
  324. package/src/components/Field/field-controls.spec.md +46 -37
  325. package/src/components/Field/field-types.ts +14 -12
  326. package/src/components/Field/field-wrapper.tsx +59 -43
  327. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  328. package/src/components/Field/field.principles.stories.tsx +5 -28
  329. package/src/components/Field/field.spec.md +5 -4
  330. package/src/components/Field/field.stories.tsx +103 -72
  331. package/src/components/Field/field.tsx +36 -4
  332. package/src/components/Field/form-validation.spec.md +4 -0
  333. package/src/components/Field/use-form-validation.ts +1 -1
  334. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  335. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  336. package/src/components/FileItem/file-item.tsx +10 -8
  337. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  338. package/src/components/FileUpload/file-upload.spec.md +3 -2
  339. package/src/components/FileUpload/file-upload.tsx +5 -1
  340. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  342. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  343. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  344. package/src/components/FileViewer/file-viewer.tsx +3 -2
  345. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  346. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  347. package/src/components/HoverCard/hover-card.spec.md +2 -2
  348. package/src/components/HoverCard/hover-card.tsx +4 -2
  349. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  350. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  351. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  352. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  353. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  354. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  355. package/src/components/Input/input.principles.stories.tsx +3 -3
  356. package/src/components/Input/input.spec.md +4 -4
  357. package/src/components/Input/input.stories.tsx +3 -3
  358. package/src/components/Input/input.tsx +13 -13
  359. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  360. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  361. package/src/components/LinkInput/link-input.spec.md +6 -2
  362. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  363. package/src/components/LinkInput/link-input.tsx +21 -19
  364. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  365. package/src/components/Notice/notice.tsx +8 -2
  366. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  367. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  368. package/src/components/NumberInput/number-input.spec.md +6 -6
  369. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  370. package/src/components/NumberInput/number-input.tsx +17 -5
  371. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  372. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  373. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  374. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  375. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  376. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  377. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  378. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  379. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  380. package/src/components/PeoplePicker/person-display.tsx +3 -3
  381. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  382. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  383. package/src/components/Popover/popover.spec.md +4 -2
  384. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  385. package/src/components/ProfileCard/profile-card.tsx +1 -1
  386. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  387. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  388. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  389. package/src/components/README.md +1 -0
  390. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  391. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  392. package/src/components/RadioGroup/radio-group.tsx +19 -14
  393. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  394. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  395. package/src/components/Rating/rating.spec.md +2 -2
  396. package/src/components/Rating/rating.stories.tsx +4 -18
  397. package/src/components/Rating/rating.tsx +5 -1
  398. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  399. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  400. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  401. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  402. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  403. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  404. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  405. package/src/components/Select/select.principles.stories.tsx +3 -3
  406. package/src/components/Select/select.spec.md +10 -1
  407. package/src/components/Select/select.stories.tsx +41 -27
  408. package/src/components/Select/select.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  410. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  411. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  412. package/src/components/SelectMenu/select-menu.tsx +38 -5
  413. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  414. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  415. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  416. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  417. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  418. package/src/components/Sheet/sheet.tsx +4 -1
  419. package/src/components/Sidebar/sidebar.tsx +1 -1
  420. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  421. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  422. package/src/components/Slider/slider.spec.md +13 -1
  423. package/src/components/Slider/slider.stories.tsx +44 -32
  424. package/src/components/Slider/slider.tsx +13 -4
  425. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  426. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  427. package/src/components/Steps/steps.spec.md +4 -2
  428. package/src/components/Steps/steps.stories.tsx +4 -56
  429. package/src/components/Steps/steps.tsx +31 -7
  430. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  431. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  432. package/src/components/Switch/switch.spec.md +4 -4
  433. package/src/components/Switch/switch.stories.tsx +3 -3
  434. package/src/components/Switch/switch.tsx +16 -10
  435. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  436. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  437. package/src/components/Tabs/tabs.spec.md +5 -2
  438. package/src/components/Tabs/tabs.stories.tsx +36 -44
  439. package/src/components/Tabs/tabs.tsx +101 -36
  440. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  441. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  442. package/src/components/Tag/tag.spec.md +4 -1
  443. package/src/components/Tag/tag.tsx +5 -3
  444. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  445. package/src/components/Textarea/textarea.spec.md +5 -5
  446. package/src/components/Textarea/textarea.tsx +24 -24
  447. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  448. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  449. package/src/components/TimePicker/time-picker.spec.md +6 -5
  450. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  451. package/src/components/TimePicker/time-picker.tsx +24 -14
  452. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  453. package/src/components/Toast/toast.stories.tsx +1 -1
  454. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  455. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  456. package/src/components/Tooltip/tooltip.spec.md +9 -3
  457. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  458. package/src/components/Tooltip/tooltip.tsx +12 -2
  459. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  460. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  461. package/src/components/TreeView/tree-view.spec.md +8 -6
  462. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  463. package/src/components/TreeView/tree-view.tsx +36 -0
  464. package/src/index.ts +13 -10
  465. package/src/lib/drag-visual.ts +2 -2
  466. package/src/lib/utils.ts +19 -0
  467. package/src/patterns/action-bar/action-bar.spec.md +1 -0
  468. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  469. package/src/patterns/element-anatomy/item-anatomy.spec.md +4 -0
  470. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  471. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  472. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  473. package/src/tokens/categorical-color.ts +5 -5
  474. package/src/tokens/color/color.spec.md +4 -4
  475. package/src/tokens/color/primitives.css +9 -2
  476. package/src/tokens/motion/motion.spec.md +6 -7
  477. package/src/tokens/opacity/opacity.spec.md +1 -1
  478. package/src/tokens/orphan-tokens.spec.md +1 -1
  479. package/src/tokens/typography/typography.spec.md +2 -0
  480. package/src/tokens/uiSize/uiSize.css +5 -0
  481. 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
 
@@ -126,8 +126,9 @@ const newEmptyGroup = (): FilterGroup => ({
126
126
  // ── Component Props ─────────────────────────────────────────────────────
127
127
 
128
128
  export interface DataTableFilterPanelProps<TData> {
129
- /** flat(無 group)or nested(1-level group)— consumer 拍板 */
130
- mode: 'flat' | 'nested'
129
+ // 2026-07-18 決策17:移除獨立 `mode` prop(單一真相源 = `value.mode` discriminant)——
130
+ // 舊設計 mode + value.mode 兩來源型別允許矛盾(mode='nested' 配 flat value → CTA 錯文案 + 死操作);
131
+ // 無外部消費者傳 mode(grep 0),全由 value.mode 推導。對齊 MUI X GridFilterModel / AG Grid 單一 model。
131
132
  /** 可被 filter 的 columns */
132
133
  columns: ColumnDef<TData, any>[]
133
134
  /** 當前 FilterTree(controlled) */
@@ -151,7 +152,6 @@ export interface DataTableFilterPanelProps<TData> {
151
152
 
152
153
  // 內部 fn — generic + ref 轉發。export 走 cast(對齊 DataTable 同 pattern)
153
154
  function DataTableFilterPanelInner<TData>({
154
- mode,
155
155
  columns,
156
156
  value,
157
157
  onChange,
@@ -314,7 +314,7 @@ function DataTableFilterPanelInner<TData>({
314
314
  // 必加 `min-h-0` 才能讓 panel 在 PopoverContent max-h cap 下正確 shrink + body scroll。
315
315
  <div ref={ref} className={cn(
316
316
  'flex flex-col h-full min-h-0',
317
- mode === 'nested'
317
+ value.mode === 'nested'
318
318
  ? 'w-[min(760px,calc(100vw-2rem))]'
319
319
  : 'w-[min(640px,calc(100vw-2rem))]',
320
320
  className,
@@ -387,9 +387,9 @@ function DataTableFilterPanelInner<TData>({
387
387
  <div>
388
388
  <Button
389
389
  variant="tertiary" size="sm" startIcon={Plus}
390
- onClick={mode === 'flat' ? addFlatCondition : addGroup}
390
+ onClick={value.mode === 'flat' ? addFlatCondition : addGroup}
391
391
  >
392
- {mode === 'nested' ? '加入篩選器' : '加篩選'}
392
+ {value.mode === 'nested' ? '加入篩選器' : '加篩選'}
393
393
  </Button>
394
394
  </div>
395
395
  </SurfaceBody>
@@ -63,8 +63,8 @@ interface DataTableInteractionLayerProps {
63
63
  * truthy → layer call this 拿 React node(已 bind value/onCommit/onCancel from controller),
64
64
  * 在 ActiveEditorHost portal(z 3,float rect)render 之。
65
65
  *
66
- * Per codex Q6.2 outline:cell 永遠 mode="display"(SSOT preserved);portal host 渲
67
- * mode="edit" 同 registry component;float pass-through + z-index 3 cover display below。
66
+ * Per codex Q6.2 outline:cell 永遠 mode="view"(SSOT preserved);portal host 渲
67
+ * mode="edit" 同 registry component;float pass-through + z-index 3 cover view below。
68
68
  */
69
69
  activeEditorRender?: (cellId: CellId, rect: CellRect) => React.ReactNode
70
70
  }
@@ -441,7 +441,7 @@ function ClipMask({ clipRect, children }: { clipRect: CellRect; children: React.
441
441
  *
442
442
  * Per codex Q2 verdict:不該進 CellRingOverlay primitive — 它是 host 不是 ring。
443
443
  * - pointerEvents:auto(child Field 接收 click / keyboard)
444
- * - background:var(--canvas)(opaque cover display Field below;Cell SSOT 保留)
444
+ * - background:var(--canvas)(opaque cover view Field below;Cell SSOT 保留)
445
445
  * - z-index 3(above hover / selected / range)
446
446
  * - children = activeEditorRender 的回傳 React node
447
447
  *
@@ -197,11 +197,11 @@ function SortRow({
197
197
  {...listeners}
198
198
  />
199
199
  <div className="flex-1 min-w-0">
200
- <Select size="sm" options={optionsForRow} value={sort.id} onChange={onChangeId} />
200
+ <Select size="sm" aria-label="排序欄位" options={optionsForRow} value={sort.id} onChange={onChangeId} />
201
201
  </div>
202
202
  <div className="w-32 shrink-0">
203
203
  {/* minRows={2} — 升冪/降冪只 2 選項,顯式縮 menu 高度(Q5) */}
204
- <Select size="sm" options={DIRECTION_OPTIONS} value={sort.desc ? 'desc' : 'asc'} onChange={onChangeDir} minRows={2} />
204
+ <Select size="sm" aria-label="排序方向" options={DIRECTION_OPTIONS} value={sort.desc ? 'desc' : 'asc'} onChange={onChangeDir} minRows={2} />
205
205
  </div>
206
206
  {/* Trash 用 text Button(Q4 對齊 filter panel)— form-control row 必 Field 同高 */}
207
207
  <Button variant="text" size="sm" iconOnly startIcon={Trash2} aria-label="刪除" onClick={onRemove} />
@@ -1,9 +1,10 @@
1
1
  // @anatomy-rationale:
2
- // SizeMatrix represented as RowHeightMatrix per row-density semantics
3
- // DataTable size 主軸是 row-height tier(compact / cozy /
4
- // comfortable),語意對應「掃描 vs 閱讀」資料密度;lg 同時連動字級放大
5
- // (sm/md text-body / lg → text-body-lg,對齊 Field,SSOT fieldDisplayTextClass)。命名沿用
6
- // Linear / Notion / Airtable 業界共識(row density,非 component size)。
2
+ // SizeMatrix RowHeightMatrix 呈現 —— DataTable 的 size(sm / md / lg)主要
3
+ // 體現在 row height 這個結構決策上(spec.md「Size 不等於 density」:size
4
+ // 這張表格「需要多緊湊」的結構決策,density 是全域使用者偏好,兩者不同軸,
5
+ // 不套用 compact / cozy / comfortable 等外部密度命名)。lg 同時連動字級放大
6
+ // (sm/md text-body / lg text-body-lg,對齊 Field,SSOT fieldDisplayTextClass)。
7
+ // @benchmark-unverified: Linear / Notion / Airtable 的 row-density 控件僅為外部近似參照,非 DS 命名依據。
7
8
  // StateBehavior covered by ColorMatrix「Row 狀態色彩」段(default / hover /
8
9
  // selected / disabled)+ Features「排序」段。Row 互動是 row-level
9
10
  // 而非元件 level,集中於 Row 色彩展示更直觀。
@@ -71,7 +72,7 @@ export const Overview: Story = {
71
72
  <div className="flex flex-col gap-10">
72
73
  <div>
73
74
  <H3>Anatomy</H3>
74
- <Desc>DataTable 基於 TanStack Table,透過 `meta.type` column type 系統自動套用對應 Field Control 的 Display 子元件渲染 cell。底層用 `&lt;div&gt;` + ARIA role(不用語義 `&lt;table&gt;`)——虛擬捲動需要絕對定位 row,frozen column 需要獨立 scroll 區域,table 的佈局模型兩者都不支援。</Desc>
75
+ <Desc>DataTable 基於 TanStack Table,透過 `meta.type` column type 系統自動套用對應 Field Control 的 view 態渲染 cell。底層用 `&lt;div&gt;` + ARIA role(不用語義 `&lt;table&gt;`)——虛擬捲動需要絕對定位 row,frozen column 需要獨立 scroll 區域,table 的佈局模型兩者都不支援。</Desc>
75
76
  <DataTable columns={columns} data={SAMPLE_DATA} height="auto" />
76
77
  </div>
77
78
 
@@ -83,7 +84,7 @@ export const Overview: Story = {
83
84
  <tbody>
84
85
  <tr><Td>L1 Structure</Td><Td>DOM 結構 + 捲動行為</Td><Td mono>&lt;div&gt; + ARIA role="table/row/cell" + useVirtualizer</Td></tr>
85
86
  <tr><Td>L2 Typography / Spacing</Td><Td>Row 高度 / Cell padding / 對齊</Td><Td mono>--table-row-* + --field-height-* token</Td></tr>
86
- <tr><Td>L3 Cell Rendering</Td><Td>根據 meta.type 自動選 Display 元件</Td><Td mono>cell-registry.tsx cellRegistry 註冊 11 型:string/number/currency/date/time/select/multiSelect/person/multiPerson/boolean/url(column-types.ts 管 type union + 對齊預設)</Td></tr>
87
+ <tr><Td>L3 Cell Rendering</Td><Td>根據 meta.type 自動選對應 Cell 元件</Td><Td mono>cell-registry.tsx cellRegistry 註冊 11 型:string/number/currency/date/time/select/multiSelect/person/multiPerson/boolean/url(column-types.ts 管 type union + 對齊預設)</Td></tr>
87
88
  <tr><Td>L4 Interactions</Td><Td>排序 / 選取 / 欄位拖動 / frozen column</Td><Td>TanStack Table features + 自訂 state</Td></tr>
88
89
  </tbody>
89
90
  </table>
@@ -132,7 +133,7 @@ export const Inspector: Story = {
132
133
  bordered: { control: 'boolean', description: '外框(嵌入已帶框容器時可設 false 避免雙重邊框)' },
133
134
  pinnedLeft: { control: 'boolean', description: 'Pin 產品名稱欄到左側,橫向捲動時保持可見' },
134
135
  pinnedRight: { control: 'boolean', description: 'Pin 上架日期欄到右側' },
135
- inlineEdit: { control: 'boolean', description: 'inline edit 視覺:cell 間加垂直分隔線(dtCellGrid)。display 態零恆顯 chevron(2026-07-08 A 案,editable affordance = hover outline);edit 態才有控件 chrome' },
136
+ inlineEdit: { control: 'boolean', description: 'inline edit 視覺:cell 間加垂直分隔線(dtCellGrid)。view 態零恆顯 chevron(2026-07-08 A 案,editable affordance = hover outline);edit 態才有控件 chrome' },
136
137
  height: {
137
138
  control: 'select',
138
139
  options: ['auto', '300px'],
@@ -182,7 +183,7 @@ export const ColumnTypes: Story = {
182
183
  <div className="flex flex-col gap-8">
183
184
  <div>
184
185
  <H3>meta.type 系統</H3>
185
- <Desc>每個 column 透過 `meta.type` 宣告資料類型,DataTable 自動選擇對應 Field Control 的 `mode="display"` 渲染——消費者不需要手寫 cell。</Desc>
186
+ <Desc>每個 column 透過 `meta.type` 宣告資料類型,DataTable 自動選擇對應 Field Control 的 `mode="view"` 渲染——消費者不需要手寫 cell。</Desc>
186
187
  <DataTable columns={columns} data={SAMPLE_DATA} height="auto" />
187
188
  </div>
188
189
 
@@ -190,21 +191,21 @@ export const ColumnTypes: Story = {
190
191
  <H3>支援的 Column Types</H3>
191
192
  <div className="overflow-x-auto">
192
193
  <table className="text-caption border-collapse">
193
- <thead><tr><Th>meta.type</Th><Th>Display 渲染</Th><Th>對齊</Th><Th>典型場景</Th></tr></thead>
194
+ <thead><tr><Th>meta.type</Th><Th>view 渲染</Th><Th>對齊</Th><Th>典型場景</Th></tr></thead>
194
195
  <tbody>
195
- <tr><Td mono>string</Td><Td mono>{`<Input mode="display">`}</Td><Td>left</Td><Td>姓名、title、slug</Td></tr>
196
- <tr><Td mono>number</Td><Td mono>{`<NumberInput mode="display">`}</Td><Td>right</Td><Td>數量、年齡</Td></tr>
197
- <tr><Td mono>currency</Td><Td mono>{`<NumberInput mode="display">`}(+ prefix)</Td><Td>right</Td><Td>金額、價格</Td></tr>
198
- <tr><Td mono>date</Td><Td mono>{`<DatePicker mode="display">`}</Td><Td>left</Td><Td>日期、時間戳</Td></tr>
199
- <tr><Td mono>boolean</Td><Td mono>{`<Checkbox mode="display">`}(勾 / 叉 icon)</Td><Td>left</Td><Td>啟用 / 可見</Td></tr>
200
- <tr><Td mono>select</Td><Td mono>{`<Select mode="display">`}</Td><Td>left</Td><Td>狀態、類別</Td></tr>
201
- <tr><Td mono>multiSelect</Td><Td mono>{`<Combobox mode="display">`}</Td><Td>left</Td><Td>多選 tags</Td></tr>
196
+ <tr><Td mono>string</Td><Td mono>{`<Input mode="view">`}</Td><Td>left</Td><Td>姓名、title、slug</Td></tr>
197
+ <tr><Td mono>number</Td><Td mono>{`<NumberInput mode="view">`}</Td><Td>right</Td><Td>數量、年齡</Td></tr>
198
+ <tr><Td mono>currency</Td><Td mono>{`<NumberInput mode="view">`}(+ prefix)</Td><Td>right</Td><Td>金額、價格</Td></tr>
199
+ <tr><Td mono>date</Td><Td mono>{`<DatePicker mode="view">`}</Td><Td>left</Td><Td>日期、時間戳</Td></tr>
200
+ <tr><Td mono>boolean</Td><Td mono>{`<Checkbox mode="view">`}(勾 / 叉 icon)</Td><Td>left</Td><Td>啟用 / 可見</Td></tr>
201
+ <tr><Td mono>select</Td><Td mono>{`<Select mode="view">`}</Td><Td>left</Td><Td>狀態、類別</Td></tr>
202
+ <tr><Td mono>multiSelect</Td><Td mono>{`<Combobox mode="view">`}</Td><Td>left</Td><Td>多選 tags</Td></tr>
202
203
  <tr><Td mono>person</Td><Td mono>PersonDisplay / MultiPersonDisplay</Td><Td>left</Td><Td>指派者、reviewer</Td></tr>
203
- <tr><Td mono>url</Td><Td mono>{`<LinkInput mode="display">`}</Td><Td>left</Td><Td>URL</Td></tr>
204
+ <tr><Td mono>url</Td><Td mono>{`<LinkInput mode="view">`}</Td><Td>left</Td><Td>URL</Td></tr>
204
205
  </tbody>
205
206
  </table>
206
207
  </div>
207
- <p className="text-footnote text-fg-muted mt-3">擴充新 type:在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(display/edit 渲染 SSOT);`column-types.ts` 只設 `align` / default metadata。兩處對齊後自動跟所有 DataTable 整合</p>
208
+ <p className="text-footnote text-fg-muted mt-3">擴充新 type:在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(view/edit 渲染 SSOT);`column-types.ts` 只設 `align` / default metadata。兩處對齊後自動跟所有 DataTable 整合</p>
208
209
  </div>
209
210
  </div>
210
211
  )
@@ -419,14 +420,14 @@ export const ColorMatrix: Story = {
419
420
  選取狀態由 __select__ 欄的 checkbox / radio 呈現,不套 row 底色;hover 與 selection 正交
420
421
  (已選 row 仍可有 hover 的 neutral-hover tint,但不疊額外 selected 底色)。
421
422
  isRowSelectable=false 僅 disable checkbox,row 不灰底(spec 禁止事項);
422
- cell-level disabled(inline edit cellDisabled)才套 --bg-disabled
423
+ (2026-07-16 cell disabled 態已廢除,cell 不再套 --bg-disabled;鎖定改用 editable=false 純 view 態)。
423
424
  </p>
424
425
  </div>
425
426
 
426
427
  <div>
427
- <H3>Cell 內 Display element 色彩</H3>
428
+ <H3>Cell 內 view element 色彩</H3>
428
429
  <Desc>
429
- Cell 內的資料元件(Tag / Person / Link / NumberDisplay)各自維持 Field Controls 的 display 色彩。
430
+ Cell 內的資料元件(Tag / Person / Link / NumberDisplay)各自維持 Field Controls 的 view 色彩。
430
431
  DataTable 不覆寫 cell 內的色彩 token,維持跨元件視覺統一。
431
432
  </Desc>
432
433
  <div className="overflow-x-auto">
@@ -434,7 +435,7 @@ export const ColorMatrix: Story = {
434
435
  <thead>
435
436
  <tr>
436
437
  <Th>meta.type</Th>
437
- <Th>Display 色彩</Th>
438
+ <Th>view 色彩</Th>
438
439
  </tr>
439
440
  </thead>
440
441
  <tbody>
@@ -463,7 +464,7 @@ export const EmptyState: Story = {
463
464
  return (
464
465
  <div>
465
466
  <H3>無資料時消費 Empty primitive</H3>
466
- <Desc>DataTable 的 empty state 走共用 `Empty` 元件——保持跟其他空狀態(SelectMenu、Combobox、Page section)視覺一致。Consumer 不需自訂,自動顯示標準空狀態。</Desc>
467
+ <Desc>DataTable 的 empty state 走共用 `Empty` 元件——保持跟其他空狀態(SelectMenu、Combobox、Page section)視覺一致。未傳 `emptyState` 時顯示下方的標準 fallback;正式產品應傳 `emptyState` 以業務語言說明「缺什麼資料 + 下一步」,避免抽象的「沒有資料」(對齊 Empty 文案準則)。</Desc>
467
468
  <DataTable columns={columns} data={[]} height="auto" />
468
469
  </div>
469
470
  )
@@ -133,9 +133,8 @@
133
133
  (在 cell content 之下),non-overlay。Per codex Q1 verdict 對齊 row selected idiom
134
134
  `--primary-subtle`(`data-table.spec.md`「L2 選取」段;原引 L170-174 之 selected-row bg 語意 2026-05-31 已廢除,改指現行段)。
135
135
  Layer 不再畫 RangeFill div(避免 layer fixed positioned bg 蓋 cell content)。 */
136
- /* 2026-05-13 V1.6 fix(codex caught medium severity):disabled cell bg dominance — disabled cell
137
- included in spreadsheet range 不該被 range fill 蓋過,disabled state visual 必勝。 */
138
- [data-range-cell]:not([data-cell-disabled="true"]) {
136
+ /* range fill bg(2026-07-16:cell disabled 態已廢除,原 `:not([data-cell-disabled])` exclusion 移除) */
137
+ [data-range-cell] {
139
138
  background: var(--primary-subtle);
140
139
  }
141
140
 
@@ -4,6 +4,7 @@ import LinkTo from '@storybook/addon-links/react'
4
4
  import type { Meta, StoryObj } from '@storybook/react'
5
5
  import { createColumnHelper } from '@tanstack/react-table'
6
6
  import { DataTable } from './data-table'
7
+ import { Empty } from '@/design-system/components/Empty/empty'
7
8
  import './column-types'
8
9
 
9
10
  const meta: Meta = {
@@ -71,7 +72,7 @@ export const UsageGuidance: Story = {
71
72
  <p>適合 DataTable 的真實業務場景(點擊跳轉「展示」頁範例):</p>
72
73
  <ul className="space-y-1">
73
74
  <li>
74
- <LinkTo kind="Design System/Components/DataTable/展示" name="數字靠右對齊"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">商品庫存後台 — 單價 / 金額數字靠右對齊</span></LinkTo>
75
+ <LinkTo kind="Design System/Components/DataTable/設計規格" name="對齊規則(跨產業共識)"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">商品庫存後台 — 單價 / 金額數字靠右對齊</span></LinkTo>
75
76
  </li>
76
77
  <li>
77
78
  <LinkTo kind="Design System/Components/DataTable/展示" name="自動行高"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">商品備註長短不一 — 自動行高撐開列高</span></LinkTo>
@@ -132,22 +133,22 @@ export const ColumnTypeRule: Story = {
132
133
  return (
133
134
  <div>
134
135
  <Rule
135
- title="✅ 宣告 `meta.type`,DataTable 自動選對應 Display"
136
- note="每個 Field Control 的 `mode='display'` 渲染(`<Input mode='display'>` / `<NumberInput mode='display'>` / `<Checkbox mode='display'>` 等)是該資料類型的唯一真實來源——format 邏輯、對齊、null 顯示都住一份。Consumer 只需宣告 type,不需重複造輪子"
136
+ title="✅ 宣告 `meta.type`,DataTable 自動選對應 view 渲染"
137
+ note="每個 Field Control 的 `mode='view'` 渲染(`<Input mode='view'>` / `<NumberInput mode='view'>` / `<Checkbox mode='view'>` 等)是該資料類型的唯一真實來源——format 邏輯、對齊、null 顯示都住一份。Consumer 只需宣告 type,不需重複造輪子"
137
138
  >
138
139
  <DataTable columns={columns} data={SAMPLE_DATA} height="auto" />
139
140
  </Rule>
140
141
 
141
142
  <Rule
142
143
  title="❌ 手寫 cell render 自訂格式化"
143
- note="每 column 自己寫 `cell: (info) => ...` 會繞過 `mode='display'` 系統——**格式化邏輯會漂移**。一個 table 的 price 顯示「$2,490」,另一個 table 的 price 顯示「2490」,一個 boolean 顯示勾 icon,另一個 boolean 顯示「是」——整個系統 format 失去一致性"
144
+ note="每 column 自己寫 `cell: (info) => ...` 會繞過 `mode='view'` 系統——**格式化邏輯會漂移**。一個 table 的 price 顯示「$2,490」,另一個 table 的 price 顯示「2490」,一個 boolean 顯示勾 icon,另一個 boolean 顯示「是」——整個系統 format 失去一致性"
144
145
  >
145
- <Label warn>除非真的需要 `mode='display'` 無法提供的客製視覺,否則一律走 meta.type 系統。客製化時完全跳過 type 讓 display 渲染不要干預</Label>
146
+ <Label warn>除非真的需要 `mode='view'` 無法提供的客製視覺,否則一律走 meta.type 系統。客製化時完全跳過 type 讓 view 渲染不要干預</Label>
146
147
  </Rule>
147
148
 
148
149
  <Rule
149
150
  title="擴充新 type:到 cell-registry.tsx 註冊"
150
- note="新增資料類型(如 `percentage`、`relative-time`)在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(display/edit 渲染 SSOT);`column-types.ts` 只設 align / default metadata。兩處對齊後自動跟所有 DataTable 整合,不在單一 table 硬寫"
151
+ note="新增資料類型(如 `percentage`、`relative-time`)在 `cell-registry.tsx` 的 `cellRegistry` map 註冊對應 Cell component(view/edit 渲染 SSOT);`column-types.ts` 只設 align / default metadata。兩處對齊後自動跟所有 DataTable 整合,不在單一 table 硬寫"
151
152
  >
152
153
  <Label>讓 column type 系統成為 single source of truth,所有 table 受惠同一次更新</Label>
153
154
  </Rule>
@@ -189,7 +190,7 @@ export const VirtualScrollRule: Story = {
189
190
 
190
191
  <Rule
191
192
  title="固定 height 數字 — 大量資料(> 100 筆),啟用 virtualization"
192
- note="傳固定高度時 TanStack Virtual 自動啟用——只渲染可見 rows。500 筆資料只渲染 ~20 rows,效能不受資料量影響"
193
+ note="傳固定高度時 TanStack Virtual 自動啟用——只渲染可見 rows。500 筆資料只渲染 ~20 rows,大幅降低列渲染成本。注意:排序 / 篩選 / 完整 row model 與記憶體成本仍隨資料量增長——超大量或遠端資料仍需分頁或 server-side 排序 / 篩選"
193
194
  >
194
195
  <DataTable columns={columns} data={bigData} height="400px" />
195
196
  <Label>↑ 500 筆資料,固定 400px 高度 → virtualizer 只渲染畫面中的 ~20 rows</Label>
@@ -218,10 +219,15 @@ export const EmptyStateRule: Story = {
218
219
  <div>
219
220
  <Rule
220
221
  title="✅ 無資料 → 消費 Empty primitive(跟系統統一)"
221
- note="DataTable empty state 走共用 `Empty` 元件——保持跟 SelectMenu / Combobox / Page section 視覺一致。Consumer 不自訂,自動顯示標準空狀態"
222
+ note="DataTable empty state 走共用 `Empty` 元件——保持跟 SelectMenu / Combobox / Page section 視覺一致。「不自訂」指不手刻自家 empty 視覺,不是省略文案:正式產品應傳 `emptyState` 以業務語言說明「缺什麼資料 + 下一步」(對齊 Empty 文案準則);未傳時才落回抽象 fallback「沒有資料」"
222
223
  >
223
- <DataTable columns={columns} data={[]} height="auto" />
224
- <Label>↑ DataTable 內部自動消費 Empty primitive</Label>
224
+ <DataTable
225
+ columns={columns}
226
+ data={[]}
227
+ height="auto"
228
+ emptyState={<Empty title="尚無商品" description="點擊上方「新增商品」開始建立第一筆" />}
229
+ />
230
+ <Label>↑ 傳 `emptyState` 消費 Empty primitive,並以業務語言描述缺什麼資料</Label>
225
231
  </Rule>
226
232
 
227
233
  <Rule
@@ -248,7 +254,7 @@ export const NotSpreadsheetRule: Story = {
248
254
  <div>
249
255
  <Rule
250
256
  title="DataTable 預設不做公式計算、不做跨 cell 選取"
251
- note="DataTable 的心智模型是「結構化資料展示」——每筆資料是一 row,每個屬性是一 column。預設不做:Excel 的公式、跨 cell range selection(Ctrl+drag)、cell clipboard paste、pivot、跨欄運算。**逃生門**:確需 Excel-like 編輯可 opt-in `spreadsheetMode` prop(Shift+click range + 方向鍵 cell 導覽 + cell editing;仍不做公式計算),對齊 spec.md L28。"
257
+ note="DataTable 的心智模型是「結構化資料展示」——每筆資料是一 row,每個屬性是一 column。預設不做:Excel 的公式、跨 cell range selection(Ctrl+drag)、cell clipboard paste、pivot、跨欄運算。**逃生門**:確需 Excel-like 編輯可 opt-in `spreadsheetMode` prop(Shift+click range + 方向鍵 cell 導覽 + cell editing;仍不做公式計算)——即使開啟 spreadsheetMode,DataTable 仍只是「可 range 選取 + 方向鍵導覽 + inline 編輯」的結構化資料表,不會變成有公式引擎的試算表。"
252
258
  >
253
259
  <Label>需要試算表能力 → 用專門 library(AG Grid Enterprise / Handsontable / Luckysheet),不往 DataTable 塞</Label>
254
260
  </Rule>
@@ -72,7 +72,7 @@ DataTable 有三種尺寸(`sm`、`md`、`lg`),透過 `size` prop 控制。
72
72
 
73
73
  水平 padding 固定,不隨 size 或 density 變化(具體 token 見 `data-table.tsx`);垂直方向由行高模式決定(見第四節)。
74
74
 
75
- **Cell / header 字級隨 size,對齊 Field family。** 三種 size 的 cell 與 header 預設字級**必與同 size 的 Field 一致**:`sm`/`md` → `text-body`(14px)、`lg` → `text-body-lg`(16px),SSOT = `fieldDisplayTextClass()`(`field-wrapper.tsx`)。`lg` 行高放大時字級同步放大,避免「字小、行高大」失衡。**機制**:typed cell 由各自 Field 控件吃 `size` 自動套用(cell-registry 各 cell display mode 必傳 `size`,**禁漏傳**否則 fallback md 卡 14px);header 與非-Field 內容(consumer 自訂 cell)由 cell wrapper / header `cn(fieldDisplayTextClass(size))` 套用。`1lh`-based cell-py 公式(見第四節)隨字級自動吸收,row 高不變。
75
+ **Cell / header 字級隨 size,對齊 Field family。** 三種 size 的 cell 與 header 預設字級**必與同 size 的 Field 一致**:`sm`/`md` → `text-body`(14px)、`lg` → `text-body-lg`(16px),SSOT = `fieldDisplayTextClass()`(`field-wrapper.tsx`)。`lg` 行高放大時字級同步放大,避免「字小、行高大」失衡。**機制**:typed cell 由各自 Field 控件吃 `size` 自動套用(cell-registry 各 cell view mode 必傳 `size`,**禁漏傳**否則 fallback md 卡 14px);header 與非-Field 內容(consumer 自訂 cell)由 cell wrapper / header `cn(fieldDisplayTextClass(size))` 套用。`1lh`-based cell-py 公式(見第四節)隨字級自動吸收,row 高不變。
76
76
 
77
77
  ### 二、高度模式(有高度約束 vs 無高度約束,決定可用的功能組合)
78
78
 
@@ -120,7 +120,7 @@ Table 層級的模式切換,不是 column 層級。跟 AG Grid / Airtable 的
120
120
 
121
121
  ### 六之二、Column 寬度 API + 不變條件(2026-05-06 v14.3)
122
122
 
123
- **命名**:`meta.width` / `meta.minWidth` / `meta.maxWidth`(px)。**不用 TanStack `size`** — DS 內 `size` 既定為 `'sm'|'md'|'lg'` density(49+ 處),避 namespace 衝突。內部 pre-process copy 到 TanStack root,resize feature 正常。No-resize default:`width` = reserve(cell ≥ width,flex 可 grow,不可 shrink)。`enableColumnResize=true`:`width` = 初始,`minWidth` = 拖拉下限(default 80)。**不變條件(invariants,L2 test + hook 守)**:(1) cell width = column width(跟 padding/state/mode 無關)(2) display↔edit cell width 0 delta (3) display↔edit cell height 0 delta(textarea `field-sizing:content`)(4) Field 填滿 cell 高度(1px 容差於 cell.border-r)(5) No-resize column ≥ meta.width。對應 `scripts/data-table-invariants.mjs`。改 `columnSizeStyle` / 切 layout 必跑 invariant test 才 commit。
123
+ **命名**:`meta.width` / `meta.minWidth` / `meta.maxWidth`(px)。**不用 TanStack `size`** — DS 內 `size` 既定為 `'sm'|'md'|'lg'` density(49+ 處),避 namespace 衝突。內部 pre-process copy 到 TanStack root,resize feature 正常。No-resize default:`width` = reserve(cell ≥ width,flex 可 grow,不可 shrink)。`enableColumnResize=true`:`width` = 初始,`minWidth` = 拖拉下限(default 80)。**不變條件(invariants,L2 test + hook 守)**:(1) cell width = column width(跟 padding/state/mode 無關)(2) view↔edit cell width 0 delta (3) view↔edit cell height 0 delta(textarea `field-sizing:content`)(4) Field 填滿 cell 高度(1px 容差於 cell.border-r)(5) No-resize column ≥ meta.width。對應 `scripts/data-table-invariants.mjs`(script 內 I1-I3 label 字串仍用 `display↔edit` — 2026-07-16 FieldMode display→view 更名前的歷史命名,語意同 view↔edit)。改 `columnSizeStyle` / 切 layout 必跑 invariant test 才 commit。
124
124
 
125
125
  ### 六之三、Runtime perf budget canonical(2026-05-14 codex+Layer A)
126
126
 
@@ -164,7 +164,7 @@ SSOT → `patterns/element-anatomy/inline-action.spec.md`「Real case 表」+ Pr
164
164
  |------|-----------|
165
165
  | Header cell internal(sort / ⌄ menu / filter funnel / pin)| `ItemInlineActionButton` `size="md"`(對齊 AG Grid / Material / Airtable / Notion / Polaris) | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
166
166
  | **Multi-sort header(≥2 columns sorted)** | **隱藏 header arrow + 取消排序 dropdown option**(K7,2026-05-04)— 無 order 編號的單個 arrow 在 multi-sort 是 partial info → 反而混淆;user 走 SortManager panel 看完整 priority(SSOT)。0/1 sort 仍秀 arrow 完整資訊。理由:現行 DS 不顯 sort order 編號,跟 Airtable / Linear / Atlassian / Carbon 純箭頭派一致;multi-sort 時這派需 SortManager fallback(world-class 共識) |
167
- | Body cell internal(display endAction / clear / edit indicator)| Field family endAction(自動繼承)。**Display 態零恆顯型別 icon(2026-07-08 A 案)**:editable affordance = hover outline(SSOT → field.spec.md L4/L6,`nakedCellEditableDisplayHover`);boolean = live Checkbox(AG Grid 同);url = hover Pencil(click-opens-link 與 edit 衝突的功能性入口,非型別 indicator)。**cell 空值 = 全空白**(2026-07-08 B 案,SSOT → field-controls.spec.md「null / undefined 值」surface 分流表) |
167
+ | Body cell internal(view endAction / clear / edit indicator)| Field family endAction(自動繼承)。**View 態零恆顯型別 icon(2026-07-08 A 案)**:editable affordance = hover outline(SSOT → field.spec.md L4/L6,`nakedCellEditableDisplayHover`);boolean = live Checkbox(AG Grid 同);url = hover Pencil(click-opens-link 與 edit 衝突的功能性入口,非型別 indicator)。**cell 空值 = 全空白**(2026-07-08 B 案,SSOT → field-controls.spec.md「null / undefined 值」surface 分流表) |
168
168
  | Row dedicated action column | Button `xs iconOnly` 24px(見「九、Row Actions」) |
169
169
  | Toolbar | Button(action-bar 共識) |
170
170
 
@@ -180,7 +180,7 @@ Cell 已 `flex items-center`,consumer render 直接 inline-flex + gap-2。Icon s
180
180
 
181
181
  ### 十一、Cell 單行截斷原則
182
182
 
183
- 固定行高下 cell 單行,空間不足:純文字 `text-overflow: ellipsis`;Tag 文字內部 truncate(Tag bg 跟縮);multiSelect 動態 `+N`;Person avatar 不縮 name truncate;Link truncate。每個 Display 元件自管 truncation,Cell `overflow-hidden` 僅 safety net。截斷必顯 `...`(禁硬裁無 ellipsis)。截斷 hover 顯 tooltip。autoRowHeight wrap 模式不適用(可換行撐 row 高)。
183
+ 固定行高下 cell 單行,空間不足:純文字 `text-overflow: ellipsis`;Tag 文字內部 truncate(Tag bg 跟縮);multiSelect 動態 `+N`;Person avatar 不縮 name truncate;Link truncate。每個 view 態元件自管 truncation,Cell `overflow-hidden` 僅 safety net。截斷必顯 `...`(禁硬裁無 ellipsis)。截斷 hover 顯 tooltip。autoRowHeight wrap 模式不適用(可換行撐 row 高)。
184
184
 
185
185
  ### 十二、可推導值用 `calc()` 表達(不硬寫結果)— 上游動,下游自動跟著算
186
186
 
@@ -442,9 +442,9 @@ Row drag + column reorder + TreeView 共用 `lib/drag-visual.ts`:source `opacity
442
442
 
443
443
  ## Overlay + cell error SSOT(Phase 9)
444
444
 
445
- **Overlay**:viewport `position:fixed inset:0` layer。`getCellRect()` 從 `getBoundingClientRect()` 取 float coords no rounding。Paint:hover/selected ring `outline outline-offset:-1px` in-place(range outer ring 已 2026-05-10 retire — range 視覺只剩 cell-bg `--primary-subtle` `[data-range-cell]`,bg 已足以標示範圍、外框冗餘);active editor host portal opaque `<div>` z 3(cell 保持 display)。**Viewport clip**(Issue 6):body panel 加 `data-datatable-panel="left|center|right"`;`getCellGeometry()` return cell+panel rect;`<ClipMask>` panel rect `overflow:hidden`,內部 `toRelRect()` 轉 mask-relative(hover/selected ring 按 panel clip,不畫出 pin boundary)。Active editor host **不 clip**。對齊 AG Grid `cellsForRangeSet` / Glide / Notion sticky-cell mask。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
445
+ **Overlay**:viewport `position:fixed inset:0` layer。`getCellRect()` 從 `getBoundingClientRect()` 取 float coords no rounding。Paint:hover/selected ring `outline outline-offset:-1px` in-place(range outer ring 已 2026-05-10 retire — range 視覺只剩 cell-bg `--primary-subtle` `[data-range-cell]`,bg 已足以標示範圍、外框冗餘);active editor host portal opaque `<div>` z 3(cell 保持 view 態)。**Viewport clip**(Issue 6):body panel 加 `data-datatable-panel="left|center|right"`;`getCellGeometry()` return cell+panel rect;`<ClipMask>` panel rect `overflow:hidden`,內部 `toRelRect()` 轉 mask-relative(hover/selected ring 按 panel clip,不畫出 pin boundary)。Active editor host **不 clip**。對齊 AG Grid `cellsForRangeSet` / Glide / Notion sticky-cell mask。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
446
446
 
447
- **Cell errors**(Issue 9):`cellErrors?: Record<string, string|string[]>` prop key `${rowId}:${colId}`。Cell display error 14px `text-error` 下方 gap-1;array→`<ul><li>`;single→`<span>`。`aria-describedby` + `aria-invalid` + `<span role="alert">`。`overflow:visible` 當有 error(搭 `autoRowHeight`)。**Per-row state SSOT** cell-render wrapper(`items-X` 等)必 consume `effectiveAutoRowForCell`,禁 global `autoRowHeight`(audit `audit-data-table-row-mode-ssot.mjs` 強制)。**Edit-clears-own-cell** 自動清視覺,consumer onCellCommit validate 後回填。**a11y caveat**:≥ 5 同時 `role="alert"` 第一次 paint AT 噪音 → consumer 可考 `role="status"` fallback。對齊 AG Grid `cellClassRules='ag-cell-error'` + Material X errorMessage + Airtable validation。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
447
+ **Cell errors**(Issue 9):`cellErrors?: Record<string, string|string[]>` prop key `${rowId}:${colId}`。Cell view 態渲 error 14px `text-error` 下方 gap-1;array→`<ul><li>`;single→`<span>`。`aria-describedby` + `aria-invalid` + `<span role="alert">`。`overflow:visible` 當有 error(搭 `autoRowHeight`)。**Per-row state SSOT** cell-render wrapper(`items-X` 等)必 consume `effectiveAutoRowForCell`,禁 global `autoRowHeight`(audit `audit-data-table-row-mode-ssot.mjs` 強制)。**Edit-clears-own-cell** 自動清視覺,consumer onCellCommit validate 後回填。**a11y caveat**:≥ 5 同時 `role="alert"` 第一次 paint AT 噪音 → consumer 可考 `role="status"` fallback。對齊 AG Grid `cellClassRules='ag-cell-error'` + Material X errorMessage + Airtable validation。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
448
448
 
449
449
  ---
450
450
 
@@ -492,7 +492,7 @@ DataTable 是 composite multi-section 元件,**不套 SizeMatrix / StateBehavior
492
492
 
493
493
  **Keyboard 行為**(目前實作 — `tableKeyboardHandler`):
494
494
  - ↑↓←→:cell-to-cell navigation **僅 `spreadsheetMode` opt-in 時生效**;selection 尚未建立時按方向鍵自動選取第一個 visible cell(鍵盤可直接進入 spreadsheet 導覽,無需滑鼠 click — 對齊 Excel / Google Sheets / AG Grid「focus grid → first cell active」,2026-07-05 D4 補);預設模式方向鍵無作用
495
- - Enter / F2:spreadsheet 模式下進 cell editing(cell 可編輯 + 非 boolean/url + 非 disabled 時);**Enter 確認後維持原格不下移**(2026-07-05 user 拍板;10 家實查:Excel 系 7 家下移、AG Grid 預設維持原格 — 採 AG Grid 派,數據 → `.claude/logs/deep-audit-2026-07-03/enter-commit-navigation-benchmark.json`;未來連續輸入需求可重議 opt-in);**edit 退出(commit / Esc)後 selection 還原至該 cell、焦點還給 table root**(editor unmount 後焦點掉到 body 才收回,不搶 user 點擊的新焦點 — 對齊 spreadsheet RFC Contract 11 + Excel / AG Grid,2026-07-05 D4 補)
495
+ - Enter / F2:spreadsheet 模式下進 cell editing(cell 可編輯 + 非 boolean/url 時);**Enter 確認後維持原格不下移**(2026-07-05 user 拍板;10 家實查:Excel 系 7 家下移、AG Grid 預設維持原格 — 採 AG Grid 派,數據 → `.claude/logs/deep-audit-2026-07-03/enter-commit-navigation-benchmark.json`;未來連續輸入需求可重議 opt-in);**edit 退出(commit / Esc)後 selection 還原至該 cell、焦點還給 table root**(editor unmount 後焦點掉到 body 才收回,不搶 user 點擊的新焦點 — 對齊 spreadsheet RFC Contract 11 + Excel / AG Grid,2026-07-05 D4 補)
496
496
  - Cmd/Ctrl+A:`mode="multi"` selection 時選全可見列(扣 disabled)
497
497
  - Esc:取消 editing(spreadsheet)/ 清 selection(selection mode);**IME 組字中的 Enter / Esc 不觸發 commit / cancel**(cell editor 帶 `isComposing` guard,2026-07-05 D4 補 — 中文選字 Enter 不誤提交半截組字)
498
498
  - Tab:進入表格後操作排序與勾選;portal edit(`experimentalActiveEditorController`)中 Tab / Shift+Tab = commit 當前 draft + 移至下一個 editable cell 進 edit(2026-07-05 D4 補 commit — 原本換格丟 draft)
@@ -511,6 +511,7 @@ DataTable 是 composite multi-section 元件,**不套 SizeMatrix / StateBehavior
511
511
  - `carousel.spec.md`
512
512
  - `circular-progress.spec.md`
513
513
  - `description-list.spec.md`
514
+ - `filter-operators.spec.md`
514
515
  - `opacity.spec.md`
515
516
  - `pagination.spec.md`
516
517
  - `scroll-area.spec.md`