@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
@@ -1,5 +1,5 @@
1
1
  // @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
2
- // @renderer-symmetry-allow: ComboboxTagStack(display path)接 consumer tagRenderer 是 Stream C 下 cycle 工作 — 2026-05-12 先 ship Issues 2/3/4 surgical fixes(placeholder vocabulary + cell surface metrics + placeholder truncate),tagRenderer display-path unify deferred per field-controls.spec.md 共享 contract a。當前 multi=1 顯示已透過 PeoplePicker tagRenderer(people-picker.tsx:426-444)PersonDisplay SSOT 對齊;其他 Combobox consumer 走 default `<Tag>` 純文字 backward-compat。
2
+ // @renderer-symmetry-allow: ComboboxTagStack(view path)接 consumer tagRenderer 是 Stream C 下 cycle 工作 — 2026-05-12 先 ship Issues 2/3/4 surgical fixes(placeholder vocabulary + cell surface metrics + placeholder truncate),tagRenderer view-path unify deferred per field-controls.spec.md 共享 contract a。當前 multi=1 顯示已透過 PeoplePicker tagRenderer(people-picker.tsx:426-444)PersonDisplay SSOT 對齊;其他 Combobox consumer 走 default `<Tag>` 純文字 backward-compat。
3
3
  // code-quality-allow: file-size — Combobox 含 NativeCombobox/CustomCombobox/useOverflowCount/OverflowTagList/ComboboxTagStack 5 子元件 + 共用 helpers,split-into-files 會破壞 measurement closures + 重複 type definitions。
4
4
  import * as React from 'react'
5
5
  import { X, ChevronDown } from 'lucide-react'
@@ -237,7 +237,7 @@ interface OverflowTagListProps {
237
237
  * 2026-05-14 I4 fix(per codex M31 verdict + user 抓「display overflow 有 avatar / edit 無」):
238
238
  * Optional renderer for hidden items in `+N` overflow popover。Default fallback = `<Tag>{label}</Tag>`
239
239
  * (純文字 chip,backward-compat)。Consumer pass 此 prop 讓 hidden items 顯示同 avatar 視覺
240
- * (對齊 display MultiPersonDisplay overflow popover Tag avatar SSOT)。
240
+ * (對齊 view path MultiPersonDisplay overflow popover Tag avatar SSOT)。
241
241
  */
242
242
  renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode
243
243
  onRemove?: (value: string) => void
@@ -297,7 +297,7 @@ function OverflowTagList({ containerRef, items, size, wrap, renderTag, renderHid
297
297
  {items.map((item, i) => (
298
298
  // 2026-05-14 I5 fix(per codex M31 verdict + user 抓「avatar stack 堆疊方向不一致」):
299
299
  // 加 z-index per-index — 前 item z 高(對齊 MultiPersonDisplay zIndex: visible.length - i
300
- // canonical + MUI AvatarGroup surplus pattern)。display + edit stack 堆疊方向統一。
300
+ // canonical + MUI AvatarGroup surplus pattern)。view + edit stack 堆疊方向統一。
301
301
  <div key={item.value} ref={el => { tagEls.current[i] = el }} className={cn('shrink-0 max-w-full', tagWrapperClassName)} style={{ zIndex: items.length - i }}>{renderTag(item, i)}</div>
302
302
  ))}
303
303
  <div ref={overflowEl} className={cn('shrink-0', overflowWrapperClassName)}>
@@ -316,9 +316,9 @@ function OverflowTagList({ containerRef, items, size, wrap, renderTag, renderHid
316
316
  )
317
317
  }
318
318
 
319
- // ── Internal tag-stack renderer (consumed by ReadonlyMultiSelect / mode='display') ───
319
+ // ── Internal tag-stack renderer (consumed by ReadonlyMultiSelect / mode='view') ───
320
320
  //
321
- // Phase B2(2026-05-05):原 ComboboxDisplay sub-component 已 retire,改 inline `<Combobox mode="display">`。
321
+ // Phase B2(2026-05-05):原 ComboboxDisplay sub-component 已 retire,改 inline `<Combobox mode="view">`。
322
322
  // 本 helper 只負責 tag-stack 內容渲染(OverflowTagList 消費),不包 Field wrapper。
323
323
  function ComboboxTagStack({
324
324
  value, options, tagSize = 'md', wrap = false, containerRef: externalRef, disabled = false,
@@ -328,7 +328,7 @@ function ComboboxTagStack({
328
328
  }) {
329
329
  const emptyDisplay = useFieldEmptyDisplay()
330
330
  const ownRef = React.useRef<HTMLDivElement>(null)
331
- if (!value || value.length === 0) return <span className={fieldEmptyColorClass(disabled ? 'disabled' : 'display')}>{emptyDisplay}</span>
331
+ if (!value || value.length === 0) return <span className={fieldEmptyColorClass(disabled ? 'disabled' : 'view')}>{emptyDisplay}</span>
332
332
  const items = value.map(v => ({ value: v, label: options?.find(o => o.value === v)?.label ?? v }))
333
333
  const disabledClass = disabled ? 'bg-disabled text-fg-disabled' : undefined
334
334
 
@@ -345,10 +345,10 @@ function ComboboxTagStack({
345
345
  )
346
346
 
347
347
  if (externalRef) return content
348
- // 2026-05-05 v9 fix(Bug 4):display path 內 wrapper 必須 `flex-1 min-w-0`,否則在 cell flex
348
+ // 2026-05-05 v9 fix(Bug 4):view path 內 wrapper 必須 `flex-1 min-w-0`,否則在 cell flex
349
349
  // parent 下不認領完整可用寬度 → OverflowTagList 量得寬度小於 edit path → 顯 `+N` 多於 edit。
350
350
  // edit path tagAreaRef wrapper 已是 `flex-1 min-w-0`(NativeCombobox/CustomCombobox line 258 / 354),
351
- // display 必對稱才 SSOT。
351
+ // view 必對稱才 SSOT。
352
352
  // 2026-05-15 F1 Q3 fix(per user round 3 verbatim「單人選取時 Tag 越界蓋 indicator」):
353
353
  // `overflow-visible` → `overflow-hidden` 讓 narrow cell width 強制 clip(Tag 內建 truncate
354
354
  // 處理 text ellipsis,stack `-ml-0.5` 負 margin 在 wrapper 內不受影響)。對齊
@@ -384,8 +384,9 @@ export interface ComboboxProps {
384
384
  /** 啟用搜尋 */
385
385
  searchable?: boolean
386
386
  /** Loading state(2026-05-15 audit B fix per user verbatim「dropdown 隨時可開,讀取在 panel 中間 CircularProgress」)。
387
- * Forward 給 SelectMenu primitive SSOT;dropdown 開啟時取代 options 顯 CircularProgress + loadingText。
388
- * Trigger 不變(user 隨時可開)。對齊 MUI Autocomplete `loadingText` + Field SSOT + Empty 元件 compose。*/
387
+ * Forward 給 SelectMenu primitive SSOT;spinner 只在無可顯示選項時佔 CommandEmpty slot 顯 CircularProgress
388
+ * (已有 options 保留顯示,不取代)。Trigger 不變(user 隨時可開)
389
+ * 對齊 MUI Autocomplete「loading 只在無 suggestions 時顯 loadingText」+ Field SSOT + Empty 元件 compose。*/
389
390
  loading?: boolean
390
391
  /** 搜尋框位置:menu(浮層內,預設)或 trigger(inline input) */
391
392
  searchIn?: 'menu' | 'trigger'
@@ -397,6 +398,14 @@ export interface ComboboxProps {
397
398
  emptyPlaceholder?: string
398
399
  /** 搜尋無結果提示(2026-07-04 Q4 拍板接線)— forward SelectMenu primitive SSOT(default「沒有符合的選項」) */
399
400
  emptyText?: string
401
+ /** 可建立新選項(creatable tag,2026-07-18 user 拍板 forward)—— 搜尋非空且無完全同名既有選項時,
402
+ * dropdown 顯 create row(Plus + `createLabel`);forward 給底層 SelectMenu(邏輯/顯示/互動 SSOT 住在 SelectMenu)。
403
+ * 僅 searchable 桌機路徑生效(需打字);native mobile 路徑不支援。對齊 Ant tags / react-select Creatable。 */
404
+ creatable?: boolean
405
+ /** 建立新選項 callback(forward SelectMenu `onCreate`)。 */
406
+ onCreate?: (value: string) => void
407
+ /** create row 文字格式(forward SelectMenu `createLabel`,預設「直接使用「{query}」」)。 */
408
+ createLabel?: (query: string) => string
400
409
  /** a11y:無 Field wrapper 時提供 role='combobox' 的 accessible name(axe aria-input-field-name) */
401
410
  'aria-label'?: string
402
411
  /** Initial open state(uncontrolled)— 對齊 Select.defaultOpen / Radix Popover canonical。
@@ -416,8 +425,8 @@ export interface ComboboxProps {
416
425
  tagRenderer?: (item: { value: string; label: string }, onRemove: () => void) => React.ReactNode
417
426
  /**
418
427
  * 2026-05-14 I4 fix:Optional renderer for hidden items in `+N` overflow popover
419
- * (對齊 display MultiPersonDisplay overflow popover 含 avatar SSOT)。PeoplePicker stack
420
- * pass 此 prop 讓 hidden items 顯 avatar + name(同 display path)。Default fallback
428
+ * (對齊 view path MultiPersonDisplay overflow popover 含 avatar SSOT)。PeoplePicker stack
429
+ * pass 此 prop 讓 hidden items 顯 avatar + name(同 view path)。Default fallback
421
430
  * `<Tag>{label}</Tag>` 純文字 backward-compat。
422
431
  */
423
432
  renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode
@@ -477,8 +486,8 @@ export interface ComboboxProps {
477
486
  visibleCountOverride?: number
478
487
  /**
479
488
  * Display 是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)
480
- * — DataTable cell display↔edit 像素級對齊用。預設 false(裸 tag stack,backward compat)。
481
- * 設 true 時 display 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,
489
+ * — DataTable cell view↔edit 像素級對齊用。預設 false(裸 tag stack,backward compat)。
490
+ * 設 true 時 view 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,
482
491
  * 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。
483
492
  */
484
493
  showDisplayEndIcon?: boolean
@@ -487,7 +496,7 @@ export interface ComboboxProps {
487
496
  // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反)
488
497
  const getIconSize = (size: string) => ICON_SIZE[size as 'sm' | 'md' | 'lg']
489
498
 
490
- // ── Shared readonly/disabled/display render ─────────────────────────────────
499
+ // ── Shared readonly/disabled/view render ─────────────────────────────────
491
500
 
492
501
  function ReadonlyMultiSelect({
493
502
  mode, variant: variantProp, width, size, options, value, wrap, className, showDisplayEndIcon = false,
@@ -504,13 +513,13 @@ function ReadonlyMultiSelect({
504
513
  const containerRef = React.useRef<HTMLDivElement>(null)
505
514
  const hasTags = (value?.length ?? 0) > 0
506
515
 
507
- // mode='display'(Phase B2 2026-05-05):純內容輸出 — tag stack 不包 Field wrapper / 不 reserve 高度。
516
+ // mode='view'(Phase B2 2026-05-05):純內容輸出 — tag stack 不包 Field wrapper / 不 reserve 高度。
508
517
  // 對齊原 ComboboxDisplay sub-component(retired)。
509
518
  // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,
510
- // 與 edit 同結構消除 cell display↔edit 像素偏移(Layer-B padding mismatch)。
511
- if (resolvedMode === 'display') {
519
+ // 與 edit 同結構消除 cell view↔edit 像素偏移(Layer-B padding mismatch)。
520
+ if (resolvedMode === 'view') {
512
521
  if (!showDisplayEndIcon) {
513
- // 2026-05-14 I2 fix(spec contract (e) display typography canonical):empty bare span 套
522
+ // 2026-05-14 I2 fix(spec contract (e) view typography canonical):empty bare span 套
514
523
  // `fieldDisplayTextClass(sz)`(sm/md→text-body,lg→text-body-lg)— 對齊跨 Field family 統一。
515
524
  if (!hasTags) return <span className={cn(fieldDisplayTextClass(sz), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>
516
525
  return (
@@ -519,8 +528,8 @@ function ReadonlyMultiSelect({
519
528
  }
520
529
  return (
521
530
  <div
522
- className={cn(fieldWrapperStyles({ mode: 'display', variant, width, size: sz }), hasTags && tagPadding[sz], className)}
523
- data-field-mode="display"
531
+ className={cn(fieldWrapperStyles({ mode: 'view', variant, width, size: sz }), hasTags && tagPadding[sz], className)}
532
+ data-field-mode="view"
524
533
  >
525
534
  {hasTags ? (
526
535
  <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap} />
@@ -538,8 +547,8 @@ function ReadonlyMultiSelect({
538
547
  <div ref={containerRef}
539
548
  className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), hasTags && tagPadding[sz],
540
549
  // 2026-05-18 #6A Round 1 Step 1/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:451):
541
- // readonly/disabled path 對齊 L293 display wrapper 已 ship 的 overflow-hidden fix。
542
- // M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟 display 不對稱。
550
+ // readonly/disabled path 對齊 L293 view wrapper 已 ship 的 overflow-hidden fix。
551
+ // M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟 view 不對稱。
543
552
  // 2026-06-27 對齊 edit path(L598-617):wrap 時 items-start + chevron self-start/tagHeight 鎖第一行;
544
553
  // paddingRight: var(--field-px) re-assert 右緣 12px(tagPadding 對稱 calc 會吃掉右緣,跟 edit 一致)。
545
554
  wrap ? 'flex-wrap items-start py-1' : 'overflow-hidden', className)}
@@ -586,7 +595,7 @@ function NativeCombobox({
586
595
  const fieldCtx = useFieldContext()
587
596
  const disabled = useResolvedFieldDisabled(disabledProp)
588
597
  const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
589
- // 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="display"> 漏 cascade
598
+ // 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="view"> 漏 cascade
590
599
  const resolvedMode = useResolvedFieldMode({ mode, disabled })
591
600
  const iconSize = getIconSize(size)
592
601
  const showClear = clearable && value.length > 0 && resolvedMode === 'edit'
@@ -633,7 +642,7 @@ function NativeCombobox({
633
642
  onClick={(e) => { if (e.target === e.currentTarget) { selectRef.current?.showPicker?.(); selectRef.current?.focus() } }}>
634
643
  {/* 2026-05-18 F2 sync(per user verbatim「modifying 修好 PeoplePicker stack 後改壞 Combobox tag display」
635
644
  + 「tag 應該要判斷所在空間最多可以呈現幾個tag(包括+n)去自動判斷何時要變成+n」):
636
- edit path tagArea 對齊 display path L293 已 ship 的 `overflow-hidden` fix。原 `overflow-visible`
645
+ edit path tagArea 對齊 view path L293 已 ship 的 `overflow-hidden` fix。原 `overflow-visible`
637
646
  讓 tag 視覺越界蓋 chevron / +N indicator(useOverflowCount measurement 對但 CSS overflow 仍露)。
638
647
  M10 violation root cause:2026-05-15 F1 Q3 只 fix display path,edit + Native(L518)沒同步。 */}
639
648
  <div ref={tagAreaRef} className={cn('flex-1 min-w-0 flex items-center relative', nakedCellRowModeAlign, wrap ? 'flex-wrap' : 'overflow-hidden')} style={{ gap: GAP }}
@@ -670,6 +679,9 @@ function CustomCombobox({
670
679
  searchAriaLabel = '搜尋選項', // i18n-allow: DS default
671
680
  emptyPlaceholder = '選擇…', // i18n-allow: DS default
672
681
  emptyText,
682
+ creatable = false,
683
+ onCreate,
684
+ createLabel,
673
685
  defaultOpen = false,
674
686
  onOpenChange,
675
687
  __triggerRef,
@@ -688,7 +700,7 @@ function CustomCombobox({
688
700
  const fieldCtx = useFieldContext()
689
701
  const error = useResolvedFieldInvalid(errorProp)
690
702
  const disabled = useResolvedFieldDisabled(disabledProp)
691
- // 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="display"> 漏 cascade
703
+ // 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode="view"> 漏 cascade
692
704
  const resolvedMode = useResolvedFieldMode({ mode, disabled })
693
705
  const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)
694
706
  const iconSize = getIconSize(size)
@@ -797,7 +809,7 @@ function CustomCombobox({
797
809
  if (e.key === 'Escape') setOpen(false)
798
810
  }}>
799
811
  {/* 2026-05-18 #6A Round 1 Step 2/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:648):
800
- CustomCombobox edit non-wrap tagArea 對齊 L293 display + L451 readonly + L518 native edit 已 ship 的 overflow-hidden fix。
812
+ CustomCombobox edit non-wrap tagArea 對齊 L293 view + L451 readonly + L518 native edit 已 ship 的 overflow-hidden fix。
801
813
  原 overflow-visible 讓 tag 越界蓋 chevron / +N indicator(user 圖三)。M10 propagation 完整 4-path align。 */}
802
814
  <div ref={tagAreaRef} className={cn('flex-1 min-w-0 flex items-center relative', nakedCellRowModeAlign, wrap ? 'flex-wrap' : 'overflow-hidden')} style={{ gap: tagAreaGap, paddingLeft: tagAreaPaddingLeftPx }}>
803
815
  {value.length > 0 ? (
@@ -863,6 +875,9 @@ function CustomCombobox({
863
875
  value={value}
864
876
  onValueChange={onChange as (value: string | string[]) => void}
865
877
  multiple
878
+ creatable={creatable}
879
+ onCreate={onCreate}
880
+ createLabel={createLabel}
866
881
  searchable={searchable && searchIn === 'menu'}
867
882
  searchPlaceholder={searchPlaceholder}
868
883
  size={size}
@@ -20,7 +20,7 @@ Command 是**搜尋 + 鍵盤導覽的指令清單**——提供搜尋框、分
20
20
 
21
21
  **實作基礎**:shadcn passthrough——基於 cmdk + Radix Dialog(Command Palette 模式)。本 DS 保留 shadcn 原結構,視覺樣式以 inline Tailwind class 直接掛在 cmdk primitive 上(`command.tsx`),token 值對齊(非結構繼承)MenuItem / Input / Empty 的 canonical token——改 MenuItem 不會自動連動 Command。
22
22
 
23
- **分類**:Internal primitive——由 SelectMenu 消費(Select / Combobox / PeoplePicker 透過 SelectMenu 使用)。App 不直接使用 Command;若要 Command Palette 類 UX,用本檔 export `CommandDialog`(cmdk + Radix Dialog 包裝,showcase「CommandPalette」story 消費)。
23
+ **分類**:Internal primitive——由 SelectMenu 消費(Select / Combobox / PeoplePicker 透過 SelectMenu 使用)。App **不從 root barrel front-door 直接 import** Command 家族;若要 Command Palette 類 UX,經 per-component subpath `@qijenchen/design-system/components/Command` 取用 `CommandDialog`(自行包裝確認後使用,對齊 `.claude/rules/ui-development.md`「Root barrel front-door 排除」— internal ≠ 禁用;cmdk + Radix Dialog 包裝,showcase「CommandPalette」story 消費)。
24
24
 
25
25
  **Layout Family**:非上述 family — composite / multi-section(多區塊組合,自 own layout)。
26
26
 
@@ -66,7 +66,7 @@ Command 通常由 `SelectMenu` 或自訂 Command Palette 元件消費——直
66
66
  - **SelectMenu**:Select / Combobox / PeoplePicker 的 searchable 浮層(**由 Field 觸發**,帶有 input field + 選中值回填)
67
67
  - **獨立 Command Palette**(Cmd+K):也用 Command 但**不在 Field 觸發**——透過全域快捷鍵開啟,用於跨頁面搜尋 / 快速動作入口
68
68
 
69
- 兩者底層都消費 Command。Field 場景用 SelectMenu(已處理 input binding);非 Field 場景(Cmd+K)用 `CommandDialog`(cmdk + Radix Dialog 包裝)。
69
+ 兩者底層都消費 Command。Field 場景用 SelectMenu(已處理 input binding);非 Field 場景(Cmd+K)用 `CommandDialog`(經 subpath `@qijenchen/design-system/components/Command` 取用,cmdk + Radix Dialog 包裝)。
70
70
 
71
71
  ---
72
72
 
@@ -97,7 +97,7 @@ Consumer 無需額外處理 a11y,保留 cmdk 原結構 + 使用 `<CommandInput>`
97
97
  - **Disabled item**:`<CommandItem disabled>` 透過 cmdk 內建支援,視覺繼承 MenuItem SSOT(`text-fg-disabled` + `aria-disabled=true` + 鍵盤導覽自動 skip + Enter 不觸發 onSelect)。skip 是「不進導覽清單」(cmdk `:not([aria-disabled="true"])` selector)— ↑/↓ 直接跳到下一個可選項,無中途 highlight。
98
98
  - **Group heading 不可選中**:heading 是 `aria-hidden` 裝飾 div(group container `role="presentation"`),不參與導覽與選取;SR 經 items wrapper `role="group"` + `aria-labelledby` 取得群組語意。
99
99
  - **Empty 後持續打字**:cmdk 每個 keystroke 重新過濾(`filtered.count` 驅動),`<CommandEmpty>` 持續顯示直到有 match;input 不鎖、不清空。
100
- - **Loading**:Command 本身非 async surface。async option fetch 應由 consumer(SelectMenu / Cmd+K palette)在外層處理 — `<CommandList>` body 切換為 `<Empty icon={<CircularProgress size={48}/>}/>`(對齊 `empty.spec.md`「現有消費者」SelectMenu loading row SSOT,禁止事項見其「禁止事項」loading 條)。Command primitive 不獨立 own loading prop。
100
+ - **Loading**:Command 本身非 async surface。async option fetch 應由 consumer(SelectMenu / Cmd+K palette)在外層處理 — `<CommandEmpty>` slot 內渲 `<Empty icon={<CircularProgress size={48}/>}/>`(spinner 只在無可顯示選項時出現;已有 options 保留顯示,不取代 — 對齊 `select.spec.md`「Loading」2026-07-04 拍板措辭 + `empty.spec.md`「現有消費者」SelectMenu loading SSOT,禁止事項見其「禁止事項」loading 條)。Command primitive 不獨立 own loading prop。
101
101
  - **Empty(no results)**:`<CommandEmpty>` 自動偵測 search filter result = 0 時渲;consumer 必傳 fallback 文案(預設 cmdk 不渲)。
102
102
  - **Dark mode / density**:Command 的 inline Tailwind class 直接消費 semantic token(`bg-neutral-hover` / `text-fg-muted` / `text-fg-disabled` 等),token 在 dark mode 自動切值——非透過 MenuItem / Input / Empty primitive 連動。density 不獨立 own(由 consumer SelectMenu 控)。
103
103
 
@@ -48,7 +48,7 @@ const CommandInput = React.forwardRef<
48
48
  React.ElementRef<typeof CommandPrimitive.Input>,
49
49
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
50
50
  >(({ className, ...props }, ref) => (
51
- <div className="flex items-center border-b border-divider px-3" cmdk-input-wrapper="">
51
+ <div className="flex shrink-0 items-center border-b border-divider px-3" cmdk-input-wrapper="">
52
52
  <Search className="mr-2 h-4 w-4 shrink-0 text-fg-muted" />
53
53
  <CommandPrimitive.Input
54
54
  ref={ref}
@@ -80,7 +80,14 @@ const CommandList = React.forwardRef<
80
80
  React.ElementRef<typeof CommandPrimitive.List>,
81
81
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
82
82
  >(({ className, ...props }, ref) => (
83
- <ScrollArea className="max-h-[var(--menu-max-height,300px)]">
83
+ /* @story-baseline: overlay-surface.spec.md#Viewport-aware-scroll-chain-invariant(M25 SSOT owner)
84
+ owner spec: overlay-surface.spec.md:34/53/347-362 —— 「浮層 body 永遠 flex-1 min-h-0 overflow-y-auto;
85
+ 中間 wrapper 都必 flex flex-col h-full min-h-0;viewport 太小 body 內壓縮捲動」。
86
+ conflicting code(修前): 本 ScrollArea 固定 max-h-300 無 flex-1 → 在夾住的 SelectMenu PopoverContent
87
+ (max-h=available-height)內撐破外殼、底部選項被裁(320px viewport 實測 bottom 425 > 320 溢出)。
88
+ 修: 加 flex-1 min-h-0(對齊 M25 canonical + HoverCard/Popover),max-h-300 降為上限。Command root 已
89
+ `flex h-full flex-col`(command.tsx:23)= chain 完整;非 flex 容器內 flex-1 為 no-op(spec:34 backward compat)。 */
90
+ <ScrollArea className="flex-1 min-h-0 max-h-[var(--menu-max-height,300px)]">
84
91
  <CommandPrimitive.List ref={ref} className={cn("overflow-x-hidden", className)} {...props} />
85
92
  </ScrollArea>
86
93
  ))
@@ -4,7 +4,7 @@
4
4
  //
5
5
  // 對齊 M17 SSOT consolidation + audit recommendation:
6
6
  // 原 `renderTypedValue` switch + `EditableCellContent` switch 兩條平行 type-switch 已 collapse
7
- // 為**一張 type → cell component** registry。每個 cell component 同時處理 display / edit mode,
7
+ // 為**一張 type → cell component** registry。每個 cell component 同時處理 view / edit mode,
8
8
  // 靠底層 Field control 的 `mode` prop 切換。
9
9
  //
10
10
  // 設計原則:
@@ -19,7 +19,7 @@
19
19
  import * as React from 'react'
20
20
  import type { ComponentType } from 'react'
21
21
  import { Pencil } from 'lucide-react'
22
- import { cn } from '@/lib/utils'
22
+ import { cn, lineClampClass } from '@/lib/utils'
23
23
  import type { ColumnType } from './column-types'
24
24
  import { Input as InputPublic } from '@/design-system/components/Input/input'
25
25
  import { Textarea as TextareaPublic } from '@/design-system/components/Textarea/textarea'
@@ -55,7 +55,7 @@ const Checkbox = CheckboxPublic as WithFieldVariantInternal<typeof CheckboxPubli
55
55
 
56
56
  // ── Types ────────────────────────────────────────────────────────────────────
57
57
 
58
- export type CellMode = 'display' | 'edit'
58
+ export type CellMode = 'view' | 'edit'
59
59
  export type CellSize = 'sm' | 'md' | 'lg'
60
60
 
61
61
  export interface CellComponentProps {
@@ -65,13 +65,13 @@ export interface CellComponentProps {
65
65
  meta: Record<string, any>
66
66
  mode: CellMode
67
67
  size: CellSize
68
+ /** 該 cell 的 accessible name(= 欄標題)。naked Field 控件在 cell 內無 FieldLabel,
69
+ * 漏此名 → editor 成無名控件(axe aria-input-field-name / select-name)。由 renderCellContent
70
+ * 從 columnDef.header 解析後注入。對齊 AG Grid / MUI X「editor aria-label = column headerName」。 */
71
+ ariaLabel?: string
68
72
  autoRowHeight: boolean
69
73
  /** 該 cell 是否可編。replaces 舊 `meta._editable` 私有 flag(Phase C M1 hack 移除)。 */
70
74
  isEditable?: boolean
71
- /** 2026-05-13:cell 是否 disabled(state overlay,orthogonal to display/edit lifecycle)。
72
- * per codex Q3 verdict:不擴 CellMode='disabled',加 prop。各 Cell function 收 true 時
73
- * 傳 `mode='disabled'` 給 inner Field control,各 Field 內部走具體 disabled token(非 wrapper opacity)。 */
74
- isDisabled?: boolean
75
75
  /** Cell 進 edit mode → 提交新值(blur / Enter / option select 都觸發)— 提交後**自動 exit edit**。
76
76
  * 適用 single-shot commit:string / number / select(single)/ person(single)/ date / time / boolean / url。 */
77
77
  onCommit?: (next: unknown) => void
@@ -112,44 +112,41 @@ function makeKeyHandler(
112
112
 
113
113
  const sizeForInput = (size: CellSize): CellSize => size
114
114
 
115
- /** 2026-05-13 Q3 helper(per codex Q3 verdict):cell display + isDisabled Field mode='disabled'。
116
- * Cell display lifecycle 不擴 CellMode='disabled',而是各 Cell display branch 翻譯 isDisabled
117
- * → Field mode='disabled' prop。inner Field 內部走具體 disabled token(text-fg-disabled / bg-disabled 等),
118
- * 非 wrapper blanket opacity-disabled 逃生艙(per color.spec.md:729)。 */
119
- const displayOrDisabled = (isDisabled?: boolean): 'display' | 'disabled' =>
120
- isDisabled ? 'disabled' : 'display'
115
+ // 2026-07-16 round16:cell「disabled」態廢除(世界級 grid disabled cell MUI X / AG Grid /
116
+ // Handsontable 皆只有 editable/readonly;meta.disabled 全庫 0 消費)。cell view 態一律 mode="view",
117
+ // 鎖定用 `editable:(row)=>false` 閘(= isCellEditable 模型)。原 displayOrDisabled helper 已移除。
121
118
 
122
119
  // ── Cell Components ──────────────────────────────────────────────────────────
123
120
 
124
- function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onCommit, onCancel, onDraft }: CellComponentProps) {
121
+ function StringCell({ value, meta, mode, size, autoRowHeight, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {
125
122
  // 2026-05-14 I9 fix(per codex+Layer A 共識):meta.maxLines opt-in line-clamp。
126
- // display autoRow 用 Tailwind arbitrary line-clamp 支援 N rows;edit textarea field-sizing
123
+ // view autoRow 用 Tailwind arbitrary line-clamp 支援 N rows;edit textarea field-sizing
127
124
  // 已 auto-grow to content,natural match clamp。
128
125
  // 2026-05-16 Round 5 audit Dim 27 fix:narrow type 取代 `as any` cast。
129
126
  const maxLines: number | undefined = (meta as { maxLines?: number } | undefined)?.maxLines
130
- const clampClass = maxLines && autoRowHeight ? `line-clamp-[${maxLines}]` : undefined
127
+ const clampClass = autoRowHeight ? lineClampClass(maxLines) : undefined
131
128
  // string type canonical(2026-05-05 v2 user 校正:input space ≥ display space):
132
- // - autoRowHeight: Textarea(display + edit)— display wrap text 撐高 row,edit textarea
129
+ // - autoRowHeight: Textarea(view + edit)— view wrap text 撐高 row,edit textarea
133
130
  // 多行輸入、`!h-full` 填 cell。對齊 Notion long-text cell canonical。
134
- // - fixed: Input(display + edit)— 單行 truncate display,單行 input edit;Field naked intrinsic
135
- // 高 = cell 高 = h-field-md,文字位置 display↔edit 完全一致。對齊 AG Grid / Material X-Grid。
131
+ // - fixed: Input(view + edit)— 單行 truncate view,單行 input edit;Field naked intrinsic
132
+ // 高 = cell 高 = h-field-md,文字位置 view↔edit 完全一致。對齊 AG Grid / Material X-Grid。
136
133
  // - autoRowHeight 是 table 框架決定(consumer 不需 per-column 設 meta.wrap)。
137
134
  // - 互動(Textarea):Esc cancel / Cmd|Ctrl+Enter commit / blur commit;Enter 保留換行
138
135
  // - 互動(Input):Esc cancel / Enter commit / blur commit
139
136
  const v = value != null ? String(value) : ''
140
- if (mode === 'display') {
137
+ if (mode === 'view') {
141
138
  // size 必傳:DataTable cell 字級隨 size 變(sm/md text-body / lg text-body-lg),
142
139
  // 對齊 Field family size→font SSOT(field-wrapper.tsx:60-64)。漏傳 → fallback md → lg 表格
143
140
  // 字卡 14px 跟 Select/Date 等有傳 size 的 cell 不一致(2026-06-08 user 抓 frozen string 欄字偏小)。
144
141
  return autoRowHeight
145
- ? <Textarea variant="naked" mode={displayOrDisabled(isDisabled)} value={v} size={size} className={clampClass} />
146
- : <Input variant="naked" mode={displayOrDisabled(isDisabled)} value={v} size={size} />
142
+ ? <Textarea variant="naked" mode="view" value={v} size={size} className={clampClass} aria-label={ariaLabel} />
143
+ : <Input variant="naked" mode="view" value={v} size={size} aria-label={ariaLabel} />
147
144
  }
148
145
  if (autoRowHeight) {
149
146
  // 2026-05-14 I8 fix(per codex verdict + user 抓「edit cell shrink」):
150
147
  // 原 `wrapRows = value.length / 40` 字元估算不準(對應實際 column width 不同
151
148
  // → cell 進 edit shrink)。改 CSS `field-sizing: content`(Chrome 123+ / FF 122+ /
152
- // Safari 17+)讓 textarea 自動 grow to content,匹配 display wrap 真實高度。
149
+ // Safari 17+)讓 textarea 自動 grow to content,匹配 view wrap 真實高度。
153
150
  // Fallback rows 仍保留給舊 browser(rows attr 在 field-sizing 支援時被覆蓋)。
154
151
  const newlineRows = (v.match(/\n/g) || []).length + 1
155
152
  const wrapRows = Math.ceil(v.length / 40)
@@ -158,6 +155,7 @@ function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onComm
158
155
  <Textarea
159
156
  autoFocus
160
157
  variant="naked"
158
+ aria-label={ariaLabel}
161
159
  size={sizeForInput(size)}
162
160
  rows={estimateRows}
163
161
  defaultValue={v}
@@ -180,6 +178,7 @@ function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onComm
180
178
  <Input
181
179
  autoFocus
182
180
  variant="naked"
181
+ aria-label={ariaLabel}
183
182
  size={sizeForInput(size)}
184
183
  defaultValue={v}
185
184
  onChange={(e) => onDraft?.(e.target.value)}
@@ -189,20 +188,21 @@ function StringCell({ value, meta, mode, size, isDisabled, autoRowHeight, onComm
189
188
  )
190
189
  }
191
190
 
192
- function NumberCell({ value, meta, mode, size, isDisabled, onCommit, onCancel, onDraft }: CellComponentProps) {
191
+ function NumberCell({ value, meta, mode, size, onCommit, onCancel, onDraft, ariaLabel }: CellComponentProps) {
193
192
  // currency 透過 columnType-aware prefix:type='currency' → 預設 '$'(可 override)
194
193
  const isCurrency = meta?.type === 'currency'
195
194
  const prefix = isCurrency ? (meta?.prefix ?? '$') : meta?.prefix
196
- // React #310 fix:useState 必在 display early-return 前無條件呼叫。同一 memo'd cell instance
197
- // 在 display↔edit 切換時被重用(render site 無 key={mode},data-table.tsx:1352),hook 數量不可變,
195
+ // React #310 fix:useState 必在 view early-return 前無條件呼叫。同一 memo'd cell instance
196
+ // 在 view↔edit 切換時被重用(render site 無 key={mode},data-table.tsx:1352),hook 數量不可變,
198
197
  // 否則 Rules of Hooks violation → React #310 crash。對齊 combobox/select hoist pattern。
199
198
  const initial = typeof value === 'number' ? value : null
200
199
  const [localValue, setLocalValue] = React.useState<number | null>(initial)
201
- if (mode === 'display') {
200
+ if (mode === 'view') {
202
201
  return (
203
202
  <NumberInput
204
203
  variant="naked"
205
- mode={displayOrDisabled(isDisabled)}
204
+ mode="view"
205
+ aria-label={ariaLabel}
206
206
  value={value as number | null}
207
207
  // size 必傳(同 StringCell)— currency/number cell 字級隨 DataTable size 變,對齊 Field SSOT。
208
208
  size={size}
@@ -215,13 +215,14 @@ function NumberCell({ value, meta, mode, size, isDisabled, onCommit, onCancel, o
215
215
  }
216
216
  // Edit mode value pre-fill canonical(2026-05-05):NumberInput edit 強制 controlled
217
217
  // (`value={value ?? ''}`)— 若 NumberCell 以 `defaultValue` 傳入,NumberInput value=undefined → ''
218
- // empty。對齊 cell-as-input「edit mode 自動帶入 display 值」(對齊 Notion / Airtable 共識),
218
+ // empty。對齊 cell-as-input「edit mode 自動帶入 view 值」(對齊 Notion / Airtable 共識),
219
219
  // 改用 local state controlled。User typing → setLocalValue;blur/Enter → onCommit(localValue)。
220
- // (initial + useState 已 hoist 到 display-return 前 — 見上方 React #310 fix。)
220
+ // (initial + useState 已 hoist 到 view-return 前 — 見上方 React #310 fix。)
221
221
  return (
222
222
  <NumberInput
223
223
  autoFocus
224
224
  variant="naked"
225
+ aria-label={ariaLabel}
225
226
  size={sizeForInput(size)}
226
227
  value={localValue}
227
228
  onChange={(v) => { setLocalValue(v); onDraft?.(v) }}
@@ -244,25 +245,25 @@ function NumberCell({ value, meta, mode, size, isDisabled, onCommit, onCancel, o
244
245
  // (對齊 Airtable / Notion canonical:click 外即關)。
245
246
  const dismissOnClose = (onCancel?: () => void) => (open: boolean) => { if (!open) onCancel?.() }
246
247
 
247
- // Mode-keyed remount canonical(2026-05-05):display↔edit 切換時,因 React reconciliation 同 type 同
248
- // position 會重用 instance,導致 `useState(defaultOpen)` 只在首次 mount 跑(那時 mode='display'
248
+ // Mode-keyed remount canonical(2026-05-05):view↔edit 切換時,因 React reconciliation 同 type 同
249
+ // position 會重用 instance,導致 `useState(defaultOpen)` 只在首次 mount 跑(那時 mode='view'
249
250
  // defaultOpen 沒給→預設 false)。後續 mode='edit' 即使傳 defaultOpen=true 也無效。
250
251
  // Fix:`key={mode}` 強制 React unmount + remount,每次切 mode 都重跑 useState init。
251
- // 對齊 Notion / Airtable cell-as-input「display 跟 edit 是不同 mount cycle」語義。
252
+ // 對齊 Notion / Airtable cell-as-input「view 跟 edit 是不同 mount cycle」語義。
252
253
 
253
- function DateCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: CellComponentProps) {
254
- if (mode === 'display') {
254
+ function DateCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {
255
+ if (mode === 'view') {
255
256
  return (
256
257
  <DatePicker
257
- key="display"
258
+ key="view"
258
259
  variant="naked"
259
- mode={displayOrDisabled(isDisabled)}
260
+ mode="view"
260
261
  value={value as string | null}
261
262
  size={size}
262
263
  formatOptions={meta?.formatOptions}
263
264
  locale={meta?.locale}
264
265
  // 2026-07-08 user 拍板 A 案(推翻 2026-05-10/06-26 兩次拍板,per 6 家 benchmark 6/6 共識
265
- // Ant/MUI X/AG Grid/Atlaskit/Notion/Airtable:display 態零恆顯型別 icon;editable
266
+ // Ant/MUI X/AG Grid/Atlaskit/Notion/Airtable:view 態零恆顯型別 icon;editable
266
267
  // affordance 統一 = hover outline(field.spec.md L4)。showDisplayEndIcon 不再傳
267
268
  //(prop 保留為 spreadsheet-flavored 消費端 opt-in 逃生門,見 field.spec.md L6)。
268
269
  />
@@ -283,18 +284,18 @@ function DateCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: C
283
284
  )
284
285
  }
285
286
 
286
- function TimeCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: CellComponentProps) {
287
- if (mode === 'display') {
287
+ function TimeCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {
288
+ if (mode === 'view') {
288
289
  return (
289
290
  <TimePicker
290
- key="display"
291
+ key="view"
291
292
  variant="naked"
292
- mode={displayOrDisabled(isDisabled)}
293
+ mode="view"
293
294
  value={value as string | null}
294
295
  size={size}
295
296
  formatOptions={meta?.formatOptions}
296
297
  locale={meta?.locale}
297
- // showDisplayEndIcon 不傳 — 2026-07-08 A 案:display 態零恆顯 icon(同 DateCell 註)
298
+ // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
298
299
  />
299
300
  )
300
301
  }
@@ -314,22 +315,22 @@ function TimeCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: C
314
315
  )
315
316
  }
316
317
 
317
- function SelectCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }: CellComponentProps) {
318
- // Display canonical(2026-05-05):cell IS variant,default plain text(no Tag pill 疊在 cell border 內)。
318
+ function SelectCell({ value, meta, mode, size, onCommit, onCancel }: CellComponentProps) {
319
+ // View canonical(2026-05-05):cell IS variant,default plain text(no Tag pill 疊在 cell border 內)。
319
320
  // Consumer 可在 column meta.display='tag' opt-in 內容導向的 Tag 視覺(category 含色彩標籤等)。
320
321
  // 對齊 JTable / AG Grid「renderer/editor 視覺一致」canonical。
321
322
  const displayMode = (meta?.display as 'plain' | 'tag' | undefined) ?? 'plain'
322
- if (mode === 'display') {
323
+ if (mode === 'view') {
323
324
  return (
324
325
  <Select
325
- key="display"
326
+ key="view"
326
327
  variant="naked"
327
- mode={displayOrDisabled(isDisabled)}
328
+ mode="view"
328
329
  value={value as string | null}
329
330
  options={meta?.options ?? []}
330
331
  size={size}
331
332
  display={displayMode}
332
- // showDisplayEndIcon 不傳 — 2026-07-08 A 案:display 態零恆顯 icon(同 DateCell 註)
333
+ // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
333
334
  selectedItemRenderer={meta?.selectedItemRenderer} // 2026-07-08 WM 戰役:status 類彩色 cell 顯示通道
334
335
  />
335
336
  )
@@ -354,19 +355,19 @@ function SelectCell({ value, meta, mode, size, isDisabled, onCommit, onCancel }:
354
355
  )
355
356
  }
356
357
 
357
- function MultiSelectCell({ value, meta, mode, size, isDisabled, autoRowHeight, onCommitLive, onCancel }: CellComponentProps) {
358
+ function MultiSelectCell({ value, meta, mode, size, autoRowHeight, onCommitLive, onCancel }: CellComponentProps) {
358
359
  const wrap = autoRowHeight && meta?.wrap === true
359
- if (mode === 'display') {
360
+ if (mode === 'view') {
360
361
  return (
361
362
  <Combobox
362
- key="display"
363
+ key="view"
363
364
  variant="naked"
364
- mode={displayOrDisabled(isDisabled)}
365
+ mode="view"
365
366
  value={(value as string[] | null) ?? []}
366
367
  options={meta?.options ?? []}
367
368
  wrap={wrap}
368
369
  size={size}
369
- // showDisplayEndIcon 不傳 — 2026-07-08 A 案:display 態零恆顯 icon(同 DateCell 註)
370
+ // showDisplayEndIcon 不傳 — 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
370
371
  />
371
372
  )
372
373
  }
@@ -386,10 +387,10 @@ function MultiSelectCell({ value, meta, mode, size, isDisabled, autoRowHeight, o
386
387
  )
387
388
  }
388
389
 
389
- function PersonCell({ value, mode, size, isDisabled, onCommit, onCancel, meta }: CellComponentProps) {
390
- if (mode === 'display') {
391
- // 2026-07-08 A 案:display 態零恆顯 icon(同 DateCell 註)
392
- return <PeoplePicker key="display" variant="naked" mode={displayOrDisabled(isDisabled)} value={value as PersonValue | null} size={size} />
390
+ function PersonCell({ value, mode, size, onCommit, onCancel, meta }: CellComponentProps) {
391
+ if (mode === 'view') {
392
+ // 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
393
+ return <PeoplePicker key="view" variant="naked" mode="view" value={value as PersonValue | null} size={size} />
393
394
  }
394
395
  return (
395
396
  <PeoplePicker
@@ -406,10 +407,10 @@ function PersonCell({ value, mode, size, isDisabled, onCommit, onCancel, meta }:
406
407
  )
407
408
  }
408
409
 
409
- function MultiPersonCell({ value, mode, size, isDisabled, onCommitLive, onCancel, meta }: CellComponentProps) {
410
- if (mode === 'display') {
411
- // 2026-07-08 A 案:display 態零恆顯 icon(同 DateCell 註)
412
- return <PeoplePicker key="display" variant="naked" mode={displayOrDisabled(isDisabled)} value={(value as PersonValue[]) ?? []} size={size} />
410
+ function MultiPersonCell({ value, mode, size, onCommitLive, onCancel, meta }: CellComponentProps) {
411
+ if (mode === 'view') {
412
+ // 2026-07-08 A 案:view 態零恆顯 icon(同 DateCell 註)
413
+ return <PeoplePicker key="view" variant="naked" mode="view" value={(value as PersonValue[]) ?? []} size={size} />
413
414
  }
414
415
  // Multi 用 onCommitLive(commit 但不 exit edit)— 每勾一人即時生效,popover 持續開
415
416
  // 直到點外面;onOpenChange(false) → onCancel exit edit。對齊 multiSelect canonical。
@@ -427,14 +428,12 @@ function MultiPersonCell({ value, mode, size, isDisabled, onCommitLive, onCancel
427
428
  )
428
429
  }
429
430
 
430
- function BooleanCell({ value, mode, meta, size, isEditable, isDisabled, onCommit }: CellComponentProps) {
431
- // boolean 不分 read/edit mode — display 渲 mode='display' 純展示;editable 時直接 toggle Checkbox
432
- // 2026-05-13 codex V1 fix:editable=true + disabled=true 之前 fall through to live Checkbox,
433
- // onCheckedChange fire(violate disabled contract)。Fix:`!isEditable || isDisabled` →
434
- // 走 display branch,Checkbox 拿 disabled mode + 不接 onCheckedChange。
435
- if (mode === 'display' && (!isEditable || isDisabled)) {
431
+ function BooleanCell({ value, mode, meta, size, isEditable, onCommit }: CellComponentProps) {
432
+ // boolean 不分 read/edit mode — view 渲 mode='view' 純展示;editable 時直接 toggle Checkbox
433
+ // 不可編(!isEditable)→ view branch,Checkbox mode="view" 純展示不接 onCheckedChange。
434
+ if (mode === 'view' && !isEditable) {
436
435
  // size 傳入 → boolean 值 icon(Check/X)@lg 縮放對齊其他 cell(對齊 editable 分支同 size 邏輯)
437
- return <Checkbox variant="naked" size={size === 'lg' ? 'lg' : 'md'} mode={displayOrDisabled(isDisabled)} checked={value === true} />
436
+ return <Checkbox variant="naked" size={size === 'lg' ? 'lg' : 'md'} mode="view" checked={value === true} />
438
437
  }
439
438
  return (
440
439
  <Checkbox
@@ -448,21 +447,21 @@ function BooleanCell({ value, mode, meta, size, isEditable, isDisabled, onCommit
448
447
 
449
448
  /**
450
449
  * UrlCell(2026-07-14 docblock 對齊實作):
451
- * display branch = `<LinkInput mode={displayOrDisabled(isDisabled)}>`(URL parse / hostname
450
+ * view branch = `<LinkInput mode="view">`(URL parse / hostname
452
451
  * 顯示一致性 SSOT);editable 互動:hover 時右側出 Pencil 鈕 → 進 edit(保留 link click 語意)。
453
452
  * edit branch = plain `<Input variant="naked">`(LinkInput edit 的 controlled value 衝突
454
453
  * revert,詳下方 edit branch 註解);URL 驗證 deferred 到 onCommit(consumer 端 validate)。
455
454
  */
456
- function UrlCell({ value, meta, mode, size, isDisabled, isEditable, onRequestEdit, onCommit, onCancel }: CellComponentProps) {
457
- if (mode === 'display') {
455
+ function UrlCell({ value, meta, mode, size, isEditable, onRequestEdit, onCommit, onCancel }: CellComponentProps) {
456
+ if (mode === 'view') {
458
457
  // showDisplayEndIcon ← D path Phase 2(2026-05-08):Field naked wrapper 包 anchor,與 Input edit 同 chrome。
459
458
  // LinkInput 此 prop = wrapper-only(無 icon,field.spec.md L6 例外)→ A 案(2026-07-08)不撤;
460
459
  // 但修 I1:原無條件 true 違反「= isEditable」knob 等式(field-controls.spec.md cell 例外),改等式。
461
460
  const display = (
462
- <LinkInput variant="naked" mode={displayOrDisabled(isDisabled)} value={value as string | null} label={meta?.linkLabel} size={size} showDisplayEndIcon={isEditable === true} />
461
+ <LinkInput variant="naked" mode="view" value={value as string | null} label={meta?.linkLabel} size={size} showDisplayEndIcon={isEditable === true} />
463
462
  )
464
- // 2026-05-13 codex V1 fix:disabled URL 不顯 Pencil affordance(parent onRequestEdit 已被攔但 UI 仍誤導)
465
- if (!isEditable || isDisabled) return display
463
+ // 不可編 URL 不顯 Pencil affordance( view 顯示連結,無編輯入口)
464
+ if (!isEditable) return display
466
465
  // editable read mode:hover Pencil 鈕(對齊 spec 第十二段「url:read = 連結 + Pencil」)
467
466
  return (
468
467
  <span className="group/cell relative flex items-center w-full"> {/* @naked-row-mode-allow: URL hover-Pencil 是 inline action 不是 value content,items-center 鎖 Pencil 對齊行高第一行(autoRow 跟 fixed 皆同視覺正確) */}
@@ -540,7 +539,7 @@ function buildCellWithSurface(Inner: ComponentType<CellComponentProps>, key: str
540
539
  漏傳 size 的 cell 也自動繼承(根治「新 cell 漏傳 size」class);size primitive 不破壞 memo identity。*/}
541
540
  <FieldSurfaceSizeProvider size={props.size}>
542
541
  {/* 2026-07-08 user 拍板:cell 可編輯訊號經獨立 boolean context 注給 child Field controls,
543
- 讓 useFieldEmptyDisplay 分流「可編輯 cell 空 display → 空白」vs「不可編輯 cell → '-'」。
542
+ 讓 useFieldEmptyDisplay 分流「可編輯 cell 空 view → 空白」vs「不可編輯 cell → '-'」。
544
543
  boolean primitive 不破壞 memo identity(同 size context)。 */}
545
544
  <FieldSurfaceEditableProvider isEditable={props.isEditable ?? false}>
546
545
  <Inner {...props} />