@qijenchen/design-system 0.1.0-beta.85 → 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 (477) 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 +11 -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 +7 -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 +9 -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/Field/field-context.ts +17 -11
  323. package/src/components/Field/field-controls.spec.md +44 -37
  324. package/src/components/Field/field-types.ts +14 -12
  325. package/src/components/Field/field-wrapper.tsx +59 -43
  326. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  327. package/src/components/Field/field.principles.stories.tsx +5 -28
  328. package/src/components/Field/field.spec.md +4 -4
  329. package/src/components/Field/field.stories.tsx +103 -72
  330. package/src/components/Field/field.tsx +36 -4
  331. package/src/components/Field/form-validation.spec.md +2 -0
  332. package/src/components/Field/use-form-validation.ts +1 -1
  333. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  334. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  335. package/src/components/FileItem/file-item.tsx +10 -8
  336. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  337. package/src/components/FileUpload/file-upload.spec.md +3 -2
  338. package/src/components/FileUpload/file-upload.tsx +5 -1
  339. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  340. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  342. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  343. package/src/components/FileViewer/file-viewer.tsx +3 -2
  344. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  345. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  346. package/src/components/HoverCard/hover-card.spec.md +2 -2
  347. package/src/components/HoverCard/hover-card.tsx +4 -2
  348. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  349. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  350. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  351. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  352. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  353. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  354. package/src/components/Input/input.principles.stories.tsx +3 -3
  355. package/src/components/Input/input.spec.md +4 -4
  356. package/src/components/Input/input.stories.tsx +3 -3
  357. package/src/components/Input/input.tsx +13 -13
  358. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  359. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  360. package/src/components/LinkInput/link-input.spec.md +6 -2
  361. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  362. package/src/components/LinkInput/link-input.tsx +21 -19
  363. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  364. package/src/components/Notice/notice.tsx +8 -2
  365. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  366. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  367. package/src/components/NumberInput/number-input.spec.md +6 -6
  368. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  369. package/src/components/NumberInput/number-input.tsx +17 -5
  370. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  371. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  372. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  373. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  374. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  375. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  376. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  377. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  378. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  379. package/src/components/PeoplePicker/person-display.tsx +3 -3
  380. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  381. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  382. package/src/components/Popover/popover.spec.md +4 -2
  383. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  384. package/src/components/ProfileCard/profile-card.tsx +1 -1
  385. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  386. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  387. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  388. package/src/components/README.md +1 -0
  389. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  390. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  391. package/src/components/RadioGroup/radio-group.tsx +19 -14
  392. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  393. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  394. package/src/components/Rating/rating.spec.md +2 -2
  395. package/src/components/Rating/rating.stories.tsx +4 -18
  396. package/src/components/Rating/rating.tsx +5 -1
  397. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  398. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  399. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  400. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  401. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  402. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  403. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  404. package/src/components/Select/select.principles.stories.tsx +3 -3
  405. package/src/components/Select/select.spec.md +9 -1
  406. package/src/components/Select/select.stories.tsx +41 -27
  407. package/src/components/Select/select.tsx +44 -26
  408. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  410. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  411. package/src/components/SelectMenu/select-menu.tsx +38 -5
  412. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  413. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  414. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  415. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  416. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  417. package/src/components/Sheet/sheet.tsx +4 -1
  418. package/src/components/Sidebar/sidebar.tsx +1 -1
  419. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  420. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  421. package/src/components/Slider/slider.spec.md +13 -1
  422. package/src/components/Slider/slider.stories.tsx +44 -32
  423. package/src/components/Slider/slider.tsx +13 -4
  424. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  425. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  426. package/src/components/Steps/steps.spec.md +4 -2
  427. package/src/components/Steps/steps.stories.tsx +4 -56
  428. package/src/components/Steps/steps.tsx +31 -7
  429. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  430. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  431. package/src/components/Switch/switch.spec.md +4 -4
  432. package/src/components/Switch/switch.stories.tsx +3 -3
  433. package/src/components/Switch/switch.tsx +16 -10
  434. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  435. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  436. package/src/components/Tabs/tabs.spec.md +5 -2
  437. package/src/components/Tabs/tabs.stories.tsx +36 -44
  438. package/src/components/Tabs/tabs.tsx +101 -36
  439. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  440. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  441. package/src/components/Tag/tag.spec.md +3 -1
  442. package/src/components/Tag/tag.tsx +5 -3
  443. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  444. package/src/components/Textarea/textarea.spec.md +5 -5
  445. package/src/components/Textarea/textarea.tsx +24 -24
  446. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  447. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  448. package/src/components/TimePicker/time-picker.spec.md +6 -5
  449. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  450. package/src/components/TimePicker/time-picker.tsx +24 -14
  451. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  452. package/src/components/Toast/toast.stories.tsx +1 -1
  453. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  454. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  455. package/src/components/Tooltip/tooltip.spec.md +9 -3
  456. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  457. package/src/components/Tooltip/tooltip.tsx +12 -2
  458. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  459. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  460. package/src/components/TreeView/tree-view.spec.md +8 -6
  461. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  462. package/src/components/TreeView/tree-view.tsx +36 -0
  463. package/src/index.ts +13 -10
  464. package/src/lib/drag-visual.ts +2 -2
  465. package/src/lib/utils.ts +19 -0
  466. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  467. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  468. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  469. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  470. package/src/tokens/categorical-color.ts +5 -5
  471. package/src/tokens/color/color.spec.md +4 -4
  472. package/src/tokens/color/primitives.css +9 -2
  473. package/src/tokens/opacity/opacity.spec.md +1 -1
  474. package/src/tokens/orphan-tokens.spec.md +1 -1
  475. package/src/tokens/typography/typography.spec.md +2 -0
  476. package/src/tokens/uiSize/uiSize.css +5 -0
  477. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -7,7 +7,7 @@
7
7
  // - data-table-filter-panel.tsx + data-table-sort-manager.tsx + data-table-column-visibility-panel.tsx(panel state 隔離)
8
8
  // - data-table-filter-group.tsx + data-table-filter-value-picker.tsx(@internal;2026-07-14 filter panel
9
9
  // 過 800 hard cap 拆檔 — row/nested-group renderer + ValueShape picker,只被 panel 消費)
10
- // - cell-registry.tsx(column type → cell display / edit 解析 SSOT)
10
+ // - cell-registry.tsx(column type → cell view / edit 解析 SSOT)
11
11
  // - data-table-interaction-layer.tsx + active-editor-controller.ts(spreadsheet overlay + portal editor)
12
12
  // - column-types.ts + filter-operators.ts(✓ Rule-of-3 SSOT,3+ consumer)
13
13
  // - filter-tree.ts(pure data + eval,test isolation)
@@ -96,7 +96,7 @@ export interface DataTableProps<TData>
96
96
  /**
97
97
  * Issue 9 cell error system(2026-05-10)。
98
98
  *
99
- * Map of `${rowId}:${colId}` → error message(string | string[])。Cell display mode 在 content
99
+ * Map of `${rowId}:${colId}` → error message(string | string[])。Cell view mode 在 content
100
100
  * 下方渲 `text-body text-error` 訊息,gap-1 spacing。Multi-error 用 array → ul / li 分行渲。
101
101
  *
102
102
  * **使用建議**:
@@ -279,13 +279,13 @@ export interface DataTablePaginationOptions {
279
279
  //
280
280
  // 原 `renderTypedValue` switch + `EditableCellContent` switch 兩條平行 type-switch
281
281
  // 已 collapse 為單一 `cellRegistry`(./cell-registry.ts)— 每個 type → 一個 cell component,
282
- // 同時處理 display + edit mode(底層 Field control 的 mode prop)。對齊 M17 SSOT consolidation。
282
+ // 同時處理 view + edit mode(底層 Field control 的 mode prop)。對齊 M17 SSOT consolidation。
283
283
  //
284
284
  // 對齊 Notion / Airtable type-aware inline edit canonical(詳 spec §十二):
285
285
  // - string / number / currency:cell click → inline edit
286
286
  // - date / time / select / multiSelect / person / multiPerson:cell click → 進 edit mode
287
287
  // - boolean:不分 read/edit mode,直接 `<Checkbox>` 點即 toggle + commit
288
- // - url:read = LinkInput display + hover Pencil button,click Pencil 才進 edit mode
288
+ // - url:read = LinkInput view + hover Pencil button,click Pencil 才進 edit mode
289
289
  //
290
290
  // Cell id format: `${rowId}__${columnId}`(編輯狀態 keying)
291
291
  // Commit: blur OR Enter OR overlay close → 呼叫 onCellCommit
@@ -393,10 +393,10 @@ function columnSizeStyle(
393
393
  //
394
394
  // **flex-basis: baseSize(2026-05-06 v14.2)**:把 baseSize 當 explicit basis(不是 `0%`)。
395
395
  // 為什麼:flex item base = basis + padding(box-sizing: border-box content-box 行為)。前 `0%`
396
- // basis → cell padding 變 base 一部分。display(padding 12)vs edit(padding 0,Field 接管)
396
+ // basis → cell padding 變 base 一部分。view(padding 12)vs edit(padding 0,Field 接管)
397
397
  // 兩態 base 不同 → flex 重分配 → user 報「Price cell 進 edit 寬度縮 12px」
398
- // (量測:Price display 130.5 → edit 118.5 = -12px)。
399
- // explicit basis = baseSize 讓 padding 不參與 base 計算 → display↔edit 寬度穩定。
398
+ // (量測:Price view 130.5 → edit 118.5 = -12px)。
399
+ // explicit basis = baseSize 讓 padding 不參與 base 計算 → view↔edit 寬度穩定。
400
400
  return { flex: `1 1 ${baseSize}px`, minWidth: baseSize, maxWidth: maxSize }
401
401
  }
402
402
 
@@ -649,12 +649,33 @@ function DraggableHeaderCell({
649
649
  : dropIndicatorSide === 'after'
650
650
  ? dropIndicatorColumn.pseudoAfter
651
651
  : ''
652
+ // dnd-kit KeyboardSensor 的 activator = listeners.onKeyDown,掛在整個 header cell 上(column
653
+ // 無獨立 activator node,不像 row drag 的 button-only handle)。巢狀互動 descendant(more-menu
654
+ // 按鈕 / resize separator / 排序 chevron)的 Enter/Space 冒泡到此 → dnd-kit preventDefault 啟動
655
+ // 欄位拖曳,吃掉按鈕原生啟動。包一層 guard:事件來自互動 descendant(非 header cell 本身)時
656
+ // 交回原生,不啟動拖曳。對齊 dnd-kit「activator node 排除互動 descendant」idiom。
657
+ const rawListeners = draggable.listeners as Record<string, ((e: React.SyntheticEvent) => void) | undefined> | undefined
658
+ const guardedListeners: Record<string, unknown> | undefined = rawListeners
659
+ ? {
660
+ ...rawListeners,
661
+ onKeyDown: (e: React.KeyboardEvent) => {
662
+ const target = e.target as HTMLElement
663
+ if (
664
+ target !== e.currentTarget &&
665
+ target.closest('button, a, input, select, textarea, [role="menuitem"], [role="separator"]')
666
+ ) {
667
+ return
668
+ }
669
+ rawListeners.onKeyDown?.(e)
670
+ },
671
+ }
672
+ : rawListeners
652
673
  return React.cloneElement(children as React.ReactElement<Record<string, unknown>>, {
653
674
  ref: setRefs,
654
675
  style: { ...(childProps.style ?? {}), ...dragStyle },
655
676
  'data-column-id': id,
656
677
  'data-column-locked': isLocked || undefined,
657
- ...(disabled ? {} : { ...draggableAttrs, ...(draggable.listeners as unknown as Record<string, unknown>) }),
678
+ ...(disabled ? {} : { ...draggableAttrs, ...(guardedListeners ?? {}) }),
658
679
  // 2026-05-06 v14.9 cursor canonical(對齊 Notion / Jira):
659
680
  // **idle hover NOT 顯 cursor-grab** — header click 觸發 sort,grab cursor 會誤導 user 以為「點 = 拖」;
660
681
  // **drag activation 後**(isDragging=true,過 8px activationConstraint)才顯 cursor-grabbing。
@@ -869,7 +890,7 @@ function RowDragHandle({ disabled, anyDragActive }: { disabled: boolean; anyDrag
869
890
  // 但 renderCellContent 每次 render 傳 3 個全新 inline closure(onCommit / onCommitLive /
870
891
  // onRequestEdit)+ `meta ?? {}` 新 object → memo shallow-compare 100% fail,防線靜默失效
871
892
  // (DataTableInner 任何 re-render — scroll / resize / drag / spreadsheet 選取 / portal keystroke —
872
- // 都讓全部 visible cells 的 Field display subtree 整棵重渲)。
893
+ // 都讓全部 visible cells 的 Field view subtree 整棵重渲)。
873
894
  // Fix:中介 memo slot — 從 parent 接 stable callback(commitCell / cancelCellEdit / onCellCommit /
874
895
  // enterCellEdit)+ primitive rowId / colId,在 slot 內 useCallback 綁 per-cell closure;
875
896
  // props 全 primitive / stable reference → memo 真命中,unchanged cells render 成本歸零。
@@ -884,11 +905,10 @@ interface MemoCellSlotProps {
884
905
  value: any
885
906
  // any-allow: free-form consumer meta bag(同 CellComponentProps.meta)
886
907
  meta: Record<string, any>
887
- mode: 'display' | 'edit'
908
+ mode: 'view' | 'edit'
888
909
  size: 'sm' | 'md' | 'lg'
889
910
  autoRowHeight: boolean
890
911
  isEditable: boolean
891
- isDisabled: boolean
892
912
  onCommitCell: (rowId: string, colId: string, next: unknown) => void
893
913
  onCancelCell: (rowId: string, colId: string) => void
894
914
  onCellCommitLive?: (rowId: string, colId: string, next: unknown) => void
@@ -897,13 +917,12 @@ interface MemoCellSlotProps {
897
917
 
898
918
  const MemoCellSlot = React.memo(function MemoCellSlot({
899
919
  Cell, rowId, colId, value, meta, mode, size, autoRowHeight,
900
- isEditable, isDisabled, onCommitCell, onCancelCell, onCellCommitLive, onEnterEdit,
920
+ isEditable, onCommitCell, onCancelCell, onCellCommitLive, onEnterEdit,
901
921
  }: MemoCellSlotProps) {
902
922
  const onCommit = React.useCallback((next: unknown) => onCommitCell(rowId, colId, next), [onCommitCell, rowId, colId])
903
923
  const onCommitLive = React.useCallback((next: unknown) => onCellCommitLive?.(rowId, colId, next), [onCellCommitLive, rowId, colId])
904
924
  const onCancel = React.useCallback(() => onCancelCell(rowId, colId), [onCancelCell, rowId, colId])
905
- // disabled guard 保留原 renderCellContent inline closure 語意(`() => !disabled && setEditingCellId(...)`)
906
- const onRequestEdit = React.useCallback(() => { if (!isDisabled) onEnterEdit(rowId, colId) }, [onEnterEdit, isDisabled, rowId, colId])
925
+ const onRequestEdit = React.useCallback(() => onEnterEdit(rowId, colId), [onEnterEdit, rowId, colId])
907
926
  return (
908
927
  <Cell
909
928
  value={value}
@@ -912,7 +931,6 @@ const MemoCellSlot = React.memo(function MemoCellSlot({
912
931
  size={size}
913
932
  autoRowHeight={autoRowHeight}
914
933
  isEditable={isEditable}
915
- isDisabled={isDisabled}
916
934
  onCommit={onCommit}
917
935
  onCommitLive={onCommitLive}
918
936
  onCancel={onCancel}
@@ -1040,28 +1058,13 @@ function DataTableInner<TData>(
1040
1058
  },
1041
1059
  [],
1042
1060
  )
1043
- // 2026-05-13 Stream C Cluster B Q3 ship(per codex Q3 verdict + user 拍板「全部馬不停蹄做完」):
1044
- // Mirror isCellEditable pattern。`column.meta.disabled` 接 bool 或 (row) => boolean fn。
1045
- // cell disabled → (a) TD 加 `bg-disabled cursor-not-allowed` + 抑制 hover, (b) inner Field
1046
- // 透過 isDisabled prop 走 mode='disabled'(各 Field type 內部具體 disabled token,非 wrapper blanket opacity),
1047
- // (c) edit entry condition: `cellEditable && !cellDisabled`。
1048
- const isCellDisabled = React.useCallback(
1049
- // any-allow: free-form consumer meta — same rationale as L143 renderTypedValue
1050
- (meta: Record<string, any> | undefined, row: unknown): boolean => {
1051
- const d = meta?.disabled
1052
- if (typeof d === 'function') return d(row) === true
1053
- return d === true
1054
- },
1055
- [],
1056
- )
1057
- // 2026-05-13:canEditCell helper consolidation(per codex V4 follow-up + user「沒理由不做」拍板)
1058
- // 抽 4-site repeated `editable && !disabled` pattern。3 path sites(keyboard / Tab / InteractionLayer)
1059
- // call canEditCell;另 2 sites(renderCellContent + onEditableCellClick)用 already-computed `editable`/
1060
- // `disabled` 變數(因為 disabled 還要單獨給 isDisabled prop + bg-disabled class),不 collapse to helper。
1061
+ // 2026-07-16 round16:cell「disabled」態廢除(世界級 grid disabled cell;meta.disabled 全庫 0 消費)
1062
+ // 鎖定 cell = `editable:(row)=>false`(= isCellEditable 模型),非灰化 disabled 態。原 isCellDisabled
1063
+ // helper + bg-disabled TD 灰化 + isDisabled prop 全移除;canEditCell 收斂為 isCellEditable。
1061
1064
  const canEditCell = React.useCallback(
1062
1065
  (meta: Record<string, unknown> | undefined, row: unknown): boolean =>
1063
- isCellEditable(meta, row) && !isCellDisabled(meta, row),
1064
- [isCellEditable, isCellDisabled],
1066
+ isCellEditable(meta, row),
1067
+ [isCellEditable],
1065
1068
  )
1066
1069
  const [sorting, setSorting] = React.useState<SortingState>(tableOptions?.state?.sorting as SortingState ?? [])
1067
1070
 
@@ -1502,7 +1505,7 @@ function DataTableInner<TData>(
1502
1505
  const hoverProps = (_idx: number): Record<string, never> => ({})
1503
1506
 
1504
1507
  // ── Cell render(Phase C 2026-05-05 — type-keyed registry SSOT)──
1505
- // 命中 columnType → 走 cellRegistry(display / edit mode 同元件 with `mode` prop);
1508
+ // 命中 columnType → 走 cellRegistry(view / edit mode 同元件 with `mode` prop);
1506
1509
  // 無 columnType → consumer 自訂 cell.columnDef.cell。
1507
1510
  const renderCellContent = (cell: ReturnType<typeof rows[number]['getVisibleCells']>[number]) => {
1508
1511
  const meta = cell.column.columnDef.meta
@@ -1510,27 +1513,25 @@ function DataTableInner<TData>(
1510
1513
  const wrap = autoRowHeight && meta?.wrap === true
1511
1514
  // 已知 compound 欄位(Tag / PersonDisplay / LinkInput 等自帶 layout)直接 bypass TruncateCell,
1512
1515
  // 因為 `truncate` 的 inline baseline context 會破壞自訂 layout 的垂直對齊。
1513
- // 2026-05-09 D-path:date / time 加入(showDisplayEndIcon → Field naked-display 需 full width 才能
1516
+ // 2026-05-09 D-path:date / time 加入(showDisplayEndIcon → Field naked-view 需 full width 才能
1514
1517
  // 右對齊 ItemSuffix。TruncateCell 的 `<span truncate min-w-0>` block-display 會 collapse Field
1515
1518
  // to content size,讓 Calendar / Clock icon 緊貼 value text 而非右邊緣)。
1516
1519
  const isKnownCompound = colType === 'select' || colType === 'multiSelect' || colType === 'person' || colType === 'multiPerson' || colType === 'url' || colType === 'date' || colType === 'time'
1517
1520
  const rowId = cell.row.id
1518
1521
  const colId = cell.column.id
1519
1522
  const editable = isCellEditable(meta, cell.row.original)
1520
- const disabled = isCellDisabled(meta, cell.row.original)
1521
1523
  const isEditingThisCell = editingCellId === cellEditId(rowId, colId)
1522
1524
 
1523
1525
  let content: React.ReactNode
1524
1526
  if (colType) {
1525
1527
  const Cell = resolveCellComponent(colType)
1526
1528
  // 2026-05-10 Slice D Step 5(D.3 portal Field):當 portal flag 啟 + cell 編輯中 →
1527
- // cell 保持 display mode(SSOT preserved per codex Q6.2),portal layer 渲 edit Field 在上。
1528
- // 預設 inline-edit:isEditingThisCell ? edit : display
1529
- // 2026-05-13 Q3 cell-disabled:disabled cell 永遠 display lifecycle(state overlay,不進 edit)。
1530
- const cellMode: 'edit' | 'display' =
1529
+ // cell 保持 view mode(SSOT preserved per codex Q6.2),portal layer 渲 edit Field 在上。
1530
+ // 預設 inline-edit:isEditingThisCell ? edit : view
1531
+ const cellMode: 'edit' | 'view' =
1531
1532
  (experimentalActiveEditorController && isEditingThisCell)
1532
- ? 'display'
1533
- : (isEditingThisCell && !disabled) ? 'edit' : 'display'
1533
+ ? 'view'
1534
+ : isEditingThisCell ? 'edit' : 'view'
1534
1535
  // 2026-07-05 D3 perf fix:改經 MemoCellSlot — 原 inline closure props 讓 CellWithSurface
1535
1536
  // memo 100% miss(詳 MemoCellSlot 檔頭註解)。
1536
1537
  content = (
@@ -1544,7 +1545,6 @@ function DataTableInner<TData>(
1544
1545
  size={size}
1545
1546
  autoRowHeight={autoRowHeight}
1546
1547
  isEditable={editable}
1547
- isDisabled={disabled}
1548
1548
  onCommitCell={commitCell}
1549
1549
  onCancelCell={cancelCellEdit}
1550
1550
  onCellCommitLive={onCellCommit}
@@ -1572,8 +1572,8 @@ function DataTableInner<TData>(
1572
1572
  const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
1573
1573
 
1574
1574
  // 2026-05-09 D-path retired:`getEditIndicator(colType)` parallel system 移除。
1575
- // Indicator authority 從 DataTable cellEl 移交 **Field naked-display branch via `showDisplayEndIcon` opt-in**
1576
- // — Select / TimePicker / DatePicker / Combobox / PeoplePicker 5 picker 的 display mode 內建
1575
+ // Indicator authority 從 DataTable cellEl 移交 **Field naked-view branch via `showDisplayEndIcon` opt-in**
1576
+ // — Select / TimePicker / DatePicker / Combobox / PeoplePicker 5 picker 的 view mode 內建
1577
1577
  // `<ItemSuffix>` 渲對應 trigger icon(同 edit DOM 結構)。LinkInput URL anchor 例外(無 suffix)。
1578
1578
  // SSOT chain:cell-registry.tsx(opt-in props)→ Field component(intrinsic icon + ItemSuffix DOM)→
1579
1579
  // item-anatomy ItemPrefix/ItemSuffix layout SSOT。詳 `.claude/planning/cell-indicator-ssot-rfc.md`。
@@ -1681,17 +1681,15 @@ function DataTableInner<TData>(
1681
1681
  const cellRowId = cell.row.id
1682
1682
  const cellColId = cell.column.id
1683
1683
  const cellEditable = isCellEditable(meta, cell.row.original)
1684
- const cellDisabled = isCellDisabled(meta, cell.row.original)
1685
1684
  const isEditingThisCell = editingCellId === cellEditId(cellRowId, cellColId)
1686
- // Indicator canonical(2026-05-09 D-path retire):**Field naked-display branch own** via
1685
+ // Indicator canonical(2026-05-09 D-path retire):**Field naked-view branch own** via
1687
1686
  // `showDisplayEndIcon` opt-in(per-picker `<ItemSuffix>` 渲 ChevronDown/Calendar/Clock)。
1688
1687
  // DataTable cellEl 不再 render parallel indicator — SSOT 對齊 Field family。
1689
1688
  // 詳 `.claude/planning/cell-indicator-ssot-rfc.md` Step 9。
1690
1689
  // Cell click → 進 edit mode(boolean 不需 — 自己 toggle;url 不需 — 走內部 Pencil button,Phase C 由 UrlCell 內處理)
1691
1690
  const cellSpreadsheetId = `${cellRowId}:${cellColId}`
1692
1691
  const isSelectedCell = spreadsheetMode && selectedCellId === cellSpreadsheetId
1693
- // 2026-05-13 Q3:cellDisabled 抑制 editable click(對齊 `editable && !disabled` invariant)
1694
- const onEditableCellClick = cellEditable && !cellDisabled && colType !== 'boolean' && colType !== 'url' && !isEditingThisCell
1692
+ const onEditableCellClick = cellEditable && colType !== 'boolean' && colType !== 'url' && !isEditingThisCell
1695
1693
  ? (e: React.MouseEvent) => {
1696
1694
  if (spreadsheetMode) {
1697
1695
  // Slice D Step 4 spreadsheet semantics(2026-05-10 user 拍板,2026-05-12 v2 fix):
@@ -1767,7 +1765,7 @@ function DataTableInner<TData>(
1767
1765
  role="cell"
1768
1766
  // group/cell + data-row-mode:讓 Field naked 用 `group-data-[row-mode=...]/cell:items-X`
1769
1767
  // 從 cell 取 alignment(autoRowHeight=auto 頂對齊 / fixed=fixed 置中)。CSS propagation,
1770
- // Field API 不變;每個 mode 內 display↔edit 同 alignment(同 Field, 同 group → 同 items)。
1768
+ // Field API 不變;每個 mode 內 view↔edit 同 alignment(同 Field, 同 group → 同 items)。
1771
1769
  // H1(2026-05-10):per-row error → effectiveAutoRowForCell 同 row.tsx effectiveAutoRow
1772
1770
  data-row-mode={effectiveAutoRowForCell ? 'auto' : 'fixed'}
1773
1771
  data-column-id={cell.column.id}
@@ -1777,8 +1775,6 @@ function DataTableInner<TData>(
1777
1775
  // Phase 9 Issue 1 fix(2026-05-10):range cell bg fill via CSS [data-range-cell],
1778
1776
  // 不在 overlay layer(避免 layer fixed-position bg 蓋 cell content)。
1779
1777
  data-range-cell={spreadsheetMode && rangeCellIdSet.has(`${cell.row.id}:${cell.column.id}`) ? '' : undefined}
1780
- // 2026-05-13 V1.6:data-cell-disabled attribute 給 CSS `:not([data-cell-disabled])` 過濾,disabled cell 不被 range fill 蓋
1781
- data-cell-disabled={cellDisabled ? 'true' : undefined}
1782
1778
  // Issue 9 cell error(2026-05-10):aria-describedby 接 error message id 給 AT 讀
1783
1779
  aria-describedby={cellErrorId}
1784
1780
  aria-invalid={hasCellError || undefined}
@@ -1817,19 +1813,16 @@ function DataTableInner<TData>(
1817
1813
  // Field naked edit border 仍 own(per Field SSOT)— 編輯時 Field 自帶 border 1px,
1818
1814
  // 跟 cell 4 邊 inset divider 視覺相疊(同 pixel)= 1 line visual,不雙線。
1819
1815
  inlineEdit && 'dtCellGrid',
1820
- onEditableCellClick && ['cursor-pointer', nakedCellEditableDisplayHover], // editable cell display hover affordance(對齊 Notion / Airtable hover-cell-shows-border canonical)
1816
+ onEditableCellClick && ['cursor-pointer', nakedCellEditableDisplayHover], // editable cell view hover affordance(對齊 Notion / Airtable hover-cell-shows-border canonical)
1821
1817
  // a11y(2026-07-14 dim-10 修):非 spreadsheet inlineEdit cell 可 Tab 聚焦(見下方
1822
1818
  // tabIndex/onKeyDown)— focus-visible ring 對齊本檔 expand button / sortable header canonical。
1823
1819
  onEditableCellClick && !spreadsheetMode && 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset',
1824
- // 2026-05-13 Q3 cell disabled SSOT(per codex Q3 verdict + user 拍板「全部馬不停蹄做完」):
1825
- // bg `--bg-disabled` component-state token(color.spec.md:671 owner)+ cursor 抑制 click affordance。
1826
- cellDisabled && 'bg-disabled cursor-not-allowed',
1827
1820
  // z-10 raise inline-edit cell;portal mode 不需(layer z-3 already on top)。
1828
1821
  isEditingThisCell && !experimentalActiveEditorController && 'z-10',
1829
1822
  )}
1830
1823
  style={{
1831
1824
  ...columnSizeStyle(cell.column, { resize: enableColumnResize, isSystemCol: isSystemColumn(cell.column.id) }),
1832
- // Padding override 只在 inline-edit cell(naked Field 撐滿 cell);portal mode cell 走正常 display padding
1825
+ // Padding override 只在 inline-edit cell(naked Field 撐滿 cell);portal mode cell 走正常 view padding
1833
1826
  ...(isEditingThisCell && !experimentalActiveEditorController ? {} : cellPadding),
1834
1827
  // Slice D Step 2(2026-05-10):flag 開時 set CSS variable 抑制 Field naked hover outline,
1835
1828
  // 讓 overlay layer 接管 hover ring paint(per RFC Contract 8 「one geometry owner, two paint owners」)。
@@ -1839,7 +1832,7 @@ function DataTableInner<TData>(
1839
1832
  onClick={onEditableCellClick}
1840
1833
  // a11y(2026-07-14 dim-10 修):非 spreadsheet 的 inlineEdit cell 原本只有 onClick —
1841
1834
  // 鍵盤 user 無法聚焦 cell、無法進入編輯(WCAG 2.1.1)。對齊 Atlassian InlineEdit
1842
- // read-view-focusable idiom:editable display cell 可 Tab 聚焦,Enter / F2 進 edit。
1835
+ // read-view-focusable idiom:editable view cell 可 Tab 聚焦,Enter / F2 進 edit。
1843
1836
  // spreadsheetMode 不加(該模式走 table-level selectedCellId 鍵盤導覽 SSOT,per-cell
1844
1837
  // tab stop 會跟 roving 模型衝突);cell 內 embedded 控件事件不攔(target guard)。
1845
1838
  tabIndex={onEditableCellClick && !spreadsheetMode ? 0 : undefined}
@@ -1852,7 +1845,7 @@ function DataTableInner<TData>(
1852
1845
  } : undefined}
1853
1846
  >
1854
1847
  {/* Issue 9 cell error(2026-05-10):有 error → cell 內外結構切 flex-col,
1855
- 上 row 渲既有 nested + content,下 row 渲 error message 14px text-error
1848
+ 上 row 渲既有 nested + content,下 row 渲 error message `text-body text-error`。
1856
1849
  無 error 時走原 flex-row(backward-compat 0 layout shift)。 */}
1857
1850
  {hasCellError ? (
1858
1851
  <span className="flex flex-col self-stretch w-full min-w-0 gap-1">
@@ -2085,8 +2078,7 @@ function DataTableInner<TData>(
2085
2078
  else if (e.key === 'ArrowLeft' && curColIdx > 0) { nextColIdx = curColIdx - 1 }
2086
2079
  else if (e.key === 'ArrowRight' && curColIdx < allCols.length - 1) { nextColIdx = curColIdx + 1 }
2087
2080
  else if (e.key === 'Enter' || e.key === 'F2') {
2088
- // Enter / F2 → 進 edit(若 cell editable + 非 boolean / url + disabled)
2089
- // 2026-05-13 codex V1 fix:加 `!isCellDisabled(meta, row)` gate(對齊 mouse click invariant)
2081
+ // Enter / F2 → 進 edit(若 cell editable + 非 boolean / url)。edit 入口統一走 canEditCell(= isCellEditable)
2090
2082
  const row = table.getRowModel().rowsById[curRowId]
2091
2083
  const colDef = table.getAllLeafColumns().find((c) => c.id === curColId)
2092
2084
  // any-allow: column meta free-form
@@ -2142,7 +2134,7 @@ function DataTableInner<TData>(
2142
2134
  },
2143
2135
  // D3 dep-hygiene fix(2026-07-06):handler 內(portal edit Enter 分支)呼叫的是 canEditCell,
2144
2136
  // 非 isCellEditable — 原 deps 列 isCellEditable 是靠 canEditCell identity-stable 才無實害的
2145
- // stale-closure 地雷;改列真實依賴 canEditCell(其 useCallback deps 已含 isCellEditable + isCellDisabled)。
2137
+ // stale-closure 地雷;改列真實依賴 canEditCell(其 useCallback deps 已含 isCellEditable)。
2146
2138
  [enabled, mode, hasAnySelection, selectableVisibleIds, setSelection,
2147
2139
  spreadsheetMode, selectedCellId, editingCellId, table, canEditCell]
2148
2140
  )
@@ -2315,16 +2307,40 @@ function DataTableInner<TData>(
2315
2307
  const colOptIn = colMeta?.resizable !== false
2316
2308
  const isResizable = enableColumnResize && !isSystemColumn(colId) && colOptIn
2317
2309
  const isResizing = header.column.getIsResizing?.()
2310
+ // 鍵盤 resize(WAI-ARIA window-splitter):方向鍵調整欄寬,公開目前值 + 下限。
2311
+ // effectiveMinWidth 對齊 drag 路徑(resolveColumnSizing minSize),step 16px。
2312
+ const effectiveMinWidth = header.column.columnDef.minSize ?? MIN_COLUMN_WIDTH
2313
+ const currentWidth = Math.round(header.column.getSize())
2314
+ const RESIZE_KEY_STEP = 16
2318
2315
  // H2: 不論 showDivider,只要 isResizable 就 render hot zone(panel boundary col 仍可拖)
2319
2316
  if (!showDivider && !isResizable) return null
2320
2317
  return (
2321
2318
  <span
2322
2319
  role={isResizable ? 'separator' : undefined}
2323
2320
  aria-orientation={isResizable ? 'vertical' : undefined}
2324
- aria-label={isResizable ? '拖曳調整欄寬' : undefined}
2321
+ aria-label={isResizable ? '調整欄寬' : undefined}
2322
+ // 鍵盤可操作 separator(WAI-ARIA window-splitter):focusable + 方向鍵調整 +
2323
+ // 公開目前寬度 / 下限。aria-valuetext 給 SR px 值(避免無 valuemax 時被誤讀成百分比)。
2324
+ tabIndex={isResizable ? 0 : undefined}
2325
+ aria-valuenow={isResizable ? currentWidth : undefined}
2326
+ aria-valuemin={isResizable ? effectiveMinWidth : undefined}
2327
+ aria-valuetext={isResizable ? `${currentWidth}px` : undefined}
2328
+ onKeyDown={isResizable ? (e: React.KeyboardEvent<HTMLSpanElement>) => {
2329
+ let next: number | null = null
2330
+ if (e.key === 'ArrowLeft') next = Math.max(effectiveMinWidth, currentWidth - RESIZE_KEY_STEP)
2331
+ else if (e.key === 'ArrowRight') next = currentWidth + RESIZE_KEY_STEP
2332
+ else if (e.key === 'Home') next = effectiveMinWidth
2333
+ if (next == null) return
2334
+ // stopPropagation:不讓方向鍵冒泡到 header 排序 / 欄位拖曳 keyboard listener。
2335
+ e.preventDefault()
2336
+ e.stopPropagation()
2337
+ table.setColumnSizing((prev) => ({ ...prev, [colId]: next as number }))
2338
+ // onColumnResize 由 columnSizing useEffect 自動 fire(非 drag 路徑不經 isResizingColumn)。
2339
+ } : undefined}
2325
2340
  className={cn(
2326
2341
  'group/resize absolute top-0 bottom-0 right-0 -mr-[3px] w-[7px]',
2327
2342
  isResizable && 'cursor-col-resize select-none',
2343
+ isResizable && 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',
2328
2344
  )}
2329
2345
  // 2026-05-12 fix v2(user 抓 R3 stopPropagation 沒生效):dnd-kit PointerSensor
2330
2346
  // 監聽 `pointerdown`,我前一輪只 stop `onMouseDown` → pointerdown 仍冒泡 →
@@ -2721,12 +2737,19 @@ function DataTableInner<TData>(
2721
2737
  // Center body 同時擁有 H + V scroll;maxHeight 限制讓 H scrollbar 落在 visible 底部
2722
2738
  data-datatable-hscroll
2723
2739
  data-datatable-panel="center"
2740
+ // a11y(scrollable-region-focusable,對齊 DS ScrollArea Viewport canonical):唯讀表格
2741
+ // 的可捲動 body 若無任何 focusable descendant,鍵盤使用者無法捲動。read-only 模式
2742
+ // (非 enabled / spreadsheet)outer table 也不 focusable → 這裡補 tabIndex=0 + 具名 +
2743
+ // inset focus ring,讓鍵盤可聚焦後方向鍵捲動;互動模式已由 outer table keyboard handler
2744
+ // + focusable cells 覆蓋,不重複加 tab stop。
2745
+ tabIndex={enabled || spreadsheetMode ? undefined : 0}
2746
+ aria-label={enabled || spreadsheetMode ? undefined : '表格內容,可捲動'}
2724
2747
  // overflow-x/y: auto — 沒 overflow 就不顯 bar。wrapper minWidth 仍 trigger H 真 overflow。
2725
2748
  // **不**用 scrollbar-gutter: stable — 那會永遠保留 V 軸 15px 空間,
2726
2749
  // content fit 時看起來像「永遠有 V 捲軸」(Image #5 bug)。
2727
2750
  // trade-off:V scroll 出現時 body 內側少 15px,header 不縮 → 右端微 misalign,
2728
2751
  // 但 content fit 視覺乾淨優先(Mac 用戶 overlay scrollbar 不可見)。
2729
- className="flex-1 min-w-0 overflow-x-auto overflow-y-auto"
2752
+ className="flex-1 min-w-0 overflow-x-auto overflow-y-auto focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring"
2730
2753
  // isFillHeight:用 JS 算的 px(bodyMaxHeight),bypass CSS % 在 flex 場景的不可靠 shrink。
2731
2754
  // 固定 px(300px etc):直接套 height。
2732
2755
  style={
@@ -2779,7 +2802,7 @@ function DataTableInner<TData>(
2779
2802
  activeEditorEnabled={experimentalActiveEditorController}
2780
2803
  // Slice D Step 5(D.3 portal Field,2026-05-10):real portal Field render callback。
2781
2804
  // Layer 在 ActiveEditorHost(z 3 float rect)render `<Cell mode="edit" />` 同 registry。
2782
- // Cell wrapper 保持 mode="display"(SSOT preserved per codex Q6.2)。
2805
+ // Cell wrapper 保持 mode="view"(SSOT preserved per codex Q6.2)。
2783
2806
  activeEditorRender={experimentalActiveEditorController ? (cellId) => {
2784
2807
  const lastColon = cellId.lastIndexOf(':')
2785
2808
  if (lastColon < 0) return null
@@ -245,6 +245,8 @@
245
245
  - **巢狀深度**:1-level cap 由 TypeScript 型別鎖死(`FilterGroup.children: FilterCondition[]`),無 runtime guard;繞過型別塞入的非 condition 物件缺 `field`/`op` → incomplete → pass-through,不 crash
246
246
  - **relative 區間邊界**:全部 local time、雙端 inclusive(`startOfDay`–`endOfDay`);`past_7_days` = 7 天前 00:00 起**含今天整天**;week 以週一起算(`weekStartsOn: 1`)
247
247
 
248
+ **A11y / Loading(明文 N/A)**:本 spec 是 Operator × ColumnType × ValueShape 資料模型 SSOT(非 UI 元件)——filter panel 的互動 a11y / loading 狀態屬 UI 層 owner(`data-table.spec.md` + filter panel 家族元件)與各 Field 控件 spec。
249
+
248
250
  ## 9. Phase B 進度
249
251
 
250
252
  - [x] ValueShape × DS 元件對照 — 完成,coverage 8/12 直接消費 + 4 預留;datetime 走 `<DatePicker showTime>` / `<DatePickerRange showTime>` prop variant(M21,非新元件)
@@ -58,7 +58,7 @@ DateGrid 是 internal primitive(見「定位」),一般 consumer 經 `DatePicker
58
58
  | 場景 | 改用 | 原因 |
59
59
  |------|------|------|
60
60
  | 日期輸入欄位 | `DatePicker` | DateGrid 是 inline,欄位需要 trigger + popup 結構 |
61
- | 純顯示單日期 | `<DatePicker mode="display">` / `Intl.DateTimeFormat` | 不需 interactive 月曆 |
61
+ | 純顯示單日期 | `<DatePicker mode="view">` / `Intl.DateTimeFormat` | 不需 interactive 月曆 |
62
62
  | 時間選擇(時分) | `TimePicker`(見 `../TimePicker/time-picker.spec.md`)| DateGrid 只處理日期層級 |
63
63
  | 事件行事曆(日程本) | 專用行事曆元件 | DateGrid 是日期選擇;事件日誌需要 event overlay / drag / week/month view 切換 |
64
64
 
@@ -248,7 +248,7 @@ export const Overview = {
248
248
  <thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
249
249
  <tbody>
250
250
  {[
251
- ['mode', "'edit' | 'display' | 'readonly' | 'disabled'", "'edit'", "顯示模式;display 為純內容輸出(DataTable cell 用)。優先序:顯式 mode prop 永遠最優先,未傳 mode 時 disabled 才升 disabled(useResolvedFieldMode);disabled 以 aria-disabled 表達(trigger 為 div role=combobox,非原生 disabled 屬性)"],
251
+ ['mode', "'edit' | 'view' | 'readonly' | 'disabled'", "'edit'", "顯示模式;view 為純內容輸出(DataTable cell 用)。優先序:顯式 mode prop 永遠最優先,未傳 mode 時 disabled 才升 disabled(useResolvedFieldMode);disabled 以 aria-disabled 表達(trigger 為 div role=combobox,非原生 disabled 屬性)"],
252
252
  ['error', 'boolean', 'false', '紅色邊框 + aria-invalid,僅 edit 模式生效'],
253
253
  ['size', "'sm' | 'md' | 'lg'", "'md'", '高度與字體,與 Button 共用 field-height token'],
254
254
  ['value', 'string | null', '—', 'ISO date string(YYYY-MM-DD)'],
@@ -708,12 +708,12 @@ export const StateBehavior = {
708
708
  <span className="text-caption font-medium text-fg-secondary">格式化 — 預設 YYYY/MM/DD 直接組;傳 formatOptions / locale 走 Intl.DateTimeFormat</span>
709
709
  <div className="overflow-x-auto">
710
710
  <table className="border-collapse text-caption">
711
- <thead><tr><Th>設定</Th><Th>readonly 預覽</Th><Th>Display 預覽</Th></tr></thead>
711
+ <thead><tr><Th>設定</Th><Th>readonly 預覽</Th><Th>view 預覽</Th></tr></thead>
712
712
  <tbody>
713
713
  <tr>
714
714
  <Td>預設(YYYY/MM/DD)</Td>
715
715
  <td className="p-2 border-b border-divider"><DatePicker mode="readonly" value="2026-04-02" /></td>
716
- <td className="p-2 border-b border-divider"><DatePicker mode="display" value="2026-04-02" /></td>
716
+ <td className="p-2 border-b border-divider"><DatePicker mode="view" value="2026-04-02" /></td>
717
717
  </tr>
718
718
  <tr>
719
719
  <Td mono>month: 'short'</Td>
@@ -721,7 +721,7 @@ export const StateBehavior = {
721
721
  <DatePicker mode="readonly" value="2026-04-02" formatOptions={{ year: 'numeric', month: 'short', day: 'numeric' }} />
722
722
  </td>
723
723
  <td className="p-2 border-b border-divider">
724
- <DatePicker mode="display" value="2026-04-02" formatOptions={{ year: 'numeric', month: 'short', day: 'numeric' }} />
724
+ <DatePicker mode="view" value="2026-04-02" formatOptions={{ year: 'numeric', month: 'short', day: 'numeric' }} />
725
725
  </td>
726
726
  </tr>
727
727
  <tr>
@@ -730,7 +730,7 @@ export const StateBehavior = {
730
730
  <DatePicker mode="readonly" value="2026-04-02" formatOptions={{ year: 'numeric', month: 'long', day: 'numeric' }} />
731
731
  </td>
732
732
  <td className="p-2 border-b border-divider">
733
- <DatePicker mode="display" value="2026-04-02" formatOptions={{ year: 'numeric', month: 'long', day: 'numeric' }} />
733
+ <DatePicker mode="view" value="2026-04-02" formatOptions={{ year: 'numeric', month: 'long', day: 'numeric' }} />
734
734
  </td>
735
735
  </tr>
736
736
  <tr>
@@ -739,13 +739,13 @@ export const StateBehavior = {
739
739
  <DatePicker mode="readonly" value="2026-04-02" locale="zh-TW" formatOptions={{ year: 'numeric', month: 'long', day: 'numeric' }} />
740
740
  </td>
741
741
  <td className="p-2 border-b border-divider">
742
- <DatePicker mode="display" value="2026-04-02" locale="zh-TW" formatOptions={{ year: 'numeric', month: 'long', day: 'numeric' }} />
742
+ <DatePicker mode="view" value="2026-04-02" locale="zh-TW" formatOptions={{ year: 'numeric', month: 'long', day: 'numeric' }} />
743
743
  </td>
744
744
  </tr>
745
745
  </tbody>
746
746
  </table>
747
747
  </div>
748
- <span className="text-[11px] text-fg-muted">edit trigger 顯示文字與 Display 都用 Intl.DateTimeFormat 格式化(formatOptions / locale prop 對兩者皆生效,跨模式一致)。</span>
748
+ <span className="text-[11px] text-fg-muted">edit trigger 顯示文字與 view 都用 Intl.DateTimeFormat 格式化(formatOptions / locale prop 對兩者皆生效,跨模式一致)。</span>
749
749
  </div>
750
750
 
751
751
  {/* Empty value display */}
@@ -761,8 +761,8 @@ export const StateBehavior = {
761
761
  <DatePicker mode="disabled" value={null} className="w-48" />
762
762
  </div>
763
763
  <div className="flex items-center gap-3">
764
- <span className="text-[11px] text-fg-muted w-20 shrink-0">Display</span>
765
- <DatePicker mode="display" value={null} />
764
+ <span className="text-[11px] text-fg-muted w-20 shrink-0">view</span>
765
+ <DatePicker mode="view" value={null} />
766
766
  </div>
767
767
  </div>
768
768
  </div>
@@ -51,7 +51,7 @@ export const UsageGuidance: Story = {
51
51
  <li><LinkTo kind="Design System/Components/DatePicker/展示" name="可清除"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">篩選器的選填截止日,填錯一鍵清空(可清除)</span></LinkTo></li>
52
52
  <li><LinkTo kind="Design System/Components/DatePicker/展示" name="尺寸"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">緊湊工具列與標準表單的尺寸對應(尺寸)</span></LinkTo></li>
53
53
  <li><LinkTo kind="Design System/Components/DatePicker/展示" name="範圍模式:訂房 / 訂機票情境"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Range:訂房 / 訂機票情境</span></LinkTo></li>
54
- <li><LinkTo kind="Design System/Components/DatePicker/展示" name="展示樣式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">審批詳情頁唯讀展示申請日期(展示樣式)</span></LinkTo></li>
54
+ <li><LinkTo kind="Design System/Components/DatePicker/展示" name="檢視樣式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">審批詳情頁唯讀展示申請日期(展示樣式)</span></LinkTo></li>
55
55
  </ul>
56
56
  <p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見下方 vs 近親 段)。</p>
57
57
  </div>
@@ -139,7 +139,7 @@ export const FormattingRule: Story = {
139
139
  <div>
140
140
  <Rule
141
141
  title="格式化跨模式一致 — 預設 YYYY/MM/DD,傳 formatOptions / locale 走 Intl.DateTimeFormat"
142
- note="未傳格式 prop 時預設直接組 YYYY/MM/DD(locale-independent);傳 formatOptions + locale 才啟用 Intl.DateTimeFormat,同時控制 readonly / disabled Display 文字與 edit trigger 顯示文字。跨模式一致、跨頁面可預期。Calendar popup 的月份語言由 Calendar 內部 locale 處理"
142
+ note="未傳格式 prop 時預設直接組 YYYY/MM/DD(locale-independent);傳 formatOptions + locale 才啟用 Intl.DateTimeFormat,同時控制 view / readonly / disabled 的格式化文字與 edit trigger 顯示文字。跨模式一致、跨頁面可預期。Calendar popup 的月份語言由 Calendar 內部 locale 處理"
143
143
  >
144
144
  <DatePicker
145
145
  mode="readonly"
@@ -157,7 +157,7 @@ export const FormattingRule: Story = {
157
157
 
158
158
  <Rule
159
159
  title="Edit trigger 文字也受 formatOptions / locale 控制"
160
- note={'原本原生 <input type="date"> 的 trigger 格式受瀏覽器 locale 控制無法干預;改自建後,edit trigger 顯示的已選日期也走 Intl.DateTimeFormat——跟 Display 模式完全一致'}
160
+ note={'原本原生 <input type="date"> 的 trigger 格式受瀏覽器 locale 控制無法干預;改自建後,edit trigger 顯示的已選日期也走 Intl.DateTimeFormat——跟 view 模式完全一致'}
161
161
  >
162
162
  <DatePicker
163
163
  value="2026-05-15"
@@ -170,7 +170,7 @@ export const FormattingRule: Story = {
170
170
 
171
171
  <Rule
172
172
  title="null 值統一顯示半形連字號"
173
- note="Display 模式 null / undefined 顯示半形 -(foreground,同 readonly value 色),與其他 Field 元件一致"
173
+ note="view 模式 null / undefined 顯示半形 -(foreground,同 readonly value 色),與其他 Field 元件一致"
174
174
  >
175
175
  <DatePicker mode="readonly" value={null} />
176
176
  </Rule>
@@ -68,7 +68,7 @@ open 軸同樣只開最小 API — **uncontrolled-only**:`defaultOpen`(初始開
68
68
  |------|------|------|
69
69
  | 日期範圍(from → to) | **`<DatePicker.Range>`**(本檔下「DatePicker.Range」段,2026-04-21 新增) | 仿 Ant `DatePicker.RangePicker` 架構:雙 input + 箭頭 + 共用 calendar icon,Popover 展開兩月份並列 |
70
70
  | 日期 + 時間(含時分) | **本元件加 `showTime` prop**(canonical 2026-05-02,Ant idiom) | DatePicker `showTime` / DatePickerRange `showTime` 內建 TimeColumns + 此刻/確定 footer;value 變 ISO datetime |
71
- | 相對時間(「3 天前」「昨天」)| 自訂 Display 元件 | DatePicker 的 Display 是絕對日期;相對時間需要計算 + locale 格式化 |
71
+ | 相對時間(「3 天前」「昨天」)| 自訂展示元件 | DatePicker 的 view 態是絕對日期;相對時間需要計算 + locale 格式化 |
72
72
  | 純文字 YYYY-MM-DD(不需要 picker)| `Input` | 如 API debug 介面、不需互動的純記錄 |
73
73
  | 生日等「只有月日、不需要年」的欄位 | 目前用 DatePicker 忍受年份 | 多數情境可接受;要極致可自訂 MonthDayPicker |
74
74
  | Notion / Google 式 event calendar 檢視 | **`<Calendar>`** 元件(見 `../Calendar/calendar.spec.md`,月/週/日 event view);**非本元件語義** | DatePicker 是「選日期」的 form control;Calendar 是「看事件」的頁面 canvas,兩者雖名字都有 calendar 但是不同 DS 元件 |
@@ -232,7 +232,7 @@ DateGrid cell 有 5 種語意視覺,每種用不同形狀/色彩語言避免混
232
232
  - **needConfirm 獨立於 showTime**(2026-07-05 D4 codify):date-only `<DatePicker needConfirm>` 亦成立,footer 渲染 gate = `showTime || needConfirm`(single 與 Range 一致)——needConfirm 時「確定」是唯一 commit 路徑,漏渲 footer = draft 永遠無法 commit 的死路(2026-07-05 修 single 漏 `|| needConfirm`)
233
233
  - showSeconds=false(default)→ TimeColumns 只顯示 H/M(對齊 Ant 預設)
234
234
  - Range cell disable(對齊 Ant `useRangeDisabledDate`):activeEnd='start' + end 已選 → date > end disabled;activeEnd='end' + start 已選 → date < start disabled
235
- - Range stadium pattern(canonical 2026-05-03 v8):rangeStart/End cell pseudo `before:rounded-l-full / rounded-r-full` 跟 button 圓的左/右半弧 EXACTLY OVERLAY → 無「凸出」(對齊 Ant `cell-range-start::before { border-radius: 9999px 0 0 9999px }`)
235
+ - Range stadium pattern(canonical 2026-05-03 v8):SSOT `../DateGrid/date-grid.spec.md`(`range_start` / `range_end` 半圓 stadium 規則;class 細節見 `date-grid.tsx`)
236
236
 
237
237
  ### 為什麼用 prop 而非分離 `<DateTimePicker>` 元件
238
238
 
@@ -258,7 +258,7 @@ DateGrid cell 有 5 種語意視覺,每種用不同形狀/色彩語言避免混
258
258
  | `formatOptions` | `Intl.DateTimeFormatOptions` | `{ year: 'numeric', month: 'short', day: 'numeric' }` |
259
259
  | `locale` | BCP 47 locale | `'zh-TW'`、`'en-US'` |
260
260
 
261
- 預設(未傳 `formatOptions` / `locale`)直接組 `YYYY/MM/DD`(locale-independent,對齊 Ant year-first;見 date-picker.tsx `formatDate` 註解);傳 `formatOptions` / `locale` 才走 `Intl.DateTimeFormat`。Display 模式(readonly / disabled / DataTable cell)與 Edit 模式 trigger 文字同一條格式化路徑,兩者一致。
261
+ 預設(未傳 `formatOptions` / `locale`)直接組 `YYYY/MM/DD`(locale-independent,對齊 Ant year-first;見 date-picker.tsx `formatDate` 註解);傳 `formatOptions` / `locale` 才走 `Intl.DateTimeFormat`。View / readonly / disabled 模式(含 DataTable cell)與 Edit 模式 trigger 文字同一條格式化路徑,兩者一致。
262
262
 
263
263
  ---
264
264
 
@@ -267,7 +267,7 @@ DateGrid cell 有 5 種語意視覺,每種用不同形狀/色彩語言避免混
267
267
  `clearable` prop 在有值時顯示 clear 按鈕(endAction)。
268
268
 
269
269
  - 只在 edit 模式顯示
270
- - 清除後 value 變為 `null`(Display 顯示半形 -,text-foreground)
270
+ - 清除後 `onChange?.('')`(空字串 = 空值;view 態顯示半形 -,text-foreground)
271
271
  - **Dual-state sync canonical**(2026-05-03 v10):X 點擊必同時 `onChange?.('')` + `setDraft(null)`(Range 同),否則 `needConfirm=true`(showTime 預設)且 popover 開著時 `displayValue=draft` 仍顯示舊值,trigger 看起來「沒清」。X 在 trigger 上是 standard clear affordance,不走 needConfirm「等確定」語義 — 立刻 commit + 同步 draft
272
272
 
273
273
  ---
@@ -284,16 +284,16 @@ DateGrid cell 有 5 種語意視覺,每種用不同形狀/色彩語言避免混
284
284
 
285
285
  DatePicker 套 `React.forwardRef` + `displayName`;`DatePickerProps` extends `Omit<React.HTMLAttributes<HTMLDivElement>, 'value' | 'onChange' | 'placeholder' | 'defaultValue'>`,剩餘 DOM attrs `...props` spread 到**當前 mode 的 root wrapper**(edit trigger `<div role="combobox">` / readonly · disabled wrapper div / Range wrapper div)。
286
286
 
287
- **例外**:`mode="display"` 預設(未 opt-in `showDisplayEndIcon`)輸出裸 `<span>`,**不** spread `...props`——consumer 傳 DOM attrs(`data-testid` / `onFocus` 等)時注意 display 模式不生效;`className` 各 mode 皆顯式接收(套在該 mode 的 root 元素)。
287
+ **例外**:`mode="view"` 預設(未 opt-in `showDisplayEndIcon`)輸出裸 `<span>`,**不** spread `...props`——consumer 傳 DOM attrs(`data-testid` / `onFocus` 等)時注意 view 模式不生效;`className` 各 mode 皆顯式接收(套在該 mode 的 root 元素)。
288
288
 
289
- **`asChild` 不支援**:trigger 是 compound(display 裸 span / edit `div role="combobox"` 不同 render tree),無單一 Slot 目標。consumer 若要自訂 trigger 視覺,改用 `<DatePicker mode="display">` + 自家 Button composition。
289
+ **`asChild` 不支援**:trigger 是 compound(view 裸 span / edit `div role="combobox"` 不同 render tree),無單一 Slot 目標。consumer 若要自訂 trigger 視覺,改用 `<DatePicker mode="view">` + 自家 Button composition。
290
290
 
291
291
  ---
292
292
 
293
293
  ## A11y 預設
294
294
 
295
295
  - Trigger:`role="combobox"` + `aria-haspopup="dialog"` + `aria-expanded={open}` + 必含 accessible name(`aria-label` / 或外層 `<label>` / 或 fieldCtx label)
296
- - Popover content:`role="dialog"`;單一日期 popover 不重覆 `aria-label`(由 trigger 的 `role="combobox"` accessible name 標示),Range popover 加 `aria-label="日期區間選擇"`
296
+ - Popover content:`role="dialog"`;單一日期 popover PopoverContent 帶 `aria-label="日期選擇"`(date-picker.tsx:650,DS default dialog label),Range popover 加 `aria-label="日期區間選擇"`
297
297
  - DateGrid 鍵盤:Arrow keys 切日 / PageUp/Down 切月 / Home/End 行首尾(react-day-picker v9 內建)
298
298
  - Trigger 鍵盤(Space / Enter open;Esc close + 回焦):單一 DatePicker 的 `<div role="combobox">` 無 native Enter/Space→click,由元件**自建 `onKeyDown`** 開 popover(Radix PopoverTrigger 只 compose onClick;date-picker.tsx:554),Esc 關閉後靠 PopoverTrigger 的 Radix **內建** `triggerRef.focus()` 回焦;Range 用 native `<button>` onClick 開、只掛 PopoverAnchor(triggerRef 恆 null → 內建回焦 no-op),改由**自建 `onCloseAutoFocus`** 手動回焦 active 端 button(date-picker.tsx:1020-1026,守 WCAG 2.4.3)
299
299
  - Range 雙 trigger:`activeEnd` state 指向當前編輯端,`aria-expanded` 對應只當該 trigger active 時 true
@@ -311,11 +311,11 @@ DatePicker 套 `React.forwardRef` + `displayName`;`DatePickerProps` extends `Omi
311
311
 
312
312
  ## 邊界案例
313
313
 
314
- - **Disabled**:Field SSOT own;resolvedMode='disabled' 走 readonly / disabled 純 wrapper 分支(無 Popover trigger、`aria-disabled`、不開 picker),文字與 Calendar icon 切 `text-fg-disabled`。readonly 不顯示 Calendar icon(類型身份 indicator 規則,SSOT field-controls.spec.md L227);disabled 保留並切 `fg-disabled`。顯式 `mode="display"` 永遠最優先(useResolvedFieldMode step 1,見 field-context.ts):display + disabled 同傳走 display 分支不套 disabled token;要 disabled chrome 傳 `disabled` 或 `mode="disabled"`。
314
+ - **Disabled**:Field SSOT own;resolvedMode='disabled' 走 readonly / disabled 純 wrapper 分支(無 Popover trigger、`aria-disabled`、不開 picker),文字與 Calendar icon 切 `text-fg-disabled`。readonly 不顯示 Calendar icon(類型身份 indicator 規則,SSOT field-controls.spec.md「下拉箭頭與類型身份 indicator」段 L266-276);disabled 保留並切 `fg-disabled`。顯式 `mode="view"` 永遠最優先(useResolvedFieldMode step 1,見 field-context.ts):view + disabled 同傳走 view 分支不套 disabled token;要 disabled chrome 傳 `disabled` 或 `mode="disabled"`。
315
315
  - **Loading(server-rendered grid)**:DatePicker 為 sync UI 不獨立 own loading。若 consumer 場景需 async date constraint fetch(如後端 disabled-dates list),consumer 應先 disable trigger 直到 fetch 完成,或在 popover 開啟後 body 切 `<Empty icon={<CircularProgress/>}/>`(對齊 panel-body loading SSOT)。本 spec scope 內不渲 loading state。
316
316
  - **Empty(no value)**:`value=null` → trigger 顯 placeholder(預設 `YYYY/MM/DD`,showTime 時 `YYYY/MM/DD HH:MM`;consumer 可傳 `placeholder` 覆寫)。無導覽目標時鍵盤焦點停留(react-day-picker v9 內建)。
317
317
  - **Invalid date input**:Field validation 處理 `aria-invalid="true"` + error border + 下方 error message;DatePicker 本身不 own validation 規則。
318
- - **極長格式化日期**:trigger 文字單行 `truncate`(ellipsis),不換行不撐高(Display / Edit / typeable / Range 雙 input 皆同)。
318
+ - **極長格式化日期**:trigger 文字單行 `truncate`(ellipsis),不換行不撐高(View / Edit / typeable / Range 雙 input 皆同)。
319
319
  - **RTL**:未實作方向鏡像(trigger / Range 雙 input / DateGrid 皆以 LTR physical 方向設計);RTL 屬 DS-wide 決策,未定(與 Chip / Breadcrumb 同口徑)。
320
320
  - **Dark mode / density**:走 Field + Popover SSOT 自動 adapt;DateGrid 內 cell 尺寸 density-aware(消費 `--field-height-sm`:md=28×28 / lg=32×32,對齊 L128 + `date-grid.spec.md:120`),隨 density 縮放而非固定。
321
321