@qijenchen/design-system 0.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/README.md +163 -0
  2. package/dist/components/Accordion/accordion.d.ts +37 -0
  3. package/dist/components/Accordion/accordion.d.ts.map +1 -0
  4. package/dist/components/Accordion/accordion.js +78 -0
  5. package/dist/components/Accordion/accordion.js.map +1 -0
  6. package/dist/components/Alert/alert.d.ts +47 -0
  7. package/dist/components/Alert/alert.d.ts.map +1 -0
  8. package/dist/components/Alert/alert.js +132 -0
  9. package/dist/components/Alert/alert.js.map +1 -0
  10. package/dist/components/AppShell/_demo-helpers.d.ts +49 -0
  11. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -0
  12. package/dist/components/AppShell/app-shell.d.ts +76 -0
  13. package/dist/components/AppShell/app-shell.d.ts.map +1 -0
  14. package/dist/components/AppShell/app-shell.js +214 -0
  15. package/dist/components/AppShell/app-shell.js.map +1 -0
  16. package/dist/components/AspectRatio/aspect-ratio.d.ts +40 -0
  17. package/dist/components/AspectRatio/aspect-ratio.d.ts.map +1 -0
  18. package/dist/components/AspectRatio/aspect-ratio.js +23 -0
  19. package/dist/components/AspectRatio/aspect-ratio.js.map +1 -0
  20. package/dist/components/Avatar/avatar.d.ts +85 -0
  21. package/dist/components/Avatar/avatar.d.ts.map +1 -0
  22. package/dist/components/Avatar/avatar.js +195 -0
  23. package/dist/components/Avatar/avatar.js.map +1 -0
  24. package/dist/components/Badge/badge.d.ts +43 -0
  25. package/dist/components/Badge/badge.d.ts.map +1 -0
  26. package/dist/components/Badge/badge.js +69 -0
  27. package/dist/components/Badge/badge.js.map +1 -0
  28. package/dist/components/Breadcrumb/breadcrumb.d.ts +163 -0
  29. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -0
  30. package/dist/components/Breadcrumb/breadcrumb.js +300 -0
  31. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -0
  32. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +46 -0
  33. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -0
  34. package/dist/components/BulkActionBar/bulk-action-bar.js +78 -0
  35. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -0
  36. package/dist/components/Button/button-group.d.ts +49 -0
  37. package/dist/components/Button/button-group.d.ts.map +1 -0
  38. package/dist/components/Button/button-group.js +46 -0
  39. package/dist/components/Button/button-group.js.map +1 -0
  40. package/dist/components/Button/button.d.ts +203 -0
  41. package/dist/components/Button/button.d.ts.map +1 -0
  42. package/dist/components/Button/button.js +309 -0
  43. package/dist/components/Button/button.js.map +1 -0
  44. package/dist/components/Calendar/calendar.d.ts +81 -0
  45. package/dist/components/Calendar/calendar.d.ts.map +1 -0
  46. package/dist/components/Calendar/calendar.js +282 -0
  47. package/dist/components/Calendar/calendar.js.map +1 -0
  48. package/dist/components/Carousel/carousel.d.ts +61 -0
  49. package/dist/components/Carousel/carousel.d.ts.map +1 -0
  50. package/dist/components/Carousel/carousel.js +276 -0
  51. package/dist/components/Carousel/carousel.js.map +1 -0
  52. package/dist/components/Chart/chart.d.ts +94 -0
  53. package/dist/components/Chart/chart.d.ts.map +1 -0
  54. package/dist/components/Chart/chart.js +233 -0
  55. package/dist/components/Chart/chart.js.map +1 -0
  56. package/dist/components/Checkbox/checkbox-group.d.ts +58 -0
  57. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -0
  58. package/dist/components/Checkbox/checkbox-group.js +28 -0
  59. package/dist/components/Checkbox/checkbox-group.js.map +1 -0
  60. package/dist/components/Checkbox/checkbox.d.ts +73 -0
  61. package/dist/components/Checkbox/checkbox.d.ts.map +1 -0
  62. package/dist/components/Checkbox/checkbox.js +125 -0
  63. package/dist/components/Checkbox/checkbox.js.map +1 -0
  64. package/dist/components/Chip/chip.d.ts +54 -0
  65. package/dist/components/Chip/chip.d.ts.map +1 -0
  66. package/dist/components/Chip/chip.js +224 -0
  67. package/dist/components/Chip/chip.js.map +1 -0
  68. package/dist/components/CircularProgress/circular-progress.d.ts +40 -0
  69. package/dist/components/CircularProgress/circular-progress.d.ts.map +1 -0
  70. package/dist/components/CircularProgress/circular-progress.js +118 -0
  71. package/dist/components/CircularProgress/circular-progress.js.map +1 -0
  72. package/dist/components/Coachmark/coachmark.d.ts +100 -0
  73. package/dist/components/Coachmark/coachmark.d.ts.map +1 -0
  74. package/dist/components/Coachmark/coachmark.js +107 -0
  75. package/dist/components/Coachmark/coachmark.js.map +1 -0
  76. package/dist/components/Combobox/combobox.d.ts +150 -0
  77. package/dist/components/Combobox/combobox.d.ts.map +1 -0
  78. package/dist/components/Combobox/combobox.js +595 -0
  79. package/dist/components/Combobox/combobox.js.map +1 -0
  80. package/dist/components/Command/command.d.ts +106 -0
  81. package/dist/components/Command/command.d.ts.map +1 -0
  82. package/dist/components/Command/command.js +123 -0
  83. package/dist/components/Command/command.js.map +1 -0
  84. package/dist/components/DataTable/active-editor-controller.d.ts +66 -0
  85. package/dist/components/DataTable/active-editor-controller.d.ts.map +1 -0
  86. package/dist/components/DataTable/cell-registry.d.ts +37 -0
  87. package/dist/components/DataTable/cell-registry.d.ts.map +1 -0
  88. package/dist/components/DataTable/cell-registry.js +377 -0
  89. package/dist/components/DataTable/cell-registry.js.map +1 -0
  90. package/dist/components/DataTable/column-types.d.ts +145 -0
  91. package/dist/components/DataTable/column-types.d.ts.map +1 -0
  92. package/dist/components/DataTable/column-types.js +17 -0
  93. package/dist/components/DataTable/column-types.js.map +1 -0
  94. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +49 -0
  95. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -0
  96. package/dist/components/DataTable/data-table-filter-panel.d.ts +30 -0
  97. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -0
  98. package/dist/components/DataTable/data-table-interaction-layer.d.ts +78 -0
  99. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -0
  100. package/dist/components/DataTable/data-table-interaction-layer.js +220 -0
  101. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -0
  102. package/dist/components/DataTable/data-table-sort-manager.d.ts +19 -0
  103. package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -0
  104. package/dist/components/DataTable/data-table.d.ts +181 -0
  105. package/dist/components/DataTable/data-table.d.ts.map +1 -0
  106. package/dist/components/DataTable/data-table.js +1851 -0
  107. package/dist/components/DataTable/data-table.js.map +1 -0
  108. package/dist/components/DataTable/filter-operators.d.ts +116 -0
  109. package/dist/components/DataTable/filter-operators.d.ts.map +1 -0
  110. package/dist/components/DataTable/filter-tree.d.ts +66 -0
  111. package/dist/components/DataTable/filter-tree.d.ts.map +1 -0
  112. package/dist/components/DataTable/lib/column-meta.d.ts +49 -0
  113. package/dist/components/DataTable/lib/column-meta.d.ts.map +1 -0
  114. package/dist/components/DateGrid/date-grid.d.ts +61 -0
  115. package/dist/components/DateGrid/date-grid.d.ts.map +1 -0
  116. package/dist/components/DateGrid/date-grid.js +168 -0
  117. package/dist/components/DateGrid/date-grid.js.map +1 -0
  118. package/dist/components/DatePicker/date-picker.d.ts +119 -0
  119. package/dist/components/DatePicker/date-picker.d.ts.map +1 -0
  120. package/dist/components/DatePicker/date-picker.js +743 -0
  121. package/dist/components/DatePicker/date-picker.js.map +1 -0
  122. package/dist/components/DescriptionList/description-list.d.ts +60 -0
  123. package/dist/components/DescriptionList/description-list.d.ts.map +1 -0
  124. package/dist/components/DescriptionList/description-list.js +77 -0
  125. package/dist/components/DescriptionList/description-list.js.map +1 -0
  126. package/dist/components/Dialog/dialog.d.ts +54 -0
  127. package/dist/components/Dialog/dialog.d.ts.map +1 -0
  128. package/dist/components/Dialog/dialog.js +151 -0
  129. package/dist/components/Dialog/dialog.js.map +1 -0
  130. package/dist/components/DropdownMenu/dropdown-menu.d.ts +111 -0
  131. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -0
  132. package/dist/components/DropdownMenu/dropdown-menu.js +288 -0
  133. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -0
  134. package/dist/components/Empty/empty.d.ts +40 -0
  135. package/dist/components/Empty/empty.d.ts.map +1 -0
  136. package/dist/components/Empty/empty.js +66 -0
  137. package/dist/components/Empty/empty.js.map +1 -0
  138. package/dist/components/Field/field-context.d.ts +77 -0
  139. package/dist/components/Field/field-context.d.ts.map +1 -0
  140. package/dist/components/Field/field-context.js +37 -0
  141. package/dist/components/Field/field-context.js.map +1 -0
  142. package/dist/components/Field/field-types.d.ts +5 -0
  143. package/dist/components/Field/field-types.d.ts.map +1 -0
  144. package/dist/components/Field/field-types.js +13 -0
  145. package/dist/components/Field/field-types.js.map +1 -0
  146. package/dist/components/Field/field-wrapper.d.ts +17 -0
  147. package/dist/components/Field/field-wrapper.d.ts.map +1 -0
  148. package/dist/components/Field/field-wrapper.js +252 -0
  149. package/dist/components/Field/field-wrapper.js.map +1 -0
  150. package/dist/components/Field/field.d.ts +127 -0
  151. package/dist/components/Field/field.d.ts.map +1 -0
  152. package/dist/components/Field/field.js +295 -0
  153. package/dist/components/Field/field.js.map +1 -0
  154. package/dist/components/FieldControlGroup/field-control-group.d.ts +74 -0
  155. package/dist/components/FieldControlGroup/field-control-group.d.ts.map +1 -0
  156. package/dist/components/FieldControlGroup/field-control-group.js +62 -0
  157. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -0
  158. package/dist/components/FileItem/file-item.d.ts +44 -0
  159. package/dist/components/FileItem/file-item.d.ts.map +1 -0
  160. package/dist/components/FileItem/file-item.js +202 -0
  161. package/dist/components/FileItem/file-item.js.map +1 -0
  162. package/dist/components/FileUpload/file-upload.d.ts +97 -0
  163. package/dist/components/FileUpload/file-upload.d.ts.map +1 -0
  164. package/dist/components/FileUpload/file-upload.js +231 -0
  165. package/dist/components/FileUpload/file-upload.js.map +1 -0
  166. package/dist/components/FileViewer/file-viewer-types.d.ts +73 -0
  167. package/dist/components/FileViewer/file-viewer-types.d.ts.map +1 -0
  168. package/dist/components/FileViewer/file-viewer.d.ts +82 -0
  169. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -0
  170. package/dist/components/FileViewer/file-viewer.js +752 -0
  171. package/dist/components/FileViewer/file-viewer.js.map +1 -0
  172. package/dist/components/FileViewer/image-renderer.d.ts +9 -0
  173. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -0
  174. package/dist/components/FileViewer/image-renderer.js +165 -0
  175. package/dist/components/FileViewer/image-renderer.js.map +1 -0
  176. package/dist/components/HoverCard/hover-card.d.ts +30 -0
  177. package/dist/components/HoverCard/hover-card.d.ts.map +1 -0
  178. package/dist/components/HoverCard/hover-card.js +61 -0
  179. package/dist/components/HoverCard/hover-card.js.map +1 -0
  180. package/dist/components/Input/input.d.ts +72 -0
  181. package/dist/components/Input/input.d.ts.map +1 -0
  182. package/dist/components/Input/input.js +148 -0
  183. package/dist/components/Input/input.js.map +1 -0
  184. package/dist/components/LinkInput/link-input.d.ts +46 -0
  185. package/dist/components/LinkInput/link-input.d.ts.map +1 -0
  186. package/dist/components/LinkInput/link-input.js +215 -0
  187. package/dist/components/LinkInput/link-input.js.map +1 -0
  188. package/dist/components/Menu/menu-item.d.ts +83 -0
  189. package/dist/components/Menu/menu-item.d.ts.map +1 -0
  190. package/dist/components/Menu/menu-item.js +209 -0
  191. package/dist/components/Menu/menu-item.js.map +1 -0
  192. package/dist/components/NameCard/name-card.d.ts +85 -0
  193. package/dist/components/NameCard/name-card.d.ts.map +1 -0
  194. package/dist/components/NameCard/name-card.js +153 -0
  195. package/dist/components/NameCard/name-card.js.map +1 -0
  196. package/dist/components/Notice/notice.d.ts +69 -0
  197. package/dist/components/Notice/notice.d.ts.map +1 -0
  198. package/dist/components/Notice/notice.js +121 -0
  199. package/dist/components/Notice/notice.js.map +1 -0
  200. package/dist/components/NumberInput/number-input.d.ts +57 -0
  201. package/dist/components/NumberInput/number-input.d.ts.map +1 -0
  202. package/dist/components/NumberInput/number-input.js +131 -0
  203. package/dist/components/NumberInput/number-input.js.map +1 -0
  204. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +23 -0
  205. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -0
  206. package/dist/components/OverflowIndicator/overflow-indicator.js +111 -0
  207. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -0
  208. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +57 -0
  209. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -0
  210. package/dist/components/PeoplePicker/avatar-stack-overflow.js +35 -0
  211. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -0
  212. package/dist/components/PeoplePicker/people-picker-helpers.d.ts +7 -0
  213. package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -0
  214. package/dist/components/PeoplePicker/people-picker-helpers.js +25 -0
  215. package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -0
  216. package/dist/components/PeoplePicker/people-picker.d.ts +77 -0
  217. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -0
  218. package/dist/components/PeoplePicker/people-picker.js +263 -0
  219. package/dist/components/PeoplePicker/people-picker.js.map +1 -0
  220. package/dist/components/PeoplePicker/person-display.d.ts +66 -0
  221. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -0
  222. package/dist/components/PeoplePicker/person-display.js +203 -0
  223. package/dist/components/PeoplePicker/person-display.js.map +1 -0
  224. package/dist/components/Popover/popover.d.ts +50 -0
  225. package/dist/components/Popover/popover.d.ts.map +1 -0
  226. package/dist/components/Popover/popover.js +113 -0
  227. package/dist/components/Popover/popover.js.map +1 -0
  228. package/dist/components/ProgressBar/progress-bar.d.ts +37 -0
  229. package/dist/components/ProgressBar/progress-bar.d.ts.map +1 -0
  230. package/dist/components/ProgressBar/progress-bar.js +86 -0
  231. package/dist/components/ProgressBar/progress-bar.js.map +1 -0
  232. package/dist/components/RadioGroup/radio-group.d.ts +78 -0
  233. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -0
  234. package/dist/components/RadioGroup/radio-group.js +153 -0
  235. package/dist/components/RadioGroup/radio-group.js.map +1 -0
  236. package/dist/components/Rating/rating.d.ts +46 -0
  237. package/dist/components/Rating/rating.d.ts.map +1 -0
  238. package/dist/components/Rating/rating.js +179 -0
  239. package/dist/components/Rating/rating.js.map +1 -0
  240. package/dist/components/ScrollArea/scroll-area.d.ts +45 -0
  241. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -0
  242. package/dist/components/ScrollArea/scroll-area.js +65 -0
  243. package/dist/components/ScrollArea/scroll-area.js.map +1 -0
  244. package/dist/components/SegmentedControl/segmented-control.d.ts +102 -0
  245. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -0
  246. package/dist/components/SegmentedControl/segmented-control.js +171 -0
  247. package/dist/components/SegmentedControl/segmented-control.js.map +1 -0
  248. package/dist/components/Select/select.d.ts +102 -0
  249. package/dist/components/Select/select.d.ts.map +1 -0
  250. package/dist/components/Select/select.js +435 -0
  251. package/dist/components/Select/select.js.map +1 -0
  252. package/dist/components/SelectMenu/select-menu.d.ts +103 -0
  253. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -0
  254. package/dist/components/SelectMenu/select-menu.js +239 -0
  255. package/dist/components/SelectMenu/select-menu.js.map +1 -0
  256. package/dist/components/SelectionControl/selection-item.d.ts +69 -0
  257. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -0
  258. package/dist/components/SelectionControl/selection-item.js +142 -0
  259. package/dist/components/SelectionControl/selection-item.js.map +1 -0
  260. package/dist/components/Separator/separator.d.ts +17 -0
  261. package/dist/components/Separator/separator.d.ts.map +1 -0
  262. package/dist/components/Separator/separator.js +39 -0
  263. package/dist/components/Separator/separator.js.map +1 -0
  264. package/dist/components/Sheet/sheet.d.ts +56 -0
  265. package/dist/components/Sheet/sheet.d.ts.map +1 -0
  266. package/dist/components/Sheet/sheet.js +145 -0
  267. package/dist/components/Sheet/sheet.js.map +1 -0
  268. package/dist/components/Sidebar/sidebar.d.ts +195 -0
  269. package/dist/components/Sidebar/sidebar.d.ts.map +1 -0
  270. package/dist/components/Sidebar/sidebar.js +826 -0
  271. package/dist/components/Sidebar/sidebar.js.map +1 -0
  272. package/dist/components/Skeleton/skeleton.d.ts +16 -0
  273. package/dist/components/Skeleton/skeleton.d.ts.map +1 -0
  274. package/dist/components/Skeleton/skeleton.js +30 -0
  275. package/dist/components/Skeleton/skeleton.js.map +1 -0
  276. package/dist/components/Slider/slider.d.ts +48 -0
  277. package/dist/components/Slider/slider.d.ts.map +1 -0
  278. package/dist/components/Slider/slider.js +108 -0
  279. package/dist/components/Slider/slider.js.map +1 -0
  280. package/dist/components/Steps/steps.d.ts +71 -0
  281. package/dist/components/Steps/steps.d.ts.map +1 -0
  282. package/dist/components/Steps/steps.js +583 -0
  283. package/dist/components/Steps/steps.js.map +1 -0
  284. package/dist/components/Switch/switch.d.ts +112 -0
  285. package/dist/components/Switch/switch.d.ts.map +1 -0
  286. package/dist/components/Switch/switch.js +179 -0
  287. package/dist/components/Switch/switch.js.map +1 -0
  288. package/dist/components/Tabs/tabs.d.ts +104 -0
  289. package/dist/components/Tabs/tabs.d.ts.map +1 -0
  290. package/dist/components/Tabs/tabs.js +316 -0
  291. package/dist/components/Tabs/tabs.js.map +1 -0
  292. package/dist/components/Tag/tag.d.ts +86 -0
  293. package/dist/components/Tag/tag.d.ts.map +1 -0
  294. package/dist/components/Tag/tag.js +172 -0
  295. package/dist/components/Tag/tag.js.map +1 -0
  296. package/dist/components/Textarea/textarea.d.ts +74 -0
  297. package/dist/components/Textarea/textarea.d.ts.map +1 -0
  298. package/dist/components/Textarea/textarea.js +224 -0
  299. package/dist/components/Textarea/textarea.js.map +1 -0
  300. package/dist/components/TimePicker/time-columns.d.ts +46 -0
  301. package/dist/components/TimePicker/time-columns.d.ts.map +1 -0
  302. package/dist/components/TimePicker/time-columns.js +173 -0
  303. package/dist/components/TimePicker/time-columns.js.map +1 -0
  304. package/dist/components/TimePicker/time-picker.d.ts +94 -0
  305. package/dist/components/TimePicker/time-picker.d.ts.map +1 -0
  306. package/dist/components/TimePicker/time-picker.js +253 -0
  307. package/dist/components/TimePicker/time-picker.js.map +1 -0
  308. package/dist/components/Toast/toast.d.ts +61 -0
  309. package/dist/components/Toast/toast.d.ts.map +1 -0
  310. package/dist/components/Toast/toast.js +76 -0
  311. package/dist/components/Toast/toast.js.map +1 -0
  312. package/dist/components/Tooltip/tooltip.d.ts +20 -0
  313. package/dist/components/Tooltip/tooltip.d.ts.map +1 -0
  314. package/dist/components/Tooltip/tooltip.js +53 -0
  315. package/dist/components/Tooltip/tooltip.js.map +1 -0
  316. package/dist/components/TreeView/tree-view.d.ts +166 -0
  317. package/dist/components/TreeView/tree-view.d.ts.map +1 -0
  318. package/dist/components/TreeView/tree-view.js +617 -0
  319. package/dist/components/TreeView/tree-view.js.map +1 -0
  320. package/dist/hooks/use-controllable.d.ts +16 -0
  321. package/dist/hooks/use-controllable.d.ts.map +1 -0
  322. package/dist/hooks/use-controllable.js +26 -0
  323. package/dist/hooks/use-controllable.js.map +1 -0
  324. package/dist/hooks/use-is-narrow-viewport.d.ts +2 -0
  325. package/dist/hooks/use-is-narrow-viewport.d.ts.map +1 -0
  326. package/dist/hooks/use-is-narrow-viewport.js +19 -0
  327. package/dist/hooks/use-is-narrow-viewport.js.map +1 -0
  328. package/dist/hooks/use-is-touch-device.d.ts +8 -0
  329. package/dist/hooks/use-is-touch-device.d.ts.map +1 -0
  330. package/dist/hooks/use-is-touch-device.js +16 -0
  331. package/dist/hooks/use-is-touch-device.js.map +1 -0
  332. package/dist/hooks/use-overflow-items.d.ts +124 -0
  333. package/dist/hooks/use-overflow-items.d.ts.map +1 -0
  334. package/dist/hooks/use-overflow-items.js +97 -0
  335. package/dist/hooks/use-overflow-items.js.map +1 -0
  336. package/dist/index.d.ts +74 -0
  337. package/dist/index.d.ts.map +1 -0
  338. package/dist/index.js +371 -0
  339. package/dist/index.js.map +1 -0
  340. package/dist/lib/drag-visual.d.ts +158 -0
  341. package/dist/lib/drag-visual.d.ts.map +1 -0
  342. package/dist/lib/drag-visual.js +96 -0
  343. package/dist/lib/drag-visual.js.map +1 -0
  344. package/dist/lib/i18n/i18n-context.d.ts +105 -0
  345. package/dist/lib/i18n/i18n-context.d.ts.map +1 -0
  346. package/dist/lib/multi-select-ordering.d.ts +54 -0
  347. package/dist/lib/multi-select-ordering.d.ts.map +1 -0
  348. package/dist/lib/multi-select-ordering.js +13 -0
  349. package/dist/lib/multi-select-ordering.js.map +1 -0
  350. package/dist/lib/utils.d.ts +12 -0
  351. package/dist/lib/utils.d.ts.map +1 -0
  352. package/dist/lib/utils.js +79 -0
  353. package/dist/lib/utils.js.map +1 -0
  354. package/dist/patterns/element-anatomy/item-anatomy.d.ts +370 -0
  355. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -0
  356. package/dist/patterns/element-anatomy/item-anatomy.js +272 -0
  357. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -0
  358. package/dist/patterns/header-canonical/chrome-header.d.ts +80 -0
  359. package/dist/patterns/header-canonical/chrome-header.d.ts.map +1 -0
  360. package/dist/patterns/header-canonical/chrome-header.js +75 -0
  361. package/dist/patterns/header-canonical/chrome-header.js.map +1 -0
  362. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts +101 -0
  363. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -0
  364. package/dist/patterns/horizontal-overflow/horizontal-overflow.js +105 -0
  365. package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -0
  366. package/dist/patterns/overlay-surface/overlay-surface.d.ts +28 -0
  367. package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -0
  368. package/dist/patterns/overlay-surface/overlay-surface.js +85 -0
  369. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -0
  370. package/dist/patterns/resize-handle/resize-handle.d.ts +102 -0
  371. package/dist/patterns/resize-handle/resize-handle.d.ts.map +1 -0
  372. package/dist/patterns/resize-handle/resize-handle.js +74 -0
  373. package/dist/patterns/resize-handle/resize-handle.js.map +1 -0
  374. package/dist/react-day-picker.css +457 -0
  375. package/dist/stories-helpers/anatomy/anatomy-utils.d.ts +40 -0
  376. package/dist/stories-helpers/anatomy/anatomy-utils.d.ts.map +1 -0
  377. package/dist/tokens/elevation/overlay-geometry.d.ts +12 -0
  378. package/dist/tokens/elevation/overlay-geometry.d.ts.map +1 -0
  379. package/dist/tokens/elevation/overlay-geometry.js +7 -0
  380. package/dist/tokens/elevation/overlay-geometry.js.map +1 -0
  381. package/dist/tokens/motion/motion.d.ts +15 -0
  382. package/dist/tokens/motion/motion.d.ts.map +1 -0
  383. package/dist/tokens/motion/motion.js +9 -0
  384. package/dist/tokens/motion/motion.js.map +1 -0
  385. package/dist/tokens/uiSize/icon-size.d.ts +53 -0
  386. package/dist/tokens/uiSize/icon-size.d.ts.map +1 -0
  387. package/package.json +92 -0
  388. package/src/README.md +32 -0
  389. package/src/components/Accordion/accordion.tsx +104 -0
  390. package/src/components/Alert/alert.tsx +188 -0
  391. package/src/components/AppShell/_demo-helpers.tsx +198 -0
  392. package/src/components/AppShell/app-shell.tsx +364 -0
  393. package/src/components/AspectRatio/aspect-ratio.tsx +58 -0
  394. package/src/components/Avatar/avatar.tsx +368 -0
  395. package/src/components/Badge/badge.tsx +104 -0
  396. package/src/components/Breadcrumb/breadcrumb.tsx +619 -0
  397. package/src/components/BulkActionBar/bulk-action-bar.tsx +156 -0
  398. package/src/components/Button/button-group.tsx +96 -0
  399. package/src/components/Button/button.tsx +539 -0
  400. package/src/components/Calendar/calendar.tsx +411 -0
  401. package/src/components/Carousel/carousel.tsx +371 -0
  402. package/src/components/Chart/chart.tsx +376 -0
  403. package/src/components/Checkbox/checkbox-group.tsx +94 -0
  404. package/src/components/Checkbox/checkbox.tsx +237 -0
  405. package/src/components/Chip/chip.tsx +359 -0
  406. package/src/components/CircularProgress/circular-progress.tsx +204 -0
  407. package/src/components/Coachmark/coachmark.tsx +255 -0
  408. package/src/components/Combobox/combobox.tsx +826 -0
  409. package/src/components/Command/command.tsx +187 -0
  410. package/src/components/DataTable/active-editor-controller.ts +72 -0
  411. package/src/components/DataTable/cell-registry.tsx +520 -0
  412. package/src/components/DataTable/column-types.ts +180 -0
  413. package/src/components/DataTable/data-table-column-visibility-panel.tsx +261 -0
  414. package/src/components/DataTable/data-table-filter-panel.tsx +813 -0
  415. package/src/components/DataTable/data-table-interaction-layer.tsx +483 -0
  416. package/src/components/DataTable/data-table-sort-manager.tsx +210 -0
  417. package/src/components/DataTable/data-table.css +165 -0
  418. package/src/components/DataTable/data-table.tsx +2924 -0
  419. package/src/components/DataTable/filter-operators.ts +225 -0
  420. package/src/components/DataTable/filter-tree.ts +313 -0
  421. package/src/components/DataTable/lib/column-meta.ts +79 -0
  422. package/src/components/DateGrid/date-grid.tsx +209 -0
  423. package/src/components/DatePicker/date-picker.tsx +1114 -0
  424. package/src/components/DescriptionList/description-list.tsx +141 -0
  425. package/src/components/Dialog/dialog.tsx +267 -0
  426. package/src/components/DropdownMenu/dropdown-menu.tsx +475 -0
  427. package/src/components/Empty/empty.tsx +108 -0
  428. package/src/components/Field/field-context.ts +136 -0
  429. package/src/components/Field/field-types.ts +52 -0
  430. package/src/components/Field/field-wrapper.tsx +348 -0
  431. package/src/components/Field/field.tsx +535 -0
  432. package/src/components/FieldControlGroup/field-control-group.tsx +136 -0
  433. package/src/components/FileItem/file-item.tsx +322 -0
  434. package/src/components/FileUpload/file-upload.tsx +326 -0
  435. package/src/components/FileViewer/file-viewer-types.ts +76 -0
  436. package/src/components/FileViewer/file-viewer.tsx +1065 -0
  437. package/src/components/FileViewer/image-renderer.tsx +256 -0
  438. package/src/components/HoverCard/hover-card.tsx +79 -0
  439. package/src/components/Input/input.tsx +233 -0
  440. package/src/components/LinkInput/link-input.tsx +304 -0
  441. package/src/components/Menu/menu-item.tsx +334 -0
  442. package/src/components/NameCard/name-card.tsx +319 -0
  443. package/src/components/Notice/notice.tsx +196 -0
  444. package/src/components/NumberInput/number-input.tsx +203 -0
  445. package/src/components/OverflowIndicator/overflow-indicator.tsx +156 -0
  446. package/src/components/PeoplePicker/avatar-stack-overflow.ts +100 -0
  447. package/src/components/PeoplePicker/people-picker-helpers.ts +76 -0
  448. package/src/components/PeoplePicker/people-picker.tsx +455 -0
  449. package/src/components/PeoplePicker/person-display.tsx +358 -0
  450. package/src/components/Popover/popover.tsx +183 -0
  451. package/src/components/ProgressBar/progress-bar.tsx +157 -0
  452. package/src/components/README.md +58 -0
  453. package/src/components/RadioGroup/radio-group.tsx +261 -0
  454. package/src/components/Rating/rating.tsx +295 -0
  455. package/src/components/ScrollArea/scroll-area.tsx +110 -0
  456. package/src/components/SegmentedControl/segmented-control.tsx +304 -0
  457. package/src/components/Select/select.tsx +658 -0
  458. package/src/components/SelectMenu/select-menu.tsx +430 -0
  459. package/src/components/SelectionControl/selection-item.tsx +261 -0
  460. package/src/components/Separator/separator.tsx +48 -0
  461. package/src/components/Sheet/sheet.tsx +240 -0
  462. package/src/components/Sidebar/sidebar.tsx +1280 -0
  463. package/src/components/Skeleton/skeleton.tsx +35 -0
  464. package/src/components/Slider/slider.tsx +158 -0
  465. package/src/components/Steps/steps.tsx +850 -0
  466. package/src/components/Switch/switch.tsx +285 -0
  467. package/src/components/Tabs/tabs.tsx +515 -0
  468. package/src/components/Tag/tag.tsx +246 -0
  469. package/src/components/Textarea/textarea.tsx +280 -0
  470. package/src/components/TimePicker/time-columns.tsx +260 -0
  471. package/src/components/TimePicker/time-picker.tsx +419 -0
  472. package/src/components/Toast/toast.tsx +129 -0
  473. package/src/components/Tooltip/tooltip.tsx +68 -0
  474. package/src/components/TreeView/tree-view.tsx +1031 -0
  475. package/src/hooks/use-controllable.ts +40 -0
  476. package/src/hooks/use-is-narrow-viewport.ts +19 -0
  477. package/src/hooks/use-is-touch-device.ts +21 -0
  478. package/src/hooks/use-overflow-items.ts +256 -0
  479. package/src/index.ts +85 -0
  480. package/src/lib/README.md +82 -0
  481. package/src/lib/drag-visual.ts +272 -0
  482. package/src/lib/i18n/README.md +60 -0
  483. package/src/lib/i18n/i18n-context.tsx +129 -0
  484. package/src/lib/multi-select-ordering.ts +61 -0
  485. package/src/lib/utils.ts +93 -0
  486. package/src/patterns/README.md +67 -0
  487. package/src/patterns/element-anatomy/item-anatomy.tsx +744 -0
  488. package/src/patterns/header-canonical/chrome-header.tsx +175 -0
  489. package/src/patterns/header-canonical/header-canonical.css +27 -0
  490. package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +217 -0
  491. package/src/patterns/overlay-surface/overlay-surface.tsx +191 -0
  492. package/src/patterns/resize-handle/resize-handle.tsx +188 -0
  493. package/src/stories-helpers/anatomy/anatomy-utils.tsx +64 -0
  494. package/src/styles/preset.css +31 -0
  495. package/src/styles/tokens.css +35 -0
  496. package/src/tokens/README.md +53 -0
  497. package/src/tokens/color/primitives.css +429 -0
  498. package/src/tokens/color/semantic.css +539 -0
  499. package/src/tokens/elevation/overlay-geometry.ts +13 -0
  500. package/src/tokens/layoutSpace/layoutSpace.css +36 -0
  501. package/src/tokens/motion/motion.css +30 -0
  502. package/src/tokens/motion/motion.ts +17 -0
  503. package/src/tokens/opacity/opacity.css +23 -0
  504. package/src/tokens/radius/radius.css +19 -0
  505. package/src/tokens/typography/typography.css +118 -0
  506. package/src/tokens/uiSize/icon-size.ts +52 -0
  507. package/src/tokens/uiSize/uiSize.css +125 -0
@@ -0,0 +1,316 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
4
+ import { cva } from "class-variance-authority";
5
+ import { cn } from "../../lib/utils.js";
6
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from "../DropdownMenu/dropdown-menu.js";
7
+ import { useScrollByPage, buildFadeMask, ARROW_BUTTON_WIDTH, OverflowScrollArrow, OverflowMenuTriggerButton } from "../../patterns/horizontal-overflow/horizontal-overflow.js";
8
+ import { ICON_SIZE } from "../../patterns/element-anatomy/item-anatomy.js";
9
+ import { useScrollEdges } from "../../hooks/use-overflow-items.js";
10
+ const TabsContext = React.createContext({ size: "md" });
11
+ const TabsValueContext = React.createContext({});
12
+ const Tabs = React.forwardRef(({ value, onValueChange, defaultValue, children, ...props }, ref) => {
13
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
14
+ const isControlled = value !== void 0;
15
+ const currentValue = isControlled ? value : internalValue;
16
+ const handleValueChange = React.useCallback(
17
+ (next) => {
18
+ if (!isControlled) setInternalValue(next);
19
+ onValueChange == null ? void 0 : onValueChange(next);
20
+ },
21
+ [isControlled, onValueChange]
22
+ );
23
+ const valueContext = React.useMemo(
24
+ () => ({ value: currentValue, onValueChange: handleValueChange }),
25
+ [currentValue, handleValueChange]
26
+ );
27
+ return /* @__PURE__ */ jsx(TabsValueContext.Provider, { value: valueContext, children: /* @__PURE__ */ jsx(
28
+ TabsPrimitive.Root,
29
+ {
30
+ ref,
31
+ value: currentValue,
32
+ onValueChange: handleValueChange,
33
+ ...props,
34
+ children
35
+ }
36
+ ) });
37
+ });
38
+ Tabs.displayName = "Tabs";
39
+ const TABS_LIST_BASE = [
40
+ "inline-flex items-stretch",
41
+ "gap-[var(--layout-space-loose)]",
42
+ "border-b border-divider"
43
+ ].join(" ");
44
+ const TabsList = React.forwardRef(({ className, size = "sm", overflow = "none", children, ...props }, ref) => {
45
+ const tabsSizeContext = React.useMemo(() => ({ size }), [size]);
46
+ if (overflow === "scroll") {
47
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(ScrollTabsList, { ref, className, ...props, children }) });
48
+ }
49
+ if (overflow === "menu") {
50
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(MenuTabsList, { ref, className, ...props, children }) });
51
+ }
52
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(
53
+ TabsPrimitive.List,
54
+ {
55
+ ref,
56
+ className: cn(TABS_LIST_BASE, "w-fit", className),
57
+ ...props,
58
+ children
59
+ }
60
+ ) });
61
+ });
62
+ TabsList.displayName = "TabsList";
63
+ const ScrollTabsList = React.forwardRef(({ className, children, ...props }, ref) => {
64
+ const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges();
65
+ const scrollByPage = useScrollByPage(scrollRef);
66
+ const maskImage = buildFadeMask({
67
+ canScroll,
68
+ atStart,
69
+ atEnd,
70
+ reserveArrowWidth: ARROW_BUTTON_WIDTH
71
+ });
72
+ return (
73
+ // 2026-05-19 fix(scroll-overflow underline clip + y auto-promote):
74
+ // outer 撤 `border-b` → owner 升到 `TabsList` (TABS_LIST_BASE 含 border-b border-divider)
75
+ // 把 trigger `after:bottom-[-1px]` 2px underline 的下半部 1px 收進 list border-box,
76
+ // 再加 `overflow-y-hidden` 明示阻 browser y auto-promote(CSS overflow-3 spec:
77
+ // overflow-x:auto + overflow-y:visible 必 compute auto)。
78
+ // 不加 `pb-px`(outer border 撤後 list border 已接 -1px 部分,加 pb 多 1px 多餘空白)。
79
+ // 對齊 Primer UnderlineNav `overflow-x:auto; overflow-y:hidden` canonical 同步動
80
+ // horizontal-overflow.spec.md L75/L101/L129 owner 升 list 內部。
81
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
82
+ /* @__PURE__ */ jsx(
83
+ "div",
84
+ {
85
+ ref: scrollRef,
86
+ className: "overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
87
+ style: { maskImage, WebkitMaskImage: maskImage },
88
+ children: /* @__PURE__ */ jsx(
89
+ TabsPrimitive.List,
90
+ {
91
+ ref,
92
+ className: cn(TABS_LIST_BASE, "w-fit", className),
93
+ ...props,
94
+ children
95
+ }
96
+ )
97
+ }
98
+ ),
99
+ !atStart && canScroll && /* @__PURE__ */ jsx(OverflowScrollArrow, { direction: "left", onClick: () => scrollByPage("left") }),
100
+ !atEnd && canScroll && /* @__PURE__ */ jsx(OverflowScrollArrow, { direction: "right", onClick: () => scrollByPage("right") })
101
+ ] })
102
+ );
103
+ });
104
+ ScrollTabsList.displayName = "ScrollTabsList";
105
+ const MenuTabsList = React.forwardRef(({ className, children, ...props }, ref) => {
106
+ const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges();
107
+ const { onValueChange, value: activeValue } = React.useContext(TabsValueContext);
108
+ const itemRefs = React.useRef(/* @__PURE__ */ new Map());
109
+ const scrollRafIdRef = React.useRef(0);
110
+ React.useEffect(() => () => {
111
+ if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current);
112
+ }, []);
113
+ const registerItem = React.useCallback(
114
+ (index) => (el) => {
115
+ if (el) itemRefs.current.set(index, el);
116
+ else itemRefs.current.delete(index);
117
+ },
118
+ []
119
+ );
120
+ const items = React.useMemo(
121
+ () => React.Children.toArray(children).filter(React.isValidElement),
122
+ [children]
123
+ );
124
+ const enhancedChildren = items.map(
125
+ (child, i) => React.cloneElement(
126
+ child,
127
+ { ref: registerItem(i) }
128
+ )
129
+ );
130
+ const maskImage = buildFadeMask({ canScroll, atStart, atEnd, reserveArrowWidth: 0 });
131
+ const handleMenuSelect = React.useCallback(
132
+ (triggerValue, index) => {
133
+ onValueChange == null ? void 0 : onValueChange(triggerValue);
134
+ if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current);
135
+ scrollRafIdRef.current = requestAnimationFrame(() => {
136
+ var _a;
137
+ scrollRafIdRef.current = 0;
138
+ (_a = itemRefs.current.get(index)) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", inline: "center", block: "nearest" });
139
+ });
140
+ },
141
+ [onValueChange]
142
+ );
143
+ return (
144
+ // 2026-05-19 fix(scroll-overflow underline clip + y auto-promote,parallel to ScrollTabsList):
145
+ // outer 改 items-stretch(menu button 容器跟 TabsList 含 border 共底線)+ 撤 border。
146
+ // list 套 TABS_LIST_BASE,inner scroll 加 overflow-y-hidden。menu button 容器自帶
147
+ // border-b border-divider 跟 TabsList border 同 y 對齊(items-stretch 保證)。
148
+ /* @__PURE__ */ jsxs("div", { className: "flex items-stretch", children: [
149
+ /* @__PURE__ */ jsx(
150
+ "div",
151
+ {
152
+ ref: scrollRef,
153
+ className: "flex-1 min-w-0 overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
154
+ style: { maskImage, WebkitMaskImage: maskImage },
155
+ children: /* @__PURE__ */ jsx(
156
+ TabsPrimitive.List,
157
+ {
158
+ ref,
159
+ className: cn(TABS_LIST_BASE, "w-fit", className),
160
+ ...props,
161
+ children: enhancedChildren
162
+ }
163
+ )
164
+ }
165
+ ),
166
+ canScroll && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0 pl-[var(--layout-space-loose)] flex items-center border-b border-divider", children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
167
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
168
+ OverflowMenuTriggerButton,
169
+ {
170
+ "aria-label": `頁籤選單(共 ${items.length} 個)`
171
+ }
172
+ ) }),
173
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: items.map((trigger, index) => {
174
+ const triggerProps = trigger.props;
175
+ const triggerValue = triggerProps.value;
176
+ if (typeof triggerValue !== "string") return null;
177
+ return /* @__PURE__ */ jsx(
178
+ DropdownMenuItem,
179
+ {
180
+ disabled: triggerProps.disabled,
181
+ selected: activeValue === triggerValue,
182
+ onSelect: () => handleMenuSelect(triggerValue, index),
183
+ children: triggerProps.children
184
+ },
185
+ triggerValue
186
+ );
187
+ }) })
188
+ ] }) })
189
+ ] })
190
+ );
191
+ });
192
+ MenuTabsList.displayName = "MenuTabsList";
193
+ const tabsTriggerVariants = cva(
194
+ [
195
+ "relative inline-flex items-center justify-center",
196
+ "gap-2",
197
+ "whitespace-nowrap",
198
+ "font-medium text-fg-secondary",
199
+ "transition-colors duration-150",
200
+ "cursor-pointer select-none",
201
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
202
+ // Trigger 無水平 padding — 寬度 = 內容寬度。triggers 間的分隔靠 TabsList 的 gap-[layout-space-loose]
203
+ // selected underline:::after 絕對定位在 bottom:-1px,2px primary-hover
204
+ // left-0/right-0 因為 trigger 已無 padding,底線等於內容寬度
205
+ // 底線蓋住 TabsList 的 1px gray border,視覺單一線條
206
+ "after:absolute after:left-0 after:right-0 after:bottom-[-1px] after:h-0.5",
207
+ "after:bg-transparent after:transition-colors after:duration-150",
208
+ // hover(未選):文字轉深
209
+ "hover:text-foreground",
210
+ // selected
211
+ "data-[state=active]:text-foreground data-[state=active]:font-medium",
212
+ "data-[state=active]:after:bg-primary-hover",
213
+ // disabled:cursor-not-allowed + 不吃 hover 色
214
+ // 不用 pointer-events-none,否則 cursor 不會改變;button[disabled] 本身就擋 click
215
+ "disabled:cursor-not-allowed disabled:text-fg-disabled",
216
+ "disabled:hover:text-fg-disabled"
217
+ ],
218
+ {
219
+ variants: {
220
+ size: {
221
+ // leading-compact:trigger 是單行文字容器,使用 1.3 行高避免 text-body/body-lg 預設 1.5 造成垂直偏移
222
+ sm: "h-[var(--tab-height-sm)] text-body leading-compact",
223
+ md: "h-[var(--tab-height-md)] text-body leading-compact",
224
+ lg: "h-[var(--tab-height-lg)] text-body-lg leading-compact"
225
+ }
226
+ },
227
+ defaultVariants: {
228
+ // size = 'sm' per header-canonical.spec.md W6:overlay / chrome / dense toolbar
229
+ // 都用 sm;獨立 page hero 用 lg。md 為 future tier(無 recommended use case)。
230
+ // 2026-05-17 從 'md' 改 'sm'(M31 codex 比稿後)— production consumer = 0,
231
+ // 影響面限 stories baseline(已過 visual diff gate)。
232
+ size: "sm"
233
+ }
234
+ }
235
+ );
236
+ const TabsTrigger = React.forwardRef(({ className, startIcon: StartIcon, badge, endIcon: EndIcon, inlineAction, children, ...props }, ref) => {
237
+ const { size } = React.useContext(TabsContext);
238
+ const iconSize = ICON_SIZE[size];
239
+ const hasSuffix = badge != null || EndIcon !== void 0 || inlineAction != null;
240
+ return /* @__PURE__ */ jsxs(
241
+ TabsPrimitive.Trigger,
242
+ {
243
+ ref,
244
+ className: cn(tabsTriggerVariants({ size }), className),
245
+ ...props,
246
+ children: [
247
+ StartIcon && /* @__PURE__ */ jsx(StartIcon, { size: iconSize, "aria-hidden": true }),
248
+ children != null && /* @__PURE__ */ jsx("span", { children }),
249
+ hasSuffix && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
250
+ badge,
251
+ EndIcon && /* @__PURE__ */ jsx(EndIcon, { size: iconSize, "aria-hidden": true }),
252
+ inlineAction != null && // 2026-05-21 split-click invariant:inlineAction 點擊不冒泡到 TabsPrimitive.Trigger。
253
+ // Radix Tabs 在 3 個 channel 觸發 tab 切換,全部 stopPropagation:
254
+ // - onMouseDown(primary, Radix Tabs source code main switch trigger)
255
+ // - onFocus(activationMode='automatic' default,focus 落內部按鈕也算「focused」)
256
+ // - onKeyDown Enter/Space(鍵盤啟動)
257
+ // 加 onPointerDown / onClick 防禦其他 framework 慣例。
258
+ // 對齊 GitHub「Code ▾」/ Linear "Triage..." split-tab 共識。
259
+ /* @__PURE__ */ jsx(
260
+ "span",
261
+ {
262
+ onPointerDown: (e) => e.stopPropagation(),
263
+ onMouseDown: (e) => e.stopPropagation(),
264
+ onClick: (e) => e.stopPropagation(),
265
+ onFocus: (e) => e.stopPropagation(),
266
+ onKeyDown: (e) => {
267
+ if (e.key === "Enter" || e.key === " ") e.stopPropagation();
268
+ },
269
+ children: inlineAction
270
+ }
271
+ )
272
+ ] })
273
+ ]
274
+ }
275
+ );
276
+ });
277
+ TabsTrigger.displayName = "TabsTrigger";
278
+ const TabsContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
279
+ TabsPrimitive.Content,
280
+ {
281
+ ref,
282
+ className: cn(
283
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1",
284
+ className
285
+ ),
286
+ ...props
287
+ }
288
+ ));
289
+ TabsContent.displayName = "TabsContent";
290
+ const tabsMeta = {
291
+ component: "Tabs",
292
+ family: null,
293
+ // non-family composite / overlay / layout
294
+ variants: {},
295
+ sizes: {
296
+ sm: { fieldHeight: 28, iconSize: 16, typography: "body" },
297
+ md: { fieldHeight: 32, iconSize: 16, typography: "body" },
298
+ lg: { fieldHeight: 40, iconSize: 20, typography: "body" }
299
+ },
300
+ states: ["default", "hover", "active", "focus-visible", "disabled"],
301
+ tokens: {
302
+ bg: ["bg-primary-hover", "bg-transparent"],
303
+ fg: ["text-fg-disabled", "text-fg-secondary", "text-foreground"],
304
+ ring: ["ring-ring"]
305
+ },
306
+ defaultSize: "sm"
307
+ };
308
+ export {
309
+ Tabs,
310
+ TabsContent,
311
+ TabsList,
312
+ TabsTrigger,
313
+ tabsMeta,
314
+ tabsTriggerVariants
315
+ };
316
+ //# sourceMappingURL=tabs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabs.js","sources":["../../../src/components/Tabs/tabs.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — foundational composite(Tabs + overflow scroll mode + dropdown switcher + inline action slot)在單一 wrapper SSOT 內,拆分會破壞 a11y / focus management chain。當前 515 < cap 800。\nimport * as React from 'react'\nimport * as TabsPrimitive from '@radix-ui/react-tabs'\nimport { cva } from 'class-variance-authority'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n} from '@/design-system/components/DropdownMenu/dropdown-menu'\nimport {\n useScrollEdges,\n useScrollByPage,\n buildFadeMask,\n ARROW_BUTTON_WIDTH,\n OverflowScrollArrow,\n OverflowMenuTriggerButton,\n} from '@/design-system/patterns/horizontal-overflow/horizontal-overflow'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n/**\n * Tabs — 基於 Radix Tabs,橋接設計系統 token\n *\n * ── 定位 ──\n * 同一上下文底下切換平行的 view。切 view(不是切 value)。\n * 切 value 用 SegmentedControl;切路由用 navigation。\n *\n * ── Size ──\n * sm h-tab-sm(32/40),★ 預設(2026-05-17 從 md 改),overlay / chrome / dense\n * md h-tab-md(40/48),future tier 無 recommended use case\n * lg h-tab-lg(48/56),page-level hero / 獨立 tabs 取代 chrome header\n *\n * ── 寬度行為 ──\n * Trigger 寬度永遠由內容決定(hug content)。\n * Triggers 之間 gap 為 --layout-space-loose(16px / 24px lg density)。\n *\n * ── Trigger 結構 ──\n * [startIcon?] [label] [suffix: badge? + endIcon?]\n * slot 間 gap-2,suffix 內 gap-1\n *\n * ── Selected underline ──\n * 使用 ::after 絕對定位在 bottom: -1px,2px primary-hover,\n * 蓋住 TabsList 的 1px gray border(單一視覺線條,不雙線)。\n */\n\n// ── Size context ──\ntype TabsSize = 'sm' | 'md' | 'lg'\ntype TabsOverflow = 'none' | 'scroll' | 'menu'\n\ninterface TabsContextValue {\n size: TabsSize\n}\nconst TabsContext = React.createContext<TabsContextValue>({ size: 'md' })\n\n// ── Root ──\n// Wrap Radix Tabs 以支援 value/onValueChange 的 context pass-through\n// (menu 模式的 overflow items 需要能 proxy click 觸發同一個 onValueChange)\ninterface TabsProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Root> {}\n\nconst TabsValueContext = React.createContext<{\n value?: string\n onValueChange?: (value: string) => void\n}>({})\n\nconst Tabs = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Root>,\n TabsProps\n>(({ value, onValueChange, defaultValue, children, ...props }, ref) => {\n // 內部維護一份 uncontrolled state,讓 overflow menu 的 proxy 有 onValueChange 可呼叫\n const [internalValue, setInternalValue] = React.useState<string | undefined>(defaultValue)\n const isControlled = value !== undefined\n const currentValue = isControlled ? value : internalValue\n\n const handleValueChange = React.useCallback(\n (next: string) => {\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange]\n )\n\n const valueContext = React.useMemo(\n () => ({ value: currentValue, onValueChange: handleValueChange }),\n [currentValue, handleValueChange]\n )\n\n return (\n <TabsValueContext.Provider value={valueContext}>\n <TabsPrimitive.Root\n ref={ref}\n value={currentValue}\n onValueChange={handleValueChange}\n {...props}\n >\n {children}\n </TabsPrimitive.Root>\n </TabsValueContext.Provider>\n )\n})\nTabs.displayName = 'Tabs'\n\n// ── List ──\n// TabsList 基礎 class — inline-flex 單列 + gap-loose + 底部 border-divider\n// 2026-05-18 改 border-border → border-divider(per user verbatim「我認為應該把 tabs 的\n// 下底線統一改成是 divider 色吧?」+「做」approval):\n// - 跟 Dialog / Sheet / Popover / Sidebar header `border-b border-divider`(neutral-4)同色\n// - withTabs scenario 下 tabs underline = chrome separator,跟 dialog 其他 separator 視覺一致\n// - Selected trigger 2px primary 仍 overlay underlying divider(對比 primary >> divider 不弱)\n// - 對齊 `color.spec.md:706-708` outer-vs-divider 判準(Dialog 結構,T-junction 思路適用)\nconst TABS_LIST_BASE = [\n 'inline-flex items-stretch',\n 'gap-[var(--layout-space-loose)]',\n 'border-b border-divider',\n].join(' ')\n\ninterface TabsListProps\n extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> {\n size?: TabsSize\n /**\n * Overflow 處理模式。詳見 tabs.spec.md 的 overflow 段。\n * 'none' ★ 預設,不處理,triggers 溢出父容器(適用 tabs 數量可控的情境)\n * 'scroll' 單行橫向滾動 + 邊緣 fade mask(Material / Polaris / iOS 作法)\n * 'menu' 塞不下收進 \"⋯\" dropdown,所有 triggers 仍在 DOM 保留 Radix a11y\n * (Ant Design / Atlassian 作法)\n */\n overflow?: TabsOverflow\n}\n\nconst TabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, size = 'sm', overflow = 'none', children, ...props }, ref) => {\n const tabsSizeContext = React.useMemo(() => ({ size }), [size])\n if (overflow === 'scroll') {\n return (\n <TabsContext.Provider value={tabsSizeContext}>\n <ScrollTabsList ref={ref} className={className} {...props}>\n {children}\n </ScrollTabsList>\n </TabsContext.Provider>\n )\n }\n if (overflow === 'menu') {\n return (\n <TabsContext.Provider value={tabsSizeContext}>\n <MenuTabsList ref={ref} className={className} {...props}>\n {children}\n </MenuTabsList>\n </TabsContext.Provider>\n )\n }\n // none(預設)\n return (\n <TabsContext.Provider value={tabsSizeContext}>\n <TabsPrimitive.List\n ref={ref}\n className={cn(TABS_LIST_BASE, 'w-fit', className)}\n {...props}\n >\n {children}\n </TabsPrimitive.List>\n </TabsContext.Provider>\n )\n})\nTabsList.displayName = 'TabsList'\n\n// ── Scroll mode ──\n//\n// 共同策略(對齊 Material 3 / Ant Design / Primer UnderlineNav 世界級作法):\n// - 容器 overflow-x-auto + overflow-y-hidden(真的可滾,鍵盤焦點可 scroll-into-view;\n// 明示 y-hidden 阻 CSS overflow-3 spec「一軸 auto 時另軸 visible compute auto」)\n// - border-b 在 TabsList 內部(TABS_LIST_BASE),不在 outer wrapper,避免\n// active underline `after:bottom:-1px` 跟 outer + overflow-x-auto 觸發 y promote bug\n// - mask / arrow / fade 全部從 horizontal-overflow pattern module 取得——\n// 參見 `patterns/horizontal-overflow/horizontal-overflow.spec.md`\n// - Menu 模式 = scroll 模式 + 額外的 ⌄ quick-jump button,點 menu item 同時\n// 觸發 onValueChange + scrollIntoView,讓使用者在 tab strip 看到選中的 tab\n// 單行水平滾動 + 邊緣 fade mask 延伸到 arrow button 底下 + 左右 always-visible arrows\n// - 鍵盤: Radix 原生方向鍵 + 瀏覽器 scroll-into-view\n// - Trackpad: 兩指橫向滑動\n// - 滑鼠滾輪: 點 arrow buttons (Shift+wheel 太隱晦)\n\nconst ScrollTabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, children, ...props }, ref) => {\n const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n const scrollByPage = useScrollByPage(scrollRef)\n const maskImage = buildFadeMask({\n canScroll,\n atStart,\n atEnd,\n reserveArrowWidth: ARROW_BUTTON_WIDTH,\n })\n\n return (\n // 2026-05-19 fix(scroll-overflow underline clip + y auto-promote):\n // outer 撤 `border-b` → owner 升到 `TabsList` (TABS_LIST_BASE 含 border-b border-divider)\n // 把 trigger `after:bottom-[-1px]` 2px underline 的下半部 1px 收進 list border-box,\n // 再加 `overflow-y-hidden` 明示阻 browser y auto-promote(CSS overflow-3 spec:\n // overflow-x:auto + overflow-y:visible 必 compute auto)。\n // 不加 `pb-px`(outer border 撤後 list border 已接 -1px 部分,加 pb 多 1px 多餘空白)。\n // 對齊 Primer UnderlineNav `overflow-x:auto; overflow-y:hidden` canonical 同步動\n // horizontal-overflow.spec.md L75/L101/L129 owner 升 list 內部。\n <div className=\"relative\">\n <div\n ref={scrollRef}\n className=\"overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n style={{ maskImage, WebkitMaskImage: maskImage }}\n >\n <TabsPrimitive.List\n ref={ref}\n className={cn(TABS_LIST_BASE, 'w-fit', className)}\n {...props}\n >\n {children}\n </TabsPrimitive.List>\n </div>\n {!atStart && canScroll && (\n <OverflowScrollArrow direction=\"left\" onClick={() => scrollByPage('left')} />\n )}\n {!atEnd && canScroll && (\n <OverflowScrollArrow direction=\"right\" onClick={() => scrollByPage('right')} />\n )}\n </div>\n )\n})\nScrollTabsList.displayName = 'ScrollTabsList'\n\n// ── Menu mode ──\n// Show-all navigator pattern (Chrome tab dropdown / VS Code editor tabs / Discord channel jumper):\n// - Menu 永遠顯示全部 tabs,active 的用 checked 標記 (單選語意)\n// - 點 menu item = onValueChange + scrollIntoView(center),把該 tab 捲到視圖中央\n// - Menu 內容穩定,跟 scroll 位置無關,使用者對「⋯ = navigator」的直覺一致\n//\n// 為什麼底層仍是 overflow-x-auto 而非 overflow-hidden:\n// - scrollIntoView 需要真實 scroll 容器\n// - 鍵盤 focus 也依賴真實 scroll 讓 browser auto scroll-into-view\n// - scrollbar 用 CSS 隱藏,視覺看不出來\n//\n// Fade mask 純視覺,軟化內容硬邊,跟 menu 機制正交 (兩者可並存)。\n// Menu button 出現條件: canScroll (有溢出空間才需要 navigator)。\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst MenuTabsList = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.List>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, children, ...props }, ref) => {\n const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n const { onValueChange, value: activeValue } = React.useContext(TabsValueContext)\n\n // Local ref map — 追蹤每個 trigger 的 DOM 元素,供 scrollIntoView 使用。\n // 不用 useOverflowIndices 因為 menu 永遠顯示全部,不需要動態 overflow 計算。\n // code-quality-allow: long-function — helper fn 結構緊密,拆 sub-fn 會跨 fn 傳 state 反而複雜\n const itemRefs = React.useRef<Map<number, HTMLElement>>(new Map())\n // 2026-05-16 audit codex Round 6:capture rAF + cancel on unmount(defensive hygiene)\n const scrollRafIdRef = React.useRef<number>(0)\n React.useEffect(() => () => { if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current) }, [])\n const registerItem = React.useCallback(\n (index: number) => (el: HTMLElement | null) => {\n if (el) itemRefs.current.set(index, el)\n else itemRefs.current.delete(index)\n },\n []\n )\n\n const items = React.useMemo(\n () => React.Children.toArray(children).filter(React.isValidElement) as React.ReactElement[],\n [children]\n )\n\n const enhancedChildren = items.map((child, i) =>\n React.cloneElement(\n child as React.ReactElement<{ ref?: React.Ref<HTMLElement> }>,\n { ref: registerItem(i) }\n )\n )\n\n // Menu 模式沒有 arrows,但仍套 fade mask (reserveArrowWidth: 0) 軟化內容硬邊\n // code-quality-allow: long-function — helper fn 結構緊密,拆 sub-fn 會跨 fn 傳 state 反而複雜\n const maskImage = buildFadeMask({ canScroll, atStart, atEnd, reserveArrowWidth: 0 })\n\n const handleMenuSelect = React.useCallback(\n (triggerValue: string, index: number) => {\n onValueChange?.(triggerValue)\n // 下一個 tick 再 scroll, 讓 Radix 先完成 data-state 更新\n if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current)\n scrollRafIdRef.current = requestAnimationFrame(() => {\n scrollRafIdRef.current = 0\n itemRefs.current.get(index)?.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' })\n })\n },\n [onValueChange]\n )\n\n return (\n // 2026-05-19 fix(scroll-overflow underline clip + y auto-promote,parallel to ScrollTabsList):\n // outer 改 items-stretch(menu button 容器跟 TabsList 含 border 共底線)+ 撤 border。\n // list 套 TABS_LIST_BASE,inner scroll 加 overflow-y-hidden。menu button 容器自帶\n // border-b border-divider 跟 TabsList border 同 y 對齊(items-stretch 保證)。\n <div className=\"flex items-stretch\">\n <div\n ref={scrollRef}\n className=\"flex-1 min-w-0 overflow-x-auto overflow-y-hidden [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n style={{ maskImage, WebkitMaskImage: maskImage }}\n >\n <TabsPrimitive.List\n ref={ref}\n className={cn(TABS_LIST_BASE, 'w-fit', className)}\n {...props}\n >\n {enhancedChildren}\n </TabsPrimitive.List>\n </div>\n {canScroll && (\n <div className=\"flex-shrink-0 pl-[var(--layout-space-loose)] flex items-center border-b border-divider\">\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <OverflowMenuTriggerButton\n aria-label={`頁籤選單(共 ${items.length} 個)`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {items.map((trigger, index) => {\n const triggerProps = trigger.props as {\n value?: string\n children?: React.ReactNode\n disabled?: boolean\n }\n const triggerValue = triggerProps.value\n if (typeof triggerValue !== 'string') return null\n // 單選 active 用 DropdownMenuItem 的 selected prop\n // → 對應 bg-neutral-selected 持續選中背景, 跟 SelectMenu 單選完全\n // 同一套 canonical 視覺, 全 DS 一致。不可用 className 發明樣式。\n return (\n <DropdownMenuItem\n key={triggerValue}\n disabled={triggerProps.disabled}\n selected={activeValue === triggerValue}\n onSelect={() => handleMenuSelect(triggerValue, index)}\n >\n {triggerProps.children}\n </DropdownMenuItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )}\n </div>\n )\n})\nMenuTabsList.displayName = 'MenuTabsList'\n\n// ── Trigger ──\nconst tabsTriggerVariants = cva(\n [\n 'relative inline-flex items-center justify-center',\n 'gap-2',\n 'whitespace-nowrap',\n 'font-medium text-fg-secondary',\n 'transition-colors duration-150',\n 'cursor-pointer select-none',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n // Trigger 無水平 padding — 寬度 = 內容寬度。triggers 間的分隔靠 TabsList 的 gap-[layout-space-loose]\n // selected underline:::after 絕對定位在 bottom:-1px,2px primary-hover\n // left-0/right-0 因為 trigger 已無 padding,底線等於內容寬度\n // 底線蓋住 TabsList 的 1px gray border,視覺單一線條\n 'after:absolute after:left-0 after:right-0 after:bottom-[-1px] after:h-0.5',\n 'after:bg-transparent after:transition-colors after:duration-150',\n // hover(未選):文字轉深\n 'hover:text-foreground',\n // selected\n 'data-[state=active]:text-foreground data-[state=active]:font-medium',\n 'data-[state=active]:after:bg-primary-hover',\n // disabled:cursor-not-allowed + 不吃 hover 色\n // 不用 pointer-events-none,否則 cursor 不會改變;button[disabled] 本身就擋 click\n 'disabled:cursor-not-allowed disabled:text-fg-disabled',\n 'disabled:hover:text-fg-disabled',\n ],\n {\n variants: {\n size: {\n // leading-compact:trigger 是單行文字容器,使用 1.3 行高避免 text-body/body-lg 預設 1.5 造成垂直偏移\n sm: 'h-[var(--tab-height-sm)] text-body leading-compact',\n md: 'h-[var(--tab-height-md)] text-body leading-compact',\n lg: 'h-[var(--tab-height-lg)] text-body-lg leading-compact',\n },\n },\n defaultVariants: {\n // size = 'sm' per header-canonical.spec.md W6:overlay / chrome / dense toolbar\n // 都用 sm;獨立 page hero 用 lg。md 為 future tier(無 recommended use case)。\n // 2026-05-17 從 'md' 改 'sm'(M31 codex 比稿後)— production consumer = 0,\n // 影響面限 stories baseline(已過 visual diff gate)。\n size: 'sm',\n },\n }\n)\n\ninterface TabsTriggerProps\n extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> {\n /** 左側 icon(LucideIcon) */\n startIcon?: LucideIcon\n /** 右側 badge(通常是計數指示器) */\n badge?: React.ReactNode\n /**\n * 右側純視覺 indicator(LucideIcon)。**僅限方向 / 狀態 indicator**:ChevronDown / Pin / Star。\n * **不要拼 click 行為** — endIcon 是 tab body 的一部分,點到也是切 tab。\n * 需要「點該後綴開 dropdown / menu」場景請用 `inlineAction` slot(2026-05-21 拆分)。\n */\n endIcon?: LucideIcon\n /**\n * Inline action slot(2026-05-21 v3 加,per user「圖一 後綴應該是 inline action」+「點擊\n * 該 tab 的 inline action 跟其他地方應該不同反應」directive):\n * 提供 `<ItemInlineAction>` / `<DropdownMenuTrigger asChild><ItemInlineAction ... /></DropdownMenuTrigger>`\n * 等獨立 click target。**TabsTrigger 自動 stopPropagation**,inline action 點擊不冒泡到 tab body,\n * 達成 split-click 行為(對齊 GitHub「Code ▾」/ Linear \"Triage...\" menu / Atlassian split-tab 共識)。\n *\n * 跟 endIcon 區別:endIcon = 純視覺 indicator(無獨立行為,連同 tab 一起 click),\n * inlineAction = 獨立 click target(自己的 handler,不切 tab)。語意分家明確。\n */\n inlineAction?: React.ReactNode\n}\n\nconst TabsTrigger = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, startIcon: StartIcon, badge, endIcon: EndIcon, inlineAction, children, ...props }, ref) => {\n const { size } = React.useContext(TabsContext)\n // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)\n const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']\n const hasSuffix = badge != null || EndIcon !== undefined || inlineAction != null\n\n return (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(tabsTriggerVariants({ size }), className)}\n {...props}\n >\n {StartIcon && <StartIcon size={iconSize} aria-hidden />}\n {children != null && <span>{children}</span>}\n {hasSuffix && (\n <span className=\"inline-flex items-center gap-1\">\n {badge}\n {EndIcon && <EndIcon size={iconSize} aria-hidden />}\n {inlineAction != null && (\n // 2026-05-21 split-click invariant:inlineAction 點擊不冒泡到 TabsPrimitive.Trigger。\n // Radix Tabs 在 3 個 channel 觸發 tab 切換,全部 stopPropagation:\n // - onMouseDown(primary, Radix Tabs source code main switch trigger)\n // - onFocus(activationMode='automatic' default,focus 落內部按鈕也算「focused」)\n // - onKeyDown Enter/Space(鍵盤啟動)\n // 加 onPointerDown / onClick 防禦其他 framework 慣例。\n // 對齊 GitHub「Code ▾」/ Linear \"Triage...\" split-tab 共識。\n <span\n onPointerDown={(e) => e.stopPropagation()}\n onMouseDown={(e) => e.stopPropagation()}\n onClick={(e) => e.stopPropagation()}\n onFocus={(e) => e.stopPropagation()}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') e.stopPropagation()\n }}\n >\n {inlineAction}\n </span>\n )}\n </span>\n )}\n </TabsPrimitive.Trigger>\n )\n})\nTabsTrigger.displayName = 'TabsTrigger'\n\n// ── Content ──\nconst TabsContent = React.forwardRef<\n React.ElementRef<typeof TabsPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n className={cn(\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n className\n )}\n {...props}\n />\n))\nTabsContent.displayName = 'TabsContent'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const tabsMeta = {\n component: 'Tabs',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n sm: { fieldHeight: 28, iconSize: 16, typography: 'body' },\n md: { fieldHeight: 32, iconSize: 16, typography: 'body' },\n lg: { fieldHeight: 40, iconSize: 20, typography: 'body' },\n },\n states: ['default', 'hover', 'active', 'focus-visible', 'disabled'],\n tokens: {\n bg: ['bg-primary-hover', 'bg-transparent'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground'],\n ring: ['ring-ring'],\n },\n defaultSize: 'sm',\n} as const\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, tabsTriggerVariants }\nexport type { TabsSize, TabsListProps, TabsTriggerProps }\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ import type { LucideIcon } from "lucide-react";
4
+ declare const tagVariants: (props?: ({
5
+ color?: "blue" | "green" | "indigo" | "magenta" | "purple" | "red" | "turquoise" | "yellow" | "neutral" | null | undefined;
6
+ size?: "sm" | "md" | "lg" | null | undefined;
7
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
+ export interface TagProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'prefix' | 'color'>, VariantProps<typeof tagVariants> {
9
+ /** 左側 icon(LucideIcon),由 Tag 統一 16px。與 avatar 互斥。 */
10
+ icon?: LucideIcon;
11
+ /** 左側 avatar(ReactNode),與 icon 互斥。 */
12
+ avatar?: React.ReactNode;
13
+ /** 可移除——Tag 自動渲染 dismiss 按鈕並控制尺寸與互動樣式 */
14
+ onDismiss?: () => void;
15
+ /** 深底白字模式(step-6 背景 + 白色前景,warning 例外) */
16
+ solid?: boolean;
17
+ /**
18
+ * 2026-05-15 Q3 真 SSOT fix(per user verbatim「同空間兩判斷點」+「不要冰山一角」):
19
+ * Tag 寬度由 parent constrain,不套預設 max-w-40(160px)。用於 cell-as-input narrow cell
20
+ * (< 160px)時 Tag fit cell 寬度 + truncate ellipsis,而非 160px 後被 cell `overflow-hidden`
21
+ * 硬切。對齊「同 cell width → 同 overflow 判斷」SSOT。Default false 保 backward compat
22
+ * (wrap layout / pill rail 等仍受 160px 保護)。
23
+ */
24
+ unbounded?: boolean;
25
+ }
26
+ declare const Tag: React.ForwardRefExoticComponent<TagProps & React.RefAttributes<HTMLDivElement>>;
27
+ export declare const tagMeta: {
28
+ readonly component: "Tag";
29
+ readonly family: 3;
30
+ readonly variants: {
31
+ readonly neutral: {
32
+ readonly purpose: "通用分類、草稿、無特定語義";
33
+ };
34
+ readonly blue: {
35
+ readonly purpose: "進行中、資訊提示、active 狀態(對應 --info)";
36
+ };
37
+ readonly red: {
38
+ readonly purpose: "錯誤、已封鎖、危險(對應 --error)";
39
+ };
40
+ readonly green: {
41
+ readonly purpose: "成功、已完成、已核准(對應 --success)";
42
+ };
43
+ readonly yellow: {
44
+ readonly purpose: "警告、待審核、注意(對應 --warning)";
45
+ };
46
+ readonly turquoise: {
47
+ readonly purpose: "分類色(無固定語義)";
48
+ };
49
+ readonly purple: {
50
+ readonly purpose: "分類色(無固定語義)";
51
+ };
52
+ readonly magenta: {
53
+ readonly purpose: "分類色(無固定語義)";
54
+ };
55
+ readonly indigo: {
56
+ readonly purpose: "分類色(無固定語義)";
57
+ };
58
+ };
59
+ readonly sizes: {
60
+ readonly sm: {
61
+ readonly fieldHeight: 28;
62
+ readonly iconSize: 16;
63
+ readonly typography: "body";
64
+ };
65
+ readonly md: {
66
+ readonly fieldHeight: 32;
67
+ readonly iconSize: 16;
68
+ readonly typography: "body";
69
+ };
70
+ readonly lg: {
71
+ readonly fieldHeight: 40;
72
+ readonly iconSize: 20;
73
+ readonly typography: "body";
74
+ };
75
+ };
76
+ readonly states: readonly ["default", "hover", "active", "focus-visible", "disabled"];
77
+ readonly tokens: {
78
+ readonly bg: readonly ["bg-neutral-active", "bg-neutral-hover", "bg-secondary", "bg-transparent"];
79
+ readonly fg: readonly ["text-foreground", "text-inverse-fg"];
80
+ readonly ring: readonly [];
81
+ };
82
+ readonly defaultVariant: "neutral";
83
+ readonly defaultSize: "md";
84
+ };
85
+ export { Tag, tagVariants };
86
+ //# sourceMappingURL=tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../../../src/components/Tag/tag.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAuB9C,QAAA,MAAM,WAAW;;;8EA4BhB,CAAA;AAiBD,MAAM,WAAW,QACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,EACpE,YAAY,CAAC,OAAO,WAAW,CAAC;IAClC,qDAAqD;IACrD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,sCAAsC;IACtC,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAyHD,QAAA,MAAM,GAAG,iFAAuD,CAAA;AAKhE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BV,CAAA;AAEV,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,CAAA"}
@@ -0,0 +1,172 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cva } from "class-variance-authority";
4
+ import { X } from "lucide-react";
5
+ import { cn } from "../../lib/utils.js";
6
+ import { Tooltip, TooltipTrigger, TooltipContent } from "../Tooltip/tooltip.js";
7
+ import { ItemInlineActionButton } from "../../patterns/element-anatomy/item-anatomy.js";
8
+ let _measureCtx = null;
9
+ function getMeasureCtx() {
10
+ if (!_measureCtx) _measureCtx = document.createElement("canvas").getContext("2d");
11
+ return _measureCtx;
12
+ }
13
+ const tagVariants = cva(
14
+ "inline-flex items-center rounded-md border border-transparent transition-colors cursor-text",
15
+ {
16
+ variants: {
17
+ color: {
18
+ // 直接引用 primitive(bg=step-1, text=step-7),不經過語義層
19
+ // step-1 在 dark mode 用 alpha 公式,step-7 用 lighter 公式——兩個 mode 都正確
20
+ neutral: "bg-secondary text-foreground",
21
+ blue: "bg-[var(--color-blue-1)] text-[var(--color-blue-7)]",
22
+ red: "bg-[var(--color-deep-orange-1)] text-[var(--color-deep-orange-7)]",
23
+ green: "bg-[var(--color-green-1)] text-[var(--color-green-7)]",
24
+ yellow: "bg-[var(--color-yellow-1)] text-[var(--color-yellow-7)]",
25
+ turquoise: "bg-[var(--color-turquoise-1)] text-[var(--color-turquoise-7)]",
26
+ purple: "bg-[var(--color-purple-1)] text-[var(--color-purple-7)]",
27
+ magenta: "bg-[var(--color-magenta-1)] text-[var(--color-magenta-7)]",
28
+ indigo: "bg-[var(--color-indigo-1)] text-[var(--color-indigo-7)]"
29
+ },
30
+ size: {
31
+ sm: "h-5 px-1 text-caption font-medium",
32
+ md: "h-6 px-1 text-body font-normal",
33
+ lg: "h-6 px-1 text-body font-normal"
34
+ }
35
+ },
36
+ defaultVariants: {
37
+ color: "neutral",
38
+ size: "md"
39
+ }
40
+ }
41
+ );
42
+ const SOLID_CLASSES = {
43
+ neutral: "bg-[var(--color-neutral-9)] text-inverse-fg",
44
+ blue: "bg-[var(--color-blue-6)] text-on-emphasis",
45
+ red: "bg-[var(--color-deep-orange-6)] text-on-emphasis",
46
+ green: "bg-[var(--color-green-6)] text-on-emphasis",
47
+ yellow: "bg-[var(--color-yellow-6)] text-[var(--warning-foreground)]",
48
+ turquoise: "bg-[var(--color-turquoise-6)] text-on-emphasis",
49
+ purple: "bg-[var(--color-purple-6)] text-on-emphasis",
50
+ magenta: "bg-[var(--color-magenta-6)] text-on-emphasis",
51
+ indigo: "bg-[var(--color-indigo-6)] text-on-emphasis"
52
+ };
53
+ const SOLID_DISMISS_HOVER = {
54
+ neutral: { hover: "var(--inverse-neutral-hover)", active: "var(--inverse-neutral-active)" },
55
+ blue: { hover: "var(--blue-hover)", active: "var(--blue-active)" },
56
+ red: { hover: "var(--red-hover)", active: "var(--red-active)" },
57
+ green: { hover: "var(--green-hover)", active: "var(--green-active)" },
58
+ yellow: { hover: "var(--yellow-hover)", active: "var(--yellow-active)" },
59
+ turquoise: { hover: "var(--turquoise-hover)", active: "var(--turquoise-active)" },
60
+ purple: { hover: "var(--purple-hover)", active: "var(--purple-active)" },
61
+ magenta: { hover: "var(--magenta-hover)", active: "var(--magenta-active)" },
62
+ indigo: { hover: "var(--indigo-hover)", active: "var(--indigo-active)" }
63
+ };
64
+ function TagDismiss({ onDismiss, label, solid, color }) {
65
+ const solidColors = solid && color ? SOLID_DISMISS_HOVER[color] : void 0;
66
+ return /* @__PURE__ */ jsx(
67
+ ItemInlineActionButton,
68
+ {
69
+ icon: X,
70
+ size: "md",
71
+ onClick: (e) => {
72
+ e.stopPropagation();
73
+ onDismiss();
74
+ },
75
+ "aria-label": `移除 ${label}`,
76
+ style: solidColors ? { "--dismiss-hover": solidColors.hover, "--dismiss-active": solidColors.active } : void 0,
77
+ hoverBgClassName: solidColors ? "group-hover/action:bg-[var(--dismiss-hover)] group-active/action:bg-[var(--dismiss-active)]" : void 0,
78
+ className: "text-current hover:text-current active:text-current"
79
+ }
80
+ );
81
+ }
82
+ function TagInner({ className, color, size, icon: Icon, avatar, onDismiss, solid, unbounded = false, children, style, ...props }, forwardedRef) {
83
+ const solidClass = solid ? SOLID_CLASSES[color ?? "neutral"] : void 0;
84
+ const ownRef = React.useRef(null);
85
+ const [isTruncated, setIsTruncated] = React.useState(false);
86
+ React.useLayoutEffect(() => {
87
+ const el = ownRef.current;
88
+ if (!el) return;
89
+ const ctx = getMeasureCtx();
90
+ const check = () => {
91
+ const textSpan = el.querySelector("[data-tag-text]");
92
+ if (!textSpan || !ctx) return;
93
+ const text = textSpan.textContent || "";
94
+ const cs = getComputedStyle(textSpan);
95
+ ctx.font = `${cs.fontWeight} ${cs.fontSize} ${cs.fontFamily}`;
96
+ const textWidth = ctx.measureText(text).width;
97
+ const padL = parseFloat(cs.paddingLeft) || 0;
98
+ const padR = parseFloat(cs.paddingRight) || 0;
99
+ const needed = textWidth + padL + padR;
100
+ setIsTruncated(needed > textSpan.clientWidth + 1);
101
+ };
102
+ check();
103
+ const obs = new ResizeObserver(check);
104
+ obs.observe(el);
105
+ return () => obs.disconnect();
106
+ }, [children]);
107
+ const label = typeof children === "string" ? children : "";
108
+ const tag = /* @__PURE__ */ jsxs(
109
+ "div",
110
+ {
111
+ ref: (el) => {
112
+ ownRef.current = el;
113
+ if (typeof forwardedRef === "function") forwardedRef(el);
114
+ else if (forwardedRef) forwardedRef.current = el;
115
+ },
116
+ "data-tag-root": "",
117
+ className: cn(tagVariants({ color, size }), solidClass, "w-fit min-w-0 overflow-hidden", className),
118
+ style: {
119
+ maxWidth: unbounded ? "var(--combobox-tag-area-inline-size, 100%)" : "min(var(--combobox-tag-area-inline-size, 10rem), 10rem)",
120
+ ...style
121
+ },
122
+ ...props,
123
+ children: [
124
+ Icon && /* @__PURE__ */ jsx(Icon, { size: 16, "aria-hidden": true }),
125
+ avatar && /* @__PURE__ */ jsx("span", { className: "shrink-0 w-4 h-4 rounded-full overflow-hidden inline-grid place-content-center [&>*]:w-full [&>*]:h-full", children: avatar }),
126
+ /* @__PURE__ */ jsx("span", { "data-tag-text": "", className: "px-1 truncate min-w-0", children }),
127
+ onDismiss && /* @__PURE__ */ jsx(TagDismiss, { onDismiss, label, solid, color: color ?? "neutral" })
128
+ ]
129
+ }
130
+ );
131
+ if (!isTruncated) return tag;
132
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
133
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: tag }),
134
+ /* @__PURE__ */ jsx(TooltipContent, { children })
135
+ ] });
136
+ }
137
+ const Tag = React.forwardRef(TagInner);
138
+ Tag.displayName = "Tag";
139
+ const tagMeta = {
140
+ component: "Tag",
141
+ family: 3,
142
+ variants: {
143
+ neutral: { purpose: "通用分類、草稿、無特定語義" },
144
+ blue: { purpose: "進行中、資訊提示、active 狀態(對應 --info)" },
145
+ red: { purpose: "錯誤、已封鎖、危險(對應 --error)" },
146
+ green: { purpose: "成功、已完成、已核准(對應 --success)" },
147
+ yellow: { purpose: "警告、待審核、注意(對應 --warning)" },
148
+ turquoise: { purpose: "分類色(無固定語義)" },
149
+ purple: { purpose: "分類色(無固定語義)" },
150
+ magenta: { purpose: "分類色(無固定語義)" },
151
+ indigo: { purpose: "分類色(無固定語義)" }
152
+ },
153
+ sizes: {
154
+ sm: { fieldHeight: 28, iconSize: 16, typography: "body" },
155
+ md: { fieldHeight: 32, iconSize: 16, typography: "body" },
156
+ lg: { fieldHeight: 40, iconSize: 20, typography: "body" }
157
+ },
158
+ states: ["default", "hover", "active", "focus-visible", "disabled"],
159
+ tokens: {
160
+ bg: ["bg-neutral-active", "bg-neutral-hover", "bg-secondary", "bg-transparent"],
161
+ fg: ["text-foreground", "text-inverse-fg"],
162
+ ring: []
163
+ },
164
+ defaultVariant: "neutral",
165
+ defaultSize: "md"
166
+ };
167
+ export {
168
+ Tag,
169
+ tagMeta,
170
+ tagVariants
171
+ };
172
+ //# sourceMappingURL=tag.js.map