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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  50. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  51. package/dist/components/DataTable/data-table-filter-panel.js +3 -4
  52. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  53. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  54. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  55. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  56. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  57. package/dist/components/DataTable/data-table.d.ts +1 -1
  58. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  59. package/dist/components/DataTable/data-table.js +44 -32
  60. package/dist/components/DataTable/data-table.js.map +1 -1
  61. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  62. package/dist/components/DatePicker/date-picker.js +4 -4
  63. package/dist/components/DatePicker/date-picker.js.map +1 -1
  64. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  65. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  66. package/dist/components/DescriptionList/description-list.js +6 -6
  67. package/dist/components/DescriptionList/description-list.js.map +1 -1
  68. package/dist/components/Dialog/dialog.d.ts +2 -2
  69. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  70. package/dist/components/Dialog/dialog.js.map +1 -1
  71. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  72. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  73. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  74. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  75. package/dist/components/Field/field-context.d.ts +16 -10
  76. package/dist/components/Field/field-context.d.ts.map +1 -1
  77. package/dist/components/Field/field-context.js.map +1 -1
  78. package/dist/components/Field/field-types.d.ts +2 -2
  79. package/dist/components/Field/field-types.d.ts.map +1 -1
  80. package/dist/components/Field/field-types.js.map +1 -1
  81. package/dist/components/Field/field-wrapper.d.ts +20 -4
  82. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  83. package/dist/components/Field/field-wrapper.js +30 -31
  84. package/dist/components/Field/field-wrapper.js.map +1 -1
  85. package/dist/components/Field/field.d.ts +1 -1
  86. package/dist/components/Field/field.d.ts.map +1 -1
  87. package/dist/components/Field/field.js +25 -3
  88. package/dist/components/Field/field.js.map +1 -1
  89. package/dist/components/Field/use-form-validation.d.ts +1 -1
  90. package/dist/components/Field/use-form-validation.js.map +1 -1
  91. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  92. package/dist/components/FileItem/file-item.js +2 -5
  93. package/dist/components/FileItem/file-item.js.map +1 -1
  94. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  95. package/dist/components/FileUpload/file-upload.js +5 -1
  96. package/dist/components/FileUpload/file-upload.js.map +1 -1
  97. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  98. package/dist/components/FileViewer/file-viewer.js +2 -1
  99. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  100. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  101. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  102. package/dist/components/HoverCard/hover-card.js +4 -2
  103. package/dist/components/HoverCard/hover-card.js.map +1 -1
  104. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  105. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  106. package/dist/components/InlineEdit/inline-edit.js +104 -62
  107. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  108. package/dist/components/Input/input.d.ts +1 -1
  109. package/dist/components/Input/input.d.ts.map +1 -1
  110. package/dist/components/Input/input.js +6 -6
  111. package/dist/components/Input/input.js.map +1 -1
  112. package/dist/components/LinkInput/link-input.d.ts +5 -5
  113. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  114. package/dist/components/LinkInput/link-input.js +3 -3
  115. package/dist/components/LinkInput/link-input.js.map +1 -1
  116. package/dist/components/Notice/notice.d.ts +17 -1
  117. package/dist/components/Notice/notice.d.ts.map +1 -1
  118. package/dist/components/Notice/notice.js +7 -1
  119. package/dist/components/Notice/notice.js.map +1 -1
  120. package/dist/components/NumberInput/number-input.d.ts +1 -1
  121. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  122. package/dist/components/NumberInput/number-input.js +12 -1
  123. package/dist/components/NumberInput/number-input.js.map +1 -1
  124. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  125. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  126. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  127. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  128. package/dist/components/PeoplePicker/people-picker.js +7 -5
  129. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  130. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  131. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  132. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  133. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  134. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  135. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  136. package/dist/components/RadioGroup/radio-group.js +1 -1
  137. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  138. package/dist/components/Rating/rating.d.ts.map +1 -1
  139. package/dist/components/Rating/rating.js +4 -0
  140. package/dist/components/Rating/rating.js.map +1 -1
  141. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  142. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  143. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  144. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  145. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  146. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  147. package/dist/components/Select/select.d.ts +16 -6
  148. package/dist/components/Select/select.d.ts.map +1 -1
  149. package/dist/components/Select/select.js +17 -5
  150. package/dist/components/Select/select.js.map +1 -1
  151. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  152. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  153. package/dist/components/SelectMenu/select-menu.js +17 -3
  154. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  155. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  156. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  157. package/dist/components/Sheet/sheet.d.ts +2 -2
  158. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  159. package/dist/components/Sheet/sheet.js.map +1 -1
  160. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  161. package/dist/components/Sidebar/sidebar.js +2 -2
  162. package/dist/components/Sidebar/sidebar.js.map +1 -1
  163. package/dist/components/Slider/slider.d.ts.map +1 -1
  164. package/dist/components/Slider/slider.js +6 -3
  165. package/dist/components/Slider/slider.js.map +1 -1
  166. package/dist/components/Steps/steps.d.ts +6 -4
  167. package/dist/components/Steps/steps.d.ts.map +1 -1
  168. package/dist/components/Steps/steps.js +19 -5
  169. package/dist/components/Steps/steps.js.map +1 -1
  170. package/dist/components/Switch/switch.d.ts +4 -4
  171. package/dist/components/Switch/switch.d.ts.map +1 -1
  172. package/dist/components/Switch/switch.js +3 -1
  173. package/dist/components/Switch/switch.js.map +1 -1
  174. package/dist/components/Tabs/tabs.d.ts +1 -1
  175. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  176. package/dist/components/Tabs/tabs.js +73 -23
  177. package/dist/components/Tabs/tabs.js.map +1 -1
  178. package/dist/components/Tag/tag.d.ts +3 -1
  179. package/dist/components/Tag/tag.d.ts.map +1 -1
  180. package/dist/components/Tag/tag.js +2 -2
  181. package/dist/components/Tag/tag.js.map +1 -1
  182. package/dist/components/Textarea/textarea.d.ts +4 -4
  183. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  184. package/dist/components/Textarea/textarea.js +15 -15
  185. package/dist/components/Textarea/textarea.js.map +1 -1
  186. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  187. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  188. package/dist/components/TimePicker/time-picker.js +8 -5
  189. package/dist/components/TimePicker/time-picker.js.map +1 -1
  190. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  191. package/dist/components/Tooltip/tooltip.js +27 -23
  192. package/dist/components/Tooltip/tooltip.js.map +1 -1
  193. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  194. package/dist/components/TreeView/tree-view.js +16 -0
  195. package/dist/components/TreeView/tree-view.js.map +1 -1
  196. package/dist/index.d.ts +7 -7
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +6 -13
  199. package/dist/index.js.map +1 -1
  200. package/dist/lib/drag-visual.d.ts +2 -2
  201. package/dist/lib/drag-visual.js.map +1 -1
  202. package/dist/lib/utils.d.ts +1 -0
  203. package/dist/lib/utils.d.ts.map +1 -1
  204. package/dist/lib/utils.js +21 -1
  205. package/dist/lib/utils.js.map +1 -1
  206. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  207. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  208. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  209. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  210. package/dist/tokens/categorical-color.d.ts +3 -3
  211. package/dist/tokens/categorical-color.d.ts.map +1 -1
  212. package/dist/tokens/categorical-color.js +2 -2
  213. package/dist/tokens/categorical-color.js.map +1 -1
  214. package/ds-canonical/fork/AGENTS.md +213 -0
  215. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  216. package/ds-canonical/fork/codex/hooks.json +16 -0
  217. package/ds-canonical/fork/governance.lock +22 -7
  218. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  219. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  220. package/ds-canonical/fork/manifest.json +10 -1
  221. package/ds-canonical/fork/preamble.md +3 -2
  222. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  223. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  224. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  225. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  226. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  227. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
  228. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  229. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  230. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  232. package/ds-canonical/references/certified-surfaces.md +20 -0
  233. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  234. package/ds-canonical/references/principle-dim-map.json +20 -2
  235. package/ds-canonical/references/props-naming.md +2 -1
  236. package/ds-canonical/references/ssot-index.md +2 -2
  237. package/ds-canonical/references/story-baseline-registry.json +2 -2
  238. package/ds-canonical/rules/story-rules.md +1 -1
  239. package/ds-canonical/rules/ui-development.md +2 -1
  240. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  241. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  242. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  243. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  244. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  245. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  246. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  247. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  248. package/ds-story-manifest.json +21 -21
  249. package/llms-full.txt +3 -3
  250. package/llms.txt +1 -1
  251. package/package.json +2 -1
  252. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  253. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  254. package/src/components/Accordion/accordion.spec.md +10 -1
  255. package/src/components/Accordion/accordion.stories.tsx +10 -5
  256. package/src/components/Accordion/accordion.tsx +7 -2
  257. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  258. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  259. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  260. package/src/components/AppShell/app-shell.spec.md +4 -0
  261. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  262. package/src/components/Avatar/avatar.tsx +1 -1
  263. package/src/components/Badge/badge.spec.md +2 -2
  264. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  265. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  266. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  267. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  268. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  269. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  270. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  271. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  272. package/src/components/Button/button-group.tsx +4 -4
  273. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  274. package/src/components/Button/button.principles.stories.tsx +1 -1
  275. package/src/components/Button/button.spec.md +2 -2
  276. package/src/components/Button/button.stories.tsx +22 -28
  277. package/src/components/Button/button.tsx +2 -1
  278. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  279. package/src/components/Calendar/calendar.spec.md +1 -1
  280. package/src/components/Carousel/carousel.spec.md +17 -1
  281. package/src/components/Carousel/carousel.tsx +93 -42
  282. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  283. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  284. package/src/components/Checkbox/checkbox.spec.md +12 -3
  285. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  286. package/src/components/Checkbox/checkbox.tsx +79 -19
  287. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  288. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  289. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  290. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  291. package/src/components/Combobox/combobox.spec.md +6 -2
  292. package/src/components/Combobox/combobox.stories.tsx +9 -36
  293. package/src/components/Combobox/combobox.tsx +42 -27
  294. package/src/components/Command/command.spec.md +3 -3
  295. package/src/components/Command/command.tsx +9 -2
  296. package/src/components/DataTable/cell-registry.tsx +75 -76
  297. package/src/components/DataTable/column-types.ts +4 -17
  298. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  299. package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
  300. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  301. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  302. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  303. package/src/components/DataTable/data-table.css +2 -3
  304. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  305. package/src/components/DataTable/data-table.spec.md +7 -7
  306. package/src/components/DataTable/data-table.stories.tsx +39 -29
  307. package/src/components/DataTable/data-table.tsx +90 -67
  308. package/src/components/DataTable/filter-operators.spec.md +2 -0
  309. package/src/components/DateGrid/date-grid.spec.md +1 -1
  310. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  311. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  312. package/src/components/DatePicker/date-picker.spec.md +9 -9
  313. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  314. package/src/components/DatePicker/date-picker.tsx +13 -13
  315. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  316. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  317. package/src/components/DescriptionList/description-list.spec.md +12 -12
  318. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  319. package/src/components/DescriptionList/description-list.tsx +10 -10
  320. package/src/components/Dialog/dialog.tsx +4 -1
  321. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  322. package/src/components/Field/field-context.ts +17 -11
  323. package/src/components/Field/field-controls.spec.md +44 -37
  324. package/src/components/Field/field-types.ts +14 -12
  325. package/src/components/Field/field-wrapper.tsx +59 -43
  326. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  327. package/src/components/Field/field.principles.stories.tsx +5 -28
  328. package/src/components/Field/field.spec.md +4 -4
  329. package/src/components/Field/field.stories.tsx +103 -72
  330. package/src/components/Field/field.tsx +36 -4
  331. package/src/components/Field/form-validation.spec.md +2 -0
  332. package/src/components/Field/use-form-validation.ts +1 -1
  333. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  334. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  335. package/src/components/FileItem/file-item.tsx +10 -8
  336. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  337. package/src/components/FileUpload/file-upload.spec.md +3 -2
  338. package/src/components/FileUpload/file-upload.tsx +5 -1
  339. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  340. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  342. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  343. package/src/components/FileViewer/file-viewer.tsx +3 -2
  344. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  345. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  346. package/src/components/HoverCard/hover-card.spec.md +2 -2
  347. package/src/components/HoverCard/hover-card.tsx +4 -2
  348. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  349. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  350. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  351. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  352. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  353. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  354. package/src/components/Input/input.principles.stories.tsx +3 -3
  355. package/src/components/Input/input.spec.md +4 -4
  356. package/src/components/Input/input.stories.tsx +3 -3
  357. package/src/components/Input/input.tsx +13 -13
  358. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  359. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  360. package/src/components/LinkInput/link-input.spec.md +6 -2
  361. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  362. package/src/components/LinkInput/link-input.tsx +21 -19
  363. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  364. package/src/components/Notice/notice.tsx +8 -2
  365. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  366. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  367. package/src/components/NumberInput/number-input.spec.md +6 -6
  368. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  369. package/src/components/NumberInput/number-input.tsx +17 -5
  370. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  371. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  372. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  373. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  374. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  375. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  376. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  377. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  378. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  379. package/src/components/PeoplePicker/person-display.tsx +3 -3
  380. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  381. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  382. package/src/components/Popover/popover.spec.md +4 -2
  383. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  384. package/src/components/ProfileCard/profile-card.tsx +1 -1
  385. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  386. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  387. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  388. package/src/components/README.md +1 -0
  389. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  390. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  391. package/src/components/RadioGroup/radio-group.tsx +19 -14
  392. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  393. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  394. package/src/components/Rating/rating.spec.md +2 -2
  395. package/src/components/Rating/rating.stories.tsx +4 -18
  396. package/src/components/Rating/rating.tsx +5 -1
  397. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  398. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  399. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  400. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  401. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  402. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  403. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  404. package/src/components/Select/select.principles.stories.tsx +3 -3
  405. package/src/components/Select/select.spec.md +9 -1
  406. package/src/components/Select/select.stories.tsx +41 -27
  407. package/src/components/Select/select.tsx +44 -26
  408. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  410. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  411. package/src/components/SelectMenu/select-menu.tsx +38 -5
  412. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  413. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  414. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  415. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  416. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  417. package/src/components/Sheet/sheet.tsx +4 -1
  418. package/src/components/Sidebar/sidebar.tsx +1 -1
  419. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  420. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  421. package/src/components/Slider/slider.spec.md +13 -1
  422. package/src/components/Slider/slider.stories.tsx +44 -32
  423. package/src/components/Slider/slider.tsx +13 -4
  424. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  425. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  426. package/src/components/Steps/steps.spec.md +4 -2
  427. package/src/components/Steps/steps.stories.tsx +4 -56
  428. package/src/components/Steps/steps.tsx +31 -7
  429. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  430. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  431. package/src/components/Switch/switch.spec.md +4 -4
  432. package/src/components/Switch/switch.stories.tsx +3 -3
  433. package/src/components/Switch/switch.tsx +16 -10
  434. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  435. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  436. package/src/components/Tabs/tabs.spec.md +5 -2
  437. package/src/components/Tabs/tabs.stories.tsx +36 -44
  438. package/src/components/Tabs/tabs.tsx +101 -36
  439. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  440. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  441. package/src/components/Tag/tag.spec.md +3 -1
  442. package/src/components/Tag/tag.tsx +5 -3
  443. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  444. package/src/components/Textarea/textarea.spec.md +5 -5
  445. package/src/components/Textarea/textarea.tsx +24 -24
  446. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  447. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  448. package/src/components/TimePicker/time-picker.spec.md +6 -5
  449. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  450. package/src/components/TimePicker/time-picker.tsx +24 -14
  451. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  452. package/src/components/Toast/toast.stories.tsx +1 -1
  453. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  454. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  455. package/src/components/Tooltip/tooltip.spec.md +9 -3
  456. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  457. package/src/components/Tooltip/tooltip.tsx +12 -2
  458. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  459. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  460. package/src/components/TreeView/tree-view.spec.md +8 -6
  461. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  462. package/src/components/TreeView/tree-view.tsx +36 -0
  463. package/src/index.ts +13 -10
  464. package/src/lib/drag-visual.ts +2 -2
  465. package/src/lib/utils.ts +19 -0
  466. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  467. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  468. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  469. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  470. package/src/tokens/categorical-color.ts +5 -5
  471. package/src/tokens/color/color.spec.md +4 -4
  472. package/src/tokens/color/primitives.css +9 -2
  473. package/src/tokens/opacity/opacity.spec.md +1 -1
  474. package/src/tokens/orphan-tokens.spec.md +1 -1
  475. package/src/tokens/typography/typography.spec.md +2 -0
  476. package/src/tokens/uiSize/uiSize.css +5 -0
  477. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -51,7 +51,7 @@ export const UsageGuidance: Story = {
51
51
  <p>適合 Input 的真實業務場景(點擊跳轉「展示」頁範例):</p>
52
52
  <ul className="space-y-1">
53
53
  <li><LinkTo kind="Design System/Components/Input/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">商品名稱欄位的編輯 / 純展示 / 唯讀 / 停用四模式</span></LinkTo></li>
54
- <li><LinkTo kind="Design System/Components/Input/展示" name="尺寸與 Button 對齊"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">搜尋列 — 輸入框與按鈕並排等高</span></LinkTo></li>
54
+ <li><LinkTo kind="Design System/Components/Input/展示" name="三種尺寸"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">搜尋列 — 輸入框與按鈕並排等高</span></LinkTo></li>
55
55
  <li><LinkTo kind="Design System/Components/Input/展示" name="尾端操作"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">密碼顯示切換 / 搜尋清除等尾端操作</span></LinkTo></li>
56
56
  <li><LinkTo kind="Design System/Components/Input/展示" name="錯誤狀態"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Email 格式錯誤的驗證回饋</span></LinkTo></li>
57
57
  </ul>
@@ -128,10 +128,10 @@ export const ModeRule: Story = {
128
128
 
129
129
  <Rule
130
130
  title="❌ 不用 readonly 作為 DataTable cell"
131
- note="readonly 仍然有 padding + 視覺 chrome,密集列表會顯得鬆散。Table cell 用 `<Input mode='display'>`(零視覺 chrome、無左右 padding;wrapper 高度同 readonly)"
131
+ note="readonly 有底色 chrome(bg-readonly),密集列表會顯得鬆散。Table cell 用 `<Input mode='view'>`(Model A:edit 幾何減 chrome —— 保留 px 與高度,只拔 border/bg;cell 內經 naked variant 由 host cell 供 padding)"
132
132
  >
133
133
  <Input mode="readonly" value="alice@example.com" />
134
- <Label warn>↑ 在 table cell 中會過高且有多餘 padding → 用 &lt;Input mode=&quot;display&quot; /&gt;</Label>
134
+ <Label warn>↑ 在 table cell 中有多餘底色 chrome → 用 &lt;Input mode=&quot;view&quot; /&gt;</Label>
135
135
  </Rule>
136
136
  </div>
137
137
  ),
@@ -92,17 +92,17 @@ endAction(host 內嵌 inline action)vs 獨立 `<Button iconOnly>` 的分界詳 `
92
92
 
93
93
  ---
94
94
 
95
- ## Display
95
+ ## View
96
96
 
97
- `<Input mode="display">` 是 identity 顯示:
97
+ `<Input mode="view">` 是 identity 顯示:
98
98
  - 有值:原樣輸出
99
- - null / undefined / 空字串:半形 `-`(hyphen),`text-foreground`(display/readonly 供檢視值同色;disabled → fg-disabled)
99
+ - null / undefined / 空字串:半形 `-`(hyphen),`text-foreground`(view/readonly 供檢視值同色;disabled → fg-disabled)
100
100
 
101
101
  ---
102
102
 
103
103
  ## Loading
104
104
 
105
- `loading?: boolean`(Field SSOT,詳 `Field/field-controls.spec.md` L70-115):右側 endAction 自動顯 `<CircularProgress/>` + `aria-busy="true"`;input 維持可編輯(Ant Input.Search editable 派,反 Material readonly 派,適合 search debounce)。
105
+ `loading?: boolean`(Field SSOT,詳 `Field/field-controls.spec.md`「Loading state」段 ~L93-138):右側 endAction 自動顯 `<CircularProgress/>` + `aria-busy="true"`;input 維持可編輯(Ant Input.Search editable 派,反 Material readonly 派,適合 search debounce)。
106
106
 
107
107
  ## 禁止事項
108
108
 
@@ -26,9 +26,9 @@ export const Modes: Story = {
26
26
  <Input defaultValue="Wireless Bluetooth Headphones" placeholder="輸入商品名稱" aria-label="商品名稱(edit mode demo)" />
27
27
  </div>
28
28
  <div>
29
- <h3 className="text-body font-bold text-foreground mb-2">display</h3>
29
+ <h3 className="text-body font-bold text-foreground mb-2">view</h3>
30
30
  <p className="text-caption text-fg-muted mb-3">純展示(read-only 內容)— 無 input chrome / 無互動 affordance</p>
31
- <Input mode="display" value="Wireless Bluetooth Headphones" aria-label="商品名稱(display mode demo)" />
31
+ <Input mode="view" value="Wireless Bluetooth Headphones" aria-label="商品名稱(view 模式示範)" />
32
32
  </div>
33
33
  <div>
34
34
  <h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
@@ -53,7 +53,7 @@ export const Modes: Story = {
53
53
 
54
54
  /* ── 尺寸與 Button 對齊 ── */
55
55
  export const SizeAlignment: Story = {
56
- name: '尺寸與 Button 對齊',
56
+ name: '三種尺寸',
57
57
  render: () => (
58
58
  <div className="flex flex-col gap-4">
59
59
  {(['sm', 'md', 'lg'] as const).map(size => (
@@ -16,7 +16,7 @@ import { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'
16
16
  export interface InputProps
17
17
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>,
18
18
  Omit<VariantProps<typeof fieldWrapperStyles>, 'mode' | 'variant' | 'width'> {
19
- /** Field display mode */
19
+ /** Field mode */
20
20
  mode?: FieldMode
21
21
  /**
22
22
  * Visual variant(正交於 mode),對齊 FieldContext.variant 透傳。
@@ -108,24 +108,24 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
108
108
  const resolvedMode: FieldMode = useResolvedFieldMode({ mode: modeProp, disabled, readOnly })
109
109
  const emptyDisplay = useFieldEmptyDisplay()
110
110
  const isEditable = resolvedMode === 'edit'
111
- const isDisplay = resolvedMode === 'display'
111
+ const isView = resolvedMode === 'view'
112
112
  // error 合併:自身 error prop OR Field context invalid
113
113
  const resolvedError = useResolvedFieldInvalid(error)
114
114
  // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)
115
115
  const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']
116
116
  const iconColor = resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted'
117
117
 
118
- // ── display mode(+ readonly 空值)純展示,渲染 <span> 取代 <input> ──
118
+ // ── view mode(+ readonly 空值)純展示,渲染 <span> 取代 <input> ──
119
119
  // 對齊 Carbon read-only / PatternFly inline-edit hidden-input / Cloudscape display-mode
120
- // 2026-07-08 user 拍板:readonly 空值也走 display-span 顯 '-'(readonly **有值** 仍走下方
120
+ // 2026-07-08 user 拍板:readonly 空值也走 view-span 顯 '-'(readonly **有值** 仍走下方
121
121
  // native <input readOnly> 保留選取/複製語意 — field-controls.spec.md「null / undefined 值」)。
122
122
  // 2026-07-14 audit Dim 26(dual-mode coherence):uncontrolled `defaultValue` 也要被
123
- // display / readonly-空值判定認得 — 原本只讀 `value`,uncontrolled Input 切 display 會誤顯 '-'。
123
+ // view / readonly-空值判定認得 — 原本只讀 `value`,uncontrolled Input 切 view 會誤顯 '-'。
124
124
  // 2026-07-14 R2(dual-model consensus,取代同日稍早 onChange-mirror 版):resolved value 改走
125
125
  // useControllable 內部 SSOT(Radix idiom,同 Select / Pagination 既有消費)。uncontrolled 時
126
126
  // native input 由 value={resolved} 內部驅動(defaultValue 只作初始值,不落 DOM attribute),
127
127
  // 修 mirror 版兩個真缺陷:
128
- // (1) remount-stale — 切 display / readonly(native input unmount)再回 edit,native input 從
128
+ // (1) remount-stale — 切 view / readonly(native input unmount)再回 edit,native input 從
129
129
  // defaultValue attribute 重掛 → 顯示 stale 初始值,與 mirror 判定分歧;
130
130
  // (2) form.reset() stale — HTML 標準 reset 不發 input event,onChange mirror 停在 reset 前的值
131
131
  // (下方 reset bridge 修)。
@@ -137,10 +137,10 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
137
137
  defaultValue: defaultValue ?? '',
138
138
  })
139
139
  const displayValue = resolved != null && resolved !== '' ? String(resolved) : null
140
- const showDisplaySpan = isDisplay || (resolvedMode === 'readonly' && displayValue == null)
140
+ const showDisplaySpan = isView || (resolvedMode === 'readonly' && displayValue == null)
141
141
 
142
142
  // form.reset() bridge(uncontrolled only):reset 恢復 defaultValue 但不發 input event →
143
- // 手動把 resolved 歸位 defaultValue。keyed on showDisplaySpan:display 分支不掛 native input,
143
+ // 手動把 resolved 歸位 defaultValue。keyed on showDisplaySpan:view 分支不掛 native input,
144
144
  // 回 edit 重掛時 effect 重跑補掛 listener。
145
145
  const innerRef = React.useRef<HTMLInputElement | null>(null)
146
146
  React.useEffect(() => {
@@ -159,7 +159,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
159
159
  }, [ref])
160
160
 
161
161
  if (showDisplaySpan) {
162
- const spanMode = isDisplay ? 'display' : 'readonly'
162
+ const spanMode = isView ? 'view' : 'readonly'
163
163
  return (
164
164
  <div
165
165
  className={cn(
@@ -181,9 +181,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
181
181
  <span
182
182
  className={cn(
183
183
  bareInputStyles,
184
- // B1 fix(2026-05-05):display mode 單行 ellipsis 截斷(對齊 Notion / Airtable / Linear
185
- // cell display canonical:single-line value 過長 → ellipsis。Textarea display 走 wrap path,
186
- // 不在此處;Input display 永遠 single-line。)
184
+ // B1 fix(2026-05-05):view mode 單行 ellipsis 截斷(對齊 Notion / Airtable / Linear
185
+ // cell display canonical:single-line value 過長 → ellipsis。Textarea view 走 wrap path,
186
+ // 不在此處;Input view 永遠 single-line。)
187
187
  'truncate',
188
188
  displayValue == null && fieldEmptyColorClass(resolvedMode),
189
189
  )}
@@ -254,7 +254,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
254
254
  )
255
255
  Input.displayName = 'Input'
256
256
 
257
- // Phase B1(2026-05-05):InputDisplay 退場。改用 `<Input mode="display" value={...} />`
257
+ // Phase B1(2026-05-05):InputDisplay 退場。改用 `<Input mode="view" value={...} />`
258
258
  // 對齊 Carbon read-only / PatternFly inline-edit hidden-input / Cloudscape display-mode 統一 mode 模型。
259
259
 
260
260
  // Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)
@@ -256,7 +256,7 @@ export const Overview = {
256
256
  <thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
257
257
  <tbody>
258
258
  {[
259
- ['mode', "'edit' | 'display' | 'readonly' | 'disabled'", "'edit'", 'FieldMode 四模式'],
259
+ ['mode', "'edit' | 'view' | 'readonly' | 'disabled'", "'edit'", 'FieldMode 四模式'],
260
260
  ['variant', "'default'", "'default'", 'Field chrome variant(naked:cell-as-input 透明 chrome,@internal,2026-07-14 型別收窄至 FieldVariantInternal)'],
261
261
  ['size', "'sm' | 'md' | 'lg'", "'md'", '尺寸,與 Button 共用 token'],
262
262
  ['error', 'boolean', 'false', '錯誤狀態,紅色邊框 + aria-invalid'],
@@ -265,7 +265,7 @@ export const Overview = {
265
265
  ['placeholder', 'string', "'https://'", '空值時的佔位文字'],
266
266
  ['disabled', 'boolean', 'false', '等同 mode="disabled"'],
267
267
  ['label', 'string', '—', '自訂顯示文字(覆蓋自動 hostname 提取)'],
268
- ['showDisplayEndIcon', 'boolean', 'false', 'display 態改包 Field naked wrapper(D-path opt-in,DataTable cell display↔edit 像素對齊;本元件 edit 無 endIcon,故僅 wrapper 無 ItemSuffix)'],
268
+ ['showDisplayEndIcon', 'boolean', 'false', 'view 態改包 Field naked wrapper(D-path opt-in,DataTable cell view↔edit 像素對齊;本元件 edit 無 endIcon,故僅 wrapper 無 ItemSuffix)'],
269
269
  ].map(([p, t, d, desc]) => (
270
270
  <tr key={p}><Td mono>{p}</Td><Td mono>{t}</Td><Td mono>{d}</Td><Td>{desc}</Td></tr>
271
271
  ))}
@@ -59,7 +59,7 @@ export const UsageGuidance: Story = {
59
59
  <LinkTo kind="Design System/Components/LinkInput/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">四模式</span></LinkTo>
60
60
  </li>
61
61
  <li>
62
- <LinkTo kind="Design System/Components/LinkInput/展示" name="展示樣式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">展示樣式</span></LinkTo>
62
+ <LinkTo kind="Design System/Components/LinkInput/展示" name="檢視樣式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">展示樣式</span></LinkTo>
63
63
  </li>
64
64
  </ul>
65
65
  <p className="text-fg-muted mt-3">判斷不確定時:先確認這個值是不是「儲存後使用者會想直接點開的完整網址」。若不是(例如純字串代號、email、內部路徑),改用 Input。下方「vs 近親」段有正反對照範例。</p>
@@ -61,6 +61,10 @@ LinkInput 是 **URL 的**輸入與顯示元件。外觀基於 Input,但 value
61
61
  - blur 時驗證格式,合法則自動切回 link 狀態
62
62
  - 格式不合法維持 input 狀態 + error 邊框,直到格式正確
63
63
 
64
+ ### View 模式幾何(Model A 明文例外)
65
+
66
+ `mode="view"` 預設(`showDisplayEndIcon=false`)渲染**裸 anchor / span**——不包 `fieldWrapperStyles`(無 px 內距、無 h-field 高度),是 `../Field/field-controls.spec.md` 共享 contract (d)「view×default = edit 幾何減 chrome(留 px)」的**明文例外**(backward compat;2026-07-16 VERIFY 拍板記錄為例外而非對齊 code)。需要與 cell edit 像素對齊時走 `showDisplayEndIcon=true` opt-in(Field naked wrapper 包覆 anchor)。typography 仍消費 contract (e)(`fieldDisplayTextClass`)。
67
+
64
68
  ---
65
69
 
66
70
  ## 驗證
@@ -85,7 +89,7 @@ URL 格式要求:必須包含 `http://` 或 `https://` protocol。
85
89
  ## 極長 URL(邊界)
86
90
 
87
91
  - **顯示文字 = hostname**:link 狀態預設只顯示 hostname(去 `www.`,如 `https://github.com/org/repo` → `github.com`),非完整 URL;`label` prop 可覆寫顯示文字。完整 URL 載於 `href`
88
- - **單行 truncate**:link / readonly / display 狀態超寬時 ellipsis 截斷,不換行
92
+ - **單行 truncate**:link / readonly / view 狀態超寬時 ellipsis 截斷,不換行
89
93
  - **編輯態**:原生 input 水平捲動,無長度上限
90
94
 
91
95
  ---
@@ -108,7 +112,7 @@ URL 格式要求:必須包含 `http://` 或 `https://` protocol。
108
112
 
109
113
  ## 為何無 StateBehavior
110
114
 
111
- LinkInput 是 **Field Controls family 成員**——互動狀態(focus / invalid / disabled / readonly)完全繼承 `../Field/field-controls.spec.md` SSOT「Mode 狀態」。LinkInput 特有的狀態(edit 輸入 vs display link-chip)已在 `Overview` 中說明。重寫 StateBehavior = 與 field-controls SSOT 漂移。
115
+ LinkInput 是 **Field Controls family 成員**——互動狀態(focus / invalid / disabled / readonly)完全繼承 `../Field/field-controls.spec.md` SSOT「Mode 狀態」。LinkInput 特有的狀態(edit 輸入 vs view link-chip)已在 `Overview` 中說明。重寫 StateBehavior = 與 field-controls SSOT 漂移。
112
116
 
113
117
  對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix` + `SizeMatrix` + `Accessibility`。互動 state 見 Input 的 `StateBehavior` + field-controls.spec.md。
114
118
 
@@ -100,8 +100,8 @@ export const Modes: Story = {
100
100
  </div>
101
101
  {/* @story-trait-rationale: pre-existing trait gaps tracked separately */}
102
102
  <div>
103
- <h3 className="text-body font-bold text-foreground mb-2">display</h3>
104
- <LinkInput mode="display" value="https://github.com" />
103
+ <h3 className="text-body font-bold text-foreground mb-2">view</h3>
104
+ <LinkInput mode="view" value="https://github.com" />
105
105
  </div>
106
106
  <div>
107
107
  <h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
@@ -119,14 +119,14 @@ export const Modes: Story = {
119
119
  ),
120
120
  }
121
121
 
122
- /* ── Display(DataTable cell 用)── */
123
- export const Display: Story = {
124
- name: '展示樣式',
122
+ /* ── View(DataTable cell 用)── */
123
+ export const View: Story = {
124
+ name: '檢視樣式',
125
125
  render: () => (
126
126
  <div className="flex flex-col gap-3">
127
- <LinkInput mode="display" value="https://www.example.com/path/to/page" />
128
- <LinkInput mode="display" value="https://github.com/user/repo" label="GitHub Repo" />
129
- <LinkInput mode="display" value={null} />
127
+ <LinkInput mode="view" value="https://www.example.com/path/to/page" />
128
+ <LinkInput mode="view" value="https://github.com/user/repo" label="GitHub Repo" />
129
+ <LinkInput mode="view" value={null} />
130
130
  </div>
131
131
  ),
132
132
  }
@@ -27,10 +27,10 @@ function formatHostname(url: string): string {
27
27
  }
28
28
  }
29
29
 
30
- // ── Display rendering(inline,2026-05-05 Phase B3 retire LinkInputDisplay)──
30
+ // ── View rendering(inline,2026-05-05 Phase B3 retire LinkInputDisplay)──
31
31
  // 取代 LinkInputDisplay sub-component:純展示 a tag,無 input chrome、無 hover affordance。
32
32
  // edit mode 內 link state(showLink branch)也共用此 helper,確保「編輯態的 link 顯示」與
33
- // display mode 的視覺完全一致(SSOT)。
33
+ // view mode 的視覺完全一致(SSOT)。
34
34
  function renderLinkAnchor(value: string, label?: string) {
35
35
  const displayText = label || formatHostname(value)
36
36
  return (
@@ -59,7 +59,7 @@ export interface LinkInputProps
59
59
  * - `'default'`(預設)— Field wrapper 完整 chrome(form / Field 內嵌)。
60
60
  * (2026-07-09 `bare` variant 退役;naked = cell-as-input substrate,@internal)
61
61
  *
62
- * mode='display' 時 chrome 無視覺意義(display 完全無 wrapper);chrome 僅作用於 edit / readonly / disabled。
62
+ * mode='view' 時 chrome 無視覺意義(view 完全無 wrapper);chrome 僅作用於 edit / readonly / disabled。
63
63
  */
64
64
  variant?: FieldVariant
65
65
  error?: boolean
@@ -71,11 +71,11 @@ export interface LinkInputProps
71
71
  /** 自訂顯示文字(非編輯時) */
72
72
  label?: string
73
73
  /**
74
- * Display 是否包 Field naked wrapper(D-path opt-in,2026-05-08)
75
- * — DataTable cell display↔edit 像素級對齊用。預設 false(裸 anchor,backward compat)。
76
- * 設 true 時 display 走 fieldWrapperStyles(naked variant)包覆 anchor,
74
+ * View 態是否包 Field naked wrapper(D-path opt-in,2026-05-08)
75
+ * — DataTable cell view↔edit 像素級對齊用。預設 false(裸 anchor,backward compat)。
76
+ * 設 true 時 view 走 fieldWrapperStyles(naked variant)包覆 anchor,
77
77
  * 與 cell edit (`<Input naked>`) 同 DOM 結構,消除 Layer-B padding mismatch。
78
- * **本元件 edit 無 endIcon(UrlCell 用 plain Input edit)→ display 也無 ItemSuffix**(僅 wrapper)。
78
+ * **本元件 edit 無 endIcon(UrlCell 用 plain Input edit)→ view 也無 ItemSuffix**(僅 wrapper)。
79
79
  */
80
80
  showDisplayEndIcon?: boolean
81
81
  }
@@ -117,12 +117,12 @@ const LinkInput = React.forwardRef<HTMLInputElement, LinkInputProps>(
117
117
  // 2026-07-05 D4:invalid 經 useResolvedFieldInvalid 統一接 fieldCtx.invalid(field-controls.spec.md
118
118
  // resolver 契約「error/invalid = prop OR fieldCtx.invalid」)— 原本紅框只吃 errorProp||localError、
119
119
  // aria-invalid 卻 inline 加 fieldCtx?.invalid → <Field invalid> 下 AT 聽到 invalid 視覺卻正常框
120
- // (聚焦還變藍)。紅框與 aria 自此同源。宣告於 display early return 之前(Rules-of-Hooks)。
120
+ // (聚焦還變藍)。紅框與 aria 自此同源。宣告於 view early return 之前(Rules-of-Hooks)。
121
121
  const fieldInvalid = useResolvedFieldInvalid(errorProp)
122
122
 
123
123
  // ── Local state / refs ──────────────────────────────────────────────────
124
- // 2026-07-04 Rules-of-Hooks 修:hooks 必在 display early return 之前宣告,
125
- // 否則 mode 於 render 間切換 display↔edit 會改變 hook 呼叫數 → React #310 crash
124
+ // 2026-07-04 Rules-of-Hooks 修:hooks 必在 view early return 之前宣告,
125
+ // 否則 mode 於 render 間切換 view↔edit 會改變 hook 呼叫數 → React #310 crash
126
126
  // (同 beta.76 Combobox 同款修法;僅搬位置,hook 邏輯不變)。
127
127
  const [editing, setEditing] = React.useState(false)
128
128
  const [localValue, setLocalValue] = React.useState(value ?? '')
@@ -145,25 +145,27 @@ const LinkInput = React.forwardRef<HTMLInputElement, LinkInputProps>(
145
145
  const focusRafIdRef = React.useRef<number>(0)
146
146
  React.useEffect(() => () => { if (focusRafIdRef.current) cancelAnimationFrame(focusRafIdRef.current) }, [])
147
147
 
148
- // ── mode='display' ─────────────────────────────────────────────────────
148
+ // ── mode='view' ─────────────────────────────────────────────────────
149
149
  // 純展示:無 input chrome / 無 hover affordance / 無 Pencil edit 入口。
150
150
  // 取代既有 LinkInputDisplay sub-component(2026-05-05 Phase B3 retire)。
151
- // Default(showDisplayEndIcon=false):無 wrapper 裸 anchor — backward compat
151
+ // Default(showDisplayEndIcon=false):無 wrapper 裸 anchor — backward compat;為 contract (d)
152
+ // Model A(view×default = edit 幾何減 chrome、留 px)之明文例外,見 link-input.spec.md
153
+ // 「View 模式幾何(Model A 明文例外)」。
152
154
  // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper 包覆 anchor,
153
155
  // 與 cell edit (`<Input naked>`) 同 DOM 結構消除像素偏移(無 ItemSuffix,因 edit 也無 endIcon)。
154
- if (resolvedMode === 'display') {
156
+ if (resolvedMode === 'view') {
155
157
  if (!showDisplayEndIcon) {
156
- // 2026-05-14 I2 fix(spec contract (e) display typography canonical):非 D-path bare
158
+ // 2026-05-14 I2 fix(spec contract (e) view typography canonical):非 D-path bare
157
159
  // anchor / span 必套 `fieldDisplayTextClass(size)`(sm/md→text-body,lg→text-body-lg)
158
- // — 對齊跨 Field family display 視覺尺寸統一。原無 font-size class → 用 browser default
159
- // 字體 → 跟其他 Field display 不一致(user 抓 I2)。truncate 同需,長 URL ellipsis(I1)。
160
+ // — 對齊跨 Field family view 視覺尺寸統一。原無 font-size class → 用 browser default
161
+ // 字體 → 跟其他 Field view 不一致(user 抓 I2)。truncate 同需,長 URL ellipsis(I1)。
160
162
  if (!value) return <span className={cn(fieldDisplayTextClass(size), fieldEmptyColorClass(resolvedMode), 'block truncate')}>{emptyDisplay}</span>
161
163
  return <span className={cn(fieldDisplayTextClass(size), 'block truncate')}>{renderLinkAnchor(value, label)}</span>
162
164
  }
163
165
  return (
164
166
  <div
165
- className={cn(fieldWrapperStyles({ mode: 'display', variant: resolvedVariant, size }), className)}
166
- data-field-mode="display"
167
+ className={cn(fieldWrapperStyles({ mode: 'view', variant: resolvedVariant, size }), className)}
168
+ data-field-mode="view"
167
169
  >
168
170
  <span className="flex-1 min-w-0 truncate">
169
171
  {value
@@ -243,7 +245,7 @@ const LinkInput = React.forwardRef<HTMLInputElement, LinkInputProps>(
243
245
  )
244
246
  }
245
247
 
246
- // edit — link display mode(有合法 URL 且未在編輯中)
248
+ // edit — link 顯示分支(有合法 URL 且未在編輯中)
247
249
  if (showLink) {
248
250
  return (
249
251
  <div
@@ -74,7 +74,7 @@ export const CompositionRules: Story = {
74
74
  <div>
75
75
  <Section title="Pattern 1 — Alert(persistent inline announcement)">
76
76
  <div className="prose prose-sm max-w-prose">
77
- <p>需要「持續顯示直到 user 主動 dismiss」→ <LinkTo kind="Design System/Components/Alert/展示" name="低調單行"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Alert 低調單行</span></LinkTo>。Alert 內部消費 Notice + 加上 dismiss button + live region ARIA(error/warning → role="alert" assertive;info/success/neutral → role="status" polite)。</p>
77
+ <p>需要「持續顯示直到 user 主動 dismiss」→ <LinkTo kind="Design System/Components/Alert/展示" name="單行(低調 vs 實心對照)"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">Alert 低調單行</span></LinkTo>。Alert 內部消費 Notice + 加上 dismiss button + live region ARIA(error/warning → role="alert" assertive;info/success/neutral → role="status" polite)。</p>
78
78
  <ul>
79
79
  <li>典型場景:付款失敗 banner / workspace 警告 / 重要通知 user 必看</li>
80
80
  <li>對齊世界級:Polaris <code>Banner</code> / Material <code>Banner</code> / Atlassian <code>InlineMessage</code> — 共識用「persistent + dismissible」</li>
@@ -208,12 +208,18 @@ export function useInverseTheme(): 'dark' | 'light' {
208
208
  }
209
209
 
210
210
  // Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)
211
- // Phase 2 fill needed: purpose descriptions + when rationale + world-class refs
211
+ // 2026-07-16 dim 78/DA3:variants 補齊 對齊 notice.spec.md frontmatter 5 variants(SSOT)
212
+ // + alertMeta `{ purpose }` idiom(Alert 是 Notice 直接 consumer,同 5-variant 語意)。
213
+ // variant 語意 = status icon 選擇(per spec「Variant」表);色彩由消費者 data-theme 控制。
212
214
  export const noticeMeta = {
213
215
  component: 'Notice',
214
216
  family: 2, // Family 2(List item layout)消費者 — 對齊 notice.spec.md frontmatter family: 2 + body「Layout Family」段
215
217
  variants: {
216
-
218
+ neutral: { purpose: '一般訊息、系統公告;無情緒色、不掛 status icon(title-only icon-less 形態)' },
219
+ info: { purpose: '資訊提示(版本更新、流程說明);Info icon' },
220
+ success: { purpose: '操作成功確認;CircleCheck icon' },
221
+ warning: { purpose: '可恢復警告(未儲存變更、連線不穩);TriangleAlert icon' },
222
+ error: { purpose: '錯誤(操作失敗、權限不足);XCircle icon' },
217
223
  },
218
224
  sizes: {
219
225
 
@@ -19,12 +19,12 @@ type StateKey = 'default' | 'hover' | 'focus' | 'error' | 'disabled'
19
19
  type SizeKey = 'sm' | 'md' | 'lg'
20
20
  type ColorSpec = { bg: string; text: string; border: string }
21
21
 
22
- const MODES: ModeKey[] = ['edit', 'display', 'readonly', 'disabled']
22
+ const MODES: ModeKey[] = ['edit', 'view', 'readonly', 'disabled']
23
23
  const SIZES: SizeKey[] = ['sm', 'md', 'lg']
24
24
 
25
25
  const MODE_DESC: Record<ModeKey, string> = {
26
26
  edit: '表單可編輯欄位,有邊框、hover / focus 回饋',
27
- display: '純展示(read-only 內容),無 input chrome、無互動 affordance',
27
+ view: '純展示值(非表單)— edit 幾何減 chrome(透明 bg/border、保留 px 內距與高度,Model A)。用在 cell / InlineEdit / 詳情',
28
28
  readonly: '表單中不可編輯但可見,灰底、無邊框(input chrome 但鎖定)',
29
29
  disabled: '停用狀態,灰底、灰字、cursor-not-allowed',
30
30
  }
@@ -37,7 +37,7 @@ const TOKEN_MAP: Record<ModeKey, Record<StateKey, ColorSpec>> = {
37
37
  error: { bg: '--surface', text: '--foreground', border: '--error' },
38
38
  disabled: { bg: '--bg-disabled', text: '--fg-disabled', border: 'transparent' },
39
39
  },
40
- display: {
40
+ view: {
41
41
  default: { bg: 'transparent', text: '--foreground', border: 'transparent' },
42
42
  hover: { bg: 'transparent', text: '--foreground', border: 'transparent' },
43
43
  focus: { bg: 'transparent', text: '--foreground', border: 'transparent' },
@@ -218,7 +218,7 @@ export const Overview = {
218
218
  {/* Format options */}
219
219
  <div className="flex flex-col gap-3">
220
220
  <H3>格式化選項</H3>
221
- <Desc>格式化在 readonly / disabled 和 `mode="display"` 生效。edit 模式輸入 raw 數值(不套格式),確保使用者能直覺地修改。</Desc>
221
+ <Desc>格式化在 readonly / disabled 和 `mode="view"` 生效。edit 模式輸入 raw 數值(不套格式),確保使用者能直覺地修改。</Desc>
222
222
  <div className="flex flex-col gap-2">
223
223
  {([
224
224
  { label: 'prefix="$"', props: { prefix: '$' }, value: 2490 },
@@ -245,7 +245,7 @@ export const Overview = {
245
245
  <thead><tr><Th>Prop</Th><Th>Type</Th><Th>Default</Th><Th>說明</Th></tr></thead>
246
246
  <tbody>
247
247
  {[
248
- ['mode', "'edit'|'display'|'readonly'|'disabled'", "'edit'", '顯示模式'],
248
+ ['mode', "'edit'|'view'|'readonly'|'disabled'", "'edit'", '顯示模式'],
249
249
  ['error', 'boolean', 'false', '紅色邊框 + aria-invalid(僅 edit 生效)'],
250
250
  ['size', "'sm'|'md'|'lg'", "'md'", '尺寸,與 Button 同 size 對齊'],
251
251
  ['value', 'number | null', '—', '數值'],
@@ -717,7 +717,7 @@ export const StateBehavior = {
717
717
  <span className="text-caption font-medium text-fg-secondary">格式化行為</span>
718
718
  <div className="overflow-x-auto">
719
719
  <table className="border-collapse text-caption">
720
- <thead><tr><Th>情境</Th><Th>edit 模式</Th><Th>readonly / Display</Th></tr></thead>
720
+ <thead><tr><Th>情境</Th><Th>edit 模式</Th><Th>readonly / view</Th></tr></thead>
721
721
  <tbody>
722
722
  {[
723
723
  ['value = 2490, prefix="$"', '2490(raw 數值)', '$2,490(格式化)'],
@@ -52,7 +52,7 @@ export const UsageGuidance: Story = {
52
52
  <p>適合 NumberInput 的真實業務場景(點擊跳轉「展示」頁範例):</p>
53
53
  <ul className="space-y-1">
54
54
  <li><LinkTo kind="Design System/Components/NumberInput/展示" name="四模式"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">四模式</span></LinkTo></li>
55
- <li><LinkTo kind="Design System/Components/NumberInput/展示" name="尺寸與 Button 對齊"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">尺寸與 Button 對齊</span></LinkTo></li>
55
+ <li><LinkTo kind="Design System/Components/NumberInput/展示" name="三種尺寸"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">尺寸與 Button 對齊</span></LinkTo></li>
56
56
  <li><LinkTo kind="Design System/Components/NumberInput/展示" name="格式化選項"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">格式化選項</span></LinkTo></li>
57
57
  <li><LinkTo kind="Design System/Components/NumberInput/展示" name="DataTable 整合"><span className="text-primary hover:text-primary-hover font-medium cursor-pointer">DataTable 整合</span></LinkTo></li>
58
58
  </ul>
@@ -63,9 +63,9 @@ export const UsageGuidance: Story = {
63
63
  <Section title="何時不用 + 替代方案">
64
64
  <Rule
65
65
  title="❌ 不用 NumberInput 做 DataTable 列表展示"
66
- note="Table cell 用 `mode='display'` 渲染,不用 edit 模式輸入元件。DataTable 的 currency 欄位自動消費 `<NumberInput mode='display'>`"
66
+ note="Table cell 用 `mode='view'` 渲染,不用 edit 模式輸入元件。DataTable 的 currency 欄位自動消費 `<NumberInput mode='view'>`"
67
67
  >
68
- <Label warn>Table cell 顯示值 → `mode='display'` 渲染,不用 edit Input</Label>
68
+ <Label warn>Table cell 顯示值 → `mode='view'` 渲染,不用 edit Input</Label>
69
69
  </Rule>
70
70
  </Section>
71
71
 
@@ -162,7 +162,7 @@ export const FormatOptionsRule: Story = {
162
162
  <div>
163
163
  <Rule
164
164
  title="prefix — 置於數字前的符號(貨幣是最常見場景)"
165
- note="prefix 出現在 readonly / display / disabled 與 DataTable cell 的格式化值;edit 模式輸入 raw 純數字、不渲染 prefix——使用者不需要自己輸入 $"
165
+ note="prefix 出現在 readonly / view / disabled 與 DataTable cell 的格式化值;edit 模式輸入 raw 純數字、不渲染 prefix——使用者不需要自己輸入 $"
166
166
  >
167
167
  <NumberInput mode="readonly" value={2490} prefix="$" />
168
168
  <NumberInput mode="readonly" value={12500} prefix="NT$" precision={0} />
@@ -61,11 +61,11 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
61
61
  ## 對齊
62
62
 
63
63
  - **Edit 模式(input)**:靠左——input 內打字是左到右
64
- - **Table cell(Display)**:靠右——縱向比較位數需要右對齊(由 DataTable 的 column type `number` / `currency` 控制)
64
+ - **Table cell(View)**:靠右——縱向比較位數需要右對齊(由 DataTable 的 column type `number` / `currency` 控制)
65
65
 
66
- ## Display
66
+ ## View
67
67
 
68
- `<NumberInput mode="display">` 在 table cell 和 Form readonly 共用 `formatNumber()` 格式化函式。
68
+ `<NumberInput mode="view">` 在 table cell 和 Form readonly 共用 `formatNumber()` 格式化函式。
69
69
 
70
70
  - 有值:格式化輸出(prefix + localized number + suffix)
71
71
  - null / undefined:半形 `-`(hyphen),`text-foreground`(disabled → fg-disabled)
@@ -103,9 +103,9 @@ col.accessor('price', {
103
103
 
104
104
  ## 邊界案例
105
105
 
106
- - **Disabled**:由 Field SSOT own(`Field/field-controls.spec.md` State machine 段)。視覺:wrapper bg → `bg-disabled`(neutral-2,`semantic.css` `--bg-disabled`)、formatted text → `text-fg-disabled`(M24 state>emphasis)。Display mode + disabled 維持格式化輸出但 token 切 disabled。
106
+ - **Disabled**:由 Field SSOT own(`Field/field-controls.spec.md` State machine 段)。視覺:wrapper bg → `bg-disabled`(neutral-2,`semantic.css` `--bg-disabled`)、formatted text → `text-fg-disabled`(M24 state>emphasis)。View mode + disabled 維持格式化輸出但 token 切 disabled。
107
107
  - **Loading**:NumberInput 不提供 loading state(`NumberInputProps` 無 `loading` prop、無 `CircularProgress` / `aria-busy` 邏輯)。數值輸入為同步操作,無 async fetch 語意;若需 async 場景(如遠端校驗)請走外層 Field validation + `endSlot` 自訂 spinner。
108
- - **Empty(null / undefined / 空字串)**:Display / readonly mode 渲半形 `-`(hyphen + `text-foreground`,disabled → fg-disabled);Edit mode placeholder 走 default placeholder color。
108
+ - **Empty(null / undefined / 空字串)**:View / readonly mode 渲半形 `-`(hyphen + `text-foreground`,disabled → fg-disabled);Edit mode placeholder 走 default placeholder color。
109
109
  - **Invalid input**(non-numeric):input 為 `type="text" inputMode="decimal"`,onChange 以 `Number(raw)` parse,NaN 時忽略不觸發 `onChange`(value 維持原值);搭配 Field validation 渲 error variant(`aria-invalid="true"` + wrapper `border-error`(hover 時 `border-error-hover`)+ 下方 error message)。
110
110
  - **輸入中間態**(`-`、`1.`、`0.0` 等 parse 後 lossy 的 raw 字串,2026-07-05 D4 codify):edit mode 以 internal draft string 承載——輸入期間 DOM 顯示 draft 原字串(負號、尾點不被 controlled 回寫吃掉),parse 成功即時同步 `onChange(parsed)`;blur / Enter commit(清 draft、顯示回 committed value,不合法殘字自然還原)、Escape 棄未提交 draft 字串、顯示回 committed value(NumberInput 為 live-commit,每次合法 parse 即 onChange,故非回復 pre-edit 原值;真 revert 需另存 snapshot,屬 API 擴充)。value 面語意不變:`''` / `'-'` 視為 `null`。對齊 Ant InputNumber / Adobe Spectrum NumberField internal draft canonical。 <!-- @benchmark-unverified -->
111
111
  - **負數 / 超大數字**:`toLocaleString(locale)` 自動處理負號與千分位分組,無特殊 prop。
@@ -125,7 +125,7 @@ col.accessor('price', {
125
125
 
126
126
  ## A11y 預設
127
127
 
128
- **ARIA / Pattern**:ARIA / keyboard 機制**僅 edit mode 適用**——edit mode 渲染 native `<input>` element(預設 a11y),且把 `...props`(含 `aria-label` / `aria-describedby` 等)轉發到該 input;該 native input 自身消費 `fieldCtx` 設定 `aria-invalid` / `aria-required` / `aria-describedby` / `aria-errormessage`(非由 Field wrapper 注入,對齊 Select / Combobox trigger 自設機制)。`display` / `readonly` / `disabled` 三 mode 渲染的是無互動純展示文字(`<div>` + `<span>`,不轉發 `aria-*`),螢幕報讀僅得格式化後的靜態值(對齊 Carbon read-only / Stripe display 慣例)。
128
+ **ARIA / Pattern**:ARIA / keyboard 機制**僅 edit mode 適用**——edit mode 渲染 native `<input>` element(預設 a11y),且把 `...props`(含 `aria-label` / `aria-describedby` 等)轉發到該 input;該 native input 自身消費 `fieldCtx` 設定 `aria-invalid` / `aria-required` / `aria-describedby` / `aria-errormessage`(非由 Field wrapper 注入,對齊 Select / Combobox trigger 自設機制)。`view` / `readonly` / `disabled` 三 mode 渲染的是無互動純展示文字(`<div>` + `<span>`,不轉發 `aria-*`),螢幕報讀僅得格式化後的靜態值(對齊 Carbon read-only / Stripe display 慣例)。
129
129
 
130
130
  **Keyboard 行為**:
131
131
 
@@ -18,7 +18,7 @@ const meta: Meta<typeof NumberInput> = {
18
18
  export default meta
19
19
  type Story = StoryObj<typeof NumberInput>
20
20
 
21
- // @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add display mode card to Modes story only.
21
+ // @story-trait-rationale: pre-existing trait gaps (Default/WithError) tracked separately; this PR scope = add view mode card to Modes story only.
22
22
  /* ── 四模式 ── */
23
23
  export const Modes: Story = {
24
24
  name: '四模式',
@@ -31,8 +31,8 @@ export const Modes: Story = {
31
31
  <NumberInput value={value} onChange={setValue} prefix="$" aria-label="價格(edit mode demo)" />
32
32
  </div>
33
33
  <div>
34
- <h3 className="text-body font-bold text-foreground mb-2">display</h3>
35
- <NumberInput mode="display" value={value} prefix="$" aria-label="價格(display mode demo)" />
34
+ <h3 className="text-body font-bold text-foreground mb-2">view</h3>
35
+ <NumberInput mode="view" value={value} prefix="$" aria-label="價格(view 模式示範)" />
36
36
  </div>
37
37
  <div>
38
38
  <h3 className="text-body font-bold text-foreground mb-2">readonly</h3>
@@ -49,7 +49,7 @@ export const Modes: Story = {
49
49
 
50
50
  /* ── 尺寸與 Button 對齊 ── */
51
51
  export const SizeAlignment: Story = {
52
- name: '尺寸與 Button 對齊',
52
+ name: '三種尺寸',
53
53
  render: () => {
54
54
  const [sm, setSm] = React.useState<number | null>(2490)
55
55
  const [md, setMd] = React.useState<number | null>(2490)
@@ -27,14 +27,26 @@ function formatNumber(
27
27
  ): string {
28
28
  if (value == null) return ''
29
29
  const { precision, prefix = '', suffix = '', locale = 'en-US' } = options
30
- const formatted = precision != null
31
- ? value.toLocaleString(locale, { minimumFractionDigits: precision, maximumFractionDigits: precision })
30
+ // 2026-07-18 決策4:precision guard —— 負數/小數/超界進 Intl.NumberFormat 會 RangeError(crash)。
31
+ // clamp 回合法 Intl 範圍 [0,20](spec canonical ≤6);超界 dev-warn。維持 number 型別(對齊世界級 4 家)
32
+ let safePrecision = precision
33
+ if (precision != null) {
34
+ const rounded = Math.round(precision)
35
+ if (rounded !== precision || precision < 0 || precision > 6) {
36
+ if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {
37
+ console.warn(`[DS] NumberInput precision ${precision} 超出 canonical 範圍 0-6(或非整數)→ clamp。請傳 0-6 整數。`)
38
+ }
39
+ }
40
+ safePrecision = Math.min(20, Math.max(0, rounded))
41
+ }
42
+ const formatted = safePrecision != null
43
+ ? value.toLocaleString(locale, { minimumFractionDigits: safePrecision, maximumFractionDigits: safePrecision })
32
44
  : value.toLocaleString(locale)
33
45
  return `${prefix}${formatted}${suffix}`
34
46
  }
35
47
 
36
48
  // Phase B1(2026-05-05):NumberInputDisplay 退場。
37
- // 改用 `<NumberInput mode="display" value={...} prefix={...} ... />`,format 邏輯在 mode='display' 分支重用。
49
+ // 改用 `<NumberInput mode="view" value={...} prefix={...} ... />`,format 邏輯在 mode='view' 分支重用。
38
50
 
39
51
  // ── Types ───────────────────────────────────────────────────────────────────
40
52
 
@@ -45,7 +57,7 @@ export interface NumberInputProps
45
57
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'value' | 'defaultValue' | 'onChange' | 'type'>,
46
58
  Omit<VariantProps<typeof fieldWrapperStyles>, 'mode' | 'variant' | 'width'>,
47
59
  NumberFormatOptions {
48
- /** Field display mode */
60
+ /** Field mode */
49
61
  mode?: FieldMode
50
62
  /**
51
63
  * Visual chrome(正交於 mode);Phase B1(2026-05-05)新增。
@@ -122,7 +134,7 @@ const NumberInput = React.forwardRef<HTMLInputElement, NumberInputProps>(
122
134
  // 同 LinkInput 2026-07-04 修法)。
123
135
  const [draft, setDraft] = React.useState<string | null>(null)
124
136
 
125
- // display / readonly / disabled 都顯示格式化值(span 取代 input)
137
+ // view / readonly / disabled 都顯示格式化值(span 取代 input)
126
138
  if (resolvedMode !== 'edit') {
127
139
  return (
128
140
  <div