@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,22 +1,24 @@
1
1
  // @internal — DS-internal 單元(Field 家族 chrome 基底,consumer 用 Field/Input 等 wrapper 不直用);不隨 index.ts re-export 進 npm public surface。
2
2
  // @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.
3
3
  import { cva } from 'class-variance-authority'
4
+ import { cn } from '@/lib/utils'
4
5
 
5
6
  // ── Field Wrapper Styles ────────────────────────────────────────────────────
6
7
  // 所有 Field 元件共用的 input wrapper 樣式。
7
8
  //
8
- // 4 種模式(2026-05-05 expand):
9
+ // 4 種模式(2026-05-05 expand;2026-07-16 round16 `display`→`view` 更名 + Model A):
9
10
  // edit — bg-surface, border, hover/focus 回饋(可編輯 input)
10
- // display 純展示( input chrome、無 affordance);語意「read-only 內容,展示給人看」。
11
- // 對齊 Carbon read-only / PatternFly inline-edit hidden-input
11
+ // view 純展示值(非表單);**Model A = edit 幾何減 chrome**(透明 bg/border,**保留 px 內距 + 高度**),
12
+ // read↔edit 零跳。對齊 Atlassian inline-edit(read=edit 幾何)+ Bootstrap plaintext(留 padding)
12
13
  // readonly — bg-readonly(neutral-2), 無邊框, 文字正常色(input chrome 但鎖定;token 獨立於 disabled)
13
14
  // disabled — bg-disabled(neutral-2), 無邊框, 文字灰化
14
15
  //
15
16
  // 2 種視覺外殼(variant;2026-07-09 `bare` 退役後):
16
- // default — 完整 chrome(form input 場景)
17
+ // default — 完整 chrome(form input 場景);view×default = edit 幾何減 chrome(留 px/py)
17
18
  // naked — cell-as-input substrate(DataTable);**edit×naked 自畫 border-based state machine**
18
19
  // (border-border → hover:border-border-hover → focus-within:border-primary → error 紅框);
19
- // display/readonly/disabled×naked transparent border,由 host cell 提供視覺邊框
20
+ // view×naked = bare(host TD padding)。**view×default ≠ view×naked**(不 collapse)。
21
+ // (2026-07-16 cell disabled 態廢除 → readonly×naked/disabled×naked 死格已移除)
20
22
  //
21
23
  // 高度:固定 h = field-height token(rem),與 Button 共用同一組 token。
22
24
 
@@ -45,7 +47,7 @@ export const fieldWrapperStyles = cva(
45
47
  variants: {
46
48
  mode: {
47
49
  edit: '',
48
- display: '',
50
+ view: '',
49
51
  readonly: '',
50
52
  disabled: '',
51
53
  },
@@ -54,7 +56,7 @@ export const fieldWrapperStyles = cva(
54
56
  default: '',
55
57
  // naked — cell-as-input(Notion / Airtable / Excel canonical)。**edit×naked 自畫** border +
56
58
  // hover:border-border-hover + focus-within:border-primary + error 紅框(v14 border-based state
57
- // machine,見下方 compoundVariants L182-196);display/readonly/disabled×naked 用 transparent
59
+ // machine,見下方 compoundVariants L182-196);view×naked 用 transparent
58
60
  // border 由 host cell 提供視覺邊框,內部 input 純文字承載。
59
61
  // 世界級對照:Airtable / Notion / Excel / Google Sheets cell editing。
60
62
  // (2026-07-09 `bare` variant 已退役 — 見 field-types.ts FieldVariant 註解;
@@ -126,13 +128,18 @@ export const fieldWrapperStyles = cva(
126
128
  },
127
129
  { mode: 'edit', variant: 'default', error: false, className: 'focus-within:!border-primary focus-within:hover:!border-primary' },
128
130
  {
129
- mode: 'display',
131
+ // 2026-07-16 round16 Model A(user GO,推翻 2026-05-13 Path Ⅰ 的 `!px-0 !py-0`):
132
+ // view×default = **edit 幾何減 chrome** — 保留 size 軸的 `px-[var(--field-px)]` + `h-field-*`,
133
+ // 只拔 border/bg(透明)。理由 = view 用在 cell/inline-edit/詳情,要對齊的是「edit 的值位置」
134
+ // (非 label 左緣),故水平垂直都留 → view 與 edit 同一顆控件、只差 chrome → read↔edit 零跳。
135
+ // 世界級對照:Atlassian inline-edit(read=edit 幾何,靠容器負邊距對齊)+ Bootstrap
136
+ // `.form-control-plaintext`(`padding: $input-padding-y 0` 留 padding);我們比 Bootstrap 更徹底
137
+ // (連水平 px 也留),因用例是 align-to-edit 非 align-to-label。詳 field-controls.spec.md「軸一 view mode」
138
+ // + planning/2026-07-15-inline-edit-field-mode-remediation.md round16。
139
+ // ⚠️ view×default ≠ view×naked:naked = bare(cell substrate,host TD 給 padding);default = 留幾何。
140
+ mode: 'view',
130
141
  variant: 'default',
131
- // 2026-05-13 Q3 Path Ⅰ(user 拍板 Path Ⅰ 全 zero chrome + codex V2 verdict + field-controls.spec.md (d)):
132
- // default display = zero chrome — !px-0 !py-0 override size token 的 px-[var(--field-px)],跟 Select / Combobox
133
- // / DatePicker / TimePicker / LinkInput non-D-path bare-span idiom 一致(Carbon read-only / Stripe
134
- // display / Notion property / Polaris readonly TextField 全 zero chrome)。
135
- className: 'bg-transparent border border-transparent !px-0 !py-0',
142
+ className: 'bg-transparent border border-transparent',
136
143
  },
137
144
  {
138
145
  mode: 'readonly',
@@ -203,7 +210,7 @@ export const fieldWrapperStyles = cva(
203
210
  { mode: 'edit', variant: 'naked', error: false, className: 'focus-within:!border-primary focus-within:hover:!border-primary' },
204
211
  {
205
212
  // 2026-05-12 fix v2(M32 root invariant audit):
206
- // Q1 root invariant?:cell-as-input display 視覺位置 = `cell.items-{X}` × `Field.height`
213
+ // Q1 root invariant?:cell-as-input view 視覺位置 = `cell.items-{X}` × `Field.height`
207
214
  // 兩變數函數;canonical = autoRow → Field intrinsic + cell.items-start
208
215
  // (text 在 cell top + cellPadding-y),fixed → Field h-field-md +
209
216
  // cell.items-center(text 在 cell vertical center)。
@@ -217,33 +224,18 @@ export const fieldWrapperStyles = cva(
217
224
  // override h-field-md → Field intrinsic line-height → cell items-start
218
225
  // 真實 anchor text at cell.top + padding。
219
226
  // Edit mode 不動(`!h-full` 保留 — border 必滿格對齊 cell border)。
220
- mode: 'display',
227
+ // 2026-07-16 round16:view×naked 保持 bare(cell substrate,host TD 給 padding)— 與 view×default
228
+ // (edit 幾何減 chrome、留 px/py)本質不同用途,**不 collapse**(round14 合併是錯的)。
229
+ mode: 'view',
221
230
  variant: 'naked',
222
231
  className: [
223
232
  'bg-transparent !rounded-none !px-0 !py-0 !h-auto',
224
233
  'border border-transparent',
225
234
  ],
226
235
  },
227
- {
228
- mode: 'readonly',
229
- variant: 'naked',
230
- className: [
231
- 'bg-transparent !rounded-none !px-0 !py-0 !h-auto',
232
- 'border border-transparent',
233
- ],
234
- },
235
- {
236
- // 2026-05-13 Q3 fix(per codex Q3 verdict + color.spec.md:729 逃生艙 rule):
237
- // 移除 `opacity-disabled` blanket — naked wrapper 只負責 substrate(透明 border + 抑制 cursor),
238
- // 內部 content(text / icon / avatar)各自 disabled context 處理(text-fg-disabled / Avatar opacity 等具體 token)。
239
- // 對齊 DataTable cell-disabled TD 加 `bg-disabled` 表達 cell-level disabled state 的 SSOT 分權。
240
- mode: 'disabled',
241
- variant: 'naked',
242
- className: [
243
- 'bg-transparent !rounded-none cursor-not-allowed !px-0 !py-0 !h-auto',
244
- 'border border-transparent',
245
- ],
246
- },
236
+ // 2026-07-16 round16:`readonly×naked` / `disabled×naked` 死格移除 —— DataTable cell 廢除
237
+ // disabled 態(view 一律 mode="view";displayOrDisabled helper 已刪)+ readonly 從不入 naked
238
+ // 路徑(全庫 0 消費)。軸對稱靠 cva 省略即天然覆蓋(base+size+透明),不需 dead compound 佔位。
247
239
  ],
248
240
  defaultVariants: {
249
241
  mode: 'edit',
@@ -264,7 +256,7 @@ export const bareInputStyles = [
264
256
  // bareInputStyles 套上,placeholder 無 ellipsis → narrow cell(<160px)硬裁無 `...`(user round 3
265
257
  // 圖一證據)。加 truncate 後 `<input>` `text-overflow: ellipsis` 啟動,符合 user 「placeholder 直接被截掉沒有變...」
266
258
  // 該顯 ellipsis 的 SSOT。對齊 data-table.spec.md:233「禁硬裁無 ellipsis」+ field-controls.spec.md:286
267
- // 共享 contract(a)「display/readonly/disabled/edit 4 mode 共享同一 renderer」semantic 對齊。
259
+ // 共享 contract(a)「view/readonly/disabled/edit 4 mode 共享同一 renderer」semantic 對齊。
268
260
  'flex-1 min-w-0 truncate bg-transparent',
269
261
  'outline-none border-none p-0',
270
262
  'text-[inherit] font-[inherit] leading-[inherit]',
@@ -300,13 +292,13 @@ export const bareInputStyles = [
300
292
  // Audit:design-system-audit Group N(periodic batch verify)
301
293
  export const nakedCellRowModeAlign = 'group-data-[row-mode=auto]/cell:items-start'
302
294
 
303
- // ── Cell-as-input Display Hover Ring(2026-05-05 v9 — sole remaining ring const)─
304
- // editable cell **display mode hover 提示**(「這 cell 可編,點 → 進 edit」affordance 信號)。
295
+ // ── Cell-as-input View Hover Ring(2026-05-05 v9 — sole remaining ring const)─
296
+ // editable cell **view mode hover 提示**(「這 cell 可編,點 → 進 edit」affordance 信號)。
305
297
  // 對齊 Notion / Airtable hover-cell-shows-border canonical。
306
298
  //
307
299
  // **為何只剩這一個**:Field naked **edit/focus/open state ring 已下沉到 Field default state
308
300
  // machine**(border-based,2026-05-05 v9 architectural rewrite),不需 outline 平行系統;
309
- // 但 display mode 沒 Field state(display = 純展示無互動),hover 提示需 cell wrapper 自加。
301
+ // 但 view mode 沒 Field state(view = 純展示無互動),hover 提示需 cell wrapper 自加。
310
302
  //
311
303
  // **2026-05-09 v15.17 revert v15.16(user 未同意 ship)— 維持 v15.13 outline+offset:-1**
312
304
  //
@@ -359,7 +351,7 @@ export const nakedCellEditableDisplayHover = 'hover:outline hover:outline-1 hove
359
351
  // ── Empty Value Display ─────────────────────────────────────────────────────
360
352
 
361
353
  // 2026-07-08 user 拍板(verbatim「我從頭到尾哪裡有說要用全形的」):空值符號 = **半形 hyphen
362
- // `-`(U+002D)**,非全形 em dash `—`(U+2014)。不可編輯(readonly / standalone display /
354
+ // `-`(U+002D)**,非全形 em dash `—`(U+2014)。不可編輯(readonly / standalone view /
363
355
  // table 不可編輯 cell)空值一律此符號 + `text-fg-muted`。分流邏輯 SSOT = field-context.ts
364
356
  // `useFieldEmptyDisplay()`(table-cell 可編輯 → 空白;其餘 → 本常數)。
365
357
  // 世界級對照:Ant ProTable `columnEmptyText` 預設 `'-'`(U+002D 半形)
@@ -367,10 +359,34 @@ export const nakedCellEditableDisplayHover = 'hover:outline hover:outline-1 hove
367
359
  export const EMPTY_DISPLAY = '-'
368
360
 
369
361
  /**
370
- * 2026-05-14 I2 fix(per field-controls.spec.md contract (e) display typography canonical):
371
- * Field family display path bare-span helper — `sm/md → text-body` / `lg → text-body-lg`,
372
- * 跨 9 元件 display 視覺尺寸統一(user 抓 LinkInput 字體跟其他 Field 不一致 = SSOT 違反)。
362
+ * 2026-05-14 I2 fix(per field-controls.spec.md contract (e) view typography canonical):
363
+ * Field family view path bare-span helper — `sm/md → text-body` / `lg → text-body-lg`,
364
+ * 跨 9 元件 view 視覺尺寸統一(user 抓 LinkInput 字體跟其他 Field 不一致 = SSOT 違反)。
373
365
  * Consumer:LinkInput / Select / Combobox / DatePicker / TimePicker non-D-path bare-span 套此 class。
374
366
  */
375
367
  export const fieldDisplayTextClass = (size: 'sm' | 'md' | 'lg'): string =>
376
368
  size === 'lg' ? 'text-body-lg' : 'text-body'
369
+
370
+ /**
371
+ * 2026-07-16 round16 Model A(user GO):Field view mode 幾何 SSOT(= view×default compound 的
372
+ * 幾何部分,抽成 class helper 供 **InlineEdit 純值/標題路徑** 消費,避免 InlineEdit 自帶重複的
373
+ * geometry cva〔M17 消重〕)。
374
+ *
375
+ * 回傳「edit 幾何減 chrome」的排版盒:
376
+ * - 水平:`px-[var(--field-px)]`(= edit 內距,靠 InlineEdit `-mx` 拉回欄左緣後,值落 edit 值位置)
377
+ * - 單行:`min-h-[var(--field-height-N)]` N∈{sm,md,lg} + `items-center`(垂直置中於 field 高度,= edit 單行)
378
+ * - 多行:`items-start` + `py-2`(頂對齊 + 上下內距,**= Textarea edit `py-2`**,textarea.tsx base;
379
+ * read↔edit 零跳)。⚠️ py-2 與 Textarea 同值 = SSOT 契約,`scripts/inline-edit-view-geometry-invariant.mjs`
380
+ * 機械鎖(Textarea py 一改即紅)。
381
+ *
382
+ * 值-格式化路徑(Select→Tag / Date / avatar)**不用**此 helper —— 直接委派 `<Control mode="view">`,
383
+ * 幾何 + 內部間距皆由控件 view×default 提供(read=edit 同一顆 → 天生一致)。
384
+ */
385
+ export const fieldViewGeometry = (size: 'sm' | 'md' | 'lg', multiline?: boolean): string =>
386
+ cn(
387
+ 'flex w-full min-w-0 px-[var(--field-px)]',
388
+ size === 'sm' && 'min-h-[var(--field-height-sm)]',
389
+ size === 'md' && 'min-h-[var(--field-height-md)]',
390
+ size === 'lg' && 'min-h-[var(--field-height-lg)]',
391
+ multiline ? 'items-start py-2' : 'items-center',
392
+ )
@@ -53,7 +53,7 @@ export const Overview: Story = {
53
53
  <tr><Td>資料格式化(千分位/貨幣/locale)</Td><Td>—</Td><Td>✓ 管</Td></tr>
54
54
  <tr><Td>驗證邏輯</Td><Td>—</Td><Td>✓ 管(+ zod schema 於 form 層)</Td></tr>
55
55
  <tr><Td>readonly 呈現</Td><Td>—</Td><Td>✓ 管</Td></tr>
56
- <tr><Td>DataTable cell 顯示</Td><Td>—</Td><Td>✓ 管(mode="display" 渲染分支)</Td></tr>
56
+ <tr><Td>DataTable cell 顯示</Td><Td>—</Td><Td>✓ 管(mode="view" 渲染分支)</Td></tr>
57
57
  </tbody>
58
58
  </table>
59
59
  </div>
@@ -72,8 +72,8 @@ export const Overview: Story = {
72
72
  ['invalid', 'boolean', 'false', 'error 狀態 + context.invalid(觸發 aria-invalid)'],
73
73
  ['disabled', 'boolean', 'false', 'context.disabled 傳給 control'],
74
74
  ['size', "'sm' | 'md' | 'lg'", "'md'", 'context.size 傳給 input-class control(Input / NumberInput / Select);primitive 不讀'],
75
- ['mode', "'edit' | 'display' | 'readonly' | 'disabled'", "'edit'", 'context.mode 傳給 Field Controls'],
76
- ['variant', "'default'", "'default'", "視覺外殼(公開型別僅 'default',2026-07-14 收窄;naked = @internal FieldVariantInternal):default 含 border+bg / naked = DataTable cell substrate:edit×naked 自畫 border-based state machine(rest/hover/focus/error),display/readonly/disabled×naked 用 transparent border;2026-07-09 `bare` 退役"],
75
+ ['mode', "'edit' | 'view' | 'readonly' | 'disabled'", "'edit'", 'context.mode 傳給 Field Controls'],
76
+ ['variant', "'default'", "'default'", "視覺外殼(公開型別僅 'default',2026-07-14 收窄;naked = @internal FieldVariantInternal):default 含 border+bg / naked = DataTable cell substrate:edit×naked 自畫 border-based state machine(rest/hover/focus/error),view×naked 用 transparent border;2026-07-09 `bare` 退役"],
77
77
  ['controlLayout', "'inline' | 'block'", '(自動偵測)', '逃生艙:覆寫 control area 佈局(consumer 手寫 JSX 當 control 無法偵測時用)'],
78
78
  ].map(([p, t, d, desc]) => (
79
79
  <tr key={p}><Td mono>{p}</Td><Td mono>{t}</Td><Td mono>{d}</Td><Td>{desc}</Td></tr>
@@ -109,7 +109,7 @@ export const Overview: Story = {
109
109
  interface InspectorArgs {
110
110
  orientation: 'vertical' | 'horizontal'
111
111
  size: 'sm' | 'md' | 'lg'
112
- mode: 'edit' | 'display' | 'readonly' | 'disabled'
112
+ mode: 'edit' | 'view' | 'readonly' | 'disabled'
113
113
  required: boolean
114
114
  invalid: boolean
115
115
  disabled: boolean
@@ -148,8 +148,8 @@ export const Inspector: Story = {
148
148
  },
149
149
  mode: {
150
150
  control: 'radio',
151
- options: ['edit', 'display', 'readonly', 'disabled'],
152
- description: 'Context 傳給控制元件:edit 可編輯 / display 純展示 / readonly 鎖定但保留輸入外觀 / disabled 停用',
151
+ options: ['edit', 'view', 'readonly', 'disabled'],
152
+ description: 'Context 傳給控制元件:edit 可編輯 / view 純展示 / readonly 鎖定但保留輸入外觀 / disabled 停用',
153
153
  },
154
154
  required: { control: 'boolean', description: 'label 文字前加 * + aria-required' },
155
155
  invalid: { control: 'boolean', description: '觸發 error border + aria-invalid;本例以 FieldError 條件替換 FieldDescription(consumer 慣例,非元件行為)' },
@@ -4,7 +4,7 @@ import React from 'react'
4
4
  import LinkTo from '@storybook/addon-links/react'
5
5
  import type { Meta, StoryObj } from '@storybook/react'
6
6
  import { Upload } from 'lucide-react'
7
- import { Field, FieldLabel, FieldDescription, FieldError, FieldGroup } from './field'
7
+ import { Field, FieldLabel, FieldDescription, FieldGroup } from './field'
8
8
  import { Input } from '@/design-system/components/Input/input'
9
9
  import { Select } from '@/design-system/components/Select/select'
10
10
  import { Button } from '@/design-system/components/Button/button'
@@ -141,33 +141,10 @@ export const UsageGuidance: Story = {
141
141
  ),
142
142
  }
143
143
 
144
- export const ResponsibilityRule: Story = {
145
- name: 'Field 只負責佈局,不管資料',
146
- render: () => (
147
- <div>
148
- <Rule
149
- title="Field 的職責 — Layout + Context,不擁有資料邏輯"
150
- note="Field 只負責:label / control / description / error 的空間關係 + 把 mode / disabled / required / invalid / id 透過 context 傳給子元件。與資料相關的一切(格式化、驗證、readonly 呈現、DataTable cell 顯示)住在 Field Control 元件本身"
151
- >
152
- <div className="max-w-sm">
153
- <FieldGroup>
154
- <Field required>
155
- <FieldLabel>電子郵件</FieldLabel>
156
- <Input type="email" placeholder="name@example.com" />
157
- <FieldDescription>我們不會公開您的電子郵件</FieldDescription>
158
- </Field>
159
- <Field invalid>
160
- <FieldLabel>密碼</FieldLabel>
161
- <Input type="password" />
162
- <FieldError>密碼必須至少 8 個字元</FieldError>
163
- </Field>
164
- </FieldGroup>
165
- </div>
166
- <Label>↑ Field 管 layout + required 星號 + error 顯示,Input 管 type=email / 驗證邏輯</Label>
167
- </Rule>
168
- </div>
169
- ),
170
- }
144
+ // ResponsibilityRule retired 2026-07-17 per audit Dim 24 —— 與 anatomy Overview「子元件責任邊界」
145
+ // 責任表 + 逐字相同的 電子郵件/密碼 範例重複;職責原則亦已由上方 UsageGuidance「❌ Field 試圖承載
146
+ // 資料型別邏輯」涵蓋(earn-existence 2-test 皆 NO)。UsageGuidance 使 principles universal-core 仍 ≥ 2,
147
+ // 無 LinkTo 引用此 story,退役零斷鏈。
171
148
 
172
149
  export const OrientationRule: Story = {
173
150
  name: '方向 選擇',
@@ -32,7 +32,7 @@ Field 是**表單欄位的佈局容器**。只負責排版(label / control / d
32
32
  Field 和 Field Controls(Input / NumberInput / DatePicker / Select / Combobox / LinkInput / PeoplePicker / Textarea)是兩件事:
33
33
 
34
34
  - **Field**(本元件):只管佈局 + 狀態 context
35
- - **Field Controls / Checkbox / Switch / RadioGroup**:管自己的資料型別 + edit/readonly/disabled 三態 + 格式化(`mode="display"` 渲染供 DataTable cell 共用)
35
+ - **Field Controls / Checkbox / Switch / RadioGroup**:管自己的資料型別 + edit/readonly/disabled 三態 + 格式化(`mode="view"` 渲染供 DataTable cell 共用)
36
36
 
37
37
  這麼拆的理由:**Checkbox 在 table cell、form field、settings row 應該是同一個 primitive**,不該為了進到 form 就被包一層 CheckboxField;form 的高度對齊由 Field 的 control area 負責,不由 primitive 本身負責。Field Controls 的詳細共用規則見 `Field/field-controls.spec.md`。
38
38
 
@@ -206,7 +206,7 @@ Field 透過 Context 暴露以下狀態給子元件(Primitive 可以透過 `us
206
206
  | `id` | FieldLabel 自動 `htmlFor`、Input 自動 `id` |
207
207
  | `descriptionId` | FieldDescription 的 id,Input 自動 `aria-describedby` |
208
208
  | `errorId` | FieldError 的 id,Input 自動 `aria-errormessage` |
209
- | `mode` | `edit` / `display` / `readonly` / `disabled`,Control 決定自己的視覺形態 |
209
+ | `mode` | `edit` / `view` / `readonly` / `disabled`,Control 決定自己的視覺形態 |
210
210
  | `disabled` | Control 顯示 disabled 樣式 |
211
211
  | `required` | FieldLabel 自動渲染 `*`;Input 自動 `aria-required` |
212
212
  | `invalid` | Control 顯示 error 邊框;Input 自動 `aria-invalid` |
@@ -416,9 +416,9 @@ Field 內的資料輸入控件(Input / NumberInput / DatePicker / Select / Com
416
416
  | **L1 Slot** | `patterns/element-anatomy/item-anatomy.tsx` | `<ItemPrefix>` / `<ItemSuffix>`(永遠 `h-[1lh]` 對齊第 1 行) |
417
417
  | **L2 Align** | `field-wrapper.tsx` `nakedCellRowModeAlign` | host cell `data-row-mode` propagate(autoRow→items-start / fixed→items-center)|
418
418
  | **L3 State machine** | **繼承 Field default v13.3**(↑ 上方 SSOT)| 不重定義 |
419
- | **L4 Display hover** | `field-wrapper.tsx` `nakedCellEditableDisplayHover` | editable cell display mode `outline-1 outline-offset:-1 outline-[var(--cell-hover-outline-color,var(--border-hover))]`(cell wrapper outline;2026-05-10 Slice D:spreadsheet overlay 啟用時 DataTable cell host 可 set `--cell-hover-outline-color: transparent` 抑制 outline、讓 overlay layer 接管 hover ring paint,fallback 即 `--border-hover` 既有行為不變)。**v15.13 design intent(user-accepted 2026-05-07)**:hover ring 蓋 cell.borderRight。**known asymmetry**(2026-05-09 user 重抓):只 **right** 邊 outline 跟 cell own border-r 同位置覆蓋成 1 條;top/left/bottom 邊 outline 在 cell.outer 內 1px,grid lines(前 row border-b / 前 cell border-r / row 自己 border-b 在 cell.outer 外 1px)露出 → 視覺 4 邊不對稱。**Pending design decision**(等 user 拍板才 ship):4 邊都蓋(spec 1 selection-style)vs 4 邊都不蓋(spec 2 inset 1px)vs 維持現狀。三層 SSOT:state source = cell wrapper / paint owner = 混合(hover=cell / edit=Field)/ grid divider = DataTable own |
419
+ | **L4 Display hover** | `field-wrapper.tsx` `nakedCellEditableDisplayHover` | editable cell view mode `outline-1 outline-offset:-1 outline-[var(--cell-hover-outline-color,var(--border-hover))]`(cell wrapper outline;2026-05-10 Slice D:spreadsheet overlay 啟用時 DataTable cell host 可 set `--cell-hover-outline-color: transparent` 抑制 outline、讓 overlay layer 接管 hover ring paint,fallback 即 `--border-hover` 既有行為不變)。**v15.13 design intent(user-accepted 2026-05-07)**:hover ring 蓋 cell.borderRight。**known asymmetry**(2026-05-09 user 重抓):只 **right** 邊 outline 跟 cell own border-r 同位置覆蓋成 1 條;top/left/bottom 邊 outline 在 cell.outer 內 1px,grid lines(前 row border-b / 前 cell border-r / row 自己 border-b 在 cell.outer 外 1px)露出 → 視覺 4 邊不對稱。**Pending design decision**(等 user 拍板才 ship):4 邊都蓋(spec 1 selection-style)vs 4 邊都不蓋(spec 2 inset 1px)vs 維持現狀。三層 SSOT:state source = cell wrapper / paint owner = 混合(hover=cell / edit=Field)/ grid divider = DataTable own |
420
420
  | **L5 Position(v14,2026-05-06 revert v12)** | naked compoundVariant flow | Field 留 layout flow,**不**用 `!absolute`(v12 absolute 跟 autoRowHeight 不相容)。視覺接受 cell `border-r grid` + Field border 2px 雙線;cell border-r divider 永遠保留(對齊 L4 Invariant divider-owner / editor-owner 分離)|
421
- | **L6 Cell trigger indicator(v16,2026-07-08 user 拍板 A 案)** | naked-display branch + `showDisplayEndIcon?: boolean` opt-in(**default off,production 不再傳**)| **display 態零恆顯型別 icon** — editable affordance 統一 = L4 hover outline。Benchmark 6/6(Ant editable-cells 純文字+hover border / MUI X singleSelect display 純文字 / AG Grid 無內建 indicator / Atlaskit v2.0.0 移除 hover-pencil 後 9 版未回歸 / Notion / Airtable click-to-edit)display 態皆無恆顯 icon;唯一反例 Google Sheets Chip/Arrow 為 spreadsheet 域可選檔位。prop 保留為 spreadsheet-flavored 消費端 opt-in 逃生門:傳 true → `<ItemSuffix>` 渲型別 icon(Select/Combobox/PeoplePicker → ChevronDown / DatePicker → Calendar / TimePicker → Clock / **LinkInput 例外 = wrapper-only 無 icon**)。cell-registry 現況:6 picker 站不傳;url 站傳 `isEditable === true`(取 wrapper chrome 對齊 edit Input,非 icon)。edit 態 chevron 照舊(edit-trigger 通道,不受此 prop 管)。**值內容 vs affordance 分層(2026-07-08 user Q2 拍板)**:值內容(`selectedItemRenderer` 輸出 / avatar / type icon 等語意呈現)歸 value renderer,display 態照常渲染,恆顯**不**違反本條;本條管的是 affordance(chevron / pencil / outline)。前身 v15 恆顯制(2026-05-10/06-26 拍板)由本輪 benchmark 重判推翻。詳 `.claude/planning/cell-indicator-ssot-rfc.md`。|
421
+ | **L6 Cell trigger indicator(v16,2026-07-08 user 拍板 A 案)** | naked-view branch + `showDisplayEndIcon?: boolean` opt-in(**default off,production 不再傳**)| **view 態零恆顯型別 icon** — editable affordance 統一 = L4 hover outline。Benchmark 6/6(Ant editable-cells 純文字+hover border / MUI X singleSelect view 純文字 https://mui.com/x/react-data-grid/editing/ / AG Grid 無內建 indicator https://www.ag-grid.com/react-data-grid/cell-editing/ / Atlaskit v2.0.0 移除 hover-pencil 後 9 版未回歸 https://github.com/pioug/atlassian-frontend-mirror/tree/main/design-system/inline-edit / Notion / Airtable click-to-edit)view 態皆無恆顯 icon;唯一反例 Google Sheets Chip/Arrow 為 spreadsheet 域可選檔位。prop 保留為 spreadsheet-flavored 消費端 opt-in 逃生門:傳 true → `<ItemSuffix>` 渲型別 icon(Select/Combobox/PeoplePicker → ChevronDown / DatePicker → Calendar / TimePicker → Clock / **LinkInput 例外 = wrapper-only 無 icon**)。cell-registry 現況:6 picker 站不傳;url 站傳 `isEditable === true`(取 wrapper chrome 對齊 edit Input,非 icon)。edit 態 chevron 照舊(edit-trigger 通道,不受此 prop 管)。**值內容 vs affordance 分層(2026-07-08 user Q2 拍板)**:值內容(`selectedItemRenderer` 輸出 / avatar / type icon 等語意呈現)歸 value renderer,view 態照常渲染,恆顯**不**違反本條;本條管的是 affordance(chevron / pencil / outline)。前身 v15 恆顯制(2026-05-10/06-26 拍板)由本輪 benchmark 重判推翻。詳 `.claude/planning/cell-indicator-ssot-rfc.md`(六家實查 SSOT)。|
422
422
 
423
423
  **前身 retire**:v4-v8 `outline-2` 平行 state(已下沉 L3)/ v9 border-only(focus 跟 open specificity tie)/ per-control `open && 'border-primary'`(v13.3 retire)/ `nakedCell{Hover,Focus,Open}Ring` 三 const / `nakedCell{Prefix,Suffix}Slot`(下沉 L1)/ **v12 `!absolute -inset-px` seamless grid**(2026-05-06 revert — autoRowHeight 不相容)/ **DataTable parallel `getEditIndicator`**(2026-05-09 D-path retire — 由 Field naked-display 透過 `showDisplayEndIcon` opt-in 自渲 ItemSuffix,跨元件 SSOT 統一)。
424
424
 
@@ -452,6 +452,7 @@ Field 內的資料輸入控件(Input / NumberInput / DatePicker / Select / Com
452
452
 
453
453
  > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
454
454
 
455
+ - `data-table.spec.md`
455
456
  - `description-list.spec.md`
456
457
  - `element-anatomy.spec.md`
457
458
  - `field-control-group.spec.md`
@@ -91,21 +91,21 @@ export const StateCascade: Story = {
91
91
  <Field mode="readonly" className="w-44"><FieldLabel>負責人</FieldLabel><Input value="王小明" onChange={() => {}} /></Field>
92
92
  <Field mode="readonly" className="w-44"><FieldLabel>同意條款</FieldLabel><Checkbox checked /></Field>
93
93
  <Field mode="readonly" className="w-44"><FieldLabel>已啟用</FieldLabel><Switch checked /></Field>
94
- <Field mode="readonly" className="w-44"><FieldLabel>未勾選範例</FieldLabel><Checkbox /></Field>
94
+ <Field mode="readonly" className="w-44"><FieldLabel>行銷電子報</FieldLabel><Checkbox /></Field>
95
95
  <Field mode="readonly" className="w-44"><FieldLabel>付款方式</FieldLabel><RadioGroup value="card"><RadioGroupItem value="card" label="信用卡" /><RadioGroupItem value="cash" label="貨到付款" /></RadioGroup></Field>
96
96
  <Field mode="readonly" className="w-44"><FieldLabel>滿意度</FieldLabel><Rating value={4} aria-label="滿意度" /></Field>
97
97
  <Field mode="readonly" className="w-44"><FieldLabel>完成度</FieldLabel><Slider defaultValue={[40]} aria-label="完成度" /></Field>
98
98
  </div>
99
99
  </div>
100
100
  <div>
101
- <p className="text-body-sm font-medium text-fg-secondary mb-3">{'<Field mode="display"> — 有展示態的控件自動切純展示(Select / DatePicker / Checkbox / Switch 修復後生效)'}</p>
101
+ <p className="text-body-sm font-medium text-fg-secondary mb-3">{'<Field mode="view"> — 有展示態的控件自動切純展示(Select / DatePicker / Checkbox / Switch 修復後生效)'}</p>
102
102
  <div className="flex flex-wrap gap-x-8 gap-y-4 max-w-3xl">
103
- <Field mode="display" className="w-44"><FieldLabel>負責人</FieldLabel><Input value="王小明" onChange={() => {}} /></Field>
104
- <Field mode="display" className="w-44"><FieldLabel>優先級</FieldLabel><Select options={CASCADE_PRIORITY} value="high" aria-label="優先級" /></Field>
105
- <Field mode="display" className="w-44"><FieldLabel>截止日</FieldLabel><DatePicker value="2026-06-20" onChange={() => {}} /></Field>
106
- <Field mode="display" className="w-44"><FieldLabel>數量</FieldLabel><NumberInput value={42} onChange={() => {}} /></Field>
107
- <Field mode="display" className="w-44"><FieldLabel>已啟用</FieldLabel><Switch checked /></Field>
108
- <Field mode="display" className="w-44"><FieldLabel>同意條款</FieldLabel><Checkbox checked /></Field>
103
+ <Field mode="view" className="w-44"><FieldLabel>負責人</FieldLabel><Input value="王小明" onChange={() => {}} /></Field>
104
+ <Field mode="view" className="w-44"><FieldLabel>優先級</FieldLabel><Select options={CASCADE_PRIORITY} value="high" aria-label="優先級" /></Field>
105
+ <Field mode="view" className="w-44"><FieldLabel>截止日</FieldLabel><DatePicker value="2026-06-20" onChange={() => {}} /></Field>
106
+ <Field mode="view" className="w-44"><FieldLabel>數量</FieldLabel><NumberInput value={42} onChange={() => {}} /></Field>
107
+ <Field mode="view" className="w-44"><FieldLabel>已啟用</FieldLabel><Switch checked /></Field>
108
+ <Field mode="view" className="w-44"><FieldLabel>同意條款</FieldLabel><Checkbox checked /></Field>
109
109
  </div>
110
110
  </div>
111
111
  </div>
@@ -143,7 +143,7 @@ export const Horizontal: Story = {
143
143
  // ── Horizontal 垂直對齊公式驗證 ─────────────────────────────────────────
144
144
 
145
145
  export const HorizontalLabelAlignment: Story = {
146
- name: '水平:標籤垂直對齊公式驗證',
146
+ name: '水平:標籤與控件垂直對齊',
147
147
  render: () => (
148
148
  <div className="max-w-3xl flex flex-col gap-8">
149
149
  <div>
@@ -153,8 +153,8 @@ export const HorizontalLabelAlignment: Story = {
153
153
  這是 padding-top: calc((field-height - 1lh) / 2) 的基本情境。
154
154
  </p>
155
155
  <Field orientation="horizontal" labelWidth="160px">
156
- <FieldLabel>短 label</FieldLabel>
157
- <Input placeholder="input 中線應與 label 對齊" />
156
+ <FieldLabel>職稱</FieldLabel>
157
+ <Input placeholder="如:資深產品設計師" />
158
158
  </Field>
159
159
  </div>
160
160
 
@@ -165,8 +165,8 @@ export const HorizontalLabelAlignment: Story = {
165
165
  視覺上 label 從 input 中線往下延伸,而不是從 input 頂部開始。
166
166
  </p>
167
167
  <Field orientation="horizontal" labelWidth="160px">
168
- <FieldLabel>這是一個會換行的很長的 label 用來驗證多行情境</FieldLabel>
169
- <Input placeholder="input 中線應與 label 第一行對齊" />
168
+ <FieldLabel>緊急聯絡人手機(發生狀況時優先撥打)</FieldLabel>
169
+ <Input placeholder="如:0912-345-678" />
170
170
  </Field>
171
171
  </div>
172
172
 
@@ -177,18 +177,27 @@ export const HorizontalLabelAlignment: Story = {
177
177
  無需 JS 測量。
178
178
  </p>
179
179
  <div className="flex flex-col gap-3">
180
- <Field orientation="horizontal" labelWidth="100px" size="sm">
181
- <FieldLabel>sm size</FieldLabel>
182
- <Input size="sm" placeholder="28px high" />
183
- </Field>
184
- <Field orientation="horizontal" labelWidth="100px" size="md">
185
- <FieldLabel>md size</FieldLabel>
186
- <Input size="md" placeholder="32px high" />
187
- </Field>
188
- <Field orientation="horizontal" labelWidth="100px" size="lg">
189
- <FieldLabel>lg size</FieldLabel>
190
- <Input size="lg" placeholder="36px high" />
191
- </Field>
180
+ <div>
181
+ <div className="text-caption text-fg-muted mb-1">小尺寸 sm — 控件高 28px</div>
182
+ <Field orientation="horizontal" labelWidth="100px" size="sm">
183
+ <FieldLabel>電子郵件</FieldLabel>
184
+ <Input size="sm" placeholder="name@example.com" />
185
+ </Field>
186
+ </div>
187
+ <div>
188
+ <div className="text-caption text-fg-muted mb-1">中尺寸 md — 控件高 32px</div>
189
+ <Field orientation="horizontal" labelWidth="100px" size="md">
190
+ <FieldLabel>電子郵件</FieldLabel>
191
+ <Input size="md" placeholder="name@example.com" />
192
+ </Field>
193
+ </div>
194
+ <div>
195
+ <div className="text-caption text-fg-muted mb-1">大尺寸 lg — 控件高 36px</div>
196
+ <Field orientation="horizontal" labelWidth="100px" size="lg">
197
+ <FieldLabel>電子郵件</FieldLabel>
198
+ <Input size="lg" placeholder="name@example.com" />
199
+ </Field>
200
+ </div>
192
201
  </div>
193
202
  </div>
194
203
  </div>
@@ -279,31 +288,40 @@ export const SegmentedControlInField: Story = {
279
288
  整個欄位改尺寸時,分段控制器也會跟著一起縮放。
280
289
  </p>
281
290
  <FieldGroup>
282
- <Field size="sm">
283
- <FieldLabel>檢視模式(sm)</FieldLabel>
284
- <SegmentedControl defaultValue="list">
285
- <SegmentedControlItem value="list">清單</SegmentedControlItem>
286
- <SegmentedControlItem value="board">看板</SegmentedControlItem>
287
- <SegmentedControlItem value="calendar">行事曆</SegmentedControlItem>
288
- </SegmentedControl>
289
- <FieldDescription>切換內容呈現方式</FieldDescription>
290
- </Field>
291
- <Field size="md">
292
- <FieldLabel>檢視模式(md)</FieldLabel>
293
- <SegmentedControl defaultValue="list">
294
- <SegmentedControlItem value="list">清單</SegmentedControlItem>
295
- <SegmentedControlItem value="board">看板</SegmentedControlItem>
296
- <SegmentedControlItem value="calendar">行事曆</SegmentedControlItem>
297
- </SegmentedControl>
298
- </Field>
299
- <Field size="lg">
300
- <FieldLabel>檢視模式(lg)</FieldLabel>
301
- <SegmentedControl defaultValue="list">
302
- <SegmentedControlItem value="list">清單</SegmentedControlItem>
303
- <SegmentedControlItem value="board">看板</SegmentedControlItem>
304
- <SegmentedControlItem value="calendar">行事曆</SegmentedControlItem>
305
- </SegmentedControl>
306
- </Field>
291
+ <div>
292
+ <div className="text-caption text-fg-muted mb-1">小尺寸 sm</div>
293
+ <Field size="sm">
294
+ <FieldLabel>檢視模式</FieldLabel>
295
+ <SegmentedControl defaultValue="list">
296
+ <SegmentedControlItem value="list">清單</SegmentedControlItem>
297
+ <SegmentedControlItem value="board">看板</SegmentedControlItem>
298
+ <SegmentedControlItem value="calendar">行事曆</SegmentedControlItem>
299
+ </SegmentedControl>
300
+ <FieldDescription>切換內容呈現方式</FieldDescription>
301
+ </Field>
302
+ </div>
303
+ <div>
304
+ <div className="text-caption text-fg-muted mb-1">中尺寸 md</div>
305
+ <Field size="md">
306
+ <FieldLabel>檢視模式</FieldLabel>
307
+ <SegmentedControl defaultValue="list">
308
+ <SegmentedControlItem value="list">清單</SegmentedControlItem>
309
+ <SegmentedControlItem value="board">看板</SegmentedControlItem>
310
+ <SegmentedControlItem value="calendar">行事曆</SegmentedControlItem>
311
+ </SegmentedControl>
312
+ </Field>
313
+ </div>
314
+ <div>
315
+ <div className="text-caption text-fg-muted mb-1">大尺寸 lg</div>
316
+ <Field size="lg">
317
+ <FieldLabel>檢視模式</FieldLabel>
318
+ <SegmentedControl defaultValue="list">
319
+ <SegmentedControlItem value="list">清單</SegmentedControlItem>
320
+ <SegmentedControlItem value="board">看板</SegmentedControlItem>
321
+ <SegmentedControlItem value="calendar">行事曆</SegmentedControlItem>
322
+ </SegmentedControl>
323
+ </Field>
324
+ </div>
307
325
  </FieldGroup>
308
326
  </div>
309
327
 
@@ -478,23 +496,35 @@ export const LabelWidth: Story = {
478
496
  name: '標籤寬度',
479
497
  render: () => (
480
498
  <div className="max-w-2xl flex flex-col gap-4">
481
- <p className="text-caption text-fg-muted">labelWidth 支援任何 CSS length 值</p>
482
- <Field orientation="horizontal" labelWidth="80px">
483
- <FieldLabel>80px</FieldLabel>
484
- <Input placeholder="short label column" />
485
- </Field>
486
- <Field orientation="horizontal" labelWidth="160px">
487
- <FieldLabel>160px(預設常用)</FieldLabel>
488
- <Input placeholder="typical settings form" />
489
- </Field>
490
- <Field orientation="horizontal" labelWidth="240px">
491
- <FieldLabel>240px(寬 label 欄)</FieldLabel>
492
- <Input placeholder="wide label column" />
493
- </Field>
494
- <Field orientation="horizontal" labelWidth="30%">
495
- <FieldLabel>30%(比例)</FieldLabel>
496
- <Input placeholder="percentage" />
497
- </Field>
499
+ <p className="text-caption text-fg-muted">labelWidth 支援任何 CSS length 值(80px / 160px / 240px / 30% 等);同一表單依最長的 label 挑一個固定寬,讓控件起點對齊。</p>
500
+ <div>
501
+ <div className="text-caption text-fg-muted mb-1">labelWidth = 80px</div>
502
+ <Field orientation="horizontal" labelWidth="80px">
503
+ <FieldLabel>城市</FieldLabel>
504
+ <Input placeholder="如:台北市" />
505
+ </Field>
506
+ </div>
507
+ <div>
508
+ <div className="text-caption text-fg-muted mb-1">labelWidth = 160px(預設常用)</div>
509
+ <Field orientation="horizontal" labelWidth="160px">
510
+ <FieldLabel>公司統一編號</FieldLabel>
511
+ <Input placeholder="8 碼數字" />
512
+ </Field>
513
+ </div>
514
+ <div>
515
+ <div className="text-caption text-fg-muted mb-1">labelWidth = 240px(寬 label 欄)</div>
516
+ <Field orientation="horizontal" labelWidth="240px">
517
+ <FieldLabel>發票寄送電子郵件地址</FieldLabel>
518
+ <Input placeholder="billing@company.com" />
519
+ </Field>
520
+ </div>
521
+ <div>
522
+ <div className="text-caption text-fg-muted mb-1">labelWidth = 30%(比例)</div>
523
+ <Field orientation="horizontal" labelWidth="30%">
524
+ <FieldLabel>備註</FieldLabel>
525
+ <Input placeholder="選填" />
526
+ </Field>
527
+ </div>
498
528
  </div>
499
529
  ),
500
530
  }
@@ -531,9 +561,9 @@ export const WithSlider: Story = {
531
561
  </Field>
532
562
 
533
563
  <Field>
534
- <FieldLabel>已鎖定</FieldLabel>
564
+ <FieldLabel>儲存空間配額</FieldLabel>
535
565
  <Slider defaultValue={[40]} disabled />
536
- <FieldDescription>不可調整的範例</FieldDescription>
566
+ <FieldDescription>由系統管理員設定,無法自行調整</FieldDescription>
537
567
  </Field>
538
568
  </FieldGroup>
539
569
  </div>
@@ -602,9 +632,9 @@ export const SliderWithLiveNumberInput: Story = {
602
632
  max={200}
603
633
  />
604
634
  </div>
635
+ {/* Slider 與 NumberInput 透過 `h-field-md` 對齊高度——實作細節,不進使用者可見文案 */}
605
636
  <FieldDescription>
606
- Slider 跟 NumberInput 同步——拖曳 slider 即時更新數字,改數字即時更新
607
- slider。兩個元件高度透過 `h-field-md` 對齊。
637
+ 拖曳滑桿或直接輸入數字都能即時調整縮放比例,範圍 0–200%。
608
638
  </FieldDescription>
609
639
  </Field>
610
640
  </div>
@@ -640,7 +670,7 @@ function UpdateProjectSettingsForm() {
640
670
  <Field required invalid={!!form.errors.name}>
641
671
  <FieldLabel>專案名稱</FieldLabel>
642
672
  <Input {...form.getInputProps('name')} />
643
- <FieldDescription>改成「產品路線圖 Q3」可觸發 submit 業務驗證(名稱重複)</FieldDescription>
673
+ <FieldDescription>專案名稱不得與其他專案重複</FieldDescription>
644
674
  <FieldError>{form.errors.name}</FieldError>
645
675
  </Field>
646
676
  <Field required invalid={!!form.errors.ownerEmail}>
@@ -700,6 +730,7 @@ export const FormValidation: Story = {
700
730
  <p className="text-caption text-fg-muted max-w-80">
701
731
  按鈕沒改不亮;打字中不報錯(blur 才驗);已出錯欄位一編輯立即清 error;
702
732
  Escape 回復原值;空 submit / 格式錯 → anchor 到第一個錯誤欄位。
733
+ 試著把名稱改成「產品路線圖 Q3」再儲存,會觸發「名稱重複」業務驗證。
703
734
  </p>
704
735
  <UpdateProjectSettingsForm />
705
736
  </div>