@qijenchen/design-system 0.1.0-beta.61 → 0.1.0-beta.63

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 (507) hide show
  1. package/CLAUDE.md +6 -6
  2. package/dist/components/Accordion/accordion.d.ts +1 -1
  3. package/dist/components/Accordion/accordion.js +1 -1
  4. package/dist/components/Accordion/accordion.js.map +1 -1
  5. package/dist/components/Alert/alert.d.ts +2 -2
  6. package/dist/components/Alert/alert.js +4 -3
  7. package/dist/components/Alert/alert.js.map +1 -1
  8. package/dist/components/AppShell/app-shell.d.ts.map +1 -1
  9. package/dist/components/AppShell/app-shell.js +4 -3
  10. package/dist/components/AppShell/app-shell.js.map +1 -1
  11. package/dist/components/Avatar/avatar.d.ts +1 -1
  12. package/dist/components/Avatar/avatar.js +2 -1
  13. package/dist/components/Avatar/avatar.js.map +1 -1
  14. package/dist/components/Badge/badge.d.ts +1 -1
  15. package/dist/components/Badge/badge.js +2 -1
  16. package/dist/components/Badge/badge.js.map +1 -1
  17. package/dist/components/Breadcrumb/breadcrumb.d.ts +1 -1
  18. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  19. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  20. package/dist/components/Button/button.d.ts +5 -5
  21. package/dist/components/Button/button.d.ts.map +1 -1
  22. package/dist/components/Button/button.js +4 -3
  23. package/dist/components/Button/button.js.map +1 -1
  24. package/dist/components/Calendar/calendar.d.ts +1 -1
  25. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  26. package/dist/components/Calendar/calendar.js +80 -69
  27. package/dist/components/Calendar/calendar.js.map +1 -1
  28. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  29. package/dist/components/Carousel/carousel.js +5 -3
  30. package/dist/components/Carousel/carousel.js.map +1 -1
  31. package/dist/components/Checkbox/checkbox-group.d.ts +2 -1
  32. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  33. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  34. package/dist/components/Checkbox/checkbox.d.ts +9 -3
  35. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  36. package/dist/components/Checkbox/checkbox.js +8 -3
  37. package/dist/components/Checkbox/checkbox.js.map +1 -1
  38. package/dist/components/Chip/chip.d.ts +2 -2
  39. package/dist/components/Chip/chip.js +3 -2
  40. package/dist/components/Chip/chip.js.map +1 -1
  41. package/dist/components/CircularProgress/circular-progress.d.ts +1 -1
  42. package/dist/components/CircularProgress/circular-progress.js +2 -1
  43. package/dist/components/CircularProgress/circular-progress.js.map +1 -1
  44. package/dist/components/Coachmark/coachmark.d.ts +4 -4
  45. package/dist/components/Coachmark/coachmark.js +2 -1
  46. package/dist/components/Coachmark/coachmark.js.map +1 -1
  47. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  48. package/dist/components/Combobox/combobox.js +17 -13
  49. package/dist/components/Combobox/combobox.js.map +1 -1
  50. package/dist/components/Command/command.d.ts +4 -0
  51. package/dist/components/Command/command.d.ts.map +1 -1
  52. package/dist/components/Command/command.js.map +1 -1
  53. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  54. package/dist/components/DataTable/data-table.js.map +1 -1
  55. package/dist/components/DateGrid/date-grid.d.ts +8 -4
  56. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  57. package/dist/components/DateGrid/date-grid.js +2 -2
  58. package/dist/components/DateGrid/date-grid.js.map +1 -1
  59. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  60. package/dist/components/DatePicker/date-picker.js +6 -4
  61. package/dist/components/DatePicker/date-picker.js.map +1 -1
  62. package/dist/components/DescriptionList/description-list.js +1 -1
  63. package/dist/components/DescriptionList/description-list.js.map +1 -1
  64. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  65. package/dist/components/Dialog/dialog.js.map +1 -1
  66. package/dist/components/DropdownMenu/dropdown-menu.d.ts +1 -1
  67. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  68. package/dist/components/DropdownMenu/dropdown-menu.js +0 -1
  69. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  70. package/dist/components/Empty/empty.d.ts +1 -1
  71. package/dist/components/Empty/empty.js.map +1 -1
  72. package/dist/components/Field/field-wrapper.js +1 -1
  73. package/dist/components/Field/field-wrapper.js.map +1 -1
  74. package/dist/components/Field/field.d.ts.map +1 -1
  75. package/dist/components/Field/field.js +1 -0
  76. package/dist/components/Field/field.js.map +1 -1
  77. package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -1
  78. package/dist/components/FieldControlGroup/field-control-group.js +1 -1
  79. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  80. package/dist/components/FileUpload/file-upload.d.ts +8 -1
  81. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  82. package/dist/components/FileUpload/file-upload.js +7 -3
  83. package/dist/components/FileUpload/file-upload.js.map +1 -1
  84. package/dist/components/FileViewer/file-viewer.d.ts +1 -1
  85. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  86. package/dist/components/FileViewer/file-viewer.js +25 -14
  87. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  88. package/dist/components/HoverCard/hover-card.d.ts +5 -1
  89. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  90. package/dist/components/HoverCard/hover-card.js +2 -1
  91. package/dist/components/HoverCard/hover-card.js.map +1 -1
  92. package/dist/components/Menu/menu-item.d.ts +6 -2
  93. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  94. package/dist/components/Menu/menu-item.js.map +1 -1
  95. package/dist/components/Notice/notice.d.ts +5 -1
  96. package/dist/components/Notice/notice.d.ts.map +1 -1
  97. package/dist/components/Notice/notice.js +2 -1
  98. package/dist/components/Notice/notice.js.map +1 -1
  99. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +4 -0
  100. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  101. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -2
  102. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  103. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  104. package/dist/components/PeoplePicker/people-picker.js +6 -2
  105. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  106. package/dist/components/Popover/popover.d.ts +1 -1
  107. package/dist/components/Popover/popover.js +2 -1
  108. package/dist/components/Popover/popover.js.map +1 -1
  109. package/dist/components/ProfileCard/profile-card.d.ts +9 -4
  110. package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
  111. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  112. package/dist/components/RadioGroup/radio-group.d.ts +6 -0
  113. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  114. package/dist/components/RadioGroup/radio-group.js +4 -0
  115. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  116. package/dist/components/ScrollArea/scroll-area.js +1 -1
  117. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  118. package/dist/components/Select/select.d.ts.map +1 -1
  119. package/dist/components/Select/select.js +14 -4
  120. package/dist/components/Select/select.js.map +1 -1
  121. package/dist/components/SelectMenu/select-menu.d.ts +4 -0
  122. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  123. package/dist/components/SelectMenu/select-menu.js +6 -3
  124. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  125. package/dist/components/SelectionControl/selection-item.d.ts +5 -1
  126. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
  127. package/dist/components/SelectionControl/selection-item.js +3 -1
  128. package/dist/components/SelectionControl/selection-item.js.map +1 -1
  129. package/dist/components/Sheet/sheet.d.ts +6 -5
  130. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  131. package/dist/components/Sheet/sheet.js.map +1 -1
  132. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  133. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  134. package/dist/components/Sidebar/sidebar.js +3 -2
  135. package/dist/components/Sidebar/sidebar.js.map +1 -1
  136. package/dist/components/Skeleton/skeleton.d.ts +1 -1
  137. package/dist/components/Skeleton/skeleton.js +2 -1
  138. package/dist/components/Skeleton/skeleton.js.map +1 -1
  139. package/dist/components/Slider/slider.d.ts +1 -1
  140. package/dist/components/Slider/slider.d.ts.map +1 -1
  141. package/dist/components/Slider/slider.js +7 -3
  142. package/dist/components/Slider/slider.js.map +1 -1
  143. package/dist/components/Steps/steps.d.ts +1 -1
  144. package/dist/components/Steps/steps.d.ts.map +1 -1
  145. package/dist/components/Steps/steps.js +9 -6
  146. package/dist/components/Steps/steps.js.map +1 -1
  147. package/dist/components/Switch/switch.d.ts +5 -5
  148. package/dist/components/Switch/switch.js +3 -3
  149. package/dist/components/Switch/switch.js.map +1 -1
  150. package/dist/components/Tabs/tabs.js +1 -1
  151. package/dist/components/Tabs/tabs.js.map +1 -1
  152. package/dist/components/Textarea/textarea.js +1 -1
  153. package/dist/components/Textarea/textarea.js.map +1 -1
  154. package/dist/components/TimePicker/time-columns.js +1 -1
  155. package/dist/components/TimePicker/time-columns.js.map +1 -1
  156. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  157. package/dist/components/TimePicker/time-picker.js +2 -1
  158. package/dist/components/TimePicker/time-picker.js.map +1 -1
  159. package/dist/components/Toast/toast.js.map +1 -1
  160. package/dist/components/Tooltip/tooltip.d.ts +1 -1
  161. package/dist/components/Tooltip/tooltip.js +2 -1
  162. package/dist/components/Tooltip/tooltip.js.map +1 -1
  163. package/dist/components/TreeView/tree-view.d.ts +4 -4
  164. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  165. package/dist/components/TreeView/tree-view.js +3 -3
  166. package/dist/components/TreeView/tree-view.js.map +1 -1
  167. package/dist/patterns/element-anatomy/item-anatomy.d.ts +3 -3
  168. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  169. package/dist/patterns/header-canonical/chrome-header.d.ts +3 -2
  170. package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -1
  171. package/dist/patterns/header-canonical/chrome-header.js.map +1 -1
  172. package/dist/patterns/overlay-surface/overlay-surface.d.ts +3 -2
  173. package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
  174. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
  175. package/ds-canonical/hooks/_log-fire.sh +3 -1
  176. package/ds-canonical/hooks/check_audit_post_report_validator.sh +21 -1
  177. package/ds-canonical/hooks/check_audit_sample_escape.sh +6 -3
  178. package/ds-canonical/hooks/check_chrome_header_avatar_canonical.sh +8 -0
  179. package/ds-canonical/hooks/check_consumer_app_invariants.sh +321 -0
  180. package/ds-canonical/hooks/check_datatable_invariants.sh +75 -12
  181. package/ds-canonical/hooks/check_escape_marker_abuse.sh +15 -1
  182. package/ds-canonical/hooks/check_field_family_invariants.sh +12 -2
  183. package/ds-canonical/hooks/check_plugin_fork_health.sh +137 -0
  184. package/ds-canonical/hooks/check_propose_discipline.sh +147 -0
  185. package/ds-canonical/hooks/check_solo_workflow.sh +11 -1
  186. package/ds-canonical/hooks/check_story_invariants.sh +63 -9
  187. package/ds-canonical/hooks/check_storybook_addon_packaging.sh +151 -0
  188. package/ds-canonical/hooks/check_tailwind_wildcard_in_docs.sh +8 -2
  189. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +25 -4
  190. package/ds-canonical/hooks/lib/_token_hygiene.sh +9 -1
  191. package/ds-canonical/hooks/session_start_governance_check.sh +7 -2
  192. package/ds-canonical/hooks/stop_self_audit.sh +2 -2
  193. package/ds-canonical/hooks/tests/test_check_addon_subdir_ship.sh +3 -2
  194. package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +12 -0
  195. package/ds-canonical/hooks/tests/test_check_consumer_app_story_title.sh +3 -2
  196. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +6 -4
  197. package/ds-canonical/hooks/tests/test_check_consumer_no_ds_catalog.sh +7 -4
  198. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +6 -4
  199. package/ds-canonical/hooks/tests/test_check_data_table_size_num_to_meta_width.sh +3 -2
  200. package/ds-canonical/hooks/tests/test_check_fork_user_plugin_install.sh +3 -2
  201. package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +9 -0
  202. package/ds-canonical/hooks/tests/test_check_propose_cite_required.sh +3 -2
  203. package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +10 -0
  204. package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +3 -2
  205. package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +10 -0
  206. package/ds-canonical/hooks/tests/test_check_storybook_addon_preset_cjs.sh +3 -2
  207. package/ds-canonical/references/build-ui-canonicals.md +2 -2
  208. package/ds-canonical/references/composition-fidelity.md +3 -3
  209. package/ds-canonical/references/naming-conventions.md +1 -0
  210. package/ds-canonical/references/ssot-consultation.md +1 -1
  211. package/ds-canonical/references/ssot-index.md +7 -7
  212. package/ds-canonical/rules/meta-patterns.md +5 -5
  213. package/ds-canonical/rules/self-verify.md +1 -1
  214. package/ds-canonical/rules/story-rules.md +2 -0
  215. package/ds-canonical/rules/ui-development.md +1 -1
  216. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +11 -2
  217. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +1 -1
  218. package/ds-canonical/skills/design-system-audit/SKILL.md +15 -15
  219. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +4 -3
  220. package/ds-story-manifest.json +15 -21
  221. package/llms-full.txt +9 -5
  222. package/llms.txt +2 -2
  223. package/package.json +1 -1
  224. package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
  225. package/src/components/Accordion/accordion.spec.md +22 -5
  226. package/src/components/Accordion/accordion.tsx +1 -1
  227. package/src/components/Alert/alert.anatomy.stories.tsx +4 -4
  228. package/src/components/Alert/alert.principles.stories.tsx +5 -5
  229. package/src/components/Alert/alert.spec.md +16 -11
  230. package/src/components/Alert/alert.stories.tsx +5 -5
  231. package/src/components/Alert/alert.tsx +2 -2
  232. package/src/components/AppShell/app-shell.principles.stories.tsx +68 -21
  233. package/src/components/AppShell/app-shell.spec.md +17 -24
  234. package/src/components/AppShell/app-shell.tsx +4 -3
  235. package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +3 -3
  236. package/src/components/AspectRatio/aspect-ratio.spec.md +15 -1
  237. package/src/components/Avatar/avatar.anatomy.stories.tsx +1 -1
  238. package/src/components/Avatar/avatar.principles.stories.tsx +8 -8
  239. package/src/components/Avatar/avatar.spec.md +25 -54
  240. package/src/components/Avatar/avatar.tsx +2 -2
  241. package/src/components/Badge/badge.principles.stories.tsx +2 -2
  242. package/src/components/Badge/badge.spec.md +22 -13
  243. package/src/components/Badge/badge.tsx +1 -1
  244. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +5 -2
  245. package/src/components/Breadcrumb/breadcrumb.spec.md +25 -25
  246. package/src/components/Breadcrumb/breadcrumb.stories.tsx +7 -32
  247. package/src/components/Breadcrumb/breadcrumb.tsx +1 -1
  248. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +2 -2
  249. package/src/components/BulkActionBar/bulk-action-bar.spec.md +20 -6
  250. package/src/components/BulkActionBar/bulk-action-bar.tsx +2 -2
  251. package/src/components/Button/button.anatomy.stories.tsx +2 -2
  252. package/src/components/Button/button.spec.md +19 -17
  253. package/src/components/Button/button.stories.tsx +1 -1
  254. package/src/components/Button/button.tsx +10 -9
  255. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  256. package/src/components/Calendar/calendar.spec.md +37 -17
  257. package/src/components/Calendar/calendar.tsx +26 -22
  258. package/src/components/Carousel/carousel.anatomy.stories.tsx +6 -6
  259. package/src/components/Carousel/carousel.principles.stories.tsx +1 -1
  260. package/src/components/Carousel/carousel.spec.md +23 -3
  261. package/src/components/Carousel/carousel.tsx +19 -4
  262. package/src/components/Chart/chart.anatomy.stories.tsx +1 -1
  263. package/src/components/Chart/chart.spec.md +20 -1
  264. package/src/components/Checkbox/checkbox-group.tsx +2 -1
  265. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +4 -4
  266. package/src/components/Checkbox/checkbox.principles.stories.tsx +2 -2
  267. package/src/components/Checkbox/checkbox.spec.md +35 -15
  268. package/src/components/Checkbox/checkbox.stories.tsx +1 -1
  269. package/src/components/Checkbox/checkbox.tsx +14 -3
  270. package/src/components/Chip/chip.anatomy.stories.tsx +5 -5
  271. package/src/components/Chip/chip.principles.stories.tsx +9 -3
  272. package/src/components/Chip/chip.spec.md +8 -9
  273. package/src/components/Chip/chip.tsx +2 -2
  274. package/src/components/CircularProgress/circular-progress.anatomy.stories.tsx +6 -6
  275. package/src/components/CircularProgress/circular-progress.spec.md +10 -11
  276. package/src/components/CircularProgress/circular-progress.stories.tsx +36 -43
  277. package/src/components/CircularProgress/circular-progress.tsx +1 -1
  278. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +1 -1
  279. package/src/components/Coachmark/coachmark.principles.stories.tsx +14 -29
  280. package/src/components/Coachmark/coachmark.spec.md +21 -13
  281. package/src/components/Coachmark/coachmark.tsx +4 -4
  282. package/src/components/Combobox/combobox.anatomy.stories.tsx +28 -28
  283. package/src/components/Combobox/combobox.principles.stories.tsx +1 -1
  284. package/src/components/Combobox/combobox.spec.md +25 -7
  285. package/src/components/Combobox/combobox.tsx +12 -3
  286. package/src/components/Command/command.anatomy.stories.tsx +1 -1
  287. package/src/components/Command/command.principles.stories.tsx +8 -8
  288. package/src/components/Command/command.spec.md +18 -8
  289. package/src/components/Command/command.tsx +8 -3
  290. package/src/components/DataTable/data-table-sort-manager.tsx +1 -1
  291. package/src/components/DataTable/data-table.anatomy.stories.tsx +9 -7
  292. package/src/components/DataTable/data-table.principles.stories.tsx +3 -3
  293. package/src/components/DataTable/data-table.spec.md +15 -11
  294. package/src/components/DataTable/data-table.stories.tsx +58 -13
  295. package/src/components/DataTable/data-table.tsx +13 -0
  296. package/src/components/DataTable/filter-operators.spec.md +19 -27
  297. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +8 -8
  298. package/src/components/DateGrid/date-grid.principles.stories.tsx +7 -7
  299. package/src/components/DateGrid/date-grid.spec.md +17 -14
  300. package/src/components/DateGrid/date-grid.tsx +8 -4
  301. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +11 -15
  302. package/src/components/DatePicker/date-picker.principles.stories.tsx +8 -8
  303. package/src/components/DatePicker/date-picker.spec.md +40 -36
  304. package/src/components/DatePicker/date-picker.stories.tsx +23 -53
  305. package/src/components/DatePicker/date-picker.tsx +12 -6
  306. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +2 -2
  307. package/src/components/DescriptionList/description-list.principles.stories.tsx +4 -18
  308. package/src/components/DescriptionList/description-list.spec.md +9 -3
  309. package/src/components/DescriptionList/description-list.stories.tsx +2 -18
  310. package/src/components/DescriptionList/description-list.tsx +1 -1
  311. package/src/components/Dialog/dialog.principles.stories.tsx +1 -1
  312. package/src/components/Dialog/dialog.spec.md +26 -11
  313. package/src/components/Dialog/dialog.stories.tsx +159 -184
  314. package/src/components/Dialog/dialog.tsx +2 -1
  315. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +2 -2
  316. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +16 -17
  317. package/src/components/DropdownMenu/dropdown-menu.spec.md +10 -15
  318. package/src/components/DropdownMenu/dropdown-menu.stories.tsx +13 -15
  319. package/src/components/DropdownMenu/dropdown-menu.tsx +12 -2
  320. package/src/components/Empty/empty.spec.md +19 -18
  321. package/src/components/Empty/empty.tsx +1 -1
  322. package/src/components/Field/field-controls.spec.md +52 -41
  323. package/src/components/Field/field-wrapper.tsx +2 -2
  324. package/src/components/Field/field.anatomy.stories.tsx +6 -5
  325. package/src/components/Field/field.principles.stories.tsx +8 -7
  326. package/src/components/Field/field.spec.md +42 -20
  327. package/src/components/Field/field.stories.tsx +9 -7
  328. package/src/components/Field/field.tsx +6 -3
  329. package/src/components/Field/form-validation.spec.md +20 -19
  330. package/src/components/FieldControlGroup/field-control-group.anatomy.stories.tsx +16 -15
  331. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +5 -1
  332. package/src/components/FieldControlGroup/field-control-group.spec.md +17 -1
  333. package/src/components/FieldControlGroup/field-control-group.stories.tsx +9 -9
  334. package/src/components/FieldControlGroup/field-control-group.tsx +4 -3
  335. package/src/components/FileItem/file-item.anatomy.stories.tsx +7 -17
  336. package/src/components/FileItem/file-item.principles.stories.tsx +7 -7
  337. package/src/components/FileItem/file-item.spec.md +24 -24
  338. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +4 -2
  339. package/src/components/FileUpload/file-upload.principles.stories.tsx +10 -12
  340. package/src/components/FileUpload/file-upload.spec.md +37 -8
  341. package/src/components/FileUpload/file-upload.tsx +5 -3
  342. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +16 -11
  343. package/src/components/FileViewer/file-viewer.principles.stories.tsx +4 -4
  344. package/src/components/FileViewer/file-viewer.spec.md +7 -19
  345. package/src/components/FileViewer/file-viewer.stories.tsx +3 -3
  346. package/src/components/FileViewer/file-viewer.tsx +42 -16
  347. package/src/components/HoverCard/hover-card.spec.md +20 -10
  348. package/src/components/HoverCard/hover-card.stories.tsx +1 -1
  349. package/src/components/HoverCard/hover-card.tsx +12 -1
  350. package/src/components/Input/input.anatomy.stories.tsx +4 -4
  351. package/src/components/Input/input.principles.stories.tsx +4 -31
  352. package/src/components/Input/input.spec.md +16 -4
  353. package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
  354. package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
  355. package/src/components/LinkInput/link-input.spec.md +14 -1
  356. package/src/components/Menu/menu-item.principles.stories.tsx +5 -5
  357. package/src/components/Menu/menu-item.spec.md +24 -12
  358. package/src/components/Menu/menu-item.tsx +7 -3
  359. package/src/components/Notice/notice.principles.stories.tsx +7 -7
  360. package/src/components/Notice/notice.spec.md +7 -5
  361. package/src/components/Notice/notice.tsx +5 -1
  362. package/src/components/NumberInput/number-input.anatomy.stories.tsx +4 -4
  363. package/src/components/NumberInput/number-input.principles.stories.tsx +13 -35
  364. package/src/components/NumberInput/number-input.spec.md +19 -0
  365. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +4 -3
  366. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +2 -5
  367. package/src/components/OverflowIndicator/overflow-indicator.spec.md +9 -1
  368. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -42
  369. package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -3
  370. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +11 -2
  371. package/src/components/PeoplePicker/people-picker.spec.md +26 -12
  372. package/src/components/PeoplePicker/people-picker.stories.tsx +14 -15
  373. package/src/components/PeoplePicker/people-picker.tsx +12 -4
  374. package/src/components/Popover/popover.spec.md +20 -11
  375. package/src/components/Popover/popover.tsx +2 -2
  376. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  377. package/src/components/ProfileCard/profile-card.principles.stories.tsx +29 -25
  378. package/src/components/ProfileCard/profile-card.spec.md +30 -10
  379. package/src/components/ProfileCard/profile-card.tsx +12 -7
  380. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +1 -1
  381. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +7 -5
  382. package/src/components/ProgressBar/progress-bar.spec.md +9 -1
  383. package/src/components/ProgressBar/progress-bar.stories.tsx +1 -1
  384. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +6 -3
  385. package/src/components/RadioGroup/radio-group.principles.stories.tsx +6 -13
  386. package/src/components/RadioGroup/radio-group.spec.md +7 -1
  387. package/src/components/RadioGroup/radio-group.tsx +10 -0
  388. package/src/components/Rating/rating.anatomy.stories.tsx +1 -0
  389. package/src/components/Rating/rating.principles.stories.tsx +9 -6
  390. package/src/components/Rating/rating.spec.md +13 -7
  391. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +44 -24
  392. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +51 -57
  393. package/src/components/ScrollArea/scroll-area.spec.md +5 -7
  394. package/src/components/ScrollArea/scroll-area.stories.tsx +110 -60
  395. package/src/components/ScrollArea/scroll-area.tsx +1 -1
  396. package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +1 -1
  397. package/src/components/SegmentedControl/segmented-control.spec.md +15 -14
  398. package/src/components/SegmentedControl/segmented-control.stories.tsx +1 -1
  399. package/src/components/Select/select.anatomy.stories.tsx +12 -11
  400. package/src/components/Select/select.principles.stories.tsx +3 -3
  401. package/src/components/Select/select.spec.md +34 -8
  402. package/src/components/Select/select.stories.tsx +2 -2
  403. package/src/components/Select/select.tsx +18 -3
  404. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +2 -2
  405. package/src/components/SelectMenu/select-menu.principles.stories.tsx +5 -5
  406. package/src/components/SelectMenu/select-menu.spec.md +19 -12
  407. package/src/components/SelectMenu/select-menu.stories.tsx +34 -27
  408. package/src/components/SelectMenu/select-menu.tsx +14 -3
  409. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  410. package/src/components/SelectionControl/selection-item.spec.md +13 -2
  411. package/src/components/SelectionControl/selection-item.stories.tsx +1 -1
  412. package/src/components/SelectionControl/selection-item.tsx +8 -2
  413. package/src/components/Separator/separator.principles.stories.tsx +2 -2
  414. package/src/components/Separator/separator.spec.md +11 -5
  415. package/src/components/Sheet/sheet.anatomy.stories.tsx +7 -6
  416. package/src/components/Sheet/sheet.principles.stories.tsx +18 -38
  417. package/src/components/Sheet/sheet.spec.md +9 -11
  418. package/src/components/Sheet/sheet.stories.tsx +2 -2
  419. package/src/components/Sheet/sheet.tsx +6 -5
  420. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +42 -33
  421. package/src/components/Sidebar/sidebar.principles.stories.tsx +4 -4
  422. package/src/components/Sidebar/sidebar.spec.md +22 -17
  423. package/src/components/Sidebar/sidebar.stories.tsx +16 -0
  424. package/src/components/Sidebar/sidebar.tsx +15 -7
  425. package/src/components/Skeleton/skeleton.anatomy.stories.tsx +2 -2
  426. package/src/components/Skeleton/skeleton.principles.stories.tsx +20 -7
  427. package/src/components/Skeleton/skeleton.spec.md +6 -4
  428. package/src/components/Skeleton/skeleton.stories.tsx +34 -26
  429. package/src/components/Skeleton/skeleton.tsx +1 -1
  430. package/src/components/Slider/slider.principles.stories.tsx +3 -3
  431. package/src/components/Slider/slider.spec.md +16 -12
  432. package/src/components/Slider/slider.stories.tsx +2 -18
  433. package/src/components/Slider/slider.tsx +6 -2
  434. package/src/components/Steps/steps.anatomy.stories.tsx +3 -3
  435. package/src/components/Steps/steps.principles.stories.tsx +9 -12
  436. package/src/components/Steps/steps.spec.md +31 -25
  437. package/src/components/Steps/steps.stories.tsx +5 -40
  438. package/src/components/Steps/steps.tsx +17 -12
  439. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  440. package/src/components/Switch/switch.spec.md +13 -0
  441. package/src/components/Switch/switch.tsx +3 -3
  442. package/src/components/Tabs/tabs.anatomy.stories.tsx +4 -4
  443. package/src/components/Tabs/tabs.principles.stories.tsx +1 -1
  444. package/src/components/Tabs/tabs.spec.md +13 -6
  445. package/src/components/Tabs/tabs.stories.tsx +3 -3
  446. package/src/components/Tabs/tabs.tsx +2 -2
  447. package/src/components/Tag/tag.anatomy.stories.tsx +15 -15
  448. package/src/components/Tag/tag.principles.stories.tsx +1 -1
  449. package/src/components/Tag/tag.spec.md +25 -5
  450. package/src/components/Textarea/textarea.anatomy.stories.tsx +3 -3
  451. package/src/components/Textarea/textarea.principles.stories.tsx +7 -7
  452. package/src/components/Textarea/textarea.spec.md +15 -3
  453. package/src/components/Textarea/textarea.tsx +1 -1
  454. package/src/components/TimePicker/time-columns.tsx +1 -1
  455. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +8 -2
  456. package/src/components/TimePicker/time-picker.spec.md +23 -3
  457. package/src/components/TimePicker/time-picker.tsx +5 -3
  458. package/src/components/Toast/toast.anatomy.stories.tsx +1 -1
  459. package/src/components/Toast/toast.spec.md +7 -4
  460. package/src/components/Toast/toast.stories.tsx +12 -6
  461. package/src/components/Toast/toast.tsx +1 -1
  462. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +1 -1
  463. package/src/components/Tooltip/tooltip.spec.md +11 -8
  464. package/src/components/Tooltip/tooltip.tsx +1 -1
  465. package/src/components/TreeView/tree-view.anatomy.stories.tsx +25 -9
  466. package/src/components/TreeView/tree-view.principles.stories.tsx +5 -5
  467. package/src/components/TreeView/tree-view.spec.md +11 -9
  468. package/src/components/TreeView/tree-view.stories.tsx +5 -3
  469. package/src/components/TreeView/tree-view.tsx +8 -5
  470. package/src/patterns/action-bar/action-bar.spec.md +11 -4
  471. package/src/patterns/element-anatomy/element-anatomy.spec.md +8 -6
  472. package/src/patterns/element-anatomy/inline-action.spec.md +18 -18
  473. package/src/patterns/element-anatomy/item-anatomy.spec.md +47 -42
  474. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -6
  475. package/src/patterns/element-anatomy/item-anatomy.tsx +3 -3
  476. package/src/patterns/header-canonical/chrome-header.tsx +3 -2
  477. package/src/patterns/header-canonical/header-canonical.spec.md +24 -11
  478. package/src/patterns/header-canonical/header-canonical.stories.tsx +9 -9
  479. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +22 -12
  480. package/src/patterns/overlay-surface/overlay-surface.spec.md +43 -39
  481. package/src/patterns/overlay-surface/overlay-surface.tsx +3 -2
  482. package/src/patterns/resize-handle/resize-handle.spec.md +10 -1
  483. package/src/patterns/resize-handle/resize-handle.stories.tsx +7 -7
  484. package/src/tokens/README.md +5 -2
  485. package/src/tokens/color/color.spec.md +17 -10
  486. package/src/tokens/color/semantic.css +2 -0
  487. package/src/tokens/density/density.spec.md +4 -14
  488. package/src/tokens/elevation/elevation.spec.md +7 -8
  489. package/src/tokens/layoutSpace/layoutSpace.spec.md +20 -27
  490. package/src/tokens/motion/motion.spec.md +15 -7
  491. package/src/tokens/opacity/opacity.spec.md +15 -26
  492. package/src/tokens/orphan-tokens.spec.md +14 -3
  493. package/src/tokens/radius/radius.spec.md +13 -15
  494. package/src/tokens/token-system.spec.md +10 -13
  495. package/src/tokens/typography/typography.spec.md +8 -12
  496. package/src/tokens/uiSize/uiSize.spec.md +28 -16
  497. /package/ds-canonical/hooks/{check_addon_subdir_ship.sh → retired/2026-06-11-prune-merge/check_addon_subdir_ship.sh} +0 -0
  498. /package/ds-canonical/hooks/{check_consumer_app_story_title.sh → retired/2026-06-11-prune-merge/check_consumer_app_story_title.sh} +0 -0
  499. /package/ds-canonical/hooks/{check_consumer_ds_primitive_misuse.sh → retired/2026-06-11-prune-merge/check_consumer_ds_primitive_misuse.sh} +0 -0
  500. /package/ds-canonical/hooks/{check_consumer_no_ds_catalog.sh → retired/2026-06-11-prune-merge/check_consumer_no_ds_catalog.sh} +0 -0
  501. /package/ds-canonical/hooks/{check_consumer_story_baseline.sh → retired/2026-06-11-prune-merge/check_consumer_story_baseline.sh} +0 -0
  502. /package/ds-canonical/hooks/{check_data_table_size_num_to_meta_width.sh → retired/2026-06-11-prune-merge/check_data_table_size_num_to_meta_width.sh} +0 -0
  503. /package/ds-canonical/hooks/{check_fork_user_plugin_install.sh → retired/2026-06-11-prune-merge/check_fork_user_plugin_install.sh} +0 -0
  504. /package/ds-canonical/hooks/{check_plugin_freshness.sh → retired/2026-06-11-prune-merge/check_plugin_freshness.sh} +0 -0
  505. /package/ds-canonical/hooks/{check_propose_cite_required.sh → retired/2026-06-11-prune-merge/check_propose_cite_required.sh} +0 -0
  506. /package/ds-canonical/hooks/{check_propose_plain_chinese.sh → retired/2026-06-11-prune-merge/check_propose_plain_chinese.sh} +0 -0
  507. /package/ds-canonical/hooks/{check_storybook_addon_preset_cjs.sh → retired/2026-06-11-prune-merge/check_storybook_addon_preset_cjs.sh} +0 -0
@@ -44,12 +44,12 @@ prefix icon 跟 label 同色(foreground),不是 fg-muted。詳見 item-ana
44
44
 
45
45
  所有 prefix 元素(checkbox、icon、avatar)共享同一個對齊容器。容器高度決定對齊行為:
46
46
 
47
- | prefix 最大高度 | 容器 | 對齊目標 |
47
+ | prefix 最大高度 | 容器高度(原則) | 對齊目標 |
48
48
  |---|---|---|
49
- | ≤ 24px | `h-[1lh]` | 第一行 label 的垂直中心 |
50
- | > 24px | `h-[calc(1lh+var(--item-gap-label-desc)+desc_1lh)]` | label + gap + description 文字塊的垂直中心 |
49
+ | ≤ 24px | 一行 label 高(inline) | 第一行 label 的垂直中心 |
50
+ | > 24px | label + gap + 一行 description 的文字塊高(block) | 文字塊的垂直中心 |
51
51
 
52
- **SSOT**:對齊公式封裝於 `patterns/element-anatomy/item-anatomy.tsx` 的 `itemPrefixAlignVariants`(2026-04-23 重構)MenuItem 消費此 primitive,不自建對齊邏輯;改 gap token(`--item-gap-label-desc`)或 font-size token 一處 → MenuItem 自動同步。
52
+ **SSOT**:對齊公式(CSS calc 細節)封裝於 `patterns/element-anatomy/item-anatomy.tsx` 的 `itemPrefixAlignVariants`(2026-04-23 重構),spec 不重述公式。MenuItem 消費此 primitive,不自建對齊邏輯;改 gap token(`--item-gap-label-desc-scanning[-lg]`;bare token 已不存在,4 變體見 `layoutSpace.css`)或 font-size token 一處 → MenuItem 自動同步。
53
53
 
54
54
  **24px 是物理限制**——16px icon 在 24px 圓內仍可辨識(內部 icon 下限 12px),但在更小的容器中 icon 會低於可讀閾值。
55
55
 
@@ -183,7 +183,7 @@ Menu item 的 prefix icon 跟 label 同色(foreground),不是 fg-muted。P
183
183
 
184
184
  ## Group
185
185
 
186
- 群組由 `MenuGroup` 包裹,`py-2`(8px)上下內距。群組緊鄰群組,無額外間距。
186
+ 群組由 `MenuGroup` 包裹,`py-2`(8px)上下內距。群組緊鄰群組無額外 margin——相鄰群組由 `[&+&]:border-t border-divider` 自動分隔(上下 py-2 合計 16px 視覺間距;Pattern A,SSOT 見 `item-anatomy.spec.md`「Group auto-separation」)。
187
187
 
188
188
  ### Group Header
189
189
 
@@ -231,6 +231,20 @@ Menu item 的 prefix icon 跟 label 同色(foreground),不是 fg-muted。P
231
231
  - `../DropdownMenu/dropdown-menu.tsx` — 操作選單
232
232
  - 未來:ContextMenu、CommandPalette
233
233
 
234
+ ### 近親分界
235
+
236
+ | | MenuItem(Family 1) | SelectionItem | List item(Family 2) |
237
+ |---|---|---|---|
238
+ | 場景 | 浮層選單 row,掃視挑一個 | form 內 Checkbox / Radio 的 label 佈局 | 內容列表 row,閱讀 |
239
+ | Clamp 預設 | label / desc 各 1 行 | `'none'` 完整閱讀(SSOT 對照表見 `../Checkbox/checkbox.spec.md`「為什麼不像 MenuItem 強制截斷?」) | 依元件(如 FileItem) |
240
+ | SSOT | `item-anatomy.spec.md`「Menu item layout」 | `../SelectionControl/selection-item.spec.md` | `item-anatomy.spec.md`「List item layout」 |
241
+
242
+ ### 常見誤解
243
+
244
+ - 直接 `<MenuItem>` 進 JSX → ❌(失去外層 Radix / cmdk a11y,見上表)
245
+ - 單選選中要加 ✓ 勾號 → ❌,DS 用 `bg-neutral-selected` 高亮(勾號影響 prefix 對齊,見「選中指示器」)
246
+ - suffix 可塞大塊內容 → ❌,實作寫死 inline 對齊只支援 ≤24px(見「Suffix 對齊(實作限制)」)
247
+
234
248
  ---
235
249
 
236
250
  ## 為何無獨立 StateBehavior story
@@ -239,7 +253,7 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
239
253
 
240
254
  獨立 StateBehavior story 會複製 ColorMatrix 內容——MenuItem 的 state 本身就是色彩表達,無額外「時序 / 動畫」可獨立呈現(不像 Accordion 有 expand/collapse 行為)。Inspector 已互動式展示 selected / disabled 單一 variant 的切換。
241
255
 
242
- 對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix`(含完整狀態色矩陣) + `SizeMatrix`。
256
+ 對應 anatomy story:保留 `Overview` + `Inspector` + `ColorMatrix`(含完整狀態色矩陣)+ `SizeMatrix` + `Accessibility`。
243
257
 
244
258
  ---
245
259
 
@@ -248,6 +262,7 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
248
262
  - **Disabled**:`disabled` prop 由 MenuItem primitive own;視覺 `text-fg-disabled`(neutral-6,M24 state>emphasis)、無 hover bg、`aria-disabled="true"`、Enter / click 不觸發 onSelect、鍵盤導覽自動 skip(由 consumer SelectMenu / DropdownMenu / cmdk 處理)。已在「選擇 / 狀態視覺規則」段 codify。
249
263
  - **Loading**:MenuItem 為單一 row primitive 非 async surface,本身不擁有 loading prop。Async option list 的 loading 由 consumer(SelectMenu / Combobox / DropdownMenu)在 list body 替換為 `<Empty icon={<CircularProgress/>}/>`(SelectMenu SSOT)。
250
264
  - **Empty(label-only / icon-only)**:label 為必傳;若無 prefix icon / avatar / checkbox,layout 自動收斂為 `[label] [suffix?]`;若無 suffix(shortcut / endAction / chevron),收斂為純 `[label]`。
265
+ - **極長 label / description**:預設各 clamp 1 行 truncate(見「Clamp 政策」),row 高度恆為兩種之一不被撐高。
251
266
  - **Dark mode**:走 semantic token 自動 adapt。
252
267
  - **Density**:`size` 由 consumer menu(`Menu` block-tier `compact` / `reading`)決定 row height + padding,MenuItem 自身不持 density state。
253
268
 
@@ -282,11 +297,8 @@ MenuItem 的狀態色(default / hover / selected / disabled)是**結構性的**
282
297
 
283
298
  > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
284
299
 
285
- - `opacity.spec.md`
286
-
287
- ## 被引用(auto-maintained,Dim 3 reciprocal audit)
288
-
289
- > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
290
-
300
+ - `dropdown-menu.spec.md`
301
+ - `item-anatomy.spec.md`
302
+ - `select-menu.spec.md`
291
303
  - `selection-item.spec.md`
292
304
  - `sidebar.spec.md`
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @internal — DS-internal 單元(per `.claude/rules/ui-development.md` Public vs Internal canonical;spec frontmatter `isInternal`)。
3
+ * 不進 root barrel front-door;由 DropdownMenu / SelectMenu 等 menu 類 DS 元件 wrap 消費,end-user app 請用 wrapper 元件。
4
+ */
1
5
  // @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.
2
6
  import * as React from 'react'
3
7
  import { cva, type VariantProps } from 'class-variance-authority'
@@ -20,7 +24,7 @@ import { ICON_SIZE, AVATAR_SIZE, ItemContent, itemPrefixAlignVariants, ROW_PADDI
20
24
  *
21
25
  * ── Prefix 對齊規則(24px 閾值)──
22
26
  * prefix ≤ 24px → h-[1lh],對齊第一行 label
23
- * prefix > 24px → h-[calc(1lh+var(--item-gap-label-desc)+desc_1lh)],對齊文字區塊
27
+ * prefix > 24px → h-[calc(1lh+var(--item-gap-label-desc-scanning)+desc_1lh)](size-aware -scanning[-lg] 變體),對齊文字區塊
24
28
  * 無 description → prefix 上限 24px
25
29
  *
26
30
  * ── Size ──
@@ -86,7 +90,7 @@ export interface MenuItemProps
86
90
  * Label 最大行數(line-clamp 截斷,超過顯示 ellipsis)。
87
91
  *
88
92
  * - `undefined`(預設 prop 值未傳)→ 套用元件預設 `1`(單行截斷,符合選單快速掃視需求)
89
- * - 數字 → 截斷到該行數
93
+ * - 數字(1-6)→ 截斷到該行數;>6 超出 line-clamp utility 支援範圍 不截斷(同 'none',見 lineClampClass)
90
94
  * - `'none'` → **明確**不截斷,自然 wrap 任意行數
91
95
  *
92
96
  * 為什麼用 `'none'` 而不是 `undefined` 表達不截斷?React props 的 destructure default
@@ -98,7 +102,7 @@ export interface MenuItemProps
98
102
  * Description 最大行數。
99
103
  *
100
104
  * - `undefined`(預設 prop 值未傳)→ 套用元件預設 `1`(跟 label 對稱,維持掃視節奏)
101
- * - 數字 → 截斷到該行數
105
+ * - 數字(1-6)→ 截斷到該行數;>6 超出 line-clamp utility 支援範圍 不截斷(同 'none',見 lineClampClass)
102
106
  * - `'none'` → 明確不截斷
103
107
  *
104
108
  * 為什麼預設 1?Menu 的設計目的是「快速掃視多個選項挑一個」,垂直空間是
@@ -26,19 +26,19 @@ export const UsageGuidance: Story = {
26
26
  <p>適合 Notice 的真實業務場景(點擊跳轉「展示」頁範例):</p>
27
27
  <ul className="space-y-1">
28
28
  <li>
29
- <LinkTo kind="Design System/Internal/Notice/展示" name="部署成功 橫幅"><span className="text-primary hover:underline font-medium cursor-pointer">部署成功 橫幅</span></LinkTo>
29
+ <LinkTo kind="Design System/Internal/Notice/展示" name="部署成功 橫幅"><span className="text-primary hover:underline font-medium cursor-pointer">CI/CD 部署成功橫幅 — 附「查看部署紀錄」動作</span></LinkTo>
30
30
  </li>
31
31
  <li>
32
- <LinkTo kind="Design System/Internal/Notice/展示" name="工作區付款失敗"><span className="text-primary hover:underline font-medium cursor-pointer">Workspace 付款失敗</span></LinkTo>
32
+ <LinkTo kind="Design System/Internal/Notice/展示" name="工作區付款失敗"><span className="text-primary hover:underline font-medium cursor-pointer">工作區付款失敗 — 附「更新付款方式」補救動作</span></LinkTo>
33
33
  </li>
34
34
  <li>
35
- <LinkTo kind="Design System/Internal/Notice/展示" name="行內通知變體對照"><span className="text-primary hover:underline font-medium cursor-pointer">行內通知變體對照</span></LinkTo>
35
+ <LinkTo kind="Design System/Internal/Notice/展示" name="行內通知變體對照"><span className="text-primary hover:underline font-medium cursor-pointer">方案限制 / 空間不足 / 連線失敗等行內提示(五種語意變體)</span></LinkTo>
36
36
  </li>
37
37
  <li>
38
- <LinkTo kind="Design System/Internal/Notice/展示" name="Toast 樣式"><span className="text-primary hover:underline font-medium cursor-pointer">Toast 樣式</span></LinkTo>
38
+ <LinkTo kind="Design System/Internal/Notice/展示" name="Toast 樣式"><span className="text-primary hover:underline font-medium cursor-pointer">「變更已儲存」「已複製連結」Toast 短暫提示</span></LinkTo>
39
39
  </li>
40
40
  <li>
41
- <LinkTo kind="Design System/Internal/Notice/展示" name="中性 純文字"><span className="text-primary hover:underline font-medium cursor-pointer">Neutral 純文字</span></LinkTo>
41
+ <LinkTo kind="Design System/Internal/Notice/展示" name="中性 純文字"><span className="text-primary hover:underline font-medium cursor-pointer">成員邀請待加入提醒 — 中性純文字</span></LinkTo>
42
42
  </li>
43
43
  </ul>
44
44
  <p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見下方 vs 近親段落)。</p>
@@ -47,7 +47,7 @@ export const UsageGuidance: Story = {
47
47
  <Section title="何時不用 + 替代">
48
48
  <p>Notice 是 internal primitive,自身有 dismiss 按鈕 + <code>onDismiss</code> callback,但不管 dismiss 後的 mount / unmount 生命週期,也無 auto-dismiss 計時——需要這些行為改用以下 consumer:</p>
49
49
  <ul>
50
- <li><strong>需要管理 dismiss 後移除(永久 inline)</strong> → 用 <code>Alert</code>(內部消費 Notice + 處理 unmount + role="alert")</li>
50
+ <li><strong>需要管理 dismiss 後移除(永久 inline)</strong> → 用 <code>Alert</code>(內部消費 Notice + 處理 unmount + live region:error/warning role="alert"、其餘 role="status")</li>
51
51
  <li><strong>需要 auto-dismiss(短暫 toast)</strong> → 用 <code>Toast</code></li>
52
52
  <li><strong>表單欄位錯誤訊息</strong> → 用 <code>Field</code> 內建 errorText,不用 Notice</li>
53
53
  </ul>
@@ -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:underline font-medium cursor-pointer">Subtle 單行</span></LinkTo>。Alert 內部消費 Notice + 加上 dismiss button + role="alert" ARIA。</p>
77
+ <p>需要「持續顯示直到 user 主動 dismiss」→ <LinkTo kind="Design System/Components/Alert/展示" name="低調單行"><span className="text-primary hover:underline 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>
@@ -25,7 +25,7 @@ Notice 是純視覺 primitive,不是獨立使用的元件。消費者:
25
25
 
26
26
  **Layout Family**:CLAUDE.md 4-Family Model **Family 2(List item layout)** 消費者。結構繼承 `patterns/element-anatomy/item-anatomy.spec.md`「List item layout」章節的 reading-mode 規格。Notice 語意為 notification(非 row collection),但視覺排版遵循 Family 2 確保跨元件視覺一致。
27
27
 
28
- **尺寸偏離(documented exception)**:Notice / Alert / Toast **單一固定 size**,**不**實作 Family 2 baseline 的 sm/md/lg。世界級共識(Material Banner/Snackbar、Polaris Banner、Atlassian InlineMessage、GitHub Flash)都是**單一 prominent size**——通知的使命是「搶注意」而非「在密度選擇裡協調」,提供 size 選項反而會讓 consumer 糾結(該用哪個 size?)而稀釋元件的目的性。同理 padding 也不隨 density 變(`px-4 py-3` 固定)——通知是跨 density 一致的訊息載體。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
28
+ **尺寸偏離(documented exception)**:Notice / Alert / Toast **單一固定 size**——不實作 Family 2 baseline 的 sm/md/lgpadding 也不隨 density 變(`px-4 py-3` 固定)。通知用單一 prominent size 強化「搶注意」的目的性,對齊世界級共識(Material Banner/Snackbar、Polaris Banner、Atlassian InlineMessage、GitHub Flash)。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
29
29
 
30
30
  ## Typography
31
31
 
@@ -107,7 +107,7 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
107
107
  - **無 SizeMatrix**:Notice / Alert / Toast **單一固定 size**(見本 spec「尺寸偏離」段),不實作 Family 2 baseline 的 sm/md/lg——通知的使命是「搶注意」而非「在密度選擇裡協調」。padding 固定 `px-4 py-3`,typography 固定 md tier(14px),不隨 density 變。
108
108
  - **無 ColorMatrix**:Notice 本身**不設 bg / text color**(見本 spec「Theme 策略」段),色彩完全由 consumer(Alert / Toast)透過 `data-theme` + `text-foreground` 控制。Notice 層級的色彩矩陣沒有意義——視覺對照屬於 consumer 的職責,應查 `alert.anatomy.stories.tsx` 與 `toast.anatomy.stories.tsx` 的 ColorMatrix。
109
109
 
110
- 對應 anatomy story:保留 `Overview` / `Inspector` / `StateBehavior`,額外追加元件特有的 `VariantIconMap`(展示 5 種 variant 對應的 status icon + 語意)。
110
+ 對應 anatomy story:保留 `Overview` / `Inspector` / `StateBehavior` / `Accessibility`,額外追加元件特有的 `VariantIconMap`(展示 5 種 variant 對應的 status icon + 語意)。
111
111
 
112
112
  ---
113
113
 
@@ -115,7 +115,7 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
115
115
 
116
116
  - **Disabled(dismiss button)**:Notice 本身不擁有 disabled state(internal primitive,無互動);內嵌的 `<Button iconOnly dismiss size="xs" />` 在 disabled context 內會自動繼承 Button disabled 視覺(`text-fg-disabled` + `cursor-not-allowed`)。Notice **不提供 disable dismiss 的 API**——`...props` 只 spread 到 root `<div>`,dismiss `<Button>` 不接收 / 不 forward 任何 consumer disabled prop,無 consumer-level prop pass-through 可停用 dismiss。對齊消費者 canonical(`../Alert/alert.spec.md`「Disabled(dismiss button)」:banner dismiss 恆可用,對齊 Polaris / Material Banner「通知關閉鈕應永遠可按」);若需防止 close action(API in-flight)被雙擊,consumer 在 `onDismiss` 內自行 debounce / 加上層鎖,不在 UI 層暴露 disabled 透傳。
117
117
  - **Loading**:Notice 非 async surface,無 loading state。Body 內若 consumer 注入 CTA Button,該 Button 自行處理 loading。
118
- - **Empty**:Notice 的 `title` 為必填(消費合約),`description` 選填;layout 至少 1 行 title 內容。`neutral` variant 不渲 status icon 時即為 title-only icon-less 形態(見 `NeutralTitleOnly` story),仍合法 render。
118
+ - **Empty**:Notice 的 `title` 為必填(TypeScript required prop,消費合約),`description` 選填;layout 至少 1 行 title 內容。誤傳空字串時照常 render(無 runtime warn / throw),空 title 的內容責任在 consumer(Alert / Toast)。`neutral` variant 不渲 status icon 時即為 title-only icon-less 形態(見 `NeutralTitleOnly` story),仍合法 render。
119
119
  - **Icon-only / variant=neutral**:`neutral` variant 不渲 status icon,layout 自動收斂為 `[title + description?] [endContent?] [dismiss X?]` 三 slot。
120
120
 
121
121
  ---
@@ -137,9 +137,9 @@ Notice 是 **Toast / Alert 共用的 layout primitive**,刻意不擁有尺寸與
137
137
  - Tab — focus dismiss button(若 dismissible)
138
138
  - Enter / Space — 觸發 focus 中的 dismiss button(原生 button 行為,呼叫 `onDismiss`)
139
139
 
140
- Notice **不**自帶 Esc-to-dismiss 行為(`notice.tsx` 無 keydown handler);dismiss 純粹由 dismiss button 的 `onClick={onDismiss}` 觸發。若 consumer(Alert / Toast)需要 Esc 關閉,於 consumer 層自行掛 keydown。
140
+ Notice **不**自帶 Esc-to-dismiss 行為(`notice.tsx` 無 keydown handler);dismiss 純粹由 dismiss button 的 `onClick={onDismiss}` 觸發。若 consumer(Alert / Toast)需要 Esc 關閉,於 consumer 層自行掛 keydown。Dismiss 後的焦點處置 Notice 同樣不管理(無 focus restoration 邏輯)——節點移除後焦點落點由 consumer(Alert / Toast host)決定。
141
141
 
142
- **Focus**:focus-visible ring 對齊 DS canonical(`outline: 2px solid var(--ring)`);focus management 由元件 own
142
+ **Focus**:唯一 focusable 元素是 dismiss `<Button>`,focus indicator Button canonical(`focus-visible:ring-2 ring-ring`,box-shadow ring 非 CSS `outline`);Notice 本身無 focus management(dismiss 後焦點處置見上段,由 consumer 決定)
143
143
 
144
144
  **驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
145
145
 
@@ -147,5 +147,7 @@ Notice **不**自帶 Esc-to-dismiss 行為(`notice.tsx` 無 keydown handler);dis
147
147
 
148
148
  > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
149
149
 
150
+ - `alert.spec.md`
150
151
  - `bulk-action-bar.spec.md`
151
152
  - `coachmark.spec.md`
153
+ - `toast.spec.md`
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @internal — DS-internal 單元(per `.claude/rules/ui-development.md` Public vs Internal canonical;spec frontmatter `isInternal`)。
3
+ * 不進 root barrel front-door;由 Alert / Toast wrap 消費,end-user app 請用 wrapper 元件。
4
+ */
1
5
  import * as React from 'react'
2
6
  import { X as XIcon, Info, CircleCheck, TriangleAlert, XCircle, type LucideIcon } from 'lucide-react'
3
7
  import { cn } from '@/lib/utils'
@@ -186,7 +190,7 @@ export const noticeMeta = {
186
190
  sizes: {
187
191
 
188
192
  },
189
- states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],
193
+ states: ['default'], // 無互動 layout primitive(spec「邊界案例」:不擁有 disabled;hover / focus 屬內嵌 dismiss Button)
190
194
  tokens: {
191
195
  bg: [],
192
196
  fg: ['text-error-text', 'text-fg-muted', 'text-fg-secondary', 'text-info-text', 'text-success-text', 'text-warning-text'],
@@ -45,7 +45,7 @@ const TOKEN_MAP: Record<ModeKey, Record<StateKey, ColorSpec>> = {
45
45
  disabled: { bg: 'transparent', text: '--fg-disabled', border: 'transparent' },
46
46
  },
47
47
  readonly: {
48
- default: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
48
+ default: { bg: '--bg-readonly', text: '--foreground', border: 'transparent' },
49
49
  hover: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
50
50
  focus: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
51
51
  error: { bg: '--bg-disabled', text: '--foreground', border: 'transparent' },
@@ -254,8 +254,8 @@ export const Overview = {
254
254
  ['precision', 'number', '—', '小數位數'],
255
255
  ['locale', 'string', "'en-US'", '數字格式 locale'],
256
256
  ['endAction', 'InlineActionConfig', '—', '右側 inline action(宣告式 API)'],
257
- ['disabled', 'boolean', 'false', '原生屬性,自動覆蓋 mode disabled'],
258
- ['readOnly', 'boolean', 'false', '原生屬性,自動覆蓋 mode readonly'],
257
+ ['disabled', 'boolean', 'false', '原生屬性;mode 未顯式指定時解析為 disabled(顯式 mode prop 永遠最優先,useResolvedFieldMode SSOT)'],
258
+ ['readOnly', 'boolean', 'false', '原生屬性;mode 未顯式指定且無 Field context mode 時解析為 readonly(優先序 mode > 有效 disabled > fieldCtx.mode > readOnly)'],
259
259
  ].map(([p, t, d, desc]) => (
260
260
  <tr key={p}><Td mono>{p}</Td><Td mono>{t}</Td><Td mono>{d}</Td><Td>{desc}</Td></tr>
261
261
  ))}
@@ -760,7 +760,7 @@ export const StateBehavior = {
760
760
  ['type="text" inputMode="decimal"', '用 text 而非 number,避免瀏覽器 spinner 干擾'],
761
761
  ['空字串 / "-" → onChange(null)', '清空或只剩負號時回傳 null'],
762
762
  ['NaN 忽略', '非數字輸入不觸發 onChange'],
763
- ['disabled / readOnly 原生屬性覆蓋 mode', 'disabled → mode="disabled", readOnly → mode="readonly"'],
763
+ ['disabled / readOnly 參與 mode 推導', 'mode 未顯式指定時:有效 disabled → "disabled"readOnly 排在 Field context mode 之後 → "readonly"(顯式 mode prop 永遠最優先,useResolvedFieldMode)'],
764
764
  ].map(([rule, desc]) => (
765
765
  <tr key={rule}><Td mono>{rule}</Td><Td>{desc}</Td></tr>
766
766
  ))}
@@ -71,7 +71,7 @@ export const UsageGuidance: Story = {
71
71
  <Section title="vs 近親元件">
72
72
  <Rule
73
73
  title="❌ 不用 NumberInput 做電話號碼或郵遞區號 → Input"
74
- note="電話不是算術數字。改用 Input + type='tel'Stripe 的電話欄用 Input,不用 NumberInput(不該加千分位或用 step)"
74
+ note="電話、郵遞區號、身分證字號、產品代碼都「長得像數字」但不是算術型 value——不做加減、不做千分位、不做 step。改用 Input + type='tel' / pattern(Stripe 的電話欄用 Input)。用 NumberInput 會錯誤套用千分位、吃掉前導零,且誤導 mobile 彈出數字鍵盤"
75
75
  >
76
76
  <NumberInput mode="readonly" value={912345678} />
77
77
  <Label warn>↑ 電話 0912-345-678 被當數值,顯示時加上千分位 912,345,678 → 數字意義錯誤(前導零也被吃掉)</Label>
@@ -94,6 +94,14 @@ export const UsageGuidance: Story = {
94
94
  <NumberInput mode="readonly" value={85.5} suffix="%" precision={1} />
95
95
  <NumberInput mode="readonly" value={12500} />
96
96
  </Rule>
97
+
98
+ <Rule
99
+ title="❌ 不用 Input 顯示數字"
100
+ note="即使值看起來「就是數字字串」,缺少格式化會讓大數字不可讀(1234567 vs 1,234,567)。Edit 與 Display 分離是 Field 設計的基本前提——用 NumberInput 兩者都得到"
101
+ >
102
+ <Input defaultValue="1234567" />
103
+ <Label warn>↑ 1234567 難讀、無貨幣前綴、無 locale、無右對齊</Label>
104
+ </Rule>
97
105
  </Section>
98
106
  </div>
99
107
  ),
@@ -153,7 +161,7 @@ export const FormatOptionsRule: Story = {
153
161
  <div>
154
162
  <Rule
155
163
  title="prefix — 置於數字前的符號(貨幣是最常見場景)"
156
- note="prefix 會同時出現在 edit、readonlyDataTable cell。使用者不需要自己輸入 $——打字就是純數字"
164
+ note="prefix 出現在 readonly / display / disabled 與 DataTable cell 的格式化值;edit 模式輸入 raw 純數字、不渲染 prefix——使用者不需要自己輸入 $"
157
165
  >
158
166
  <NumberInput mode="readonly" value={2490} prefix="$" />
159
167
  <NumberInput mode="readonly" value={12500} prefix="NT$" precision={0} />
@@ -186,36 +194,6 @@ export const FormatOptionsRule: Story = {
186
194
  ),
187
195
  }
188
196
 
189
- export const DataTypeMatchRule: Story = {
190
- name: '數字一律用 NumberInput',
191
- render: () => (
192
- <div>
193
- <Rule
194
- title="所有數值資料都用 NumberInput——不用 Input type=number"
195
- note="NumberInput 提供:千分位格式化、locale 切換、prefix/suffix、precision、edit 左 / table 右 對齊、DataTable 自動整合。原生 input type=number 這些都沒有"
196
- >
197
- <NumberInput mode="readonly" value={1234567} prefix="$" />
198
- <NumberInput mode="readonly" value={85.5} suffix="%" precision={1} />
199
- <NumberInput mode="readonly" value={12500} />
200
- </Rule>
201
-
202
- <Rule
203
- title="❌ 不用 Input 顯示數字"
204
- note="即使值看起來「就是數字字串」,缺少格式化會讓大數字不可讀(1234567 vs 1,234,567)。Edit 與 Display 分離是 Field 設計的基本前提——用 NumberInput 兩者都得到"
205
- >
206
- <Input defaultValue="1234567" />
207
- <Label warn>↑ 1234567 難讀、無貨幣前綴、無 locale、無右對齊</Label>
208
- </Rule>
209
-
210
- <Rule
211
- title="❌ 看起來像數字但不是算術型的資料:用 Input"
212
- note="電話、郵遞區號、身分證字號、產品代碼都「長得像數字」但不是算術型 value——不做加減、不做千分位、不做 step。用 NumberInput 會錯誤套用千分位(0912-345-678 變成「912,345,678」)、誤導 mobile 彈出數字鍵盤且關閉符號輸入"
213
- >
214
- <NumberInput mode="readonly" value={912345678} />
215
- <Label warn>↑ 電話 0912-345-678 被當數值,顯示時加上千分位 912,345,678 → 數字意義錯誤(前導零也被吃掉)</Label>
216
- <Input defaultValue="0912-345-678" />
217
- <Label>↑ 電話用 Input(可自訂 type=tel 或 pattern),保留 dash / 前導零</Label>
218
- </Rule>
219
- </div>
220
- ),
221
- }
197
+ // @story-trait-rationale: DataTypeMatchRule(數字一律用 NumberInput)retired 2026-06-11 per audit Dim 24/25 —
198
+ // 與 UsageGuidance「vs 近親元件」段完整重複(✅ NumberInput-over-Input / ❌ 電話號碼非算術型);
199
+ // 唯一未覆蓋的「❌ 不用 Input 顯示數字」與「非算術型資料」完整 note 已折入 UsageGuidance。
@@ -19,6 +19,10 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
19
19
 
20
20
  共用規則見 `../Field/field-controls.spec.md`。本文件只記錄 NumberInput 特有的原則。
21
21
 
22
+ ## Controlled-only rationale(Dim 26)
23
+
24
+ 本元件採 **controlled-only**:`value` + `onChange`,不支援 `defaultValue` uncontrolled fallback(value pair V1)。對齊 Field 家族 canonical(Combobox / DatePicker / TimePicker / SelectMenu 同,rationale 見各 spec 同名段);NumberInput 另因 raw 輸入 ↔ 格式化值的 parse pipeline 以 `null` 為空值 sentinel,dual-mode 會複製 parse 狀態。未來要改 dual-mode 需 `useControllableState` helper,屬 major API 擴充。
25
+
22
26
  **Layout Family**:CLAUDE.md 4-Family Model **Family 4(Field control layout)** 消費者。結構繼承 `components/Field/field-controls.spec.md` 的 `fieldWrapperStyles + [startIcon?] [<editable>] [endAction?]` 規格,視覺對齊 Family 1(Menu item)讓 SelectMenu trigger + options 連續一致。
23
27
 
24
28
  ---
@@ -39,6 +43,8 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
39
43
  | 視覺調整數值(音量、亮度、滑動調整)| `Slider` | 使用者目標是「感受」而非「輸入精確值」 |
40
44
  | 大量帶小數的科學計算 | `Input` + 自訂驗證 | 極端精度需求超出 NumberInput 格式化能力 |
41
45
 
46
+ **常見誤解**:(1)「看起來像數字」≠ 數值——電話 / 郵遞區號 / 身分證號用 `Input`(見上表);(2)百分比 value 直接存 `85` 非 `0.85`,`suffix='%'` 純顯示;(3)NumberInput **無** step ↑↓ stepper——純值輸入,加減互動走 `endSlot`(見禁止事項)。
47
+
42
48
  ---
43
49
 
44
50
  ## 格式化選項
@@ -50,6 +56,8 @@ NumberInput 是**數值的**輸入與顯示元件。格式化邏輯:`toLocaleS
50
56
  | `precision` | 小數位數 | `85.50` |
51
57
  | `locale` | 數字格式 locale | 預設 `en-US` |
52
58
 
59
+ 千分位**無獨立 prop**——由 `toLocaleString(locale)` 自動產生(含負號與超大數字分組)。「何時用」列的四種格式化(千分位 / 前綴 / 後綴 / 精度)= 上表 3 個 prop + 此預設行為的映射。
60
+
53
61
  ## 對齊
54
62
 
55
63
  - **Edit 模式(input)**:靠左——input 內打字是左到右
@@ -99,6 +107,10 @@ col.accessor('price', {
99
107
  - **Loading**:NumberInput 不提供 loading state(`NumberInputProps` 無 `loading` prop、無 `CircularProgress` / `aria-busy` 邏輯)。數值輸入為同步操作,無 async fetch 語意;若需 async 場景(如遠端校驗)請走外層 Field validation + `endSlot` 自訂 spinner。
100
108
  - **Empty(null / undefined / 空字串)**:Display mode 渲 `—`(em dash + `text-fg-muted`);Edit mode placeholder 走 default placeholder color。
101
109
  - **Invalid input**(non-numeric):input 為 `type="text" inputMode="decimal"`,onChange 以 `Number(raw)` parse,NaN 時忽略不觸發 `onChange`(value 維持原值);搭配 Field validation 渲 error variant(`aria-invalid="true"` + `text-fg-error` border + 下方 error message)。
110
+ - **負數 / 超大數字**:`toLocaleString(locale)` 自動處理負號與千分位分組,無特殊 prop。
111
+ - **科學記號輸入**(`1e5`):`Number(raw)` parse 為 `100000`,非 NaN 即觸發 `onChange`(`number-input.tsx:136-138`)。
112
+ - **精度上限**:`precision` > 6 為禁止事項(浮點精度雜訊),極端精度走 `Input` + 自驗證。
113
+ - **RTL**:未實作方向鏡像(edit 靠左 / table cell 靠右皆以 LTR 設計);RTL 屬 DS-wide 決策,未定(與 Chip / Breadcrumb 同口徑)。
102
114
  - **Dark mode / density**:走 Field SSOT,不獨立 own。
103
115
 
104
116
  ---
@@ -123,3 +135,10 @@ col.accessor('price', {
123
135
 
124
136
  **驗證**:Storybook a11y addon panel 應 0 critical violation;鍵盤完整可操作(無需滑鼠)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
125
137
 
138
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
139
+
140
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
141
+
142
+ - `date-picker.spec.md`
143
+ - `input.spec.md`
144
+ - `slider.spec.md`
@@ -4,7 +4,8 @@
4
4
  // ShapeMatrix(3.)已對照 shape × 色彩 token + consumer 場景。HoverCard
5
5
  // content 走深色 tooltip,色彩繼承 tooltip token。
6
6
  // StateBehavior N/A — Trigger pill 本身無 hover 視覺(hover 觸發 HoverCard
7
- // 展開即是 state 表達);無 focus / active / disabled。openDelay /
7
+ // 展開即是 state 表達);無 active / disabled;focus-visible ring 屬 a11y
8
+ // focusable 修正(2026-06-01 #13,見 Accessibility story)非獨立視覺軸。openDelay /
8
9
  // closeDelay 等行為已於 Inspector 展示。HoverCard 內容互動由消費的內容
9
10
  // 元件(Avatar / Tag)各自負責。
10
11
  import type { Meta, StoryObj } from '@storybook/react'
@@ -321,7 +322,7 @@ function OverflowInspector() {
321
322
  </tr>
322
323
  <tr>
323
324
  <Td mono>openDelay</Td>
324
- <Td mono>700msHOVER_DELAY_RICH_MS)</Td>
325
+ <Td mono>500msHOVER_DELAY_PLAIN_MS)</Td>
325
326
  </tr>
326
327
  <tr>
327
328
  <Td mono>closeDelay</Td>
@@ -542,7 +543,7 @@ export const Accessibility = {
542
543
  render: () => (
543
544
  <div className="max-w-3xl text-body text-fg-secondary">
544
545
  <h3 className="text-h5 text-foreground mb-2">無障礙設計</h3>
545
- <p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 passive 計數 span(cursor-default,無 tabIndex / role / Enter handler)。HoverCard 在 hover 或 trigger 取得 focus 時自動展開,沒有「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。\n\n Focus :trigger 本身不是 tab stopHoverCard 內展開的可互動內容(人員 tag / ProfileCard)由各自內容元件負責 focus 管理。\n\n 驗證 :Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。"}</p>
546
+ <p className="whitespace-pre-line">{"摘要:\n\n ARIA / Pattern :對齊 [W3C ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/patterns/) 對應 pattern。\n\n 互動行為 :\n\n +N trigger 是 keyboard-focusable 計數 span(tabIndex=0 + role=\"button\" + aria-haspopup=\"dialog\";2026-06-01 #13 由純 passive 改 focusable,修 WCAG 2.1.1 違反)。HoverCard 在 hover 或 trigger 取得 focus 時自動展開,沒有「按 Enter 開選單」的鍵盤指令,也沒有 click 切換。\n\n Focus :trigger tab stop(focus-visible ring,鍵盤使用者可 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的可互動內容(人員 tag / ProfileCard)由各自內容元件負責 focus 管理。\n\n 驗證 :Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。"}</p>
546
547
  </div>
547
548
  ),
548
549
  }
@@ -27,10 +27,7 @@ export const UsageGuidance: Story = {
27
27
  <LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="Combobox 標籤溢出"><span className="text-primary hover:underline font-medium cursor-pointer">Combobox 標籤溢出</span></LinkTo>
28
28
  </li>
29
29
  <li>
30
- <LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="人員頭像 疊合 +N"><span className="text-primary hover:underline font-medium cursor-pointer">人員頭像 疊合 +N</span></LinkTo>
31
- </li>
32
- <li>
33
- <LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="形狀對照"><span className="text-primary hover:underline font-medium cursor-pointer">形狀對照</span></LinkTo>
30
+ <LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="人員頭像 疊合 +N"><span className="text-primary hover:underline font-medium cursor-pointer">PR reviewer 頭像疊合 +N(只顯前 3 位)</span></LinkTo>
34
31
  </li>
35
32
  <li>
36
33
  <LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="Breadcrumb 中段收合"><span className="text-primary hover:underline font-medium cursor-pointer">Breadcrumb 中段收合</span></LinkTo>
@@ -39,7 +36,7 @@ export const UsageGuidance: Story = {
39
36
  <LinkTo kind="Design System/Internal/OverflowIndicator/展示" name="DataTable 人員欄位"><span className="text-primary hover:underline font-medium cursor-pointer">DataTable 人員欄位</span></LinkTo>
40
37
  </li>
41
38
  </ul>
42
- <p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件( <code>Vs*Rule</code> stories)。</p>
39
+ <p className="text-fg-muted mt-3">判斷不確定時:對照 spec.md「何時用 / 何時不用」段;若仍不符,改用近親元件(見下方 vs 近親段落)。</p>
43
40
  </div>
44
41
 
45
42
  {/* vs 近親 — VsScrollAreaRule — 原 VsScrollAreaRule */}
@@ -67,6 +67,15 @@ sm / md 跟 Tag 同階(20/24px),lg 對齊 md(尺寸需求一致,不需
67
67
 
68
68
  ---
69
69
 
70
+ ## 邊界案例
71
+
72
+ - **count ≤ 0**:元件自行不渲染(return `null`)——「無溢出」時 consumer 不需條件渲染
73
+ - **大數值**:`+N` 原樣顯示(無 `99+` 縮寫),trigger `min-w` 起步、隨位數自然加寬
74
+ - **極窄容器 / 貼 viewport 邊**:浮層定位與翻邊由 HoverCard(Radix collision)處理,見 `hover-card.spec.md`
75
+ - **已展開時項目變動**:children 變動觸發浮層寬度重新量測(shrink-wrap re-measure)
76
+
77
+ ---
78
+
70
79
  ## 禁止事項
71
80
 
72
81
  - ❌ 用 Tooltip 取代 HoverCard——溢出內容可能需要互動
@@ -116,4 +125,3 @@ OverflowIndicator 是 **composite**(HoverCard trigger + tag-styled `+N` span + H
116
125
  **Focus**:trigger 是 tab stop(keyboard 可達 + focus-visible ring,讓鍵盤使用者也能 focus 開啟 HoverCard 看溢出內容);HoverCard 內展開的可互動內容(如人員 tag / ProfileCard)由各自的內容元件負責 focus 管理。
117
126
 
118
127
  **驗證**:Storybook a11y addon panel 應 0 critical violation;HoverCard 內容透過 hover 或 focus 自動顯示(非鍵盤指令觸發)。WCAG AA contrast ≥ 4.5:1(text)/ 3:1(UI)。
119
-
@@ -120,49 +120,13 @@ export const AvatarStackOverflow: Story = {
120
120
  ),
121
121
  }
122
122
 
123
- /* ═══════════════════════════════════════════════════════════════════════════
124
- Story 3:形狀對照(circle vs tag)
125
- ═══════════════════════════════════════════════════════════════════════════ */
126
-
127
- export const Shapes: Story = {
128
- name: '形狀對照',
129
- render: () => (
130
- <div className="flex flex-col gap-6">
131
- <div className="flex flex-col gap-2">
132
- <span className="text-caption text-fg-muted">shape="circle" — 搭配 Avatar stack 用,圓形 pill</span>
133
- <div className="flex items-center gap-3">
134
- <OverflowIndicator count={3} shape="circle" size="sm">
135
- <div className="text-caption">sm 20px</div>
136
- </OverflowIndicator>
137
- <OverflowIndicator count={12} shape="circle" size="md">
138
- <div className="text-caption">md 24px</div>
139
- </OverflowIndicator>
140
- <OverflowIndicator count={99} shape="circle" size="lg">
141
- <div className="text-caption">lg 24px</div>
142
- </OverflowIndicator>
143
- </div>
144
- </div>
145
-
146
- <div className="flex flex-col gap-2">
147
- <span className="text-caption text-fg-muted">shape="tag" — 搭配 Tag 組溢出,rounded-md rectangle</span>
148
- <div className="flex items-center gap-3">
149
- <OverflowIndicator count={3} shape="tag" size="sm">
150
- <div className="text-caption">sm Tag 樣式</div>
151
- </OverflowIndicator>
152
- <OverflowIndicator count={12} shape="tag" size="md">
153
- <div className="text-caption">md Tag 樣式</div>
154
- </OverflowIndicator>
155
- <OverflowIndicator count={99} shape="tag" size="lg">
156
- <div className="text-caption">lg Tag 樣式</div>
157
- </OverflowIndicator>
158
- </div>
159
- </div>
160
- </div>
161
- ),
162
- }
123
+ // @story-trait-rationale: Shapes(形狀對照)retired 2026-06-11 per audit Dim 24/25 —
124
+ // shape × size 全矩陣已由 anatomy ShapeMatrix「Shape × Size 視覺矩陣」+ SizeMatrix
125
+ // (overflow-indicator.anatomy.stories.tsx)完整覆蓋,展示層只留真實業務場景;
126
+ // principles UsageGuidance 對應 LinkTo 已同步移除。
163
127
 
164
128
  /* ═══════════════════════════════════════════════════════════════════════════
165
- Story 4:Breadcrumb 中段收合(+N 顯示隱藏路徑)
129
+ Story 3:Breadcrumb 中段收合(+N 顯示隱藏路徑)
166
130
  ═══════════════════════════════════════════════════════════════════════════ */
167
131
 
168
132
  export const BreadcrumbCollapse: Story = {
@@ -192,7 +156,7 @@ export const BreadcrumbCollapse: Story = {
192
156
  }
193
157
 
194
158
  /* ═══════════════════════════════════════════════════════════════════════════
195
- Story 5:DataTable row 的指派人員溢出
159
+ Story 4:DataTable row 的指派人員溢出
196
160
  ═══════════════════════════════════════════════════════════════════════════ */
197
161
 
198
162
  const rows = [
@@ -1,8 +1,12 @@
1
+ /**
2
+ * @internal — DS-internal 單元(per `.claude/rules/ui-development.md` Public vs Internal canonical;spec frontmatter `isInternal`)。
3
+ * 不進 root barrel front-door;由 Combobox / PeoplePicker 等 DS 元件 wrap 消費,end-user app 請用 wrapper 元件。
4
+ */
1
5
  import * as React from 'react'
2
6
  import { cn } from '@/lib/utils'
3
7
  import { HoverCard, HoverCardTrigger, HoverCardContent } from '@/design-system/components/HoverCard/hover-card'
4
8
  import { tagVariants } from '@/design-system/components/Tag/tag'
5
- import { HOVER_DELAY_RICH_MS, HOVER_DELAY_CLOSE_MS } from '@/design-system/tokens/motion/motion'
9
+ import { HOVER_DELAY_PLAIN_MS, HOVER_DELAY_CLOSE_MS } from '@/design-system/tokens/motion/motion'
6
10
 
7
11
  /**
8
12
  * OverflowIndicator — +N 觸發器 + HoverCard 顯示溢出內容
@@ -126,9 +130,11 @@ const OverflowIndicator = React.forwardRef<HTMLSpanElement, OverflowIndicatorPro
126
130
  )
127
131
 
128
132
  // 2026-05-18 fix(per user audit「所有 hovercard 應消費 hover delay token」+ motion.spec.md SSOT):
129
- // rich tier(可互動 popup,user 可移浮層上操作)= HOVER_DELAY_RICH_MS;close = HOVER_DELAY_CLOSE_MS。
133
+ // plain tier(純列表展開、無 fetch)= HOVER_DELAY_PLAIN_MS,per motion.spec.md 對照表 row;
134
+ // close = HOVER_DELAY_CLOSE_MS。2026-06-11 修:2026-05-18 token 遷移誤挑 rich(原 hardcode 200/300
135
+ // 兩 tier 皆非,遷移未對照 spec 表)— popup 可互動性由 close 緩衝保障,與 open tier 無關。
130
136
  return (
131
- <HoverCard openDelay={HOVER_DELAY_RICH_MS} closeDelay={HOVER_DELAY_CLOSE_MS}>
137
+ <HoverCard openDelay={HOVER_DELAY_PLAIN_MS} closeDelay={HOVER_DELAY_CLOSE_MS}>
132
138
  <HoverCardTrigger asChild>
133
139
  {trigger}
134
140
  </HoverCardTrigger>
@@ -97,12 +97,14 @@ export const Overview: Story = {
97
97
  export const Inspector: Story = {
98
98
  name: '元件檢閱器',
99
99
  parameters: {
100
- docs: { description: { story: '右側 Controls 切 props 即時 render,取代 Figma inspect。切 `mode` 看 edit / display / readonly / disabled 視覺差異,切 `size` 對照 field-height tier' } },
100
+ docs: { description: { story: '右側 Controls 切 props 即時 render,取代 Figma inspect。切 `mode` 看 edit / display / readonly / disabled 視覺差異,切 `size` 對照 field-height tier,切 `variant` 看 default / bare / naked chrome 差異。' } },
101
101
  },
102
102
  args: {
103
103
  mode: 'edit',
104
+ variant: 'default',
104
105
  size: 'md',
105
106
  disabled: false,
107
+ showDisplayEndIcon: false,
106
108
  value: SAMPLE_PEOPLE[0],
107
109
  people: SAMPLE_PEOPLE,
108
110
  searchPlaceholder: '搜尋指派對象…',
@@ -110,8 +112,10 @@ export const Inspector: Story = {
110
112
  },
111
113
  argTypes: {
112
114
  mode: { control: 'radio', options: ['edit', 'display', 'readonly', 'disabled'] },
115
+ variant: { control: 'radio', options: ['default', 'bare', 'naked'] },
113
116
  size: { control: 'radio', options: ['sm', 'md', 'lg'] },
114
117
  disabled: { control: 'boolean' },
118
+ showDisplayEndIcon: { control: 'boolean' },
115
119
  searchPlaceholder: { control: 'text' },
116
120
  emptyText: { control: 'text' },
117
121
  },
@@ -131,6 +135,11 @@ export const ModeMatrix: Story = {
131
135
  <Desc>Field 樣式 + 展開觸發 Popover + Command 搜尋。</Desc>
132
136
  <PeoplePicker people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} onChange={() => {}} />
133
137
  </div>
138
+ <div>
139
+ <H3>display</H3>
140
+ <Desc>裸 PersonDisplay(Avatar + Name),無 field chrome——DataTable cell / detail panel 純顯示。</Desc>
141
+ <PeoplePicker mode="display" people={SAMPLE_PEOPLE} value={SAMPLE_PEOPLE[0]} />
142
+ </div>
134
143
  <div>
135
144
  <H3>readonly</H3>
136
145
  <Desc>顯示選中人員(Avatar + Name),無 dropdown trigger、無搜尋。</Desc>
@@ -236,7 +245,7 @@ export const ColorMatrix: Story = {
236
245
  </tr>
237
246
  <tr>
238
247
  <Td mono>readonly</Td>
239
- <Td><TokenCell token="--bg-disabled" display="bg-disabled(鎖定底)" /></Td>
248
+ <Td><TokenCell token="--bg-readonly" display="bg-readonly(鎖定底)" /></Td>
240
249
  <Td>—(no border)</Td>
241
250
  <Td><TokenCell token="--foreground" /></Td>
242
251
  </tr>