@qijenchen/design-system 0.1.0-beta.3 → 0.1.0-beta.32

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 (1041) hide show
  1. package/CLAUDE.md +201 -0
  2. package/README.md +155 -0
  3. package/cli-init.mjs +90 -0
  4. package/dist/components/Accordion/accordion.d.ts +37 -0
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -0
  6. package/dist/components/Accordion/accordion.js +78 -0
  7. package/dist/components/Accordion/accordion.js.map +1 -0
  8. package/dist/components/Accordion/index.d.ts +2 -0
  9. package/dist/components/Accordion/index.d.ts.map +1 -0
  10. package/dist/components/Accordion/index.js +9 -0
  11. package/dist/components/Accordion/index.js.map +1 -0
  12. package/dist/components/Alert/alert.d.ts +47 -0
  13. package/dist/components/Alert/alert.d.ts.map +1 -0
  14. package/dist/components/Alert/alert.js +132 -0
  15. package/dist/components/Alert/alert.js.map +1 -0
  16. package/dist/components/Alert/index.d.ts +2 -0
  17. package/dist/components/Alert/index.d.ts.map +1 -0
  18. package/dist/components/Alert/index.js +7 -0
  19. package/dist/components/Alert/index.js.map +1 -0
  20. package/dist/components/AppShell/_demo-helpers.d.ts +49 -0
  21. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -0
  22. package/dist/components/AppShell/app-shell.d.ts +76 -0
  23. package/dist/components/AppShell/app-shell.d.ts.map +1 -0
  24. package/dist/components/AppShell/app-shell.js +214 -0
  25. package/dist/components/AppShell/app-shell.js.map +1 -0
  26. package/dist/components/AppShell/index.d.ts +2 -0
  27. package/dist/components/AppShell/index.d.ts.map +1 -0
  28. package/dist/components/AppShell/index.js +7 -0
  29. package/dist/components/AppShell/index.js.map +1 -0
  30. package/dist/components/AspectRatio/aspect-ratio.d.ts +40 -0
  31. package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -0
  32. package/dist/components/AspectRatio/aspect-ratio.js +23 -0
  33. package/dist/components/AspectRatio/aspect-ratio.js.map +1 -0
  34. package/dist/components/AspectRatio/index.d.ts +2 -0
  35. package/dist/components/AspectRatio/index.d.ts.map +1 -0
  36. package/dist/components/AspectRatio/index.js +6 -0
  37. package/dist/components/AspectRatio/index.js.map +1 -0
  38. package/dist/components/Avatar/avatar.d.ts +85 -0
  39. package/dist/components/Avatar/avatar.d.ts.map +1 -0
  40. package/dist/components/Avatar/avatar.js +195 -0
  41. package/dist/components/Avatar/avatar.js.map +1 -0
  42. package/dist/components/Avatar/index.d.ts +2 -0
  43. package/dist/components/Avatar/index.d.ts.map +1 -0
  44. package/dist/components/Avatar/index.js +6 -0
  45. package/dist/components/Avatar/index.js.map +1 -0
  46. package/dist/components/Badge/badge.d.ts +43 -0
  47. package/dist/components/Badge/badge.d.ts.map +1 -0
  48. package/dist/components/Badge/badge.js +69 -0
  49. package/dist/components/Badge/badge.js.map +1 -0
  50. package/dist/components/Badge/index.d.ts +2 -0
  51. package/dist/components/Badge/index.d.ts.map +1 -0
  52. package/dist/components/Badge/index.js +7 -0
  53. package/dist/components/Badge/index.js.map +1 -0
  54. package/dist/components/Breadcrumb/breadcrumb.d.ts +163 -0
  55. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -0
  56. package/dist/components/Breadcrumb/breadcrumb.js +300 -0
  57. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -0
  58. package/dist/components/Breadcrumb/index.d.ts +2 -0
  59. package/dist/components/Breadcrumb/index.d.ts.map +1 -0
  60. package/dist/components/Breadcrumb/index.js +12 -0
  61. package/dist/components/Breadcrumb/index.js.map +1 -0
  62. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +46 -0
  63. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -0
  64. package/dist/components/BulkActionBar/bulk-action-bar.js +78 -0
  65. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -0
  66. package/dist/components/BulkActionBar/index.d.ts +2 -0
  67. package/dist/components/BulkActionBar/index.d.ts.map +1 -0
  68. package/dist/components/BulkActionBar/index.js +7 -0
  69. package/dist/components/BulkActionBar/index.js.map +1 -0
  70. package/dist/components/Button/button-group.d.ts +49 -0
  71. package/dist/components/Button/button-group.d.ts.map +1 -0
  72. package/dist/components/Button/button-group.js +46 -0
  73. package/dist/components/Button/button-group.js.map +1 -0
  74. package/dist/components/Button/button.d.ts +203 -0
  75. package/dist/components/Button/button.d.ts.map +1 -0
  76. package/dist/components/Button/button.js +309 -0
  77. package/dist/components/Button/button.js.map +1 -0
  78. package/dist/components/Button/index.d.ts +2 -0
  79. package/dist/components/Button/index.d.ts.map +1 -0
  80. package/dist/components/Button/index.js +8 -0
  81. package/dist/components/Button/index.js.map +1 -0
  82. package/dist/components/Calendar/calendar.d.ts +81 -0
  83. package/dist/components/Calendar/calendar.d.ts.map +1 -0
  84. package/dist/components/Calendar/calendar.js +282 -0
  85. package/dist/components/Calendar/calendar.js.map +1 -0
  86. package/dist/components/Calendar/index.d.ts +2 -0
  87. package/dist/components/Calendar/index.d.ts.map +1 -0
  88. package/dist/components/Calendar/index.js +6 -0
  89. package/dist/components/Calendar/index.js.map +1 -0
  90. package/dist/components/Carousel/carousel.d.ts +61 -0
  91. package/dist/components/Carousel/carousel.d.ts.map +1 -0
  92. package/dist/components/Carousel/carousel.js +276 -0
  93. package/dist/components/Carousel/carousel.js.map +1 -0
  94. package/dist/components/Carousel/index.d.ts +2 -0
  95. package/dist/components/Carousel/index.d.ts.map +1 -0
  96. package/dist/components/Carousel/index.js +11 -0
  97. package/dist/components/Carousel/index.js.map +1 -0
  98. package/dist/components/Chart/chart.d.ts +94 -0
  99. package/dist/components/Chart/chart.d.ts.map +1 -0
  100. package/dist/components/Chart/chart.js +233 -0
  101. package/dist/components/Chart/chart.js.map +1 -0
  102. package/dist/components/Chart/index.d.ts +2 -0
  103. package/dist/components/Chart/index.d.ts.map +1 -0
  104. package/dist/components/Chart/index.js +11 -0
  105. package/dist/components/Chart/index.js.map +1 -0
  106. package/dist/components/Checkbox/checkbox-group.d.ts +58 -0
  107. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -0
  108. package/dist/components/Checkbox/checkbox-group.js +28 -0
  109. package/dist/components/Checkbox/checkbox-group.js.map +1 -0
  110. package/dist/components/Checkbox/checkbox.d.ts +73 -0
  111. package/dist/components/Checkbox/checkbox.d.ts.map +1 -0
  112. package/dist/components/Checkbox/checkbox.js +125 -0
  113. package/dist/components/Checkbox/checkbox.js.map +1 -0
  114. package/dist/components/Checkbox/index.d.ts +2 -0
  115. package/dist/components/Checkbox/index.d.ts.map +1 -0
  116. package/dist/components/Checkbox/index.js +7 -0
  117. package/dist/components/Checkbox/index.js.map +1 -0
  118. package/dist/components/Chip/chip.d.ts +54 -0
  119. package/dist/components/Chip/chip.d.ts.map +1 -0
  120. package/dist/components/Chip/chip.js +224 -0
  121. package/dist/components/Chip/chip.js.map +1 -0
  122. package/dist/components/Chip/index.d.ts +2 -0
  123. package/dist/components/Chip/index.d.ts.map +1 -0
  124. package/dist/components/Chip/index.js +8 -0
  125. package/dist/components/Chip/index.js.map +1 -0
  126. package/dist/components/CircularProgress/circular-progress.d.ts +40 -0
  127. package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -0
  128. package/dist/components/CircularProgress/circular-progress.js +118 -0
  129. package/dist/components/CircularProgress/circular-progress.js.map +1 -0
  130. package/dist/components/CircularProgress/index.d.ts +2 -0
  131. package/dist/components/CircularProgress/index.d.ts.map +1 -0
  132. package/dist/components/CircularProgress/index.js +6 -0
  133. package/dist/components/CircularProgress/index.js.map +1 -0
  134. package/dist/components/Coachmark/coachmark.d.ts +100 -0
  135. package/dist/components/Coachmark/coachmark.d.ts.map +1 -0
  136. package/dist/components/Coachmark/coachmark.js +107 -0
  137. package/dist/components/Coachmark/coachmark.js.map +1 -0
  138. package/dist/components/Coachmark/index.d.ts +2 -0
  139. package/dist/components/Coachmark/index.d.ts.map +1 -0
  140. package/dist/components/Coachmark/index.js +6 -0
  141. package/dist/components/Coachmark/index.js.map +1 -0
  142. package/dist/components/Combobox/combobox.d.ts +150 -0
  143. package/dist/components/Combobox/combobox.d.ts.map +1 -0
  144. package/dist/components/Combobox/combobox.js +608 -0
  145. package/dist/components/Combobox/combobox.js.map +1 -0
  146. package/dist/components/Combobox/index.d.ts +2 -0
  147. package/dist/components/Combobox/index.d.ts.map +1 -0
  148. package/dist/components/Combobox/index.js +6 -0
  149. package/dist/components/Combobox/index.js.map +1 -0
  150. package/dist/components/Command/command.d.ts +106 -0
  151. package/dist/components/Command/command.d.ts.map +1 -0
  152. package/dist/components/Command/command.js +123 -0
  153. package/dist/components/Command/command.js.map +1 -0
  154. package/dist/components/Command/index.d.ts +2 -0
  155. package/dist/components/Command/index.d.ts.map +1 -0
  156. package/dist/components/Command/index.js +14 -0
  157. package/dist/components/Command/index.js.map +1 -0
  158. package/dist/components/DataTable/active-editor-controller.d.ts +66 -0
  159. package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -0
  160. package/dist/components/DataTable/cell-registry.d.ts +37 -0
  161. package/dist/components/DataTable/cell-registry.d.ts.map +1 -0
  162. package/dist/components/DataTable/cell-registry.js +377 -0
  163. package/dist/components/DataTable/cell-registry.js.map +1 -0
  164. package/dist/components/DataTable/column-types.d.ts +145 -0
  165. package/dist/components/DataTable/column-types.d.ts.map +1 -0
  166. package/dist/components/DataTable/column-types.js +17 -0
  167. package/dist/components/DataTable/column-types.js.map +1 -0
  168. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +49 -0
  169. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -0
  170. package/dist/components/DataTable/data-table-filter-panel.d.ts +30 -0
  171. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -0
  172. package/dist/components/DataTable/data-table-interaction-layer.d.ts +78 -0
  173. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -0
  174. package/dist/components/DataTable/data-table-interaction-layer.js +220 -0
  175. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -0
  176. package/dist/components/DataTable/data-table-sort-manager.d.ts +19 -0
  177. package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -0
  178. package/dist/components/DataTable/data-table.d.ts +181 -0
  179. package/dist/components/DataTable/data-table.d.ts.map +1 -0
  180. package/dist/components/DataTable/data-table.js +1851 -0
  181. package/dist/components/DataTable/data-table.js.map +1 -0
  182. package/dist/components/DataTable/filter-operators.d.ts +116 -0
  183. package/dist/components/DataTable/filter-operators.d.ts.map +1 -0
  184. package/dist/components/DataTable/filter-tree.d.ts +66 -0
  185. package/dist/components/DataTable/filter-tree.d.ts.map +1 -0
  186. package/dist/components/DataTable/index.d.ts +2 -0
  187. package/dist/components/DataTable/index.d.ts.map +1 -0
  188. package/dist/components/DataTable/index.js +8 -0
  189. package/dist/components/DataTable/index.js.map +1 -0
  190. package/dist/components/DataTable/lib/column-meta.d.ts +49 -0
  191. package/dist/components/DataTable/lib/column-meta.d.ts.map +1 -0
  192. package/dist/components/DateGrid/date-grid.d.ts +61 -0
  193. package/dist/components/DateGrid/date-grid.d.ts.map +1 -0
  194. package/dist/components/DateGrid/date-grid.js +168 -0
  195. package/dist/components/DateGrid/date-grid.js.map +1 -0
  196. package/dist/components/DateGrid/index.d.ts +2 -0
  197. package/dist/components/DateGrid/index.d.ts.map +1 -0
  198. package/dist/components/DateGrid/index.js +6 -0
  199. package/dist/components/DateGrid/index.js.map +1 -0
  200. package/dist/components/DatePicker/date-picker.d.ts +119 -0
  201. package/dist/components/DatePicker/date-picker.d.ts.map +1 -0
  202. package/dist/components/DatePicker/date-picker.js +743 -0
  203. package/dist/components/DatePicker/date-picker.js.map +1 -0
  204. package/dist/components/DatePicker/index.d.ts +2 -0
  205. package/dist/components/DatePicker/index.d.ts.map +1 -0
  206. package/dist/components/DatePicker/index.js +8 -0
  207. package/dist/components/DatePicker/index.js.map +1 -0
  208. package/dist/components/DescriptionList/description-list.d.ts +60 -0
  209. package/dist/components/DescriptionList/description-list.d.ts.map +1 -0
  210. package/dist/components/DescriptionList/description-list.js +77 -0
  211. package/dist/components/DescriptionList/description-list.js.map +1 -0
  212. package/dist/components/DescriptionList/index.d.ts +2 -0
  213. package/dist/components/DescriptionList/index.d.ts.map +1 -0
  214. package/dist/components/DescriptionList/index.js +7 -0
  215. package/dist/components/DescriptionList/index.js.map +1 -0
  216. package/dist/components/Dialog/dialog.d.ts +54 -0
  217. package/dist/components/Dialog/dialog.d.ts.map +1 -0
  218. package/dist/components/Dialog/dialog.js +151 -0
  219. package/dist/components/Dialog/dialog.js.map +1 -0
  220. package/dist/components/Dialog/index.d.ts +2 -0
  221. package/dist/components/Dialog/index.d.ts.map +1 -0
  222. package/dist/components/Dialog/index.js +16 -0
  223. package/dist/components/Dialog/index.js.map +1 -0
  224. package/dist/components/DropdownMenu/dropdown-menu.d.ts +111 -0
  225. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -0
  226. package/dist/components/DropdownMenu/dropdown-menu.js +288 -0
  227. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -0
  228. package/dist/components/DropdownMenu/index.d.ts +2 -0
  229. package/dist/components/DropdownMenu/index.d.ts.map +1 -0
  230. package/dist/components/DropdownMenu/index.js +21 -0
  231. package/dist/components/DropdownMenu/index.js.map +1 -0
  232. package/dist/components/Empty/empty.d.ts +40 -0
  233. package/dist/components/Empty/empty.d.ts.map +1 -0
  234. package/dist/components/Empty/empty.js +66 -0
  235. package/dist/components/Empty/empty.js.map +1 -0
  236. package/dist/components/Empty/index.d.ts +2 -0
  237. package/dist/components/Empty/index.d.ts.map +1 -0
  238. package/dist/components/Empty/index.js +6 -0
  239. package/dist/components/Empty/index.js.map +1 -0
  240. package/dist/components/Field/field-context.d.ts +77 -0
  241. package/dist/components/Field/field-context.d.ts.map +1 -0
  242. package/dist/components/Field/field-context.js +37 -0
  243. package/dist/components/Field/field-context.js.map +1 -0
  244. package/dist/components/Field/field-types.d.ts +5 -0
  245. package/dist/components/Field/field-types.d.ts.map +1 -0
  246. package/dist/components/Field/field-types.js +13 -0
  247. package/dist/components/Field/field-types.js.map +1 -0
  248. package/dist/components/Field/field-wrapper.d.ts +17 -0
  249. package/dist/components/Field/field-wrapper.d.ts.map +1 -0
  250. package/dist/components/Field/field-wrapper.js +252 -0
  251. package/dist/components/Field/field-wrapper.js.map +1 -0
  252. package/dist/components/Field/field.d.ts +127 -0
  253. package/dist/components/Field/field.d.ts.map +1 -0
  254. package/dist/components/Field/field.js +295 -0
  255. package/dist/components/Field/field.js.map +1 -0
  256. package/dist/components/Field/index.d.ts +2 -0
  257. package/dist/components/Field/index.d.ts.map +1 -0
  258. package/dist/components/Field/index.js +10 -0
  259. package/dist/components/Field/index.js.map +1 -0
  260. package/dist/components/FieldControlGroup/field-control-group.d.ts +74 -0
  261. package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -0
  262. package/dist/components/FieldControlGroup/field-control-group.js +62 -0
  263. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -0
  264. package/dist/components/FieldControlGroup/index.d.ts +2 -0
  265. package/dist/components/FieldControlGroup/index.d.ts.map +1 -0
  266. package/dist/components/FieldControlGroup/index.js +6 -0
  267. package/dist/components/FieldControlGroup/index.js.map +1 -0
  268. package/dist/components/FileItem/file-item.d.ts +44 -0
  269. package/dist/components/FileItem/file-item.d.ts.map +1 -0
  270. package/dist/components/FileItem/file-item.js +202 -0
  271. package/dist/components/FileItem/file-item.js.map +1 -0
  272. package/dist/components/FileItem/index.d.ts +2 -0
  273. package/dist/components/FileItem/index.d.ts.map +1 -0
  274. package/dist/components/FileItem/index.js +6 -0
  275. package/dist/components/FileItem/index.js.map +1 -0
  276. package/dist/components/FileUpload/file-upload.d.ts +97 -0
  277. package/dist/components/FileUpload/file-upload.d.ts.map +1 -0
  278. package/dist/components/FileUpload/file-upload.js +231 -0
  279. package/dist/components/FileUpload/file-upload.js.map +1 -0
  280. package/dist/components/FileUpload/index.d.ts +2 -0
  281. package/dist/components/FileUpload/index.d.ts.map +1 -0
  282. package/dist/components/FileUpload/index.js +6 -0
  283. package/dist/components/FileUpload/index.js.map +1 -0
  284. package/dist/components/FileViewer/file-viewer-types.d.ts +73 -0
  285. package/dist/components/FileViewer/file-viewer-types.d.ts.map +1 -0
  286. package/dist/components/FileViewer/file-viewer.d.ts +82 -0
  287. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -0
  288. package/dist/components/FileViewer/file-viewer.js +752 -0
  289. package/dist/components/FileViewer/file-viewer.js.map +1 -0
  290. package/dist/components/FileViewer/image-renderer.d.ts +9 -0
  291. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -0
  292. package/dist/components/FileViewer/image-renderer.js +165 -0
  293. package/dist/components/FileViewer/image-renderer.js.map +1 -0
  294. package/dist/components/FileViewer/index.d.ts +2 -0
  295. package/dist/components/FileViewer/index.d.ts.map +1 -0
  296. package/dist/components/FileViewer/index.js +7 -0
  297. package/dist/components/FileViewer/index.js.map +1 -0
  298. package/dist/components/HoverCard/hover-card.d.ts +30 -0
  299. package/dist/components/HoverCard/hover-card.d.ts.map +1 -0
  300. package/dist/components/HoverCard/hover-card.js +61 -0
  301. package/dist/components/HoverCard/hover-card.js.map +1 -0
  302. package/dist/components/HoverCard/index.d.ts +2 -0
  303. package/dist/components/HoverCard/index.d.ts.map +1 -0
  304. package/dist/components/HoverCard/index.js +8 -0
  305. package/dist/components/HoverCard/index.js.map +1 -0
  306. package/dist/components/Input/index.d.ts +2 -0
  307. package/dist/components/Input/index.d.ts.map +1 -0
  308. package/dist/components/Input/index.js +6 -0
  309. package/dist/components/Input/index.js.map +1 -0
  310. package/dist/components/Input/input.d.ts +72 -0
  311. package/dist/components/Input/input.d.ts.map +1 -0
  312. package/dist/components/Input/input.js +148 -0
  313. package/dist/components/Input/input.js.map +1 -0
  314. package/dist/components/LinkInput/index.d.ts +2 -0
  315. package/dist/components/LinkInput/index.d.ts.map +1 -0
  316. package/dist/components/LinkInput/index.js +6 -0
  317. package/dist/components/LinkInput/index.js.map +1 -0
  318. package/dist/components/LinkInput/link-input.d.ts +46 -0
  319. package/dist/components/LinkInput/link-input.d.ts.map +1 -0
  320. package/dist/components/LinkInput/link-input.js +215 -0
  321. package/dist/components/LinkInput/link-input.js.map +1 -0
  322. package/dist/components/Menu/index.d.ts +2 -0
  323. package/dist/components/Menu/index.d.ts.map +1 -0
  324. package/dist/components/Menu/index.js +9 -0
  325. package/dist/components/Menu/index.js.map +1 -0
  326. package/dist/components/Menu/menu-item.d.ts +83 -0
  327. package/dist/components/Menu/menu-item.d.ts.map +1 -0
  328. package/dist/components/Menu/menu-item.js +209 -0
  329. package/dist/components/Menu/menu-item.js.map +1 -0
  330. package/dist/components/NameCard/index.d.ts +2 -0
  331. package/dist/components/NameCard/index.d.ts.map +1 -0
  332. package/dist/components/NameCard/index.js +8 -0
  333. package/dist/components/NameCard/index.js.map +1 -0
  334. package/dist/components/NameCard/name-card.d.ts +85 -0
  335. package/dist/components/NameCard/name-card.d.ts.map +1 -0
  336. package/dist/components/NameCard/name-card.js +153 -0
  337. package/dist/components/NameCard/name-card.js.map +1 -0
  338. package/dist/components/Notice/index.d.ts +2 -0
  339. package/dist/components/Notice/index.d.ts.map +1 -0
  340. package/dist/components/Notice/index.js +8 -0
  341. package/dist/components/Notice/index.js.map +1 -0
  342. package/dist/components/Notice/notice.d.ts +69 -0
  343. package/dist/components/Notice/notice.d.ts.map +1 -0
  344. package/dist/components/Notice/notice.js +121 -0
  345. package/dist/components/Notice/notice.js.map +1 -0
  346. package/dist/components/NumberInput/index.d.ts +2 -0
  347. package/dist/components/NumberInput/index.d.ts.map +1 -0
  348. package/dist/components/NumberInput/index.js +7 -0
  349. package/dist/components/NumberInput/index.js.map +1 -0
  350. package/dist/components/NumberInput/number-input.d.ts +57 -0
  351. package/dist/components/NumberInput/number-input.d.ts.map +1 -0
  352. package/dist/components/NumberInput/number-input.js +131 -0
  353. package/dist/components/NumberInput/number-input.js.map +1 -0
  354. package/dist/components/OverflowIndicator/index.d.ts +2 -0
  355. package/dist/components/OverflowIndicator/index.d.ts.map +1 -0
  356. package/dist/components/OverflowIndicator/index.js +6 -0
  357. package/dist/components/OverflowIndicator/index.js.map +1 -0
  358. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +23 -0
  359. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -0
  360. package/dist/components/OverflowIndicator/overflow-indicator.js +111 -0
  361. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -0
  362. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +57 -0
  363. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -0
  364. package/dist/components/PeoplePicker/avatar-stack-overflow.js +35 -0
  365. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -0
  366. package/dist/components/PeoplePicker/index.d.ts +2 -0
  367. package/dist/components/PeoplePicker/index.d.ts.map +1 -0
  368. package/dist/components/PeoplePicker/index.js +9 -0
  369. package/dist/components/PeoplePicker/index.js.map +1 -0
  370. package/dist/components/PeoplePicker/people-picker-helpers.d.ts +7 -0
  371. package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -0
  372. package/dist/components/PeoplePicker/people-picker-helpers.js +25 -0
  373. package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -0
  374. package/dist/components/PeoplePicker/people-picker.d.ts +77 -0
  375. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -0
  376. package/dist/components/PeoplePicker/people-picker.js +263 -0
  377. package/dist/components/PeoplePicker/people-picker.js.map +1 -0
  378. package/dist/components/PeoplePicker/person-display.d.ts +66 -0
  379. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -0
  380. package/dist/components/PeoplePicker/person-display.js +203 -0
  381. package/dist/components/PeoplePicker/person-display.js.map +1 -0
  382. package/dist/components/Popover/index.d.ts +2 -0
  383. package/dist/components/Popover/index.d.ts.map +1 -0
  384. package/dist/components/Popover/index.js +14 -0
  385. package/dist/components/Popover/index.js.map +1 -0
  386. package/dist/components/Popover/popover.d.ts +50 -0
  387. package/dist/components/Popover/popover.d.ts.map +1 -0
  388. package/dist/components/Popover/popover.js +113 -0
  389. package/dist/components/Popover/popover.js.map +1 -0
  390. package/dist/components/ProgressBar/index.d.ts +2 -0
  391. package/dist/components/ProgressBar/index.d.ts.map +1 -0
  392. package/dist/components/ProgressBar/index.js +6 -0
  393. package/dist/components/ProgressBar/index.js.map +1 -0
  394. package/dist/components/ProgressBar/progress-bar.d.ts +37 -0
  395. package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -0
  396. package/dist/components/ProgressBar/progress-bar.js +86 -0
  397. package/dist/components/ProgressBar/progress-bar.js.map +1 -0
  398. package/dist/components/RadioGroup/index.d.ts +2 -0
  399. package/dist/components/RadioGroup/index.d.ts.map +1 -0
  400. package/dist/components/RadioGroup/index.js +8 -0
  401. package/dist/components/RadioGroup/index.js.map +1 -0
  402. package/dist/components/RadioGroup/radio-group.d.ts +78 -0
  403. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -0
  404. package/dist/components/RadioGroup/radio-group.js +153 -0
  405. package/dist/components/RadioGroup/radio-group.js.map +1 -0
  406. package/dist/components/Rating/index.d.ts +2 -0
  407. package/dist/components/Rating/index.d.ts.map +1 -0
  408. package/dist/components/Rating/index.js +6 -0
  409. package/dist/components/Rating/index.js.map +1 -0
  410. package/dist/components/Rating/rating.d.ts +46 -0
  411. package/dist/components/Rating/rating.d.ts.map +1 -0
  412. package/dist/components/Rating/rating.js +179 -0
  413. package/dist/components/Rating/rating.js.map +1 -0
  414. package/dist/components/ScrollArea/index.d.ts +2 -0
  415. package/dist/components/ScrollArea/index.d.ts.map +1 -0
  416. package/dist/components/ScrollArea/index.js +7 -0
  417. package/dist/components/ScrollArea/index.js.map +1 -0
  418. package/dist/components/ScrollArea/scroll-area.d.ts +45 -0
  419. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -0
  420. package/dist/components/ScrollArea/scroll-area.js +65 -0
  421. package/dist/components/ScrollArea/scroll-area.js.map +1 -0
  422. package/dist/components/SegmentedControl/index.d.ts +2 -0
  423. package/dist/components/SegmentedControl/index.d.ts.map +1 -0
  424. package/dist/components/SegmentedControl/index.js +9 -0
  425. package/dist/components/SegmentedControl/index.js.map +1 -0
  426. package/dist/components/SegmentedControl/segmented-control.d.ts +102 -0
  427. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -0
  428. package/dist/components/SegmentedControl/segmented-control.js +171 -0
  429. package/dist/components/SegmentedControl/segmented-control.js.map +1 -0
  430. package/dist/components/Select/index.d.ts +2 -0
  431. package/dist/components/Select/index.d.ts.map +1 -0
  432. package/dist/components/Select/index.js +6 -0
  433. package/dist/components/Select/index.js.map +1 -0
  434. package/dist/components/Select/select.d.ts +102 -0
  435. package/dist/components/Select/select.d.ts.map +1 -0
  436. package/dist/components/Select/select.js +435 -0
  437. package/dist/components/Select/select.js.map +1 -0
  438. package/dist/components/SelectMenu/index.d.ts +2 -0
  439. package/dist/components/SelectMenu/index.d.ts.map +1 -0
  440. package/dist/components/SelectMenu/index.js +6 -0
  441. package/dist/components/SelectMenu/index.js.map +1 -0
  442. package/dist/components/SelectMenu/select-menu.d.ts +103 -0
  443. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -0
  444. package/dist/components/SelectMenu/select-menu.js +239 -0
  445. package/dist/components/SelectMenu/select-menu.js.map +1 -0
  446. package/dist/components/SelectionControl/index.d.ts +2 -0
  447. package/dist/components/SelectionControl/index.d.ts.map +1 -0
  448. package/dist/components/SelectionControl/index.js +7 -0
  449. package/dist/components/SelectionControl/index.js.map +1 -0
  450. package/dist/components/SelectionControl/selection-item.d.ts +69 -0
  451. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -0
  452. package/dist/components/SelectionControl/selection-item.js +142 -0
  453. package/dist/components/SelectionControl/selection-item.js.map +1 -0
  454. package/dist/components/Separator/index.d.ts +2 -0
  455. package/dist/components/Separator/index.d.ts.map +1 -0
  456. package/dist/components/Separator/index.js +6 -0
  457. package/dist/components/Separator/index.js.map +1 -0
  458. package/dist/components/Separator/separator.d.ts +17 -0
  459. package/dist/components/Separator/separator.d.ts.map +1 -0
  460. package/dist/components/Separator/separator.js +39 -0
  461. package/dist/components/Separator/separator.js.map +1 -0
  462. package/dist/components/Sheet/index.d.ts +2 -0
  463. package/dist/components/Sheet/index.d.ts.map +1 -0
  464. package/dist/components/Sheet/index.js +17 -0
  465. package/dist/components/Sheet/index.js.map +1 -0
  466. package/dist/components/Sheet/sheet.d.ts +56 -0
  467. package/dist/components/Sheet/sheet.d.ts.map +1 -0
  468. package/dist/components/Sheet/sheet.js +145 -0
  469. package/dist/components/Sheet/sheet.js.map +1 -0
  470. package/dist/components/Sidebar/index.d.ts +2 -0
  471. package/dist/components/Sidebar/index.d.ts.map +1 -0
  472. package/dist/components/Sidebar/index.js +24 -0
  473. package/dist/components/Sidebar/index.js.map +1 -0
  474. package/dist/components/Sidebar/sidebar.d.ts +195 -0
  475. package/dist/components/Sidebar/sidebar.d.ts.map +1 -0
  476. package/dist/components/Sidebar/sidebar.js +826 -0
  477. package/dist/components/Sidebar/sidebar.js.map +1 -0
  478. package/dist/components/Skeleton/index.d.ts +2 -0
  479. package/dist/components/Skeleton/index.d.ts.map +1 -0
  480. package/dist/components/Skeleton/index.js +6 -0
  481. package/dist/components/Skeleton/index.js.map +1 -0
  482. package/dist/components/Skeleton/skeleton.d.ts +16 -0
  483. package/dist/components/Skeleton/skeleton.d.ts.map +1 -0
  484. package/dist/components/Skeleton/skeleton.js +30 -0
  485. package/dist/components/Skeleton/skeleton.js.map +1 -0
  486. package/dist/components/Slider/index.d.ts +2 -0
  487. package/dist/components/Slider/index.d.ts.map +1 -0
  488. package/dist/components/Slider/index.js +7 -0
  489. package/dist/components/Slider/index.js.map +1 -0
  490. package/dist/components/Slider/slider.d.ts +48 -0
  491. package/dist/components/Slider/slider.d.ts.map +1 -0
  492. package/dist/components/Slider/slider.js +108 -0
  493. package/dist/components/Slider/slider.js.map +1 -0
  494. package/dist/components/Steps/index.d.ts +2 -0
  495. package/dist/components/Steps/index.d.ts.map +1 -0
  496. package/dist/components/Steps/index.js +12 -0
  497. package/dist/components/Steps/index.js.map +1 -0
  498. package/dist/components/Steps/steps.d.ts +71 -0
  499. package/dist/components/Steps/steps.d.ts.map +1 -0
  500. package/dist/components/Steps/steps.js +583 -0
  501. package/dist/components/Steps/steps.js.map +1 -0
  502. package/dist/components/Switch/index.d.ts +2 -0
  503. package/dist/components/Switch/index.d.ts.map +1 -0
  504. package/dist/components/Switch/index.js +7 -0
  505. package/dist/components/Switch/index.js.map +1 -0
  506. package/dist/components/Switch/switch.d.ts +112 -0
  507. package/dist/components/Switch/switch.d.ts.map +1 -0
  508. package/dist/components/Switch/switch.js +179 -0
  509. package/dist/components/Switch/switch.js.map +1 -0
  510. package/dist/components/Tabs/index.d.ts +2 -0
  511. package/dist/components/Tabs/index.d.ts.map +1 -0
  512. package/dist/components/Tabs/index.js +10 -0
  513. package/dist/components/Tabs/index.js.map +1 -0
  514. package/dist/components/Tabs/tabs.d.ts +104 -0
  515. package/dist/components/Tabs/tabs.d.ts.map +1 -0
  516. package/dist/components/Tabs/tabs.js +316 -0
  517. package/dist/components/Tabs/tabs.js.map +1 -0
  518. package/dist/components/Tag/index.d.ts +2 -0
  519. package/dist/components/Tag/index.d.ts.map +1 -0
  520. package/dist/components/Tag/index.js +7 -0
  521. package/dist/components/Tag/index.js.map +1 -0
  522. package/dist/components/Tag/tag.d.ts +86 -0
  523. package/dist/components/Tag/tag.d.ts.map +1 -0
  524. package/dist/components/Tag/tag.js +172 -0
  525. package/dist/components/Tag/tag.js.map +1 -0
  526. package/dist/components/Textarea/index.d.ts +2 -0
  527. package/dist/components/Textarea/index.d.ts.map +1 -0
  528. package/dist/components/Textarea/index.js +7 -0
  529. package/dist/components/Textarea/index.js.map +1 -0
  530. package/dist/components/Textarea/textarea.d.ts +74 -0
  531. package/dist/components/Textarea/textarea.d.ts.map +1 -0
  532. package/dist/components/Textarea/textarea.js +224 -0
  533. package/dist/components/Textarea/textarea.js.map +1 -0
  534. package/dist/components/TimePicker/index.d.ts +2 -0
  535. package/dist/components/TimePicker/index.d.ts.map +1 -0
  536. package/dist/components/TimePicker/index.js +6 -0
  537. package/dist/components/TimePicker/index.js.map +1 -0
  538. package/dist/components/TimePicker/time-columns.d.ts +46 -0
  539. package/dist/components/TimePicker/time-columns.d.ts.map +1 -0
  540. package/dist/components/TimePicker/time-columns.js +173 -0
  541. package/dist/components/TimePicker/time-columns.js.map +1 -0
  542. package/dist/components/TimePicker/time-picker.d.ts +94 -0
  543. package/dist/components/TimePicker/time-picker.d.ts.map +1 -0
  544. package/dist/components/TimePicker/time-picker.js +253 -0
  545. package/dist/components/TimePicker/time-picker.js.map +1 -0
  546. package/dist/components/Toast/index.d.ts +2 -0
  547. package/dist/components/Toast/index.d.ts.map +1 -0
  548. package/dist/components/Toast/index.js +7 -0
  549. package/dist/components/Toast/index.js.map +1 -0
  550. package/dist/components/Toast/toast.d.ts +61 -0
  551. package/dist/components/Toast/toast.d.ts.map +1 -0
  552. package/dist/components/Toast/toast.js +76 -0
  553. package/dist/components/Toast/toast.js.map +1 -0
  554. package/dist/components/Tooltip/index.d.ts +2 -0
  555. package/dist/components/Tooltip/index.d.ts.map +1 -0
  556. package/dist/components/Tooltip/index.js +9 -0
  557. package/dist/components/Tooltip/index.js.map +1 -0
  558. package/dist/components/Tooltip/tooltip.d.ts +20 -0
  559. package/dist/components/Tooltip/tooltip.d.ts.map +1 -0
  560. package/dist/components/Tooltip/tooltip.js +53 -0
  561. package/dist/components/Tooltip/tooltip.js.map +1 -0
  562. package/dist/components/TreeView/index.d.ts +2 -0
  563. package/dist/components/TreeView/index.d.ts.map +1 -0
  564. package/dist/components/TreeView/index.js +8 -0
  565. package/dist/components/TreeView/index.js.map +1 -0
  566. package/dist/components/TreeView/tree-view.d.ts +166 -0
  567. package/dist/components/TreeView/tree-view.d.ts.map +1 -0
  568. package/dist/components/TreeView/tree-view.js +638 -0
  569. package/dist/components/TreeView/tree-view.js.map +1 -0
  570. package/dist/hooks/use-controllable.d.ts +16 -0
  571. package/dist/hooks/use-controllable.d.ts.map +1 -0
  572. package/dist/hooks/use-controllable.js +26 -0
  573. package/dist/hooks/use-controllable.js.map +1 -0
  574. package/dist/hooks/use-is-narrow-viewport.d.ts +2 -0
  575. package/dist/hooks/use-is-narrow-viewport.d.ts.map +1 -0
  576. package/dist/hooks/use-is-narrow-viewport.js +19 -0
  577. package/dist/hooks/use-is-narrow-viewport.js.map +1 -0
  578. package/dist/hooks/use-is-touch-device.d.ts +8 -0
  579. package/dist/hooks/use-is-touch-device.d.ts.map +1 -0
  580. package/dist/hooks/use-is-touch-device.js +16 -0
  581. package/dist/hooks/use-is-touch-device.js.map +1 -0
  582. package/dist/hooks/use-overflow-items.d.ts +124 -0
  583. package/dist/hooks/use-overflow-items.d.ts.map +1 -0
  584. package/dist/hooks/use-overflow-items.js +97 -0
  585. package/dist/hooks/use-overflow-items.js.map +1 -0
  586. package/dist/index.d.ts +74 -0
  587. package/dist/index.d.ts.map +1 -0
  588. package/dist/index.js +393 -0
  589. package/dist/index.js.map +1 -0
  590. package/dist/lib/drag-visual.d.ts +158 -0
  591. package/dist/lib/drag-visual.d.ts.map +1 -0
  592. package/dist/lib/drag-visual.js +96 -0
  593. package/dist/lib/drag-visual.js.map +1 -0
  594. package/dist/lib/i18n/i18n-context.d.ts +105 -0
  595. package/dist/lib/i18n/i18n-context.d.ts.map +1 -0
  596. package/dist/lib/multi-select-ordering.d.ts +54 -0
  597. package/dist/lib/multi-select-ordering.d.ts.map +1 -0
  598. package/dist/lib/multi-select-ordering.js +13 -0
  599. package/dist/lib/multi-select-ordering.js.map +1 -0
  600. package/dist/lib/utils.d.ts +12 -0
  601. package/dist/lib/utils.d.ts.map +1 -0
  602. package/dist/lib/utils.js +79 -0
  603. package/dist/lib/utils.js.map +1 -0
  604. package/dist/patterns/element-anatomy/index.d.ts +2 -0
  605. package/dist/patterns/element-anatomy/index.d.ts.map +1 -0
  606. package/dist/patterns/element-anatomy/index.js +20 -0
  607. package/dist/patterns/element-anatomy/index.js.map +1 -0
  608. package/dist/patterns/element-anatomy/item-anatomy.d.ts +370 -0
  609. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -0
  610. package/dist/patterns/element-anatomy/item-anatomy.js +272 -0
  611. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -0
  612. package/dist/patterns/header-canonical/chrome-header.d.ts +80 -0
  613. package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -0
  614. package/dist/patterns/header-canonical/chrome-header.js +75 -0
  615. package/dist/patterns/header-canonical/chrome-header.js.map +1 -0
  616. package/dist/patterns/header-canonical/index.d.ts +2 -0
  617. package/dist/patterns/header-canonical/index.d.ts.map +1 -0
  618. package/dist/patterns/header-canonical/index.js +5 -0
  619. package/dist/patterns/header-canonical/index.js.map +1 -0
  620. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +101 -0
  621. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -0
  622. package/dist/patterns/horizontal-overflow/horizontal-overflow.js +105 -0
  623. package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -0
  624. package/dist/patterns/horizontal-overflow/index.d.ts +2 -0
  625. package/dist/patterns/horizontal-overflow/index.d.ts.map +1 -0
  626. package/dist/patterns/horizontal-overflow/index.js +14 -0
  627. package/dist/patterns/horizontal-overflow/index.js.map +1 -0
  628. package/dist/patterns/overlay-surface/index.d.ts +2 -0
  629. package/dist/patterns/overlay-surface/index.d.ts.map +1 -0
  630. package/dist/patterns/overlay-surface/index.js +7 -0
  631. package/dist/patterns/overlay-surface/index.js.map +1 -0
  632. package/dist/patterns/overlay-surface/overlay-surface.d.ts +28 -0
  633. package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -0
  634. package/dist/patterns/overlay-surface/overlay-surface.js +85 -0
  635. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -0
  636. package/dist/patterns/resize-handle/index.d.ts +2 -0
  637. package/dist/patterns/resize-handle/index.d.ts.map +1 -0
  638. package/dist/patterns/resize-handle/index.js +5 -0
  639. package/dist/patterns/resize-handle/index.js.map +1 -0
  640. package/dist/patterns/resize-handle/resize-handle.d.ts +102 -0
  641. package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -0
  642. package/dist/patterns/resize-handle/resize-handle.js +74 -0
  643. package/dist/patterns/resize-handle/resize-handle.js.map +1 -0
  644. package/dist/react-day-picker.css +457 -0
  645. package/dist/stories-helpers/anatomy/anatomy-utils.d.ts +40 -0
  646. package/dist/stories-helpers/anatomy/anatomy-utils.d.ts.map +1 -0
  647. package/dist/tokens/elevation/overlay-geometry.d.ts +12 -0
  648. package/dist/tokens/elevation/overlay-geometry.d.ts.map +1 -0
  649. package/dist/tokens/elevation/overlay-geometry.js +7 -0
  650. package/dist/tokens/elevation/overlay-geometry.js.map +1 -0
  651. package/dist/tokens/motion/motion.d.ts +15 -0
  652. package/dist/tokens/motion/motion.d.ts.map +1 -0
  653. package/dist/tokens/motion/motion.js +9 -0
  654. package/dist/tokens/motion/motion.js.map +1 -0
  655. package/dist/tokens/uiSize/icon-size.d.ts +53 -0
  656. package/dist/tokens/uiSize/icon-size.d.ts.map +1 -0
  657. package/ds-canonical/commands/README.md +26 -0
  658. package/ds-canonical/commands/gov-status.md +79 -0
  659. package/ds-canonical/hooks/README.md +145 -0
  660. package/ds-canonical/hooks/_log-fire.sh +44 -0
  661. package/ds-canonical/hooks/block_prototype_imports.py +111 -0
  662. package/ds-canonical/hooks/check_app_shell_primary_header_consistency.sh +68 -0
  663. package/ds-canonical/hooks/check_audit_post_report_validator.sh +88 -0
  664. package/ds-canonical/hooks/check_audit_sample_escape.sh +73 -0
  665. package/ds-canonical/hooks/check_benchmark_citation.sh +106 -0
  666. package/ds-canonical/hooks/check_canonical_propagation.sh +189 -0
  667. package/ds-canonical/hooks/check_chrome_header_handcraft.sh +70 -0
  668. package/ds-canonical/hooks/check_codex_brief_invariants.sh +83 -0
  669. package/ds-canonical/hooks/check_codex_collab_5step.sh +108 -0
  670. package/ds-canonical/hooks/check_datatable_invariants.sh +117 -0
  671. package/ds-canonical/hooks/check_dim_count_drift.sh +72 -0
  672. package/ds-canonical/hooks/check_field_controls_contracts.sh +110 -0
  673. package/ds-canonical/hooks/check_field_family_invariants.sh +205 -0
  674. package/ds-canonical/hooks/check_file_size_budget.sh +60 -0
  675. package/ds-canonical/hooks/check_header_with_tabs_border.sh +87 -0
  676. package/ds-canonical/hooks/check_main_branch_workbench.sh +93 -0
  677. package/ds-canonical/hooks/check_naming_and_abstraction.sh +165 -0
  678. package/ds-canonical/hooks/check_opacity_token_usage.sh +149 -0
  679. package/ds-canonical/hooks/check_pattern_invariants.sh +194 -0
  680. package/ds-canonical/hooks/check_peoplepicker_ssot_drift.sh +56 -0
  681. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +53 -0
  682. package/ds-canonical/hooks/check_propose_plain_chinese.sh +74 -0
  683. package/ds-canonical/hooks/check_propose_pre_grep_verify.sh +70 -0
  684. package/ds-canonical/hooks/check_select_all_canonical.sh +58 -0
  685. package/ds-canonical/hooks/check_solo_workflow.sh +258 -0
  686. package/ds-canonical/hooks/check_spec_class_drift.sh +88 -0
  687. package/ds-canonical/hooks/check_story_invariants.sh +612 -0
  688. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +105 -0
  689. package/ds-canonical/hooks/check_tab_lg_chrome_header_equal.sh +66 -0
  690. package/ds-canonical/hooks/check_wrapper_primitive_schema_drift.sh +104 -0
  691. package/ds-canonical/hooks/enforce_home_charter.sh +44 -0
  692. package/ds-canonical/hooks/inject_pending_self_audit.sh +204 -0
  693. package/ds-canonical/hooks/lib/_approval_re.sh +33 -0
  694. package/ds-canonical/hooks/lib/_code_quality.sh +73 -0
  695. package/ds-canonical/hooks/lib/_cva_default_sync.sh +69 -0
  696. package/ds-canonical/hooks/lib/_governance_coverage_check.sh +49 -0
  697. package/ds-canonical/hooks/lib/_hardcoded_strings.sh +163 -0
  698. package/ds-canonical/hooks/lib/_layout_space_canonical.sh +56 -0
  699. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +141 -0
  700. package/ds-canonical/hooks/lib/_person_data_richness.sh +42 -0
  701. package/ds-canonical/hooks/lib/_story_compile_drift.sh +48 -0
  702. package/ds-canonical/hooks/lib/_token_hygiene.sh +95 -0
  703. package/ds-canonical/hooks/log_governance_fires.sh +50 -0
  704. package/ds-canonical/hooks/log_skill_invokes.sh +41 -0
  705. package/ds-canonical/hooks/post_edit_dispatcher.sh +62 -0
  706. package/ds-canonical/hooks/retired/check_anatomy_section_numbering.sh +106 -0
  707. package/ds-canonical/hooks/retired/check_avatar_hovercard.sh +90 -0
  708. package/ds-canonical/hooks/retired/check_button_icon_literal.sh.retired-2026-04-28 +38 -0
  709. package/ds-canonical/hooks/retired/check_container_breathing.sh +142 -0
  710. package/ds-canonical/hooks/retired/check_governance_compliance.sh +61 -0
  711. package/ds-canonical/hooks/retired/check_icon_only_padding_formula.sh +104 -0
  712. package/ds-canonical/hooks/retired/check_item_content_primitive.sh +150 -0
  713. package/ds-canonical/hooks/retired/check_item_list_gap.sh +153 -0
  714. package/ds-canonical/hooks/retired/check_sideoffset_canonical.sh +65 -0
  715. package/ds-canonical/hooks/retired/check_spec_iteration_tag.sh +87 -0
  716. package/ds-canonical/hooks/retired/check_ssot_consultation.sh +88 -0
  717. package/ds-canonical/hooks/retired/check_sync_update.sh +20 -0
  718. package/ds-canonical/hooks/retired/check_third_party_dom_verified.sh +95 -0
  719. package/ds-canonical/hooks/retired/enforce_home_charter.sh +125 -0
  720. package/ds-canonical/hooks/retired/post_edit_canonical_interrogate.sh +109 -0
  721. package/ds-canonical/hooks/retired/pre_edit_spec_check.sh +68 -0
  722. package/ds-canonical/hooks/retired/pre_new_component_spec.sh +39 -0
  723. package/ds-canonical/hooks/retired/pre_write_subsumption_check.sh +112 -0
  724. package/ds-canonical/hooks/retired/stop_meta_self_audit.sh.retired-2026-05-13 +76 -0
  725. package/ds-canonical/hooks/retired/tests/test_check_anatomy_section_numbering.sh +14 -0
  726. package/ds-canonical/hooks/retired/tests/test_check_avatar_hovercard.sh +15 -0
  727. package/ds-canonical/hooks/retired/tests/test_check_container_breathing.sh +15 -0
  728. package/ds-canonical/hooks/retired/tests/test_check_governance_compliance.sh +15 -0
  729. package/ds-canonical/hooks/retired/tests/test_check_icon_only_padding_formula.sh +79 -0
  730. package/ds-canonical/hooks/retired/tests/test_check_item_content_primitive.sh +15 -0
  731. package/ds-canonical/hooks/retired/tests/test_check_item_list_gap.sh +163 -0
  732. package/ds-canonical/hooks/retired/tests/test_check_sideoffset_canonical.sh +15 -0
  733. package/ds-canonical/hooks/retired/tests/test_check_spec_iteration_tag.sh +15 -0
  734. package/ds-canonical/hooks/retired/tests/test_check_ssot_consultation.sh +15 -0
  735. package/ds-canonical/hooks/retired/tests/test_check_sync_update.sh +14 -0
  736. package/ds-canonical/hooks/retired/tests/test_check_third_party_dom_verified.sh +15 -0
  737. package/ds-canonical/hooks/retired/tests/test_enforce_home_charter.sh +15 -0
  738. package/ds-canonical/hooks/retired/tests/test_pre_edit_spec_check.sh +15 -0
  739. package/ds-canonical/hooks/retired/tests/test_pre_new_component_spec.sh +15 -0
  740. package/ds-canonical/hooks/retired/tests/test_pre_write_subsumption_check.sh +63 -0
  741. package/ds-canonical/hooks/session_start_governance_check.sh +263 -0
  742. package/ds-canonical/hooks/stop_passive_logging.sh +322 -0
  743. package/ds-canonical/hooks/stop_self_audit.sh +450 -0
  744. package/ds-canonical/hooks/tests/KNOWN-BROKEN.md +15 -0
  745. package/ds-canonical/hooks/tests/run-all.sh +76 -0
  746. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +143 -0
  747. package/ds-canonical/hooks/tests/test_check_app_shell_primary_header_consistency.sh +140 -0
  748. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +115 -0
  749. package/ds-canonical/hooks/tests/test_check_audit_sample_escape.sh +93 -0
  750. package/ds-canonical/hooks/tests/test_check_benchmark_citation.sh +115 -0
  751. package/ds-canonical/hooks/tests/test_check_canonical_propagation.sh +133 -0
  752. package/ds-canonical/hooks/tests/test_check_chrome_header_handcraft.sh +123 -0
  753. package/ds-canonical/hooks/tests/test_check_code_quality.sh +15 -0
  754. package/ds-canonical/hooks/tests/test_check_codex_collab_5step.sh +96 -0
  755. package/ds-canonical/hooks/tests/test_check_cva_default_sync.sh +15 -0
  756. package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +122 -0
  757. package/ds-canonical/hooks/tests/test_check_dim_count_drift.sh +98 -0
  758. package/ds-canonical/hooks/tests/test_check_field_controls_contracts.sh +126 -0
  759. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +194 -0
  760. package/ds-canonical/hooks/tests/test_check_file_size_budget.sh +32 -0
  761. package/ds-canonical/hooks/tests/test_check_hardcoded_strings.sh +14 -0
  762. package/ds-canonical/hooks/tests/test_check_header_with_tabs_border.sh +110 -0
  763. package/ds-canonical/hooks/tests/test_check_layout_space_canonical.sh +73 -0
  764. package/ds-canonical/hooks/tests/test_check_main_branch_workbench.sh +147 -0
  765. package/ds-canonical/hooks/tests/test_check_naming_and_abstraction.sh +136 -0
  766. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +110 -0
  767. package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +126 -0
  768. package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +148 -0
  769. package/ds-canonical/hooks/tests/test_check_peoplepicker_ssot_drift.sh +108 -0
  770. package/ds-canonical/hooks/tests/test_check_person_data_richness.sh +58 -0
  771. package/ds-canonical/hooks/tests/test_check_pixel_quantified_audit.sh +142 -0
  772. package/ds-canonical/hooks/tests/test_check_propose_plain_chinese.sh +126 -0
  773. package/ds-canonical/hooks/tests/test_check_propose_pre_grep_verify.sh +117 -0
  774. package/ds-canonical/hooks/tests/test_check_select_all_canonical.sh +125 -0
  775. package/ds-canonical/hooks/tests/test_check_solo_workflow.sh +201 -0
  776. package/ds-canonical/hooks/tests/test_check_spec_class_drift.sh +135 -0
  777. package/ds-canonical/hooks/tests/test_check_story_anatomy.sh.broken +197 -0
  778. package/ds-canonical/hooks/tests/test_check_story_category.sh.broken +187 -0
  779. package/ds-canonical/hooks/tests/test_check_story_compile_drift.sh +15 -0
  780. package/ds-canonical/hooks/tests/test_check_story_invariants.sh +209 -0
  781. package/ds-canonical/hooks/tests/test_check_story_name_jargon.sh.broken +53 -0
  782. package/ds-canonical/hooks/tests/test_check_story_slot_split.sh +156 -0
  783. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +176 -0
  784. package/ds-canonical/hooks/tests/test_check_tab_lg_chrome_header_equal.sh +138 -0
  785. package/ds-canonical/hooks/tests/test_check_token_hygiene.sh +21 -0
  786. package/ds-canonical/hooks/tests/test_check_wrapper_primitive_schema_drift.sh +169 -0
  787. package/ds-canonical/hooks/tests/test_enforce_home_charter.sh +77 -0
  788. package/ds-canonical/hooks/tests/test_inject_pending_self_audit.sh +125 -0
  789. package/ds-canonical/hooks/tests/test_log_governance_fires.sh +10 -0
  790. package/ds-canonical/hooks/tests/test_log_skill_invokes.sh +7 -0
  791. package/ds-canonical/hooks/tests/test_post_edit_dispatcher.sh +108 -0
  792. package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +143 -0
  793. package/ds-canonical/hooks/tests/test_stop_capture_metrics.sh +95 -0
  794. package/ds-canonical/hooks/tests/test_stop_governance_drift_check.sh.broken +125 -0
  795. package/ds-canonical/hooks/tests/test_stop_harvest_corrections.sh +10 -0
  796. package/ds-canonical/hooks/tests/test_stop_passive_logging.sh +100 -0
  797. package/ds-canonical/hooks/tests/test_stop_self_audit.sh +76 -0
  798. package/ds-canonical/hooks/tests/test_stop_tsc_sanity.sh +10 -0
  799. package/ds-canonical/references/README.md +43 -0
  800. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +74 -0
  801. package/ds-canonical/references/build-ui-canonicals.md +69 -0
  802. package/ds-canonical/references/cva-patterns.md +41 -0
  803. package/ds-canonical/references/drag-canonical.md +331 -0
  804. package/ds-canonical/references/item-anatomy-recipe.md +225 -0
  805. package/ds-canonical/references/naming-conventions.md +56 -0
  806. package/ds-canonical/references/principle-dim-map.json +515 -0
  807. package/ds-canonical/references/props-naming.md +45 -0
  808. package/ds-canonical/references/spec-rules.md +58 -0
  809. package/ds-canonical/references/ssot-consultation.md +63 -0
  810. package/ds-canonical/references/ssot-index.md +40 -0
  811. package/ds-canonical/references/story-baseline-registry.json +79 -0
  812. package/ds-canonical/references/structural-token-retention.md +42 -0
  813. package/ds-canonical/references/tailwind-gotchas.md +87 -0
  814. package/ds-canonical/references/ui-dev-rules.md +60 -0
  815. package/ds-canonical/rules/README.md +34 -0
  816. package/ds-canonical/rules/meta-patterns.md +87 -0
  817. package/ds-canonical/rules/self-verify.md +53 -0
  818. package/ds-canonical/rules/spec-rules.md +25 -0
  819. package/ds-canonical/rules/story-rules.md +56 -0
  820. package/ds-canonical/rules/ui-development.md +87 -0
  821. package/ds-canonical/skills/README.md +88 -0
  822. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +181 -0
  823. package/ds-canonical/skills/code-quality-audit/SKILL.md +63 -0
  824. package/ds-canonical/skills/codex-collab/SKILL.md +249 -0
  825. package/ds-canonical/skills/codex-collab/references/brief-template.md +48 -0
  826. package/ds-canonical/skills/codex-collab/references/transport.md +58 -0
  827. package/ds-canonical/skills/codify-corrections/SKILL.md +184 -0
  828. package/ds-canonical/skills/codify-principle/SKILL.md +151 -0
  829. package/ds-canonical/skills/component-quality-gate/SKILL.md +102 -0
  830. package/ds-canonical/skills/component-quality-gate/references/checklist.md +79 -0
  831. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +247 -0
  832. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +123 -0
  833. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +165 -0
  834. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +91 -0
  835. package/ds-canonical/skills/delivery-handoff/SKILL.md +229 -0
  836. package/ds-canonical/skills/delivery-handoff/references/flow-diagram.md +180 -0
  837. package/ds-canonical/skills/delivery-handoff/references/handoff-template.md +177 -0
  838. package/ds-canonical/skills/delivery-handoff/references/inventory-checklist.md +196 -0
  839. package/ds-canonical/skills/design-system-audit/SKILL.md +343 -0
  840. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1260 -0
  841. package/ds-canonical/skills/design-system-audit/references/checkpoints.md +240 -0
  842. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +240 -0
  843. package/ds-canonical/skills/design-system-audit/references/principle-audit-protocol.md +364 -0
  844. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +175 -0
  845. package/ds-canonical/skills/design-system-audit/references/spec-template.md +66 -0
  846. package/ds-canonical/skills/ensure-canonical/SKILL.md +196 -0
  847. package/ds-canonical/skills/governance-health/SKILL.md +146 -0
  848. package/ds-canonical/skills/knowledge-prune/SKILL.md +303 -0
  849. package/ds-canonical/skills/new-component/SKILL.md +170 -0
  850. package/ds-canonical/skills/new-component/references/new-component-checklist.md +85 -0
  851. package/ds-canonical/skills/performance-audit/SKILL.md +107 -0
  852. package/ds-canonical/skills/product-ui-audit/SKILL.md +230 -0
  853. package/ds-canonical/skills/product-ui-audit/references/audit-checks.md +246 -0
  854. package/ds-canonical/skills/product-ui-audit/references/common-misuses.md +329 -0
  855. package/ds-canonical/skills/product-ui-audit/references/report-template.md +159 -0
  856. package/ds-canonical/skills/propose-options/SKILL.md +177 -0
  857. package/ds-canonical/skills/prototype/SKILL.md +244 -0
  858. package/ds-canonical/skills/prototype/references/audit-checks.md +37 -0
  859. package/ds-canonical/skills/prototype/references/benchmark-sources.md +94 -0
  860. package/ds-canonical/skills/prototype/references/checkpoints.md +191 -0
  861. package/ds-canonical/skills/prototype/references/evaluation-matrix.md +141 -0
  862. package/ds-canonical/skills/prototype/references/ooux-template.md +198 -0
  863. package/ds-canonical/skills/prototype/references/proposal-template.md +229 -0
  864. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +198 -0
  865. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +159 -0
  866. package/ds-canonical/skills/story-writing/SKILL.md +122 -0
  867. package/ds-canonical/skills/story-writing/references/anatomy-standard.md +217 -0
  868. package/ds-canonical/skills/story-writing/references/category-templates.md +174 -0
  869. package/ds-canonical/skills/story-writing/references/example-selection.md +70 -0
  870. package/ds-canonical/skills/story-writing/references/self-check.md +20 -0
  871. package/ds-canonical/skills/ux-audit/SKILL.md +130 -0
  872. package/ds-canonical/skills/visual-audit/SKILL.md +245 -0
  873. package/ds-canonical/skills/visual-audit/output/.gitkeep +0 -0
  874. package/ds-canonical/skills/visual-audit/references/audit-architecture.md +100 -0
  875. package/ds-canonical/skills/visual-audit/references/visual-checklist.md +297 -0
  876. package/ds-canonical/skills/visual-audit/references/world-class-benchmarks.md +198 -0
  877. package/ds-canonical/templates/_README.md +23 -0
  878. package/ds-canonical/templates/dashboard-app.tsx +145 -0
  879. package/ds-story-manifest.json +1690 -0
  880. package/package.json +22 -9
  881. package/src/components/Accordion/accordion.spec.md +114 -0
  882. package/src/components/Accordion/index.ts +5 -0
  883. package/src/components/Alert/alert.spec.md +197 -0
  884. package/src/components/Alert/index.ts +5 -0
  885. package/src/components/AppShell/app-shell.spec.md +331 -0
  886. package/src/components/AppShell/index.ts +5 -0
  887. package/src/components/AspectRatio/aspect-ratio.spec.md +134 -0
  888. package/src/components/AspectRatio/index.ts +5 -0
  889. package/src/components/Avatar/avatar.spec.md +319 -0
  890. package/src/components/Avatar/index.ts +5 -0
  891. package/src/components/Badge/badge.spec.md +380 -0
  892. package/src/components/Badge/index.ts +5 -0
  893. package/src/components/Breadcrumb/breadcrumb.spec.md +251 -0
  894. package/src/components/Breadcrumb/breadcrumb.tsx +26 -16
  895. package/src/components/Breadcrumb/index.ts +5 -0
  896. package/src/components/BulkActionBar/bulk-action-bar.spec.md +210 -0
  897. package/src/components/BulkActionBar/index.ts +5 -0
  898. package/src/components/Button/button.spec.md +445 -0
  899. package/src/components/Button/index.ts +5 -0
  900. package/src/components/Calendar/calendar.spec.md +242 -0
  901. package/src/components/Calendar/index.ts +5 -0
  902. package/src/components/Carousel/carousel.spec.md +253 -0
  903. package/src/components/Carousel/index.ts +5 -0
  904. package/src/components/Chart/chart.spec.md +155 -0
  905. package/src/components/Chart/index.ts +5 -0
  906. package/src/components/Checkbox/checkbox.spec.md +344 -0
  907. package/src/components/Checkbox/index.ts +5 -0
  908. package/src/components/Chip/chip.spec.md +230 -0
  909. package/src/components/Chip/index.ts +5 -0
  910. package/src/components/CircularProgress/circular-progress.spec.md +268 -0
  911. package/src/components/CircularProgress/index.ts +5 -0
  912. package/src/components/Coachmark/coachmark.spec.md +230 -0
  913. package/src/components/Coachmark/index.ts +5 -0
  914. package/src/components/Combobox/combobox.spec.md +180 -0
  915. package/src/components/Combobox/combobox.tsx +6 -6
  916. package/src/components/Combobox/index.ts +5 -0
  917. package/src/components/Command/command.spec.md +171 -0
  918. package/src/components/Command/index.ts +5 -0
  919. package/src/components/DataTable/data-table.spec.md +525 -0
  920. package/src/components/DataTable/index.ts +5 -0
  921. package/src/components/DateGrid/date-grid.spec.md +215 -0
  922. package/src/components/DateGrid/index.ts +5 -0
  923. package/src/components/DatePicker/date-picker.spec.md +334 -0
  924. package/src/components/DatePicker/index.ts +5 -0
  925. package/src/components/DescriptionList/description-list.spec.md +214 -0
  926. package/src/components/DescriptionList/index.ts +5 -0
  927. package/src/components/Dialog/dialog.spec.md +193 -0
  928. package/src/components/Dialog/dialog.tsx +4 -4
  929. package/src/components/Dialog/index.ts +5 -0
  930. package/src/components/DropdownMenu/dropdown-menu.spec.md +241 -0
  931. package/src/components/DropdownMenu/index.ts +5 -0
  932. package/src/components/Empty/empty.spec.md +204 -0
  933. package/src/components/Empty/index.ts +5 -0
  934. package/src/components/Field/field-controls.spec.md +338 -0
  935. package/src/components/Field/field.spec.md +438 -0
  936. package/src/components/Field/form-validation.spec.md +142 -0
  937. package/src/components/Field/index.ts +5 -0
  938. package/src/components/FieldControlGroup/field-control-group.spec.md +176 -0
  939. package/src/components/FieldControlGroup/index.ts +5 -0
  940. package/src/components/FileItem/file-item.spec.md +467 -0
  941. package/src/components/FileItem/index.ts +5 -0
  942. package/src/components/FileUpload/file-upload.spec.md +123 -0
  943. package/src/components/FileUpload/index.ts +5 -0
  944. package/src/components/FileViewer/file-viewer.spec.md +373 -0
  945. package/src/components/FileViewer/index.ts +5 -0
  946. package/src/components/HoverCard/hover-card.spec.md +149 -0
  947. package/src/components/HoverCard/index.ts +5 -0
  948. package/src/components/Input/index.ts +5 -0
  949. package/src/components/Input/input.spec.md +193 -0
  950. package/src/components/LinkInput/index.ts +5 -0
  951. package/src/components/LinkInput/link-input.spec.md +130 -0
  952. package/src/components/Menu/index.ts +5 -0
  953. package/src/components/Menu/menu-item.spec.md +283 -0
  954. package/src/components/NameCard/index.ts +5 -0
  955. package/src/components/NameCard/name-card.spec.md +171 -0
  956. package/src/components/Notice/index.ts +5 -0
  957. package/src/components/Notice/notice.spec.md +149 -0
  958. package/src/components/NumberInput/index.ts +5 -0
  959. package/src/components/NumberInput/number-input.spec.md +126 -0
  960. package/src/components/OverflowIndicator/index.ts +5 -0
  961. package/src/components/OverflowIndicator/overflow-indicator.spec.md +120 -0
  962. package/src/components/PeoplePicker/index.ts +5 -0
  963. package/src/components/PeoplePicker/people-picker.spec.md +263 -0
  964. package/src/components/Popover/index.ts +5 -0
  965. package/src/components/Popover/popover.spec.md +191 -0
  966. package/src/components/Popover/popover.tsx +1 -1
  967. package/src/components/ProgressBar/index.ts +5 -0
  968. package/src/components/ProgressBar/progress-bar.spec.md +232 -0
  969. package/src/components/RadioGroup/index.ts +5 -0
  970. package/src/components/RadioGroup/radio-group.spec.md +141 -0
  971. package/src/components/Rating/index.ts +5 -0
  972. package/src/components/Rating/rating.spec.md +208 -0
  973. package/src/components/ScrollArea/index.ts +5 -0
  974. package/src/components/ScrollArea/scroll-area.spec.md +145 -0
  975. package/src/components/SegmentedControl/index.ts +5 -0
  976. package/src/components/SegmentedControl/segmented-control.spec.md +295 -0
  977. package/src/components/Select/index.ts +5 -0
  978. package/src/components/Select/select.spec.md +299 -0
  979. package/src/components/SelectMenu/index.ts +5 -0
  980. package/src/components/SelectMenu/select-menu.spec.md +220 -0
  981. package/src/components/SelectionControl/index.ts +5 -0
  982. package/src/components/SelectionControl/selection-item.spec.md +128 -0
  983. package/src/components/Separator/index.ts +5 -0
  984. package/src/components/Separator/separator.spec.md +109 -0
  985. package/src/components/Sheet/index.ts +5 -0
  986. package/src/components/Sheet/sheet.spec.md +141 -0
  987. package/src/components/Sheet/sheet.tsx +1 -1
  988. package/src/components/Sidebar/index.ts +5 -0
  989. package/src/components/Sidebar/sidebar.spec.md +706 -0
  990. package/src/components/Skeleton/index.ts +5 -0
  991. package/src/components/Skeleton/skeleton.spec.md +104 -0
  992. package/src/components/Slider/index.ts +5 -0
  993. package/src/components/Slider/slider.spec.md +353 -0
  994. package/src/components/Steps/index.ts +5 -0
  995. package/src/components/Steps/steps.spec.md +465 -0
  996. package/src/components/Switch/index.ts +5 -0
  997. package/src/components/Switch/switch.spec.md +215 -0
  998. package/src/components/Tabs/index.ts +5 -0
  999. package/src/components/Tabs/tabs.spec.md +314 -0
  1000. package/src/components/Tag/index.ts +5 -0
  1001. package/src/components/Tag/tag.spec.md +282 -0
  1002. package/src/components/Textarea/index.ts +5 -0
  1003. package/src/components/Textarea/textarea.spec.md +151 -0
  1004. package/src/components/TimePicker/index.ts +5 -0
  1005. package/src/components/TimePicker/time-picker.spec.md +279 -0
  1006. package/src/components/TimePicker/time-picker.tsx +4 -4
  1007. package/src/components/Toast/index.ts +5 -0
  1008. package/src/components/Toast/toast.spec.md +177 -0
  1009. package/src/components/Tooltip/index.ts +5 -0
  1010. package/src/components/Tooltip/tooltip.spec.md +132 -0
  1011. package/src/components/TreeView/index.ts +5 -0
  1012. package/src/components/TreeView/tree-view.spec.md +388 -0
  1013. package/src/components/TreeView/tree-view.tsx +24 -12
  1014. package/src/index.ts +70 -69
  1015. package/src/patterns/action-bar/action-bar.spec.md +458 -0
  1016. package/src/patterns/element-anatomy/element-anatomy.spec.md +215 -0
  1017. package/src/patterns/element-anatomy/index.ts +5 -0
  1018. package/src/patterns/element-anatomy/inline-action.spec.md +304 -0
  1019. package/src/patterns/element-anatomy/item-anatomy.spec.md +1042 -0
  1020. package/src/patterns/header-canonical/header-canonical.spec.md +285 -0
  1021. package/src/patterns/header-canonical/index.ts +5 -0
  1022. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +191 -0
  1023. package/src/patterns/horizontal-overflow/index.ts +5 -0
  1024. package/src/patterns/overlay-surface/index.ts +5 -0
  1025. package/src/patterns/overlay-surface/overlay-surface.spec.md +419 -0
  1026. package/src/patterns/resize-handle/index.ts +5 -0
  1027. package/src/patterns/resize-handle/resize-handle.spec.md +109 -0
  1028. package/src/styles/tokens.css +42 -0
  1029. package/src/tokens/README.md +2 -0
  1030. package/src/tokens/color/color.spec.md +772 -0
  1031. package/src/tokens/density/density.spec.md +127 -0
  1032. package/src/tokens/elevation/elevation.spec.md +72 -0
  1033. package/src/tokens/layoutSpace/layoutSpace.spec.md +303 -0
  1034. package/src/tokens/motion/motion.spec.md +97 -0
  1035. package/src/tokens/opacity/opacity.spec.md +78 -0
  1036. package/src/tokens/orphan-tokens.spec.md +117 -0
  1037. package/src/tokens/radius/radius.spec.md +123 -0
  1038. package/src/tokens/token-system.spec.md +243 -0
  1039. package/src/tokens/typography/typography.spec.md +202 -0
  1040. package/src/tokens/uiSize/uiSize.css +16 -0
  1041. package/src/tokens/uiSize/uiSize.spec.md +428 -0
@@ -0,0 +1,1042 @@
1
+ <!-- @benchmark-cited: D5 retrofit 2026-05-18 — body claims marked per-claim @benchmark-unverified inline; canonical source URLs in frontmatter benchmark list. -->
2
+
3
+ # Item Anatomy 設計原則(Family 1 + Family 2 row 結構 SSOT)
4
+
5
+ > **Super-foundational SSOT rationale**(2026-04-24 approved,cap 1200 例外):
6
+ > 涵蓋 Family 1 + Family 2 跨 10+ row primitive 的 SSOT(結構 canonical、slot 規則、24px 閾值對齊公式、選擇狀態視覺、新 primitive 建立指南、Inline Action 分家)。本 spec 是**全 DS 最大 SSOT**,前次 prune 嘗試搬 canonical 搬到 references 後 user 確認違反 2-home,restored。長期收斂路徑:`.claude/planning/row-primitive-consolidation.md`(SidebarMenuButton / TreeItem 消費 menuItemVariants 後可搬「獨立實作風險」節,估縮 ~100 行)。
7
+
8
+ ## 定位
9
+
10
+ 本 spec 是 design system **row anatomy(Family 1 + Family 2)的深度 SSOT**——包含:
11
+
12
+ - **Family 1: Menu item anatomy**(scanning mode,menu 容器內緊湊單列)深度規格
13
+ - **Family 2: List item anatomy**(reading mode,頁面上閱讀式單列)深度規格
14
+ - **runtime primitive**:`<MenuItem>`(canonical F1 wrapper in `components/Menu/`)+ slot components `<ItemPrefix>` / `<ItemIcon>` / `<ItemAvatar>` / `<ItemLabel>` / `<ItemInlineAction>` / `<ItemSuffix>` + `RowSizeProvider` / `useRowSize` context(實作於 `item-anatomy.tsx`)
15
+ - F1 + F2 共用結構骨架:`[prefix] [content] [suffix]` + `items-start` + `h-[1lh]` wrapper + 24px 閾值 / card header 規則
16
+
17
+ **不包含**(去其他 SSOT):
18
+ - **4-Family Model taxonomy** → 同 folder `element-anatomy.spec.md`(cross-pattern/cross-component governance doc)
19
+ - **Family 3: Pill anatomy** → `components/Button/button.spec.md`「Pill Layout」章節
20
+ - **Family 4: Field control anatomy** → `components/Field/field-controls.spec.md`
21
+
22
+ **命名**: folder `item-anatomy/` = spec `item-anatomy.spec.md` = tsx `item-anatomy.tsx`,scope = F1/F2 row anatomy。「item」對齊世界級 idiom(Material `ListItem` / Polaris `ResourceItem` / Ant `List.Item`);slot components 用 `Item{Slot}` 命名(`ItemIcon` / `ItemAvatar` / `ItemLabel` / `ItemSuffix` / `ItemInlineAction`)—— 對齊 Radix compound-component 風格。無 `ItemLayout` 這種帶「Layout」後綴的 export(違反「element-level 不用 layout 字」鐵律)。
23
+
24
+ ---
25
+
26
+ ## Family 1: Menu item anatomy(scanning mode,SSOT)
27
+
28
+ **用途**:Menu 容器內的掃視單列。使用者眼睛快速移動、選項密集、tight density。
29
+
30
+ **結構**:`[small icon/avatar 16-20px] [content: label 單行 + desc 選用] [small suffix action/chevron]`,leading-compact,字體偏小。
31
+
32
+ **消費者**:
33
+
34
+ | 元件 | 所在檔案 | 備註 |
35
+ |------|---------|------|
36
+ | `MenuItem`(含 `header` 模式) | `components/Menu/menu-item.tsx` | **Canonical 實作** |
37
+ | `TreeItem` | `components/TreeView/tree-view.tsx` | 階層結構 |
38
+ | `SidebarMenuButton` / `SidebarGroupLabel` | `components/Sidebar/sidebar.tsx` | Sidebar 專用 menu item |
39
+ | `DropdownMenuItem` | 重用 MenuItem | `components/DropdownMenu/dropdown-menu.tsx` |
40
+ | `SelectMenu`(→ `Select` searchable / `Combobox` searchable / `PeoplePicker`) | `components/SelectMenu/select-menu.tsx` | internal primitive,內部 CommandGroup > MenuItem 走 Family 1 |
41
+
42
+ **`MenuItem` 的 `menuItemVariants` cva 是 Family 1 canonical**——寫任何新 menu-context row 元件前,先讀它,複製 padding 公式 + variant 結構,不要自己發明。
43
+
44
+ ### 部分繼承者(partial consumer)— 非 Family 1 正式消費者
45
+
46
+ 以下元件**只繼承 Family 1 的部分規則**(如 gap-2 slot 間距 / 字體 tier / hover 行為),結構上不是 row primitive。列在此保持 reciprocal 完整,但不強制 follow 全部 Family 1 規格:
47
+
48
+ | 元件 | 繼承的部分 | 不繼承的部分 |
49
+ |------|----------|-----------|
50
+ | `Tabs`(Trigger) | gap-2 slot 間距、scanning 字體 tier、hover 行為 | 結構是**橫向 inline**(非垂直 row), 高度系統對標 Button, 無 prefix/content/suffix column | 詳細對標分析見 `components/Tabs/tabs.spec.md`「Tabs 不完全屬於 item-layout」段 |
51
+
52
+ ---
53
+
54
+ ## Family 2: List item layout(reading mode,SSOT)
55
+
56
+ **用途**:頁面上的閱讀式單列。使用者讀取內容、需要 description 多行、looser density。
57
+
58
+ **結構**:`[larger icon/avatar 20-24px] [content: label + multi-line description OK] [suffix action/button/counter]`,reading typography(default leading),字體略大於 Family 1。
59
+
60
+ **消費者**:
61
+
62
+ | 元件 | 所在檔案 | 備註 |
63
+ |------|---------|------|
64
+ | `StepItem` / `StepLabel` / `StepDescription` | `components/Steps/steps.tsx` | **明文例外**:indicator inline 對齊 label 第一行,不走 24px 閾值(見 `components/Steps/steps.spec.md` 的「對 item-layout 的明文例外」節) |
65
+ | `FileItem`(rich mode) | `components/FileItem/file-item.tsx` | icon/avatar 作 item boundary,不只是 prefix |
66
+ | `Notice`(→ `Alert` / `Toast`) | `components/Notice/notice.tsx` | 語意為 notification 而非 row collection,但**視覺排版遵循 Family 2**確保跨元件視覺語言一致 |
67
+ | `SelectionItem` variant | `components/SelectionControl/selection-item.tsx` | Prefix 是 selection control(Checkbox / Radio indicator),用於頁面 RadioGroup / Checkbox group |
68
+
69
+ **為什麼 Notice 是 Family 2(即使語意不同)**:Notice / Alert / Toast 的 `[icon] [title + description] [action buttons / dismiss]` 結構就是 List item layout 的 prefix / content / suffix——語意不同(通知 vs 列表),但**結構和排版原則必須一致**,否則同個系統內會產生兩套表面形式相同但規則不同的版面,跨元件視覺語言漂移。
70
+
71
+ **SelectionItem variant 特徵**:prefix slot 放 Checkbox/Radio indicator(而非 icon/avatar),其餘結構完全遵循 Family 2。RadioGroup / Checkbox group 在頁面上直接展開使用時走此 variant。
72
+
73
+ ---
74
+
75
+ ## List item 範疇的必消費 primitive canonical(2026-04-22)
76
+
77
+ **鐵律**:只要判斷內容屬於 **list item 範疇**(不管一行兩行、不管有沒有 icon、不管 overlay 內還是頁面上),**預設先按照 item-anatomy 的方式消費既有 primitive**——不准 hand-craft `<div className="flex py-3">...</div>` 繞過 anatomy canonical。
78
+
79
+ ### 世界級對照(所有世界級 DS 都有統一的 item primitive,不讓 consumer 自刻)
80
+
81
+ | DS | Primitive 名稱 | 對應 slot API |
82
+ |----|--------------|---------------|
83
+ | **Material M3** | `ListItem` + `ListItemText` + `ListItemAvatar` + `ListItemIcon` + `ListItemSecondaryAction` | avatar / icon / primary text / secondary text / trailing action |
84
+ | **Shopify Polaris** | `ResourceItem` + `ResourceList` | media(avatar / thumbnail)/ name / accessibilityLabel / shortcutActions |
85
+ | **Atlassian(ADG)** | `Item` / `ItemGroup`(primitive + composition) | elemBefore / elemAfter / description |
86
+ | **Ant Design** | `List.Item` + `List.Item.Meta` | avatar / title / description / actions |
87
+ | **GitHub Primer** | `ActionList.Item`(+ `LeadingVisual` / `TrailingVisual` / `Description`) | leadingVisual / trailingVisual / description |
88
+ | **Apple HIG(UIKit)** | `UIListContentConfiguration`(system-provided cell layout) | image / text / secondaryText |
89
+
90
+ **共識**:每家 DS 都 ship list item primitive + slot API,禁止 consumer 自刻 — 自刻 = 跨產品視覺語言斷裂。
91
+
92
+ ### 判斷流程(content 類型 → primitive 選擇)
93
+
94
+ ```
95
+ 這段內容是什麼?
96
+
97
+ ├─ list item 範疇(一筆資料一列、重複 N 次的結構化條目)?
98
+ │ │
99
+ │ ├─ 緊湊掃視(menu 容器 / cmd palette / dropdown)?
100
+ │ │ → <MenuItem>(Family 1 scanning,SSOT) + slot components
101
+ │ │
102
+ │ ├─ 閱讀式(頁面上、overlay body 內、avatar+title+desc)?
103
+ │ │ → Family 2(reading) — 目前沒有單一 <ListItem> primitive,
104
+ │ │ 先 compose:使用 slot components(<ItemIcon> / <ItemAvatar> /
105
+ │ │ <ItemLabel> / <ItemSuffix> / <ItemInlineAction>)照 Family 2
106
+ │ │ 結構 + tokens 組裝;或直接消費既有 Family 2 consumer
107
+ │ │ (FileItem rich / SelectionItem / Notice 的 anatomy)
108
+ │ │
109
+ │ └─ Key-Value 配對(Label: Value 形式的屬性展示 / metadata 列)?
110
+ │ → <DescriptionList> + <DescriptionItem>(horizontal / vertical)
111
+ │ SSOT: components/DescriptionList/description-list.spec.md
112
+
113
+ └─ 非 list item 範疇(form / prose / single block / illustration)?
114
+ → 不走 item primitive,走 Field / 文字 / 自訂 layout
115
+ ```
116
+
117
+ ### Key-Value(DescriptionList)vs List item(MenuItem / Family 2)的邊界
118
+
119
+ | Content shape | 消費 | 理由 |
120
+ |---------------|------|------|
121
+ | `[avatar] Title\nSubtitle` / `[icon] Label` | **MenuItem / Family 2** | 語意是「一個實體 / 一筆資料」,title 是 item 識別 |
122
+ | `Email:user@x.com` / `Created: 2026-04-22` | **DescriptionList** | 語意是「同一實體的 N 個屬性」,label 是 key,不是 item 識別 |
123
+ | 一排 `[status dot] Project name [count]` | **MenuItem / Family 2** | 實體列表(每個 project 是獨立 item) |
124
+ | NameCard 裡 profile 的「職稱 / 部門 / 到期日」 | **DescriptionList(horizontal)** | 同一人的多個 metadata 屬性 |
125
+
126
+ ### ❌ 禁止(自刻 = 繞過 anatomy canonical)
127
+
128
+ - ❌ overlay body 裡 `<div className="flex items-center gap-3 py-3 hover:bg-neutral-hover">...</div>` 當 list item(應用 MenuItem / ItemAvatar + ItemLabel + ItemSuffix slot components)
129
+ - ❌ 頁面上 key-value 自刻 `<div className="grid grid-cols-[120px_1fr]"><span>Email</span><span>...</span></div>`(應用 DescriptionList + DescriptionItem)
130
+ - ❌ 為「就一兩行」偷懶不消費 primitive(一行也是 list item,照走 MenuItem)
131
+ - ❌ 自發明 row 結構(勿用 `prefix` / `suffix` / `left` / `right` 命名,勿自刻 24px item 閾值)
132
+
133
+ ### 消費前的 4-step check
134
+
135
+ 1. `ls packages/design-system/src/patterns/element-anatomy/`(確認 item-anatomy primitive 存在)
136
+ 2. grep 近親 consumer(MenuItem / FileItem / SelectionItem / Notice)看 slot 怎麼用
137
+ 3. 判斷 key-value vs list item(見上表)選對 primitive
138
+ 4. 內部結構不命中既有 slot → 回 item-anatomy.spec.md 擴 API,**不自刻繞過**
139
+
140
+ ### 寫任何 list / key-value UI 前 grep 自檢
141
+
142
+ ```bash
143
+ # 看有沒有繞過 item-anatomy 的手刻 list item
144
+ rg "className=\"flex.*py-[0-9].*hover:bg\" packages/design-system/src src/hooks --type tsx
145
+ # 看有沒有繞過 DescriptionList 的手刻 key-value grid
146
+ rg "grid-cols-\[[0-9]+px_1fr\]" packages/design-system/src src/hooks --type tsx
147
+ ```
148
+
149
+ 非空 = drift,要改用 primitive。
150
+
151
+ ---
152
+
153
+ ## 任何未來的 row 元件
154
+
155
+ 必須先判斷屬於 Family 1 或 Family 2,然後照對應章節的規則做。**不要自己發明新規格**——發明前必先讀本 spec 全文 + CLAUDE.md「4-Family Model」。
156
+
157
+ ---
158
+
159
+ ## Row primitives 必須共用的結構規格(跨 Family 1 + 2 共用)
160
+
161
+ ### Row primitives 必須共用的規格
162
+
163
+ - **水平 padding**: `px-[var(--layout-space-loose)]`(sidebar context) / `px-3`(menu context),由 consumer 脈絡決定
164
+ - **垂直 padding**: `py-[calc((var(--field-height-N) N∈{sm,md,lg}-1lh)/2)]` 的 item-layout 公式
165
+ - **字重**: `font-medium`(500),**不隨 selected 變**
166
+ - **預設文字色**: `text-fg-secondary`(neutral-8);icon 透過 currentColor 繼承
167
+ - **Hover**: `bg-neutral-hover` + `text-foreground`
168
+ - **Active / selected**: `bg-neutral-selected` + `text-foreground`(不加字重,避免跳動)
169
+ - **無 rounded**: full-width fill
170
+ - **無 gap 在 items 之間**: items 緊貼(SidebarMenu / TreeView / DropdownMenuGroup 容器不設 flex gap)
171
+ - **Size variants**: sm / md / lg 跟 `--field-height-*` family 一致
172
+ - **Icon 尺寸控制**: 用 `ICON_SIZE` 常數 `{ sm: 16, md: 16, lg: 20 }` 對齊 `--field-height-*`,並**透過 `size` prop 直接傳給 Lucide icon**(不要用 CSS selector 如 `[&>svg]:size-4`——當 icon 被包在 `h-[1lh]` wrapper 裡時,`>` 直接子選擇器失效,Lucide 會 fallback 到 24px 預設)。MenuItem / TreeView / SidebarMenuButton 都這樣做,新元件照抄
173
+ - **Row header(分組標題)**: 用 `MenuItem header={true}` 模式,`font-medium text-fg-muted pointer-events-none` + 與 items **完全相同**的 row geometry(同 px / 同 py / 同 text size)
174
+
175
+ ### Prefix 垂直對齊:`items-start` + `h-[1lh]` wrapper(**永遠這樣**,不要做例外)
176
+
177
+ 所有 row primitives 的 outer flex 用 **`items-start`** + prefix(icon / avatar / checkbox / indicator)包在 **`h-[1lh] shrink-0 flex items-center`** 容器。這是**底層規則,不可跳過**。
178
+
179
+ ```tsx
180
+ // ✅ 正確(TreeItem / SidebarMenuButton / MenuItem 都這樣)
181
+ <div className="flex items-start gap-2">
182
+ <span className="h-[1lh] shrink-0 flex items-center">
183
+ <Icon size={16} /> {/* 或 Avatar / Checkbox */}
184
+ </span>
185
+ <span className="min-w-0 flex-1 truncate">{label}</span>
186
+ </div>
187
+ ```
188
+
189
+ **為什麼**:
190
+ - **單行 label**(`truncate` = `line-clamp-1`,絕大多數情境):prefix 透過 `h-[1lh]` 對齊第一行文字中線 → **視覺效果等同 `items-center`**,垂直置中完美
191
+ - **多行 label**(罕見但可能發生):prefix 仍然留在第一行,不隨文字下移
192
+
193
+ **禁止**:
194
+ - ❌ 用 `items-center` 取代 `items-start`——看似單行簡化,但多行時 prefix 會飄移,且**會讓你之後踩坑**時想不起「為什麼當初沒 follow pattern」
195
+ - ❌ 用 `items-start` 但不包 `h-[1lh]` wrapper——prefix 會對齊 label top 而非第一行 baseline,當 prefix 高度 ≠ 文字 line-height 時(例如 Avatar 24 vs text 18)視覺歪斜
196
+
197
+ **asChild 的 consumer 也必須遵守**:用 asChild 讓 SidebarMenuButton / TreeItem 接受自訂 children(例如塞 Avatar 而非 LucideIcon)時,consumer 必須**自己**把 prefix 包進 `h-[1lh] shrink-0 flex items-center` 容器,不能省略。
198
+
199
+ ### Card header 大 prefix 對齊(avatar > text block)
200
+
201
+ Row primitive 的 24px 閾值規則適用於**列表行**(prefix 跟 text block 接近等高)。當 prefix 遠大於 text block 時(如 64px profile avatar 搭配 1-2 行文字),改用 **card header 模式**:
202
+
203
+ ```tsx
204
+ <div className="flex items-start gap-3">
205
+ <Avatar size={64} />
206
+ <div className="flex flex-col justify-center min-w-0 flex-1" style={{ minHeight: 64 }}>
207
+ <span>Name</span>
208
+ <span>Subtitle</span>
209
+ </div>
210
+ </div>
211
+ ```
212
+
213
+ **規則**:text column 用 `justify-center` + `minHeight: prefix-size`。
214
+
215
+ | 情境 | 表現 |
216
+ |---|---|
217
+ | 短文字(< prefix 高度) | 文字垂直置中於 prefix 高度 |
218
+ | 長文字(> prefix 高度) | 文字自然撐高,`items-start` 讓 prefix 頂部對齊 |
219
+
220
+ 適用場景:NameCard profile header、FileItem rich、未來的 profile page header。
221
+ 不適用:row primitives(MenuItem / TreeItem / Sidebar)——那些走 24px 閾值。
222
+
223
+ ---
224
+
225
+ ## 垂直 padding 歸屬:row 集合不加 py,由外層容器負責
226
+
227
+ **Row 集合元件**(TreeView root、SidebarMenu ul、DropdownMenuGroup 內容)**自己不加垂直 padding**。上下呼吸空間**永遠由外層容器提供**:
228
+
229
+ | Row 集合 | 外層容器 | 容器 py |
230
+ |---|---|---|
231
+ | `SidebarMenu` | `SidebarGroup` | `py-2` |
232
+ | `TreeView`(在 sidebar 內) | `SidebarGroupContent`(父層 `SidebarGroup py-2`) | 繼承 `py-2` |
233
+ | `TreeView`(在 dropdown 浮層) | `DropdownMenuContent` | `py-2`(content 自帶) |
234
+ | `TreeView`(獨立使用,如 story demo) | consumer 自己的 wrapper div | **必須自己加** `py-2` |
235
+ | `MenuItem` 集合 | `MenuGroup` | `py-2` + `[&+&]:border-t` 自動分隔 |
236
+ | `DropdownMenuItem` 集合 | `DropdownMenuContent` | `py-2` |
237
+
238
+ ### 為什麼
239
+
240
+ Row 集合是**內容(content)**,不是區段(region)。加 py 到 row 集合會在不同外層容器下「各加一層」導致雙重 padding,或「單獨使用時沒呼吸空間」貼邊。
241
+
242
+ **曾經發生的 bug**:TreeView 原本硬寫 `py-2`,放進 `SidebarGroup`(也有 `py-2`)導致 label 和 first tree item 之間多出 8px 無法解釋的 gap;後來改成「只有 menu context 加 py-2」,結果 story 的 bordered wrapper 不屬於 menu context,items 貼邊。最終解法:TreeView root 一律不加 py,所有外層容器自己負責。
243
+
244
+ ### 實作規則
245
+
246
+ - 寫 row 集合元件(新 tree / menu / list)時,**root div 不加 py**
247
+ - 容器元件(group / section wrapper)**一定要加 `py-2`**
248
+ - Story demo 在 bordered container 展示 row 集合時,**wrapper 必須自己加 `py-2`**,否則 items 會貼邊
249
+ - 這條規則適用「所有 row 集合」,不只 TreeView——新增任何類似元件遵守
250
+
251
+ ---
252
+
253
+ ## Group auto-separation
254
+
255
+ **跨 Menu-like 元件統一設計語言**。SSOT 段落:`MenuGroup` / `DropdownMenuGroup` / 未來的 `ContextMenuGroup` 等 row group primitives 共享此設計語言。
256
+
257
+ ### 設計語言
258
+
259
+ - **每個 group 上下各 8px padding**
260
+ - **相鄰 group 之間用 `border-divider` 分隔**
261
+ - **兩個 group 之間視覺 gap = 8(上 bottom)+ 8(下 top)= 16px + border**
262
+
263
+ Consumer 不需手動插 Separator——把同類 items 包進 Group,自動分隔。
264
+
265
+ ### 兩種 CSS 實作(視覺等價,差別在 padding 住哪層)
266
+
267
+ | | **Pattern A**(Group 自帶 padding) | **Pattern B**(Container 提供邊界 padding) |
268
+ |---|---|---|
269
+ | 典型案例 | `MenuGroup`(menu-item.tsx) | `DropdownMenuGroup`(dropdown-menu.tsx) |
270
+ | 何時用 | 外層容器**無** `py-2`(例:`Command.List`) | 外層容器**已有** `py-2`(例:`DropdownMenuContent`) |
271
+ | CSS | `py-2 [&+&]:border-t [&+&]:border-divider` | `[&+&]:mt-2 [&+&]:pt-2 [&+&]:border-t [&+&]:border-divider` |
272
+ | 邊界 padding 來源 | Group 自己的 py-2 | Container 的 py-2 |
273
+ | Group 間 gap | 8 + 8 = 16 + border | 0 + 8 + 8 = 16 + border |
274
+
275
+ **視覺結果 100% 等價**——都是 Content 邊界 8px + 相鄰 group 間 16px + border。
276
+
277
+ ### 為什麼不強制統一 CSS
278
+
279
+ 不同外層容器(`Command.List` vs `DropdownMenuPrimitive.Content`)對 padding 的預期不同(Radix 的 Content 自帶 `py-2` 是為了鍵盤導覽 focus offset,移除會破壞行為)。**強行統一 CSS 會破壞外層 primitive 的預期**——所以允許兩種 Pattern,但**視覺結果必須等價**(16px gap + border)。
280
+
281
+ ### 新增 group primitive 的檢查清單
282
+
283
+ 建立新的 Menu-like group 元件(例 `ContextMenuGroup`、`CommandGroup` 擴充)時:
284
+
285
+ 1. **確認外層容器有沒有 `py-2`**
286
+ - 有 → 用 Pattern B(`[&+&]:mt-2 [&+&]:pt-2 [&+&]:border-t [&+&]:border-divider`)
287
+ - 沒有 → 用 Pattern A(`py-2 [&+&]:border-t [&+&]:border-divider`)
288
+ 2. **視覺驗證**:兩個相鄰 group 之間 gap **必須** = 16px + border。不可多、不可少
289
+ 3. **加 cross-reference 註解**:tsx 檔裡指向本 spec 段落,讓未來維護者知道這是跨元件 SSOT
290
+ 4. **不創新 CSS**:只能從 Pattern A / B 二選一,不自己發明第三種公式
291
+
292
+ ### 歷史錯誤
293
+
294
+ 本 session 曾寫過 `[&+&]:mt-1 [&+&]:pt-1`(只有 4+4 = 8px gap)——**錯誤**,少於設計語言的 16px。後修正為 `mt-2 pt-2`。
295
+
296
+ **避免方式**:新增 group primitive 時先檢查 MenuGroup 的視覺 gap,用同樣距離。
297
+
298
+ ---
299
+
300
+ ## 連續 item 貼邊合法性(2026-04-22 canonical)
301
+
302
+ **核心原則**(user 明示):連續 item 之間是否需要 gap,取決於**該 item 的永久視覺層會不會在視覺上跟相鄰 item 相連**——不是所有 item 都需要 gap,也不是所有 item 都可以貼邊。
303
+
304
+ ### 公式(3 條)
305
+
306
+ ```
307
+ 1. 同類 standalone card/pill(bg + radius + inset)list
308
+ → 必 gap(防 card/pill 融合失去 identity)
309
+
310
+ 2. 同類 permanent flush / permanent transparent list
311
+ → 0 gap 合法;分隔靠 border-b / 底部 progress bar / connector line
312
+
313
+ 3. 混合視覺語言 list(standalone card + flush-with-separator,或任兩類混用)
314
+ → 必取最保守 gap(= max(各類最小 gap))
315
+ 原因:相鄰兩類的 affordance 會互相吸收 —— 分隔線型 item 的底線 / progress bar
316
+ 緊貼 card 型 item 的 bg 邊時,分隔線被 card 邊界吸收,變成「card 的一部分」
317
+ 而不是「獨立分隔 affordance」。必 gap 讓各類保留自己的視覺語言。
318
+ ```
319
+
320
+ **關鍵定義**:
321
+ - **standalone card/pill**:item 有 **permanent** visible container(bg 色塊 或 邊框)+ radius + **不貼父容器邊**(max-w / inset 讓 item 明顯是獨立輪廓)
322
+ - **flush full-width**:item 貼父容器邊、無 per-item radius、bg 透明或繼承父層。分隔靠 border-b / progress bar / separator(分隔線型 affordance)
323
+ - **permanent transparent**:item 靜態完全透明;有 radius 但只在 hover / selected / focus state 可見(M3 Nav drawer idiom)
324
+
325
+ **為什麼 state 不獨立列規則**:state 視覺(hover / focus / active / selected)跟隨 permanent layer 分類,不獨立觸發。瞬時 state(hover/focus/active)單一 item 啟用不會創造相鄰衝突;selected 的連續 bg 在 permanent flush / transparent item 上是 **multi-select feature**(Finder / Gmail / Notion idiom),在 permanent standalone card 上依然必 gap(card identity 保留)。
326
+
327
+ ### 世界級 benchmark(2026-04-22 掃 6 家)
328
+
329
+ | DS | menu item | file/card list | table row | settings row |
330
+ |----|-----------|---------------|-----------|-------------|
331
+ | Polaris | flush + border-b,0 gap | ResourceList flush rows border-b;MediaCard standalone 才 card | IndexTable flush border-b 0 gap | Card.Section Divider 0 gap |
332
+ | Material M3 | flush 0 gap | Card `variant="outlined"` stack `gap 8–16dp` | DataTable flush border-b 0 gap | Nav drawer 有 radius 但 **permanent 透明 → 0 gap** |
333
+ | Atlassian | Menu flush 0 gap | `<Stack space="space.100">` 8px standalone cards | DynamicTable flush border-b 0 gap | Nav rounded 透明 bg 0 gap |
334
+ | Ant Design | default flush 0 gap | Upload picture-card **gap 8px**;text/picture flush 0 gap | Table flush border-b 0 gap | List bordered flush + divider 0 gap |
335
+ | Carbon | flush + 1px border-b 0 gap | FileUploaderItem flush 0 gap border-b | DataTable flush border-b 0 gap | Side-nav flush 0 gap |
336
+ | Apple HIG | N/A | Inset Grouped:**group radius / row permanent 透明 → 0 gap**;group 之間 gap | N/A | Settings Inset Grouped 同左 |
337
+
338
+ **6 家共識**:default list row = flush 0 gap + separator;升級 standalone card stack 才需 gap(Material Card / Ant picture-card / Atlassian Stack)。**關鍵反例**(M12 counter-example avoidance):M3 Nav drawer / Apple Inset Grouped 兩者都**有 radius**但 permanent 透明 → 仍 0 gap。證明「radius ≠ 必 gap」,真 trigger 是 **permanent standalone container**。
339
+
340
+ ### 對照表
341
+
342
+ | Item 類型 | 永久視覺層 | gap | 依據 |
343
+ |-----------|-----------|-----|------|
344
+ | **MenuItem / Select / DropdownMenuItem / SidebarMenuButton / TreeItem** | permanent transparent(radius 只在 state 可見) | **0 gap 合法** | state 稀疏不創造永久相連 |
345
+ | **SelectionItem**(Radio / Checkbox row) | permanent transparent(code 驗證 `flex items-start gap-2`,無 bg/border/radius) | **0 gap 合法** | 選中靠 control 視覺非 row bg |
346
+ | **DataTable row** | flush + border-b 分隔線 | **0 gap 合法** | border-b 分隔線型 affordance |
347
+ | **FileItem compact + progress bar**(Type A upload manager) | flush + 底部 progress bar 分隔線 | **0 gap 合法** | 同 DataTable;progress bar 分隔線型 affordance(user 2026-04-22 確認) |
348
+ | **FileItem rich**(永遠 card) | `border + bg-surface + rounded-md + inset` → **standalone card** | **必 gap ≥ 8px** | Card 邊框融合失去 identity |
349
+ | **FileItem compact + bg-secondary**(Type B form attachment 靜態) | `bg-secondary + rounded-md + inset` → **standalone pill** | **必 gap ≥ 4px** | bg 塊融合消失 item 邊界 |
350
+ | **StepItem / Timeline item** | permanent transparent item + connector line | **0 gap 合法** | connector 提供連接(分隔線型 affordance 的連接版) |
351
+
352
+ ### 新 item 元件 checklist
353
+
354
+ 建新 row/item 元件時,開 spec 必自問:
355
+
356
+ 1. 本元件**永久**視覺是:(a) standalone card/pill(bg + radius + inset)/ (b) flush full-width / (c) 完全 transparent?
357
+ 2. 若 (a) → spec 必明寫「list wrapper 必 gap ≥ Xpx」+ rationale
358
+ 3. 若 (b)(c) → spec 寫「list wrapper 可 0 gap」+(b)列出 separator affordance 來源
359
+
360
+ ### 反例(本 session 修正)
361
+
362
+ - `file-upload.stories.tsx` compact list(Type B `bg-secondary` standalone pill)→ 改 `gap-1`
363
+ - `file-upload.stories.tsx` rich list(standalone card)→ 改 `gap-2` + 移除 `border overflow-hidden` 外框
364
+ - `file-item.stories.tsx` Rich / HoverSwap rich block / Clickable:同上
365
+
366
+ ### 跟 Group auto-separation 的關係
367
+
368
+ 本規則處理**單一 group 內 item 之間**;「Group auto-separation」處理**相鄰 group 之間**(自帶 16px + border 分隔)。
369
+
370
+ ---
371
+
372
+ ## 結構:四個獨立 slot
373
+
374
+ 所有 item layout 元件共用一個 4-slot 結構,**每個 slot 各自獨立決定對齊**:
375
+
376
+ ```
377
+ [control?] [prefix?] [content] [suffix?]
378
+ ↑ ↑ ↑ ↑
379
+ always follows flex-1 follows
380
+ inline 24px min-w-0 24px
381
+ rule rule
382
+ ```
383
+
384
+ | Slot | 用途 | 出現條件 | 對齊規則 |
385
+ |---|---|---|---|
386
+ | **control** | Selection 機制(Checkbox / RadioGroupItem) | 只有 SelectionItem 有 | **永遠 inline**(`h-[1lh]`) |
387
+ | **prefix** | 視覺輔助(icon / avatar / thumbnail) | 可選,在所有 item 元件 | 24px 閾值規則 |
388
+ | **content** | label + 可選 description | 永遠存在 | 佔滿剩餘空間,`flex-1 min-w-0` |
389
+ | **suffix** | label 的 metadata(tag、chevron、time、count) | 可選,在所有 item 元件 | **24px 閾值規則(跟 prefix 同公式但獨立)** |
390
+
391
+ **suffix 可以塞什麼**(支援 Switch 同時遵守 24px 閾值):
392
+
393
+ | Suffix 類型 | 可塞? | 對齊 | 說明 |
394
+ |-----------|------|------|------|
395
+ | ✅ 唯讀 metadata | Tag / Badge / time / count / value text | 24px 閾值 | 補充 label 資訊,不搶 row click target |
396
+ | ✅ 方向指示 | ChevronRight / ChevronDown | 24px 閾值 | 純視覺提示,row 本身仍整列可點 |
397
+ | ✅ Inline Action(單一副動作) | `ItemInlineAction`(⋯ 刪除、+ 加入) | 24px 閾值 | 明確點擊靶子 ≤ 24px,`stopPropagation` 避免搶 row click |
398
+ | ✅ **互動 control(Switch / Checkbox / Select)** — **同樣走 24px 閾值 + 處理點擊語義** | 24px 閾值(大多符合:sm/md Switch 20×40、Checkbox 16/20) | 見下「互動 control 在 suffix」 |
399
+
400
+ ### 互動 control 在 suffix(Switch / Checkbox / Select)
401
+
402
+ Menu item / dropdown item 的 suffix 是**可以**塞 Switch / Checkbox / Select 的——世界級 dropdown menu(macOS / Windows / VS Code 的 View menu、Notion 的 page options)普遍用 menu item + trailing toggle/checkmark 呈現「此項 on/off」。**條件**:必須遵守 item-anatomy 的對齊 + 點擊語義規則。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
403
+
404
+ **視覺對齊**(跟 `Tag` / `Chevron` 共用規則):
405
+
406
+ - Switch sm/md = 20×40(高 20px ≤ 24)→ `h-[1lh]` inline 對齊 label 第一行
407
+ - Switch lg = 24×48(高 24px = 24)→ `h-[1lh]` inline(等號邊界)
408
+ - Checkbox sm/md = 16×16 / lg = 20×20 → 全部 `h-[1lh]` inline
409
+ - **高度全部 ≤ 24**,自然套用 24px 閾值 canonical,不需特殊邏輯
410
+
411
+ **點擊語義**(關鍵):
412
+
413
+ MenuItem 承載 Switch 時,**整列 row 的 click = toggle 這個 control**(不是另外導覽的動作)。語義是「這整列 row = 一個 toggle 行為」,row 本身 label + 尾端 Switch 共同構成 toggle 介面。避開「row click 做 A、suffix click 做 B」的歧義,因為 A 跟 B 都是 toggle 同一個狀態。
414
+
415
+ ```tsx
416
+ // ✅ Canonical:row click 與 suffix Switch 同步 toggle(row 可點擊、Switch 視覺反映狀態)
417
+ <DropdownMenuItem
418
+ suffix={<Switch checked={dark} tabIndex={-1} aria-hidden />}
419
+ onClick={() => setDark(!dark)}
420
+ >
421
+ Dark mode
422
+ </DropdownMenuItem>
423
+
424
+ // ❌ 錯:row 跟 Switch 各自獨立,兩個不同 action
425
+ <DropdownMenuItem onClick={navigate('/settings')}>
426
+ Dark mode
427
+ <Switch checked={dark} onCheckedChange={setDark} /> {/* Switch 有自己的 click,搶 row click */}
428
+ </DropdownMenuItem>
429
+ ```
430
+
431
+ **Switch 實作細節**:放 suffix 時 Switch 應 `tabIndex={-1}` + `aria-hidden`(或去掉自己的 click handler),讓 **row 成為唯一互動靶子**、Switch 純視覺反映狀態。Radix `DropdownMenuCheckboxItem` 的 Checkbox 就是這模式(checkmark 是視覺,整列是 trigger)。Switch 類比採用同樣規則。
432
+
433
+ **何時用 suffix Switch vs Field horizontal**:
434
+
435
+ | 情境 | 用 | 原因 |
436
+ |------|---|------|
437
+ | **Menu / Dropdown 內的 toggle 清單**(View menu / Display options / Page toolbar filter menu) | `MenuItem` + suffix Switch | 已在 overlay 容器,menu 整列 row 就是 click target,Switch 是狀態視覺 |
438
+ | **Settings page 的獨立 toggle row**(不在 overlay,是 page layout) | `<Field orientation="horizontal">` + Switch 齊右 | 見 `components/Switch/switch.spec.md`「settings list canonical」 |
439
+
440
+ 兩者**結構一致**(label 左 / toggle 右齊),差別只在**容器層級**(menu item = overlay row / Field horizontal = page row)。
441
+
442
+ **世界級對照**:macOS View menu「Show toolbar」+ ✓ / Figma View menu「Show layout grids」+ toggle / VS Code View menu「Toggle sidebar」+ ✓——都是 menu item + trailing toggle/check 的 canonical 應用。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
443
+
444
+ **外層**:`flex items-start`——多行時 control / prefix / suffix 的 Y 不隨文字下移。
445
+
446
+ ### Control 跟 prefix 是兩個不同的 slot
447
+
448
+ `control` 跟 `prefix` 不是同一件事,**可以同時存在**:
449
+
450
+ ```
451
+ [checkbox] [avatar] [name + email] ← Notion sharing modal
452
+ [checkbox] [icon] [permission name] ← Permission picker
453
+ [checkbox] [channel icon] [channel name] ← Slack channel picker
454
+ ```
455
+
456
+ `control` 是「selection 的機制」(必有,且永遠 inline,因為它是點擊靶子);`prefix` 是「視覺輔助」(可選,跟 label 內容相關)。兩者各自獨立對齊,不互相同步。
457
+
458
+ ---
459
+
460
+
461
+ ## 24px 閾值對齊規則(Prefix 與 Suffix 共用同一條公式)
462
+
463
+
464
+ **核心原則**:每個 slot 的對齊容器高度由**自己內容物的大小**決定。Prefix 和 suffix 用的是**完全一樣**的公式,只是各自獨立判斷,不互相同步。
465
+
466
+ ### 公式
467
+
468
+ | 內容物高度 | 對齊容器 | 對齊目標 |
469
+ |---|---|---|
470
+ | ≤ 24px | `h-[1lh]` | 第一行 label 的垂直中心 |
471
+ | > 24px(+ 有 description) | `h-[calc(1lh + 2px + desc_1lh)]` | label + gap + description 文字塊的垂直中心 |
472
+ | > 24px(無 description) | `h-[1lh]` | 強制 inline(沒有文字塊可對齊) |
473
+
474
+ ### 為什麼 prefix 和 suffix 各自獨立(不互相同步)
475
+
476
+ 之前的版本說「suffix 永遠跟 prefix 使用相同的對齊容器高度」是錯的。Prefix 和 suffix **各自反映自己內容物的視覺重量**,不應該被綁在一起。
477
+
478
+ **1. Slot 內容物的本質不同**
479
+
480
+ - **Prefix** 是「item 的視覺主體」(avatar = 這個人是誰、icon = 這個東西是什麼)。當 prefix 是大 avatar 時,它的視覺重量平衡整個文字塊,所以對齊文字塊中心。
481
+ - **Suffix** 是「label 的 metadata」(Tag = 屬於哪一類、Chevron = 可展開、Time = 何時)。它修飾的對象是 label 第一行,所以對齊第一行。
482
+
483
+ 兩個 slot 的視覺角色不同,被強迫同步反而違反它們各自的對齊邏輯。
484
+
485
+ **2. 業界 convention 全部如此**
486
+
487
+ Apple Mail / Gmail / iOS Settings / Material 3 / Atlassian DSP / Polaris ResourceItem——**全部**是「prefix 跟 suffix 各自獨立對齊」。沒有任何一個把小 suffix 強迫對齊到大 avatar 中心。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
488
+
489
+ | 系統 | Prefix(大 avatar) | Suffix(小元素) |
490
+ |---|---|---|
491
+ | Apple Mail | Avatar 40px → 文字塊中心 | Date → Subject 第一行 |
492
+ | Gmail | Star icon → 第一行 | Time → Subject 第一行 |
493
+ | iOS Settings | Icon ≤24px → 第一行 | Chevron → Label 第一行 |
494
+ | Material 3 List | Leading icon → 第一行 | Trailing icon → top-aligned |
495
+
496
+ **3. 視覺重量平衡**
497
+
498
+ 把小 suffix 強迫對齊大 avatar 中心,小 suffix 會「下沉」到 description 行,**視覺上跟 label 失聯**。對齊 label 第一行則讓 suffix 跟它修飾的對象在同一條基準線上,視覺重量自然分配。
499
+
500
+ ### 大塊 suffix 的對待方式(symmetric 規則)
501
+
502
+ `suffix > 24px` 的場景雖然罕見,但**完全套用同一條公式**——當 suffix 是 thumbnail、stacked badge 等大塊內容時,自己的對齊容器走 block calc,對齊文字塊中心。
503
+
504
+ | 場景 | Prefix | Suffix | 結果 |
505
+ |---|---|---|---|
506
+ | 標準選單(MenuItem 大宗) | icon 16px / avatar 24px | Tag / Chevron(≤24px) | 兩邊都 inline |
507
+ | 用戶選單(avatar + name + role) | avatar 32px(block) | Chevron(≤24px) | Prefix block,suffix inline ← **各自獨立** |
508
+ | 帶縮圖列表(thumbnail + title + 縮圖) | icon 16px(inline) | thumbnail 40px(block) | Prefix inline,suffix block ← **各自獨立** |
509
+ | 雙視覺重的卡片 | avatar 40px(block) | thumbnail 40px(block) | 兩邊都 block |
510
+
511
+ **沒有「prefix 跟 suffix 必須同步」的情況。** 每個 slot 反映自己內容物的視覺重量,各自走公式。
512
+
513
+ ### Avatar 尺寸選擇
514
+
515
+ **用於 prefix slot**。Avatar 尺寸是 **consumer 依視覺重量意圖決定**的——有兩組預設可選,對齊模式跟著 size 走,**不跟著 description 的有無走**。
516
+
517
+ **兩組預設尺寸**(依 row size):
518
+
519
+ | 預設組 | sm | md | lg | 視覺重量 | 典型用途 |
520
+ |---|---|---|---|---|---|
521
+ | **`AVATAR_SIZE.inline`** | 20 | 24 | 24 | 輕 | 扁平 row、footer user、單行選項、**小 avatar + 短 desc** |
522
+ | **`AVATAR_SIZE.block`** | 32 | 32 | 40 | 重 | 人物卡、顯著身份辨識、avatar 是 item 的主體 |
523
+
524
+ **對齊模式由 size 決定**(24px 閾值):
525
+
526
+ | Avatar size | 有無 description | 對齊容器 | 說明 |
527
+ |---|---|---|---|
528
+ | ≤ 24 | 無 | `h-[1lh]` inline | 單行,對齊第一行 label |
529
+ | **≤ 24** | **有** | **`h-[1lh]` inline** | **小 avatar 視覺輕,仍對齊第一行**——不強迫跨越兩行 |
530
+ | > 24 | 無 | `h-[1lh]` inline | 大 avatar 但無 desc,仍對齊第一行(block 沒意義) |
531
+ | > 24 | 有 | `h-[block calc]` block | 大 avatar 視覺重,平衡 label + desc 整個文字塊 |
532
+
533
+ **關鍵**:consumer 可以自由選擇「小 avatar + description」——那是完全合法的組合,此時 avatar inline 對齊第一行 label,description 從第二行自然往下。沒有「有 desc 就必須用 block 尺寸」的規則。
534
+
535
+ **程式化規則**(scope:**row context only** — Sidebar / SelectMenu / TreeView / Combobox / Menu 等 row primitive 子樹內):consumer **必須**用 `<ItemAvatar>` / `<ItemIcon>` helper 元件,**禁止** `import { AVATAR_SIZE }` 手動查表,更**禁止**硬寫 `<Avatar size={N} />`。
536
+
537
+ **Scope 例外:Chrome header 不是 row context**(per `header-canonical.spec.md` 4.5):chrome header 有自己的 spec-level avatar canonical = 24px(density-fixed / row-size-fixed),用 raw `<Avatar size={24}>` + `--chrome-header-avatar-size` CSS token。Chrome header avatar 不參與 row anatomy 對齊機制(無 sm/md/lg row size lookup 需求)。詳 `header-canonical.spec.md` 4.5「Chrome header avatar SSOT」段。
538
+
539
+ ```tsx
540
+ import { ItemAvatar, ItemIcon } from "@/design-system/patterns/element-anatomy/item-anatomy"
541
+
542
+ // 案例 A:扁平 row,無 desc → ItemAvatar 預設 inline,自動查 AVATAR_SIZE.inline[rowSize]
543
+ <ItemAvatar alt="Alan" color="blue" />
544
+
545
+ // 案例 B:avatar 是 item 主體(人物卡)→ mode="block",跨文字塊對齊
546
+ <ItemAvatar mode="block" alt="Alan" color="blue" />
547
+ <span>Alan Chen</span>
548
+ <span className="text-caption">Design lead</span>
549
+
550
+ // 案例 C:icon prefix → ItemIcon 自動查 ICON_SIZE[rowSize]
551
+ <ItemIcon icon={Folder} />
552
+ ```
553
+
554
+ `<ItemAvatar>` / `<ItemIcon>` 會:
555
+ 1. 從 `RowSizeContext` 讀取當前 row size(由 row primitive 例如 `SidebarProvider` / `SelectMenu` 內部 propagate)
556
+ 2. 查對應常數(`AVATAR_SIZE[mode][size]` / `ICON_SIZE[size]`)
557
+ 3. 自動包在 `ItemPrefix`(`h-[1lh] shrink-0 flex items-center`)wrapper 內
558
+
559
+ **Consumer 完全看不到 size 數字、看不到 AVATAR_SIZE 常數、看不到 ItemPrefix wrapper——不可能寫錯。**
560
+
561
+ Canonical 對齊模式判斷:`MenuItem` 的 `isBlockAlign = avatarPx > 24 && !!description`——元件根據 24px 閾值**自動決定**對齊容器高度,不需要 consumer 額外指定 align prop。
562
+
563
+ ### ❌ 為什麼不能硬寫 `size={24}`
564
+
565
+ 硬寫會造成兩種漂移,兩種都是**真實發生過的 bug**:
566
+
567
+ 1. **跨 size 漂移**:寫死 24 僅與 md 規格相符;sm 應為 20、lg 為 24,硬寫讓 sm 渲染出 24(比規格大 4px),Row size 變體 story 三欄並排時 sm 欄的 avatar 尺寸違反 canonical。
568
+ 2. **跨 consumer 漂移**:每個 asChild consumer 各自硬寫,未來改 inline sm 從 20→18 就要全域搜改,漏一個就漂移。
569
+
570
+ **這條規則跟 `ICON_SIZE` 的程式化邏輯一致**——icon / avatar / inline action hover bg 都從 `item-layout` module 單一來源 import,row primitive 的任何尺寸常數永遠不在 consumer 側重新定義。
571
+
572
+ ### Token: `--item-icon-size` / `--item-avatar-size`(2026-05-22 codify)
573
+
574
+ **Local token family(per `--item-*` prefix 既有 family,e.g., `--item-prefix-slot` / `--item-gap-label-desc`)**。
575
+
576
+ 由 row primitive(目前 SidebarProvider)透過 inline style 注入,**JS const → CSS var mirror**:
577
+
578
+ | Token | JS const source | sm | md | lg |
579
+ |---|---|---|---|---|
580
+ | `--item-icon-size` | `ICON_SIZE[size]` | 16 | 16 | 20 |
581
+ | `--item-avatar-size` | `AVATAR_SIZE.inline[size]` | 20 | 24 | 24 |
582
+
583
+ **Consumer**:SidebarMenuButton collapsed pl 公式(`(sidebar-width-icon - --item-{icon,avatar}-size) / 2`),讓所有 prefix center 鎖回 rail center = GlobalHeader toggle geometry。Future row primitive(SelectMenu / DropdownMenu / TreeView)如需同 cascade 可消費同 token。
584
+
585
+ **Sync invariant**:CSS var 必鏡像 JS const。SidebarProvider re-render → CSS var 更新 → consumer formula 自動 cascade。
586
+
587
+ **uniformPrefix mixing override**:當 `:has([data-prefix-type=icon]):has([data-prefix-type=avatar])` 觸發,`--item-icon-size` 被 cascade override 成 `var(--mixed-prefix-slot)`(24),因 ItemPrefix wrapper 被撐到 slot 寬,effective prefix width = slot 非 icon glyph。用 Tailwind `!` important 修飾子蓋過 inline style specificity。
588
+
589
+ ### asChild pattern 的責任——用 helper 元件免除全部負擔
590
+
591
+ 普通 consumer(`<SidebarMenuButton startIcon={X}>{label}</SidebarMenuButton>`)不處理 prefix——元件內部自己渲染。
592
+
593
+ `asChild` pattern(Radix Slot)要求 consumer 自己組 children。**過去這代表 consumer 要處理全部尺寸查表**——曾發生 bug:三欄 sm/md/lg 並排時 avatar 全部寫 24,sm 欄應為 20 卻顯示 24。
594
+
595
+ **現在透過 `<ItemAvatar>` / `<ItemIcon>` helper,asChild consumer 零尺寸責任**:
596
+
597
+ ```tsx
598
+ // ✅ 正確:helper 從 RowSizeContext 自動拿 size
599
+ <SidebarMenuButton asChild>
600
+ <button type="button">
601
+ <ItemAvatar alt="Alan Chen" color="blue" />
602
+ <ItemLabel>Alan Chen</ItemLabel>
603
+ </button>
604
+ </SidebarMenuButton>
605
+
606
+ // ❌ 錯誤:手動 Avatar + 硬寫 size,sm 欄會顯示錯誤尺寸
607
+ <SidebarMenuButton asChild>
608
+ <button type="button">
609
+ <span className="h-[1lh] shrink-0 flex items-center">
610
+ <Avatar size={24} alt="Alan Chen" color="blue" />
611
+ </span>
612
+ <span data-sidebar="menu-label">Alan Chen</span>
613
+ </button>
614
+ </SidebarMenuButton>
615
+ ```
616
+
617
+ **Row primitive 實作者的責任**:元件內部必須用 `<RowSizeProvider value={size}>` 包裹整個子樹(包含 Slot children 的路徑),確保 descendant helper 能讀到 context。`SidebarProvider` 已內建這個——其他 row primitive 新增 asChild 支援時必須跟進。
618
+
619
+ **禁止事項**(違反的話 review 會擋):
620
+ - ❌ asChild consumer 裡出現 `<Avatar size={N} />`(用 `<ItemAvatar>`)
621
+ - ❌ asChild consumer 裡出現 `<Icon size={N} />`(用 `<ItemIcon>`)
622
+ - ❌ asChild consumer 裡出現 `import { AVATAR_SIZE, ICON_SIZE }` 手動查表(helper 已封裝)
623
+ - ❌ asChild consumer 裡手刻 `h-[1lh] shrink-0 flex items-center` wrapper(helper 內部已包)
624
+
625
+ Avatar 元件自身的規格(icon 模式、fallback、內部 icon 尺寸)見 `Avatar/avatar.spec.md`。
626
+
627
+ ### Prefix 類型對齊:作用域是「同一 group 內」,不是整個元件
628
+
629
+ Label x 位置受 prefix 尺寸影響(icon 16 vs avatar 24,差 8px)。**對齊只在同一 group 內的多個 items 之間成立**——跨 group 本來就不該強求,每個 group 的 prefix 反映自己的語意重量。
630
+
631
+ | 情境 | 對齊要求 | 理由 |
632
+ |---|---|---|
633
+ | **同 group 多 items** | Prefix 類型必須一致(全 icon 或全 avatar) | 多個 label 需要齊左掃視,prefix 類型混用會讓 label x 跳動,破壞 row rhythm |
634
+ | **同 group 單一 item** | **無對齊負擔**,用 prefix 自然尺寸 | 沒有相鄰 label 可參照,縮小 prefix 只是為了對齊一個不存在的東西 |
635
+ | **跨 group** | **永不強求對齊** | 不同 group 的語意本來就不同(主導覽 icon / user identity avatar / thumbnail list),各自反映視覺重量 |
636
+
637
+ **範例**:Sidebar footer 只有一個 user row(Alan Chen)→ 用 inline avatar 24px 的自然預設,不需要縮成 16px 去對齊上方 main nav 的 icon。Main nav 和 footer 是不同 group,本來就該各自獨立。
638
+
639
+ **業界 convention**:Apple HIG list section、Material 3 list、Atlassian DSP 全部採用「section-scoped consistency」——同一 section 內 leading element 類型一致,跨 section 變化是正常的。沒有任何世界級系統要求整個 sidebar / menu 所有 prefix 強迫同尺寸。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
640
+
641
+ ❌ **錯誤示範**:為了讓 footer avatar 跟 main nav icon 齊左,把 avatar 從 24 改成 16——這是用錯誤方向修了一個根本不存在的問題,且違反 Avatar 尺寸公式。
642
+
643
+ ### Uniform prefix slot
644
+
645
+ **Row-primitive 全域對齊(opt-in)**。機制:CSS `:has()` selector 在 row-primitive **頂層容器**(`<SidebarProvider uniformPrefix>` / 未來其他 row primitive 的 root)偵測整個子樹同時存在 `data-prefix-type="icon"` 和 `"avatar"` 後代(由 `<ItemIcon>` / `<ItemAvatar>` 自動標記)時,**全域**套用固定 prefix 槽——跨 menu / 跨 group 所有 label x 統一對齊。
646
+
647
+ **世界級兩派,我們把 A 設為預設、B 提供 opt-in**:
648
+
649
+ | School | 代表 | 行為 | 我們的預設? |
650
+ |---|---|---|---|
651
+ | A | Slack / VS Code Explorer / Discord | Per-section 獨立 prefix 寬度 | **✅ 預設** |
652
+ | B | Notion / Linear / Atlassian Confluence | 全域對齊 | 🟡 Opt-in via `uniformPrefix` | <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
653
+
654
+ 兩派都是世界級慣例,沒有絕對對錯。**選 A 作為預設的理由**:
655
+
656
+ 1. **Explicit > implicit**:auto-detect 是 CSS `:has()` 魔法,consumer 沒主動要求就在背後動排版,違反「程式行為應該從 source code 一眼看出」原則
657
+ 2. **保留分組視覺語意**:不同 group / menu 在概念上代表不同層級,獨立的視覺節奏是 sectioning 的訊號
658
+ 3. **Opt-in 成本極低**:想要 Notion 風格的 consumer,加 `uniformPrefix` 一個字就好
659
+
660
+ **Auto-detect 開啟後零成本**:CSS `:has()` 在不混用時完全 no-op,單一 prefix 類型的 sidebar 行為跟以前完全一樣。所以 opt-in 的代價只是「打那個 prop」,沒有 runtime perf 成本。
661
+
662
+ ### 機制細節
663
+
664
+ - `<ItemIcon>` 渲染的 `<ItemPrefix>` 自動帶 `data-prefix-type="icon"`
665
+ - `<ItemAvatar>` 渲染的 `<ItemPrefix>` 自動帶 `data-prefix-type="avatar"`
666
+ - Row-primitive 頂層容器(`SidebarProvider` 的 wrapper div)在 inline style 預設一個 `--mixed-prefix-slot` 候選值(= `AVATAR_SIZE.inline[size]`,20/24/24 @ sm/md/lg)
667
+ - 同一個 wrapper 用 Tailwind variant `has-[[data-prefix-type=icon]]:has-[[data-prefix-type=avatar]]:[--item-prefix-slot:var(--mixed-prefix-slot)]` 條件化把候選值賦給 `--item-prefix-slot`
668
+ - `<ItemPrefix>` 讀取 `--item-prefix-slot`(預設 `auto`,有值則套槽 + center),自動套用
669
+
670
+ **單一類型時**:沒有任何一個後代有 `data-prefix-type=avatar`(或反過來),`:has()` 不命中,`--item-prefix-slot` 維持 `auto`,prefix 縮到自然寬度。**完全沒有 ghost spacing**。
671
+
672
+ ### Per-row-primitive override(罕見 escape hatch)
673
+
674
+ `SidebarMenu` 的 `uniformPrefix` prop:
675
+
676
+ | 值 | 行為 |
677
+ |---|---|
678
+ | 不傳(預設) | 繼承 SidebarProvider 的全域 auto |
679
+ | `true` | 強制這個 menu 套槽,即使單一類型 |
680
+ | `false` | 強制關閉這個 menu 的對齊,即使全域偵測到混用 |
681
+
682
+ `uniformPrefix={false}` 用法極罕見——為「我刻意要這個 menu 跟其他 menu 視覺上不同步」的場景保留。
683
+
684
+ ### 其他 row primitive 怎麼接
685
+
686
+ 要對齊 Notion 模式,在 row primitive 的頂層 wrapper(例如 `<TreeView>` 的 root)加: <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
687
+
688
+ ```tsx
689
+ const slotStyle = getUniformPrefixSlotStyle(size)
690
+ <div
691
+ style={{ "--mixed-prefix-slot": slotStyle["--item-prefix-slot"], ...style }}
692
+ className="has-[[data-prefix-type=icon]]:has-[[data-prefix-type=avatar]]:[--item-prefix-slot:var(--mixed-prefix-slot)]"
693
+ >
694
+ {children}
695
+ </div>
696
+ ```
697
+
698
+ `<ItemIcon>` / `<ItemAvatar>` 已自動標記 `data-prefix-type`,row primitive 實作者不用處理。
699
+
700
+ **禁止**:
701
+
702
+ - ❌ 拿 escape hatch `uniformPrefix={false}` 配合 mixed prefix 沒有設計理由——這違反使用者視覺直覺,只在「刻意製造視覺斷層」時才該用
703
+ - ❌ 在 row primitive 的某個中層元件再做一次 `:has()` 偵測——應該由頂層容器一次處理,中層不該重複 logic
704
+
705
+
706
+
707
+ ## SelectionItem:Control 跟 Prefix 同高度(不歪斜)
708
+
709
+ `SelectionItem` 永遠有 **control** slot(checkbox / radio)。當 prefix(icon / avatar)也存在時,**兩者必須在同一條 baseline**——否則視覺歪斜。
710
+
711
+ ### 規則:control 跟著 prefix 的對齊走
712
+
713
+ | prefix 模式 | Control 對齊 | Prefix 對齊 | 結果 |
714
+ |---|---|---|---|
715
+ | **inline**(icon / 小 avatar,≤24px) | `h-[1lh]` | `h-[1lh]` | 兩者都在 label 第一行 |
716
+ | **block**(大 avatar >24px + 有 desc) | **`h-[block calc]`** | `h-[block calc]` | 兩者都在 text block center |
717
+
718
+ ```
719
+ Inline 模式:
720
+
721
+ [✓][avatar 24] Alice Chen
722
+ Design lead
723
+
724
+ Block 模式:
725
+
726
+ ┌──────┐
727
+ [✓] │ A │ Alice Chen
728
+ │ 32px │ Design lead
729
+ └──────┘
730
+ ```
731
+
732
+ Block 模式時 checkbox 不在 label 第一行——它跟 avatar 在同一高度(text block center)。這沒問題,因為 form picker 整列可點擊,checkbox 的位置不影響操作;checkbox 跟 avatar 構成「selection + identity」的視覺單元,應該同高。
733
+
734
+ ### 為什麼不是「checkbox 固定在 label 第一行、avatar 自由 block」?
735
+
736
+ 那樣會歪斜:
737
+
738
+ ```
739
+ ❌ 歪斜:checkbox 跟 avatar 在不同高度
740
+
741
+ [✓] ──── label 第一行
742
+ ┌──────┐
743
+ │avatar│ Alice Chen
744
+ │ 32 │ Design lead
745
+ └──────┘
746
+ ```
747
+
748
+ 業界零個成功案例。只要左側有兩個元素(control + prefix),它們必須在同一條 baseline 上。
749
+
750
+ ### 業界 form picker 對照
751
+
752
+ | 系統 | Avatar | 對齊 | 備註 |
753
+ |---|---|---|---|
754
+ | **GitHub** | 20px | inline | 小 avatar,不需要 block |
755
+ | **Linear** | 20px | inline | 同上 |
756
+ | **Microsoft Teams** | 24-28px | inline | 簡單列表 |
757
+ | **Notion sharing** | 28px | block(avatar center) | 無左 checkbox(click row 選取) |
758
+ | **Slack invite** | 36px | block(avatar center) | checkbox 在右側 suffix |
759
+
760
+ 有 left checkbox 的(GitHub/Linear/Teams)都用 inline。想 block 的(Notion/Slack)則不用 left checkbox——要嘛 click row 選取,要嘛 checkbox 在右。
761
+
762
+ **我們的 SelectionItem 兩個都支援**:左 checkbox + block 時,checkbox 跟 avatar 同步下移到 text block center,不歪斜。
763
+
764
+ ---
765
+
766
+ ## 兩種閱讀模式
767
+
768
+ | | 掃描模式 | 閱讀模式 |
769
+ |---|---|---|
770
+ | **場景** | 浮層 / overlay(一掃而過) | 頁面 / 表單(仔細閱讀) |
771
+ | **Label 行高** | `leading-compact` (1.3) | 預設 (1.5) |
772
+ | **Description 字體** | 降一級(14→12px, 16→14px) | 最小 14px(14→14px, 16→14px) |
773
+ | **Description 顏色** | `fg-secondary` | `fg-secondary` |
774
+ | **Label ↔ Desc 間距** | 2px via `--item-gap-label-desc` token(SSOT)| 同左 |
775
+
776
+ **SSOT 架構(2026-04-23 更新)**:
777
+ - **Token**:`--item-gap-label-desc`(值 2px,定義於 `tokens/layoutSpace/layoutSpace.css`)
778
+ - **Primitive**:`<ItemContent label description descriptionTone>`(from `item-anatomy.tsx`,封裝 flex-col + token gap)
779
+ - **Consumer 消費 2 擇 1**:
780
+ - 直接 token:`mt-[var(--item-gap-label-desc)]` / `gap-[var(--item-gap-label-desc)]`
781
+ - 或 primitive:`<ItemContent label=... description=... descriptionTone=...>`
782
+ - **改值一處(token)→ 全 DS 同步**,不用 grep 手改 13+ 檔
783
+
784
+ **偏離 canonical 規則**:Consumer 若有明確合理理由不用 primitive / 自訂 label-desc typography,**必在該元件 `spec.md` 明文 rationale**。
785
+
786
+ ### ItemContent primitive 消費表(2026-04-23 盤點)
787
+
788
+ | Consumer | Primitive 消費 | Rationale |
789
+ |----------|--------------|-----------|
790
+ | **FileItem**(rich + compact) | ✅ ItemContent + ItemPrefix + ItemInlineActionButton | 純 row-item layout,完美 fit |
791
+ | **Notice / Alert / Toast** | ✅ ItemContent + ItemPrefix | title+desc 標準 row-item 結構 |
792
+ | **NameCard** | ✅ ItemContent(+ `labelTruncate=false` + `labelClassName` escape hatch) | 偏離 rationale:card context 用 `text-body-lg font-medium`,非一般 body label |
793
+ | **MenuItem** | ✅ ItemContent(`mode="scanning"\|"scanning-lg"`)+ `itemPrefixAlignVariants` cva SSOT | Content 用 ItemContent 配合 size-aware scanning mode(sm/md = caption / lg = body-compact);label+desc clamp 透過 className escape hatch(MenuItem 特化 labelMaxLines / descMaxLines 語意) |
794
+ | **Sidebar / TreeView** | ✅ ItemPrefix(+ 其他 primitives) | Label-only(無 description),不需 ItemContent |
795
+ | **Empty** | ❌ token-direct only | **結構限制**:centered stack pattern(icon → title → desc → action 垂直居中),非 row-item 佈局。保持手刻 |
796
+ | **Dialog**(DialogTitle / DialogDescription) | ❌ token-direct only | **結構限制**:title 跟 desc 是獨立 Radix `<DialogTitle>` / `<DialogDescription>` component(aria-labelledby / aria-describedby 語義),非同層 span 配對 |
797
+ | **DescriptionList** | ❌ token-direct only | **語義限制**:用 `<dl>/<dt>/<dd>` HTML semantic elements,非 div+span |
798
+ | **SelectionItem** | ❌ token-direct only | **a11y 限制**:label 必為 `<label htmlFor={id}>` 表單 control 關聯(form association);ItemContent 渲染 `<span>` 會破壞 form a11y |
799
+ | **Switch**(standalone mode with label+desc) | ❌ token-direct only | **a11y 限制(同 SelectionItem)**:standalone mode 用 `<label htmlFor={inputId}>` 包 label+desc+switch,form control 關聯必要。Control-only mode(放 MenuItem suffix 等)不涉及 label+desc,不在 ItemContent scope |
800
+ | **Steps**(`StepDescription`) | ❌ token-direct only | **API 限制**:StepLabel 跟 StepDescription 是獨立 public forwardRef subcomponent,consumer 分開寫;遷 ItemContent(single-component API)= breaking API |
801
+
802
+ **共 5 consumer 消費 primitive(FileItem / Notice / NameCard / MenuItem / TreeView・Sidebar),5 consumer 保 token-direct 各有 a11y / semantic / API 結構限制**。Token 層 SSOT 100% 覆蓋(改 `--item-gap-label-desc` 全 DS 同步);primitive 層覆蓋結構能 fit 的 consumer。
803
+
804
+ **Switch 跟 SelectionItem 同 blocker**(2026-04-23 user 糾正):兩者都是 `<label htmlFor>` 表單 control 關聯結構,ItemContent 用 `<span>` 渲染 label 會破壞 form a11y。這類結構**只能 token-level SSOT**(實際已做)。
805
+
806
+ ### `<ItemContent mode>` prop(2026-04-23 擴充)
807
+
808
+ Primitive 直接封裝 scanning / reading 兩種 typography:
809
+
810
+ ```tsx
811
+ <ItemContent label="..." description="..." mode="reading" /> {/* 預設,繼承 text-body */}
812
+ <ItemContent label="..." description="..." mode="scanning" /> {/* desc 縮為 text-caption + leading-compact */}
813
+ ```
814
+
815
+ World-class benchmark(6 家 DS):
816
+ - Material M3:`<List dense>` boolean
817
+ - Carbon:`size="sm\|md\|lg\|xl"` enum
818
+ - Ant:`size="small\|default\|large"` enum
819
+ - Polaris / Atlassian / Apple HIG:typography token 手選(無 density prop)
820
+ - 6 家共識:14/20 vs 16/24 兩擋 body 表達 scanning vs reading
821
+
822
+ 本 DS 採 density-prop 派(A 派),跟 Material / Carbon / Ant 對齊。`mode` 比 `dense` 更 self-documenting。 <!-- @benchmark-unverified: see frontmatter benchmark list for canonical DS source URL -->
823
+
824
+ **未來改 scanning typography(e.g. 從 caption 12 改到 caption 13)**:只改 `--font-caption-size` token 一處 → 所有 `mode="scanning"` 的 consumer 同步動。
825
+
826
+ ### Suffix block formula 的 `2px` 也 tokenize(2026-04-23)
827
+
828
+ `h-[calc(1lh+2px+desc_1lh)]` 中的 `2px` 原 hard-code(item-anatomy.stories / MenuItem cva / SelectionItem cva),
829
+ 2026-04-23 全改為 `var(--item-gap-label-desc)` — 同 token 傳播到 block 公式。改 gap 值一處,
830
+ inline 跟 block 兩層 formula 同步動。
831
+
832
+ **Enforcement**:
833
+ - Hook `check_item_content_primitive.sh`(2026-04-23)P1 warn:component .tsx 出現硬寫 `mt-0.5` / `gap-0.5` 提示改 token / primitive
834
+ - Consumer 刻意 hard-code 加 `// @item-gap-exempt: <reason>` 豁免 + rationale 在 spec
835
+ | **判斷標準** | 使用者快速掃描選擇 | 使用者停留閱讀 |
836
+
837
+ **兩種模式的唯一差異是行高。** Description 在所有模式都降一級字體——label 是要辨識的目標,description 是補充,尺寸差有助快速區分。
838
+
839
+ ---
840
+
841
+ ## Icon 色彩原則
842
+
843
+ 一條統一規則,跨所有元件(詳見 `color.spec.md`):
844
+
845
+ | 判斷 | 顏色 | 範例 |
846
+ |---|---|---|
847
+ | icon 代表內容或類別 | **與 label 同色** | Mail「電子郵件」、Settings「設定」 |
848
+ | icon 代表危險操作 | **與 label 同色**(text-error) | Trash2「刪除」 |
849
+ | icon 純指示方向/展開 | `fg-muted`(neutral-7) | ChevronRight、ChevronDown、ExternalLink |
850
+ | suffix value 文字 | `fg-muted`,**字體大小與 label 相同** | "深色"、"已啟用" |
851
+ | disabled 時 | `fg-disabled` | 全部統一 |
852
+
853
+ ---
854
+
855
+ ## 消費元件預設
856
+
857
+ 每個消費元件根據場景自訂間距,但結構和對齊規則不變:
858
+
859
+ ### MenuItem / DropdownMenuItem(浮層選單)
860
+
861
+ | 屬性 | 值 | 原因 |
862
+ |---|---|---|
863
+ | padding-y | `calc((field-height - 1lh) / 2)` | 單行高度 = field-height,對齊 Button / Input |
864
+ | padding-x | 12px (`px-3`) | 選單項目的標準水平間距 |
865
+ | prefix ↔ content gap | 8px (`gap-2`) | 緊湊但可辨識 |
866
+ | suffix 獨立後綴 gap | 8px (`gap-2`) | tag / badge / endIcon 間距 |
867
+ | suffix 子選單指示 gap | 4px (`gap-1`) | value / badge / ChevronRight 更緊湊 |
868
+ | 閱讀模式 | 掃描模式 | 浮層內一掃而過 |
869
+
870
+ ### SelectionItem(表單 Checkbox / Radio)
871
+
872
+ | 屬性 | 值 | 原因 |
873
+ |---|---|---|
874
+ | padding-y | `calc((field-height - 1lh) / 2)` | 單行高度 = field-height,對齊同 size 的 Input |
875
+ | padding-x | 無(由外層容器決定) | 表單佈局各異 |
876
+ | prefix ↔ content gap | 8px (`gap-2`) | 控件與 label 的標準間距 |
877
+ | 閱讀模式 | 閱讀模式 | 表單內仔細閱讀 |
878
+
879
+ ### ListItem(頁面列表,未來元件)
880
+
881
+ | 屬性 | 值 | 原因 |
882
+ |---|---|---|
883
+ | padding-y | 12px (`py-3`) | 舒適的列表行高,觸控友好 |
884
+ | padding-x | 16px (`px-4`) | 頁面內容的標準水平間距 |
885
+ | prefix ↔ content gap | 12px (`gap-3`) | 較寬鬆,適合較大的 avatar / thumbnail |
886
+ | 閱讀模式 | 閱讀模式 | 頁面內停留閱讀 |
887
+
888
+ ---
889
+
890
+ ## Chevron 方向慣例(位置決定旋轉公式)
891
+
892
+ 世界級系統的 chevron 旋轉慣例**由位置決定**,不由「展開/收合」的語意決定。一個 UI 內兩種位置的 chevron 可以共存,各自遵守自己位置的規則不衝突。
893
+
894
+ | 位置 | Base icon | Open 時 | Rotate 量 | 慣例 | 語意 |
895
+ |---|---|---|---|---|---|
896
+ | **Prefix**(item 起始,tree disclosure) | `ChevronRight` (`>`) | `v` | `rotate-90` | Tree disclosure | 箭頭指向內容所在 |
897
+ | **Suffix**(header 尾端,section trigger) | `ChevronDown` (`v`) | `^` | `rotate-180` | Accordion / section header | 箭頭指示下一個可執行方向 |
898
+
899
+ **Canonical 引用**:
900
+
901
+ - **Prefix = rotate-90**:Finder、VS Code、Notion、Xcode、iOS Files、本系統 TreeView
902
+ - **Suffix = rotate-180**:Radix Accordion、shadcn Collapsible、Material Expansion Panel、Linear section header、Slack section header、本系統 SidebarGroup collapsible
903
+
904
+ **為什麼兩種慣例可以共存**:位置本身就是區分訊號。prefix chevron 緊貼 item icon,使用者讀作「這個 item 有子項」;suffix chevron 靠右 ml-auto,使用者讀作「點這裡展開/收合整個 section」。混用不會造成混淆——混用的是位置/角色,不是同一個角色兩種行為。
905
+
906
+ **禁止**:
907
+
908
+ - ❌ Prefix 位置用 `ChevronDown` + rotate-180——prefix 慣例是 tree / 子項展開,用 ChevronDown 把語意切到 accordion,位置與 icon 錯配
909
+ - ❌ Suffix 位置用 `ChevronRight` + rotate-90——suffix 慣例是 section accordion,用 ChevronRight 把語意切到 tree item,違反 accordion 慣例
910
+ - ❌ 用 ChevronUp / ChevronDown 兩個 icon 切換(用 transform rotate 就好,免去 state transition 的閃爍)
911
+
912
+ **實作範例**:
913
+
914
+ ```tsx
915
+ // Prefix(TreeItem)
916
+ <ChevronRight className="transition-transform [data-expanded=true]_&:rotate-90" />
917
+
918
+ // Suffix(SidebarGroup collapsible trigger)
919
+ <ChevronDown className="transition-transform [[data-state=open]_&]:rotate-180" />
920
+ ```
921
+
922
+ ---
923
+
924
+
925
+ ## Inline Action 設計規格 → `inline-action.spec.md`(2026-04-24 抽出,獨立 SSOT)
926
+
927
+ 嵌入 Tag dismiss / Field endAction / Row suffix action 的 icon primitive。完整 265 行視覺規格 / API / predicate / Icon 色 / same-row consistency → 見 `patterns/element-anatomy/inline-action.spec.md`。
928
+
929
+ ## 選擇 / 狀態視覺規則
930
+
931
+ 這一節是曾經連續犯錯的類別,兩條互補規則。
932
+
933
+ ### 規則 A: 用元件既有的 state prop,不要用 className 發明樣式
934
+
935
+ **任何元件既有的狀態 prop(`selected` / `checked` / `disabled` / `pressed` / `active` / `invalid` / `loading` 等),消費端必須用 prop,禁止用 `className` 疊加自創樣式表達同一個狀態**。
936
+
937
+ 理由:
938
+ - 既有 prop 背後綁定 **canonical token**(`bg-neutral-selected` / `border-primary-hover` 等),一改全系統同步
939
+ - `className` 自創樣式繞過 canonical,導致「同一狀態在不同元件產生視覺分歧」的跨元件漂移
940
+ - 既有 prop 通常也綁 ARIA attributes(`aria-selected` / `aria-checked` 等),自創樣式會丟失 a11y 語意
941
+
942
+ #### 真實犯錯紀錄
943
+
944
+ > **Case**: Tabs overflow menu 的 active 項目。`DropdownMenuItem` 本來就有 `selected` prop 對應 `bg-neutral-selected`(跟 SelectMenu 單選 canonical 視覺完全一致),但繞過 prop 直接寫 `className={cn(isActive && 'font-medium text-primary-hover')}` 發明一套「粗體藍字」樣式。結果跟 SelectMenu 同類別的單選視覺完全不一致,使用者一眼看出「為什麼這個 dropdown 跟那個 dropdown 不一樣」。
945
+
946
+ #### 正確做法
947
+
948
+ ```tsx
949
+ // ✅ 對: 用 DropdownMenuItem 的 selected prop(canonical bg-neutral-selected)
950
+ <DropdownMenuItem selected={isActive} onSelect={...}>{label}</DropdownMenuItem>
951
+
952
+ // ❌ 錯: 用 className 自創樣式
953
+ <DropdownMenuItem className={cn(isActive && 'font-medium text-primary-hover')}>{label}</DropdownMenuItem>
954
+
955
+ // ❌ 錯: 用錯 semantic 的 prop
956
+ <DropdownMenuCheckboxItem checked={isActive}>{label}</DropdownMenuCheckboxItem>
957
+ ```
958
+
959
+ #### 檢查法(寫任何 selection / state 樣式前必做)
960
+
961
+ 1. **grep 元件 props interface**,看它有沒有相關的 state prop(`selected`、`checked`、`disabled`、`active`、`pressed`、`invalid`...)
962
+ 2. 有 → **一定用那個 prop**,不用 className
963
+ 3. 沒有 → 先暫停,問「是不是該補這個 prop 到元件本身」,不要直接在 consumer 用 className 繞過
964
+ 4. 確認沒必要補 prop 才用 className
965
+
966
+ ### 規則 B: 選擇語意必須對應指示器視覺
967
+
968
+ Selection control(Dropdown / Menu / List / SegmentedControl / Chip)的 item 視覺指示器,必須對應該 control 的 selection model。使用者看一眼就應該能判斷「我可以選多個 vs 我只能選一個」。
969
+
970
+ | Selection Model | Canonical 視覺 | 禁止 |
971
+ |---|---|---|
972
+ | **多選**(checkbox semantic) | `DropdownMenuCheckboxItem`(方塊勾)、SelectionItem checkbox | radio 圓圈、bg 高亮(無方塊會誤以為單選) |
973
+ | **單選 in dropdown / menu** | `DropdownMenuItem` 的 `selected` prop → `bg-neutral-selected` 持續選中背景(跟 SelectMenu 單選同一套) | **checkbox 方塊**(暗示多選)、**radio 圓圈**(dropdown 不用 radio 指示器,RadioGroup 才用) |
974
+ | **單選 as always-visible form control** | `RadioGroup` + `RadioGroupItem`(圓圈) | — |
975
+
976
+ #### 為什麼 dropdown 單選不用 radio 圓圈
977
+
978
+ 本系統(跟 macOS / Chrome / VS Code 一致)在「隱藏在 dropdown 內的單選」統一用**持續高亮背景**(`bg-neutral-selected`),不用 radio 圓圈指示器。radio 圓圈只用在**永遠可見的 form RadioGroup**。
979
+ 兩者視覺完全不同但都是單選,差異來自「使用場景」:
980
+ - **Dropdown 單選(隱藏)**: 打開時視覺極簡,只高亮 current,點了就關、切換 context → SelectMenu / DropdownMenu 單選
981
+ - **Form RadioGroup(常駐)**: 永遠展開,使用者在填表時掃視所有選項 → radio 圓圈讓「這是一組互斥選項」一眼可辨
982
+
983
+ #### 新元件檢查法
984
+
985
+ 設計或審查 selection control 時:
986
+ 1. **單選 or 多選?** → 選對 primitive
987
+ 2. **隱藏型(dropdown)or 常駐型(form control)?** → 選對視覺語言
988
+ 3. **看 consumer 要用什麼 state prop,不要繞過 prop 用 className**(跟上面規則 A 合用)
989
+
990
+ **這兩條規則是曾經連續犯錯的原因**。違反規則 A 會造成「同狀態不同視覺」,違反規則 B 會造成「視覺誤導 mental model」。寫新元件或審查現有元件時兩條都檢查。
991
+
992
+ ---
993
+
994
+ ## 新元件 checklist
995
+
996
+ 建立新的「prefix + content + suffix」元件時:
997
+
998
+ 1. ✅ 確定閱讀模式(掃描 or 閱讀)→ 決定 typography 策略
999
+ 2. ✅ 確定 padding-y(field-height 公式 or 固定值)
1000
+ 3. ✅ 確定 padding-x 和 gap
1001
+ 4. ✅ prefix 對齊容器遵循 24px 閾值(小→inline / 大+desc→block)
1002
+ 5. ✅ suffix 對齊容器**獨立判斷**(不跟 prefix 綁定,見「24px 閾值對齊規則」的 suffix 獨立說明)
1003
+ 6. ✅ 外層 `flex items-start`,prefix / suffix 各自包 `h-[1lh]`(或 block calc)wrapper
1004
+ 7. ✅ Prefix 用 `<ItemIcon>` / `<ItemAvatar>` helper,**禁止**硬寫 `<Avatar size={N} />` 或 `<Icon size={N} />`
1005
+ 8. ✅ Icon 尺寸用 `ICON_SIZE` 常數 + `size` prop 直接傳給 Lucide,不用 CSS `[&>svg]:size-*` selector
1006
+ 9. ✅ Label span 有 `min-w-0 flex-1 truncate`(或用 `<ItemLabel>` helper)
1007
+ 10. ✅ Suffix inline action 用 `<ItemInlineAction>` / `<ItemInlineActionButton>`,**禁止**複製 hover-bg 絕對定位 JSX
1008
+ 11. ✅ Row primitive 容器用 `<RowSizeProvider value={size}>` 包住所有 children,讓 helper 元件能讀到 size
1009
+ 12. ✅ icon 色彩遵循「代表內容 = label 同色,指示方向 = fg-muted」
1010
+ 13. ✅ description 字體遵循閱讀模式規則
1011
+
1012
+ ---
1013
+
1014
+ ## Recipe + 自我檢查 → `.claude/references/item-anatomy-recipe.md`
1015
+
1016
+ 建立新 row primitive 的 7 步 workflow + audit grep guard + SidebarMenuButton 獨立實作風險,搬到 `.claude/references/item-anatomy-recipe.md`(spec 2026-04-24 prune 瘦身 — Recipe 是 workflow 類,搬 reference 減 spec 體積)。
1017
+
1018
+ 本節僅保留 pointer。建 row primitive → 讀 reference + 本 spec 的結構 / padding / 24px 閾值 / slot 規範 / 選擇狀態視覺 / Inline Action spec 等 canonical。
1019
+
1020
+ ## 被引用(auto-maintained,Dim 3 reciprocal audit)
1021
+
1022
+ > 本節由 `scripts/add-reciprocal-pointers.mjs` 自動維護,列出在 SSOT 語境下指向本 spec 的其他 spec。若要手動補充,寫在本節之前。
1023
+
1024
+ - `alert.spec.md`
1025
+ - `command.spec.md`
1026
+ - `data-table.spec.md`
1027
+ - `dropdown-menu.spec.md`
1028
+ - `empty.spec.md`
1029
+ - `field.spec.md`
1030
+ - `file-item.spec.md`
1031
+ - `menu-item.spec.md`
1032
+ - `notice.spec.md`
1033
+ - `overlay-surface.spec.md`
1034
+ - `select-menu.spec.md`
1035
+ - `select.spec.md`
1036
+ - `selection-item.spec.md`
1037
+ - `sidebar.spec.md`
1038
+ - `tag.spec.md`
1039
+ - `time-picker.spec.md`
1040
+ - `toast.spec.md`
1041
+ - `tree-view.spec.md`
1042
+ - `typography.spec.md`