@qijenchen/design-system 0.1.0-beta.145 → 0.1.0-beta.147

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 (576) hide show
  1. package/dist/components/Accordion/accordion.d.ts +1 -1
  2. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  3. package/dist/components/Accordion/accordion.js +8 -3
  4. package/dist/components/Accordion/accordion.js.map +1 -1
  5. package/dist/components/AccountMenu/account-menu.d.ts.map +1 -1
  6. package/dist/components/AccountMenu/account-menu.js.map +1 -1
  7. package/dist/components/AgentPanel/agent-panel-fab.d.ts +7 -1
  8. package/dist/components/AgentPanel/agent-panel-fab.d.ts.map +1 -1
  9. package/dist/components/AgentPanel/agent-panel-fab.js +36 -14
  10. package/dist/components/AgentPanel/agent-panel-fab.js.map +1 -1
  11. package/dist/components/AgentPanel/agent-panel-logo.d.ts +3 -3
  12. package/dist/components/AgentPanel/agent-panel-logo.js.map +1 -1
  13. package/dist/components/AgentPanel/agent-panel.d.ts +1 -1
  14. package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -1
  15. package/dist/components/AgentPanel/agent-panel.js +28 -22
  16. package/dist/components/AgentPanel/agent-panel.js.map +1 -1
  17. package/dist/components/AppShell/app-shell.d.ts +1 -1
  18. package/dist/components/AppShell/app-shell.js +1 -1
  19. package/dist/components/AppShell/app-shell.js.map +1 -1
  20. package/dist/components/Avatar/avatar.d.ts +95 -1
  21. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  22. package/dist/components/Avatar/avatar.js +106 -15
  23. package/dist/components/Avatar/avatar.js.map +1 -1
  24. package/dist/components/Avatar/index.js +14 -2
  25. package/dist/components/Breadcrumb/breadcrumb.d.ts +4 -2
  26. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  27. package/dist/components/Breadcrumb/breadcrumb.js +2 -2
  28. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  29. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  30. package/dist/components/BulkActionBar/bulk-action-bar.js +27 -2
  31. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  32. package/dist/components/Button/button.d.ts +2 -2
  33. package/dist/components/Button/button.d.ts.map +1 -1
  34. package/dist/components/Button/button.js +118 -22
  35. package/dist/components/Button/button.js.map +1 -1
  36. package/dist/components/Calendar/calendar.d.ts +34 -10
  37. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  38. package/dist/components/Calendar/calendar.js +210 -36
  39. package/dist/components/Calendar/calendar.js.map +1 -1
  40. package/dist/components/Carousel/carousel.d.ts +1 -1
  41. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  42. package/dist/components/Carousel/carousel.js +3 -2
  43. package/dist/components/Carousel/carousel.js.map +1 -1
  44. package/dist/components/Chart/chart.d.ts +1 -0
  45. package/dist/components/Chart/chart.d.ts.map +1 -1
  46. package/dist/components/Chart/chart.js +8 -0
  47. package/dist/components/Chart/chart.js.map +1 -1
  48. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  49. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  50. package/dist/components/Checkbox/checkbox.js +10 -2
  51. package/dist/components/Checkbox/checkbox.js.map +1 -1
  52. package/dist/components/Chip/chip.d.ts +1 -1
  53. package/dist/components/Chip/chip.d.ts.map +1 -1
  54. package/dist/components/Chip/chip.js +4 -2
  55. package/dist/components/Chip/chip.js.map +1 -1
  56. package/dist/components/Combobox/combobox.d.ts +1 -1
  57. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  58. package/dist/components/Combobox/combobox.js +37 -11
  59. package/dist/components/Combobox/combobox.js.map +1 -1
  60. package/dist/components/Command/command.d.ts +1 -1
  61. package/dist/components/Command/command.d.ts.map +1 -1
  62. package/dist/components/Command/command.js +106 -8
  63. package/dist/components/Command/command.js.map +1 -1
  64. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  65. package/dist/components/DataTable/cell-registry.js +3 -2
  66. package/dist/components/DataTable/cell-registry.js.map +1 -1
  67. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  68. package/dist/components/DataTable/data-table-column-visibility-panel.js +24 -24
  69. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  70. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -1
  71. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  72. package/dist/components/DataTable/data-table-interaction-layer.js +3 -4
  73. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  74. package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -1
  75. package/dist/components/DataTable/data-table-sort-manager.js +20 -20
  76. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  77. package/dist/components/DataTable/data-table.d.ts +8 -5
  78. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  79. package/dist/components/DataTable/data-table.js +197 -71
  80. package/dist/components/DataTable/data-table.js.map +1 -1
  81. package/dist/components/DateGrid/date-grid.d.ts +1 -1
  82. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  83. package/dist/components/DateGrid/date-grid.js +358 -225
  84. package/dist/components/DateGrid/date-grid.js.map +1 -1
  85. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  86. package/dist/components/DatePicker/date-picker.js +16 -1
  87. package/dist/components/DatePicker/date-picker.js.map +1 -1
  88. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  89. package/dist/components/Dialog/dialog.js +55 -43
  90. package/dist/components/Dialog/dialog.js.map +1 -1
  91. package/dist/components/DropdownMenu/dropdown-menu-keyboard.d.ts +86 -0
  92. package/dist/components/DropdownMenu/dropdown-menu-keyboard.d.ts.map +1 -0
  93. package/dist/components/DropdownMenu/dropdown-menu-keyboard.js +172 -0
  94. package/dist/components/DropdownMenu/dropdown-menu-keyboard.js.map +1 -0
  95. package/dist/components/DropdownMenu/dropdown-menu.d.ts +6 -1
  96. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  97. package/dist/components/DropdownMenu/dropdown-menu.js +50 -39
  98. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  99. package/dist/components/Field/field-context.d.ts +4 -0
  100. package/dist/components/Field/field-context.d.ts.map +1 -1
  101. package/dist/components/Field/field-context.js +1 -2
  102. package/dist/components/Field/field-context.js.map +1 -1
  103. package/dist/components/Field/field-edit-keys.d.ts +8 -0
  104. package/dist/components/Field/field-edit-keys.d.ts.map +1 -1
  105. package/dist/components/Field/field-edit-keys.js +3 -0
  106. package/dist/components/Field/field-edit-keys.js.map +1 -1
  107. package/dist/components/Field/field-wrapper.d.ts +18 -1
  108. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  109. package/dist/components/Field/field-wrapper.js +39 -10
  110. package/dist/components/Field/field-wrapper.js.map +1 -1
  111. package/dist/components/Field/field.d.ts +3 -2
  112. package/dist/components/Field/field.d.ts.map +1 -1
  113. package/dist/components/Field/field.js +2 -1
  114. package/dist/components/Field/field.js.map +1 -1
  115. package/dist/components/FileItem/file-item.d.ts +26 -2
  116. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  117. package/dist/components/FileItem/file-item.js +82 -25
  118. package/dist/components/FileItem/file-item.js.map +1 -1
  119. package/dist/components/FileItem/index.js +4 -2
  120. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  121. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  122. package/dist/components/FileUpload/file-upload.js +132 -55
  123. package/dist/components/FileUpload/file-upload.js.map +1 -1
  124. package/dist/components/FileViewer/file-viewer.d.ts +1 -1
  125. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  126. package/dist/components/FileViewer/file-viewer.js +9 -4
  127. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  128. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  129. package/dist/components/InlineEdit/inline-edit.js +1 -1
  130. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  131. package/dist/components/Input/input.d.ts.map +1 -1
  132. package/dist/components/Input/input.js +6 -1
  133. package/dist/components/Input/input.js.map +1 -1
  134. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  135. package/dist/components/LinkInput/link-input.js +20 -4
  136. package/dist/components/LinkInput/link-input.js.map +1 -1
  137. package/dist/components/Notice/notice.js +1 -1
  138. package/dist/components/Notice/notice.js.map +1 -1
  139. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  140. package/dist/components/NumberInput/number-input.js +6 -1
  141. package/dist/components/NumberInput/number-input.js.map +1 -1
  142. package/dist/components/OverflowIndicator/index.js +2 -1
  143. package/dist/components/OverflowIndicator/overflow-indicator.d.ts +19 -1
  144. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  145. package/dist/components/OverflowIndicator/overflow-indicator.js +47 -27
  146. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  147. package/dist/components/Pagination/pagination.d.ts +1 -1
  148. package/dist/components/Pagination/pagination.js +1 -1
  149. package/dist/components/Pagination/pagination.js.map +1 -1
  150. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +7 -6
  151. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts.map +1 -1
  152. package/dist/components/PeoplePicker/avatar-stack-overflow.js +6 -7
  153. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  154. package/dist/components/PeoplePicker/people-picker-helpers.d.ts.map +1 -1
  155. package/dist/components/PeoplePicker/people-picker-helpers.js +1 -1
  156. package/dist/components/PeoplePicker/people-picker-helpers.js.map +1 -1
  157. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  158. package/dist/components/PeoplePicker/people-picker.js +2 -2
  159. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  160. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  161. package/dist/components/PeoplePicker/person-display.js +26 -28
  162. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  163. package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
  164. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  165. package/dist/components/RadioGroup/radio-group.d.ts +1 -1
  166. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  167. package/dist/components/RadioGroup/radio-group.js +10 -4
  168. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  169. package/dist/components/Rating/rating.d.ts +28 -6
  170. package/dist/components/Rating/rating.d.ts.map +1 -1
  171. package/dist/components/Rating/rating.js +97 -80
  172. package/dist/components/Rating/rating.js.map +1 -1
  173. package/dist/components/ScrollArea/scroll-area.d.ts +1 -1
  174. package/dist/components/ScrollArea/scroll-area.js +1 -1
  175. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  176. package/dist/components/SegmentedControl/segmented-control.d.ts +1 -1
  177. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  178. package/dist/components/SegmentedControl/segmented-control.js +3 -2
  179. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  180. package/dist/components/Select/select.d.ts.map +1 -1
  181. package/dist/components/Select/select.js +15 -8
  182. package/dist/components/Select/select.js.map +1 -1
  183. package/dist/components/SelectMenu/index.js +2 -1
  184. package/dist/components/SelectMenu/index.js.map +1 -1
  185. package/dist/components/SelectMenu/select-menu-keyboard.d.ts +59 -0
  186. package/dist/components/SelectMenu/select-menu-keyboard.d.ts.map +1 -0
  187. package/dist/components/SelectMenu/select-menu-keyboard.js +107 -0
  188. package/dist/components/SelectMenu/select-menu-keyboard.js.map +1 -0
  189. package/dist/components/SelectMenu/select-menu.d.ts +1 -22
  190. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  191. package/dist/components/SelectMenu/select-menu.js +18 -34
  192. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  193. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
  194. package/dist/components/SelectionControl/selection-item.js +1 -0
  195. package/dist/components/SelectionControl/selection-item.js.map +1 -1
  196. package/dist/components/Sidebar/sidebar.d.ts +7 -9
  197. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  198. package/dist/components/Sidebar/sidebar.js +171 -50
  199. package/dist/components/Sidebar/sidebar.js.map +1 -1
  200. package/dist/components/Slider/slider.d.ts +1 -1
  201. package/dist/components/Slider/slider.d.ts.map +1 -1
  202. package/dist/components/Slider/slider.js +9 -4
  203. package/dist/components/Slider/slider.js.map +1 -1
  204. package/dist/components/Steps/steps.d.ts.map +1 -1
  205. package/dist/components/Steps/steps.js +54 -26
  206. package/dist/components/Steps/steps.js.map +1 -1
  207. package/dist/components/Switch/switch.d.ts +1 -1
  208. package/dist/components/Switch/switch.d.ts.map +1 -1
  209. package/dist/components/Switch/switch.js +7 -2
  210. package/dist/components/Switch/switch.js.map +1 -1
  211. package/dist/components/Tabs/tabs.d.ts +1 -1
  212. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  213. package/dist/components/Tabs/tabs.js +39 -4
  214. package/dist/components/Tabs/tabs.js.map +1 -1
  215. package/dist/components/Tag/tag.d.ts +1 -1
  216. package/dist/components/Tag/tag.d.ts.map +1 -1
  217. package/dist/components/Tag/tag.js +3 -2
  218. package/dist/components/Tag/tag.js.map +1 -1
  219. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  220. package/dist/components/Textarea/textarea.js +8 -2
  221. package/dist/components/Textarea/textarea.js.map +1 -1
  222. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  223. package/dist/components/TimePicker/time-columns.js +8 -4
  224. package/dist/components/TimePicker/time-columns.js.map +1 -1
  225. package/dist/components/TimePicker/time-picker.d.ts +1 -1
  226. package/dist/components/TimePicker/time-picker.js +1 -1
  227. package/dist/components/TimePicker/time-picker.js.map +1 -1
  228. package/dist/components/TreeView/tree-view.d.ts +9 -5
  229. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  230. package/dist/components/TreeView/tree-view.js +266 -214
  231. package/dist/components/TreeView/tree-view.js.map +1 -1
  232. package/dist/hooks/use-input-modality.d.ts +12 -17
  233. package/dist/hooks/use-input-modality.d.ts.map +1 -1
  234. package/dist/hooks/use-input-modality.js +4 -34
  235. package/dist/hooks/use-input-modality.js.map +1 -1
  236. package/dist/hooks/use-overflow-items.d.ts.map +1 -1
  237. package/dist/hooks/use-overflow-items.js +2 -0
  238. package/dist/hooks/use-overflow-items.js.map +1 -1
  239. package/dist/hooks/use-truncated.d.ts.map +1 -1
  240. package/dist/hooks/use-truncated.js.map +1 -1
  241. package/dist/index.d.ts +3 -0
  242. package/dist/index.d.ts.map +1 -1
  243. package/dist/index.js +23 -3
  244. package/dist/index.js.map +1 -1
  245. package/dist/lib/drag-announcements.d.ts +32 -0
  246. package/dist/lib/drag-announcements.d.ts.map +1 -1
  247. package/dist/lib/drag-announcements.js +39 -1
  248. package/dist/lib/drag-announcements.js.map +1 -1
  249. package/dist/lib/focus-after-trigger.d.ts +45 -0
  250. package/dist/lib/focus-after-trigger.d.ts.map +1 -0
  251. package/dist/lib/focus-after-trigger.js +66 -0
  252. package/dist/lib/focus-after-trigger.js.map +1 -0
  253. package/dist/lib/overlay-coexistence.js +1 -1
  254. package/dist/lib/roving-list-keyboard.d.ts +208 -0
  255. package/dist/lib/roving-list-keyboard.d.ts.map +1 -0
  256. package/dist/lib/roving-list-keyboard.js +174 -0
  257. package/dist/lib/roving-list-keyboard.js.map +1 -0
  258. package/dist/lib/utils.d.ts.map +1 -1
  259. package/dist/lib/utils.js +6 -1
  260. package/dist/lib/utils.js.map +1 -1
  261. package/dist/patterns/element-anatomy/item-anatomy.d.ts +4 -4
  262. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  263. package/dist/patterns/element-anatomy/item-anatomy.js +14 -4
  264. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  265. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -1
  266. package/dist/patterns/horizontal-overflow/horizontal-overflow.js +25 -0
  267. package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -1
  268. package/dist/patterns/overlay-surface/overlay-surface.d.ts.map +1 -1
  269. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
  270. package/dist/tokens/categorical-color.d.ts +6 -1
  271. package/dist/tokens/categorical-color.d.ts.map +1 -1
  272. package/dist/tokens/categorical-color.js.map +1 -1
  273. package/dist/tokens/uiSize/icon-size.d.ts +1 -1
  274. package/dist/tokens/uiSize/stack-gap.d.ts +18 -0
  275. package/dist/tokens/uiSize/stack-gap.d.ts.map +1 -0
  276. package/dist/tokens/uiSize/stack-gap.js +5 -0
  277. package/dist/tokens/uiSize/stack-gap.js.map +1 -0
  278. package/ds-canonical/fork/codex/agents/skills/performance-audit/SKILL.md +1 -1
  279. package/ds-canonical/fork/codex/hooks.json +1 -1
  280. package/ds-canonical/fork/consumer/lock.json +17 -14
  281. package/ds-canonical/fork/consumer/managed-files/423729840acdd43c812f17c245b871716c6b60f76e4d3e94864d0e34a815bf8d.blob +9 -0
  282. package/ds-canonical/fork/consumer/managed-files/46f10bc55cdfdf834d0749eebff42ea0bb8576f361b36d2b6ba1851354c50150.blob +47 -9
  283. package/ds-canonical/fork/consumer/managed-files/5a0d134a2645114c8caac20458070b00a7f0fd55b3e8805b7325cb4cf52fa15e.blob +110 -0
  284. package/ds-canonical/fork/consumer/managed-files/5af0a46760af338d51fd0f7950675f8e97f7d2f09386b8818fcd7a58e6654e75.blob +790 -0
  285. package/ds-canonical/fork/consumer/managed-files/68bfcddff9c4a16388c248cd34fb66163e9e64b3d809a48ef3984f6ae4ff6d12.blob +211 -0
  286. package/ds-canonical/fork/consumer/managed-files/7eb6cc60abfdabaf6617c336058fad1454ccde08889295767bfd9b7fd153cc6e.blob +45 -6
  287. package/ds-canonical/fork/consumer/managed-files/92e4828cdcb96ff0d01daa16f6885f24045a8e72820665650f2a1890dc3a446c.blob +42 -2
  288. package/ds-canonical/fork/consumer/managed-files/ab072e7f2eca51f0e18a5e18c4b333260ee5d219a12cc6df5bb2d683f0b2734d.blob +27 -1
  289. package/ds-canonical/fork/consumer/managed-files/e71c65f45c6af7ce12b6b3c0d8028f185da5b719e2050c9b2a6b243d41ae4878.blob +62 -14
  290. package/ds-canonical/fork/governance.lock +41 -17
  291. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +16 -4
  292. package/ds-canonical/fork/hooks/check_consumer_code_quality.sh +3 -1
  293. package/ds-canonical/fork/hooks/check_pattern_invariants.sh +13 -9
  294. package/ds-canonical/fork/launchers/settings-hooks.json +1 -1
  295. package/ds-canonical/fork/manifest.json +17 -11
  296. package/ds-canonical/fork/providers/claude/skills/performance-audit/SKILL.md +1 -1
  297. package/ds-canonical/fork/providers/codex/hook-config.json +1 -1
  298. package/ds-canonical/fork/providers/codex/skills/performance-audit/SKILL.md +1 -1
  299. package/ds-canonical/fork/skills/performance-audit/SKILL.md +1 -1
  300. package/ds-canonical/hooks/check_consumer_app_invariants.sh +16 -4
  301. package/ds-canonical/hooks/check_consumer_code_quality.sh +3 -1
  302. package/ds-canonical/hooks/check_datatable_invariants.sh +4 -1
  303. package/ds-canonical/hooks/check_pattern_invariants.sh +13 -9
  304. package/ds-canonical/hooks/check_plugin_fork_health.sh +8 -1
  305. package/ds-canonical/hooks/check_propose_discipline.sh +8 -1
  306. package/ds-canonical/hooks/check_storybook_addon_packaging.sh +8 -1
  307. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +64 -2
  308. package/ds-canonical/hooks/lib/_overlay_handcraft.sh +5 -2
  309. package/ds-canonical/hooks/registrations.json +12 -7
  310. package/ds-canonical/hooks/session_start_governance_check.sh +16 -0
  311. package/ds-canonical/hooks/tests/test_check_consumer_app_invariants.sh +25 -0
  312. package/ds-canonical/hooks/tests/test_check_consumer_code_quality.sh +4 -0
  313. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +14 -0
  314. package/ds-canonical/hooks/tests/test_check_datatable_invariants.sh +24 -0
  315. package/ds-canonical/hooks/tests/test_check_overlay_handcraft.sh +32 -0
  316. package/ds-canonical/hooks/tests/test_check_pattern_invariants.sh +59 -0
  317. package/ds-canonical/hooks/tests/test_check_plugin_fork_health.sh +32 -1
  318. package/ds-canonical/hooks/tests/test_check_propose_discipline.sh +21 -0
  319. package/ds-canonical/hooks/tests/test_check_storybook_addon_packaging.sh +21 -0
  320. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +97 -0
  321. package/ds-canonical/hooks/tests/test_session_start_governance_check.sh +49 -0
  322. package/ds-canonical/references/README.md +12 -6
  323. package/ds-canonical/references/drag-canonical.md +3 -1
  324. package/ds-canonical/references/focus-canonical.md +26 -13
  325. package/ds-canonical/references/governance-audit-coverage.md +1 -1
  326. package/ds-canonical/references/hit-area-canonical.md +361 -0
  327. package/ds-canonical/references/item-anatomy-recipe.md +4 -2
  328. package/ds-canonical/references/keyboard-model-canonical.md +559 -0
  329. package/ds-canonical/rules/meta-patterns.md +4 -4
  330. package/ds-canonical/rules/self-verify.md +4 -4
  331. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +1 -1
  332. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +96 -0
  333. package/ds-canonical/skills/knowledge-prune/SKILL.md +4 -1
  334. package/ds-canonical/skills/performance-audit/SKILL.md +1 -1
  335. package/ds-story-manifest.json +19 -7
  336. package/llms-full.txt +2 -2
  337. package/llms.txt +2 -2
  338. package/package.json +3 -1
  339. package/src/components/Accordion/accordion.anatomy.stories.tsx +3 -3
  340. package/src/components/Accordion/accordion.spec.md +1 -1
  341. package/src/components/Accordion/accordion.tsx +8 -3
  342. package/src/components/AccountMenu/account-menu.spec.md +2 -3
  343. package/src/components/AccountMenu/account-menu.tsx +0 -1
  344. package/src/components/AgentPanel/agent-decision-card.spec.md +88 -0
  345. package/src/components/AgentPanel/agent-panel-fab.spec.md +151 -0
  346. package/src/components/AgentPanel/agent-panel-fab.tsx +67 -24
  347. package/src/components/AgentPanel/agent-panel-logo.spec.md +87 -0
  348. package/src/components/AgentPanel/agent-panel-logo.tsx +3 -3
  349. package/src/components/AgentPanel/agent-panel.anatomy.stories.tsx +1 -1
  350. package/src/components/AgentPanel/agent-panel.principles.stories.tsx +1 -1
  351. package/src/components/AgentPanel/agent-panel.spec.md +30 -275
  352. package/src/components/AgentPanel/agent-panel.stories.tsx +113 -8
  353. package/src/components/AgentPanel/agent-panel.tsx +59 -22
  354. package/src/components/Alert/alert.anatomy.stories.tsx +1 -1
  355. package/src/components/AppShell/app-shell.tsx +1 -1
  356. package/src/components/AspectRatio/aspect-ratio.anatomy.stories.tsx +10 -15
  357. package/src/components/Avatar/avatar.anatomy.stories.tsx +23 -26
  358. package/src/components/Avatar/avatar.principles.stories.tsx +10 -10
  359. package/src/components/Avatar/avatar.spec.md +45 -6
  360. package/src/components/Avatar/avatar.stories.tsx +8 -8
  361. package/src/components/Avatar/avatar.tsx +227 -21
  362. package/src/components/Badge/badge.anatomy.stories.tsx +16 -21
  363. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +3 -3
  364. package/src/components/Breadcrumb/breadcrumb.spec.md +3 -3
  365. package/src/components/Breadcrumb/breadcrumb.tsx +5 -3
  366. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +1 -1
  367. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +1 -1
  368. package/src/components/BulkActionBar/bulk-action-bar.spec.md +1 -0
  369. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +57 -2
  370. package/src/components/BulkActionBar/bulk-action-bar.tsx +32 -2
  371. package/src/components/Button/button.anatomy.stories.tsx +174 -33
  372. package/src/components/Button/button.spec.md +23 -8
  373. package/src/components/Button/button.tsx +116 -21
  374. package/src/components/Calendar/calendar.anatomy.stories.tsx +34 -11
  375. package/src/components/Calendar/calendar.principles.stories.tsx +44 -1
  376. package/src/components/Calendar/calendar.spec.md +97 -20
  377. package/src/components/Calendar/calendar.stories.tsx +101 -4
  378. package/src/components/Calendar/calendar.tsx +379 -74
  379. package/src/components/Carousel/carousel.anatomy.stories.tsx +16 -17
  380. package/src/components/Carousel/carousel.spec.md +48 -2
  381. package/src/components/Carousel/carousel.tsx +9 -3
  382. package/src/components/Chart/chart.anatomy.stories.tsx +7 -5
  383. package/src/components/Chart/chart.spec.md +32 -7
  384. package/src/components/Chart/chart.tsx +9 -0
  385. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +21 -28
  386. package/src/components/Checkbox/checkbox.spec.md +4 -2
  387. package/src/components/Checkbox/checkbox.tsx +10 -2
  388. package/src/components/Chip/chip.anatomy.stories.tsx +1 -1
  389. package/src/components/Chip/chip.spec.md +2 -1
  390. package/src/components/Chip/chip.tsx +4 -2
  391. package/src/components/Combobox/combobox.anatomy.stories.tsx +30 -37
  392. package/src/components/Combobox/combobox.spec.md +11 -3
  393. package/src/components/Combobox/combobox.tsx +43 -12
  394. package/src/components/Command/command.spec.md +11 -0
  395. package/src/components/Command/command.tsx +143 -10
  396. package/src/components/DataTable/cell-registry.tsx +5 -1
  397. package/src/components/DataTable/data-table-column-visibility-panel.tsx +5 -6
  398. package/src/components/DataTable/data-table-interaction-layer.tsx +27 -14
  399. package/src/components/DataTable/data-table-known-defects.spec.md +72 -0
  400. package/src/components/DataTable/data-table-scroll-performance.spec.md +295 -0
  401. package/src/components/DataTable/data-table-sort-manager.tsx +5 -6
  402. package/src/components/DataTable/data-table.anatomy.stories.tsx +1 -1
  403. package/src/components/DataTable/data-table.css +64 -0
  404. package/src/components/DataTable/data-table.spec.md +70 -346
  405. package/src/components/DataTable/data-table.stories.tsx +56 -9
  406. package/src/components/DataTable/data-table.tsx +392 -103
  407. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +2 -2
  408. package/src/components/DateGrid/date-grid.spec.md +163 -1
  409. package/src/components/DateGrid/date-grid.tsx +270 -7
  410. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +18 -27
  411. package/src/components/DatePicker/date-picker.spec.md +6 -2
  412. package/src/components/DatePicker/date-picker.tsx +20 -1
  413. package/src/components/Dialog/dialog.spec.md +6 -2
  414. package/src/components/Dialog/dialog.stories.tsx +18 -9
  415. package/src/components/Dialog/dialog.tsx +83 -48
  416. package/src/components/DropdownMenu/dropdown-menu-keyboard.ts +255 -0
  417. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +32 -33
  418. package/src/components/DropdownMenu/dropdown-menu.spec.md +18 -5
  419. package/src/components/DropdownMenu/dropdown-menu.stories.tsx +58 -1
  420. package/src/components/DropdownMenu/dropdown-menu.tsx +70 -33
  421. package/src/components/Empty/empty.spec.md +1 -2
  422. package/src/components/Field/field-context.ts +9 -4
  423. package/src/components/Field/field-controls.spec.md +5 -2
  424. package/src/components/Field/field-edit-keys.ts +12 -0
  425. package/src/components/Field/field-wrapper.tsx +76 -10
  426. package/src/components/Field/field.anatomy.stories.tsx +1 -1
  427. package/src/components/Field/field.spec.md +11 -6
  428. package/src/components/Field/field.stories.tsx +24 -1
  429. package/src/components/Field/field.tsx +10 -4
  430. package/src/components/FileItem/file-item.anatomy.stories.tsx +20 -10
  431. package/src/components/FileItem/file-item.principles.stories.tsx +14 -7
  432. package/src/components/FileItem/file-item.spec.md +50 -48
  433. package/src/components/FileItem/file-item.stories.tsx +41 -28
  434. package/src/components/FileItem/file-item.tsx +184 -50
  435. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +11 -15
  436. package/src/components/FileUpload/file-upload.spec.md +27 -1
  437. package/src/components/FileUpload/file-upload.stories.tsx +33 -0
  438. package/src/components/FileUpload/file-upload.tsx +173 -43
  439. package/src/components/FileViewer/file-viewer.tsx +9 -4
  440. package/src/components/HoverCard/hover-card.stories.tsx +2 -2
  441. package/src/components/InlineEdit/inline-edit.spec.md +2 -0
  442. package/src/components/InlineEdit/inline-edit.tsx +8 -3
  443. package/src/components/Input/input.anatomy.stories.tsx +23 -31
  444. package/src/components/Input/input.spec.md +11 -0
  445. package/src/components/Input/input.tsx +6 -1
  446. package/src/components/LinkInput/link-input.anatomy.stories.tsx +18 -21
  447. package/src/components/LinkInput/link-input.principles.stories.tsx +4 -4
  448. package/src/components/LinkInput/link-input.spec.md +12 -1
  449. package/src/components/LinkInput/link-input.tsx +37 -4
  450. package/src/components/Menu/menu-item.anatomy.stories.tsx +50 -56
  451. package/src/components/Menu/menu-item.spec.md +1 -1
  452. package/src/components/Menu/menu-item.stories.tsx +48 -42
  453. package/src/components/Notice/notice.anatomy.stories.tsx +8 -16
  454. package/src/components/Notice/notice.spec.md +1 -1
  455. package/src/components/Notice/notice.tsx +1 -1
  456. package/src/components/NumberInput/number-input.anatomy.stories.tsx +21 -28
  457. package/src/components/NumberInput/number-input.spec.md +2 -0
  458. package/src/components/NumberInput/number-input.tsx +8 -1
  459. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +28 -48
  460. package/src/components/OverflowIndicator/overflow-indicator.spec.md +13 -1
  461. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +12 -9
  462. package/src/components/OverflowIndicator/overflow-indicator.tsx +32 -12
  463. package/src/components/Pagination/pagination.spec.md +1 -0
  464. package/src/components/Pagination/pagination.tsx +1 -1
  465. package/src/components/PeoplePicker/avatar-stack-overflow.ts +14 -13
  466. package/src/components/PeoplePicker/people-picker-helpers.ts +5 -2
  467. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +1 -1
  468. package/src/components/PeoplePicker/people-picker.spec.md +4 -2
  469. package/src/components/PeoplePicker/people-picker.tsx +1 -4
  470. package/src/components/PeoplePicker/person-display.tsx +45 -28
  471. package/src/components/Popover/popover.anatomy.stories.tsx +1 -1
  472. package/src/components/Popover/popover.principles.stories.tsx +3 -12
  473. package/src/components/Popover/popover.spec.md +7 -3
  474. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  475. package/src/components/ProfileCard/profile-card.spec.md +1 -1
  476. package/src/components/ProfileCard/profile-card.tsx +0 -3
  477. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +11 -21
  478. package/src/components/ProgressBar/progress-bar.spec.md +1 -1
  479. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +17 -24
  480. package/src/components/RadioGroup/radio-group.spec.md +1 -1
  481. package/src/components/RadioGroup/radio-group.tsx +22 -4
  482. package/src/components/Rating/rating.anatomy.stories.tsx +131 -124
  483. package/src/components/Rating/rating.principles.stories.tsx +69 -43
  484. package/src/components/Rating/rating.spec.md +142 -63
  485. package/src/components/Rating/rating.stories.tsx +11 -15
  486. package/src/components/Rating/rating.tsx +131 -117
  487. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  488. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +6 -3
  489. package/src/components/ScrollArea/scroll-area.spec.md +3 -1
  490. package/src/components/ScrollArea/scroll-area.stories.tsx +5 -2
  491. package/src/components/ScrollArea/scroll-area.tsx +1 -1
  492. package/src/components/SegmentedControl/segmented-control.anatomy.stories.tsx +1 -1
  493. package/src/components/SegmentedControl/segmented-control.spec.md +2 -2
  494. package/src/components/SegmentedControl/segmented-control.tsx +3 -2
  495. package/src/components/Select/select.anatomy.stories.tsx +26 -35
  496. package/src/components/Select/select.spec.md +4 -3
  497. package/src/components/Select/select.tsx +11 -4
  498. package/src/components/SelectMenu/select-menu-keyboard.ts +218 -0
  499. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +6 -17
  500. package/src/components/SelectMenu/select-menu.spec.md +12 -4
  501. package/src/components/SelectMenu/select-menu.tsx +21 -56
  502. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +9 -33
  503. package/src/components/SelectionControl/selection-item.spec.md +2 -2
  504. package/src/components/SelectionControl/selection-item.tsx +3 -1
  505. package/src/components/Separator/separator.stories.tsx +4 -4
  506. package/src/components/Sheet/sheet.principles.stories.tsx +31 -13
  507. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +1 -1
  508. package/src/components/Sidebar/sidebar.spec.md +73 -6
  509. package/src/components/Sidebar/sidebar.stories.tsx +82 -4
  510. package/src/components/Sidebar/sidebar.tsx +281 -64
  511. package/src/components/Skeleton/skeleton.spec.md +1 -1
  512. package/src/components/Slider/slider.anatomy.stories.tsx +1 -1
  513. package/src/components/Slider/slider.spec.md +6 -5
  514. package/src/components/Slider/slider.tsx +13 -8
  515. package/src/components/Steps/steps-state-visuals.spec.md +157 -0
  516. package/src/components/Steps/steps.anatomy.stories.tsx +1 -0
  517. package/src/components/Steps/steps.spec.md +59 -142
  518. package/src/components/Steps/steps.stories.tsx +1 -1
  519. package/src/components/Steps/steps.tsx +125 -33
  520. package/src/components/Switch/switch.spec.md +3 -3
  521. package/src/components/Switch/switch.tsx +6 -1
  522. package/src/components/Tabs/tabs.spec.md +5 -1
  523. package/src/components/Tabs/tabs.tsx +42 -3
  524. package/src/components/Tag/tag.anatomy.stories.tsx +24 -28
  525. package/src/components/Tag/tag.spec.md +10 -11
  526. package/src/components/Tag/tag.tsx +3 -3
  527. package/src/components/Textarea/textarea.tsx +7 -1
  528. package/src/components/TimePicker/time-columns.tsx +9 -4
  529. package/src/components/TimePicker/time-picker.spec.md +4 -1
  530. package/src/components/TimePicker/time-picker.tsx +1 -1
  531. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +6 -15
  532. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -16
  533. package/src/components/Tooltip/tooltip.spec.md +2 -1
  534. package/src/components/TreeView/tree-view.anatomy.stories.tsx +35 -13
  535. package/src/components/TreeView/tree-view.spec.md +67 -38
  536. package/src/components/TreeView/tree-view.stories.tsx +221 -12
  537. package/src/components/TreeView/tree-view.tsx +463 -356
  538. package/src/hooks/use-input-modality.ts +17 -46
  539. package/src/hooks/use-overflow-items.ts +4 -0
  540. package/src/hooks/use-truncated.ts +3 -2
  541. package/src/index.ts +17 -0
  542. package/src/lib/README.md +2 -0
  543. package/src/lib/drag-announcements.ts +78 -0
  544. package/src/lib/focus-after-trigger.ts +102 -0
  545. package/src/lib/roving-list-keyboard.ts +400 -0
  546. package/src/lib/utils.ts +5 -0
  547. package/src/patterns/action-bar/action-bar.spec.md +2 -0
  548. package/src/patterns/element-anatomy/inline-action.spec.md +16 -12
  549. package/src/patterns/element-anatomy/item-anatomy.spec.md +98 -6
  550. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +75 -70
  551. package/src/patterns/element-anatomy/item-anatomy.tsx +17 -6
  552. package/src/patterns/element-anatomy/truncated-text.spec.md +1 -0
  553. package/src/patterns/header-canonical/header-canonical.spec.md +3 -2
  554. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +2 -0
  555. package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +36 -0
  556. package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +28 -0
  557. package/src/patterns/overlay-surface/overlay-chrome-sizing.spec.md +180 -0
  558. package/src/patterns/overlay-surface/overlay-surface.spec.md +8 -162
  559. package/src/patterns/overlay-surface/overlay-surface.tsx +5 -3
  560. package/src/patterns/resize-handle/resize-handle.spec.md +3 -3
  561. package/src/styles/base.css +1 -1
  562. package/src/tokens/categorical-color.ts +6 -1
  563. package/src/tokens/color/color.spec.md +91 -24
  564. package/src/tokens/color/color.stories.tsx +50 -2
  565. package/src/tokens/color/primitives.css +41 -38
  566. package/src/tokens/color/semantic.css +105 -36
  567. package/src/tokens/layoutSpace/layoutSpace.spec.md +2 -0
  568. package/src/tokens/motion/motion.spec.md +31 -8
  569. package/src/tokens/orphan-tokens.spec.md +1 -1
  570. package/src/tokens/uiSize/icon-size.ts +1 -1
  571. package/src/tokens/uiSize/stack-gap.ts +17 -0
  572. package/src/tokens/uiSize/uiSize.css +12 -0
  573. package/src/tokens/uiSize/uiSize.spec.md +17 -16
  574. package/src/tokens/uiSize/uiSize.stories.tsx +1 -1
  575. package/dist/node_modules/aria-hidden/dist/es2015/index.js +0 -147
  576. package/dist/node_modules/aria-hidden/dist/es2015/index.js.map +0 -1
@@ -14,7 +14,8 @@ export interface FileItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>
14
14
  * card border 多餘 = 雙層容器);avatar 作每筆 item 視覺邊界。compact 的進度條/灰底不受 surface 影響
15
15
  * (由 status 決定)。
16
16
  * surface-driven(非 status-driven):避免 form 內 rich 上傳中變無邊框、存好變 card 的邊框閃爍。
17
- * 列間 gap 由 List wrapper canonical 決定(form rich 8px / upload-manager rich 12px tight / compact 4px,見 spec)。
17
+ * 列間 gap 由 List wrapper canonical 決定(form rich 8px / form compact 4px / upload-manager 0 —— 列自帶上下 tight/2,
18
+ * 列間 ink 距仍 12,2026-09-25 待辦總帳 B12;見 spec)。
18
19
  */
19
20
  surface?: 'form' | 'upload-manager';
20
21
  status?: 'uploading' | 'completed' | 'error';
@@ -39,6 +40,29 @@ export interface FileItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>
39
40
  onDownload?: () => void;
40
41
  onRetry?: () => void;
41
42
  }
43
+ /**
44
+ * @internal
45
+ * 焦點框的「框圖層」:與列同形同大的 `::before`(file-item.spec.md「焦點框 × 貼著列底的進度條」)。
46
+ * 只在**列底貼著進度條**時用 —— form 的 compact 列有 status 時。upload-manager 的進度條離列底 tight/2、
47
+ * rich 的進度條在內容區,都碰不到框,照舊把框畫在列上。
48
+ * 為什麼要另一層:進度條住在列裡。框若畫在列上,列是進度條的祖先,遮罩會連進度條一起挖掉;
49
+ * 畫在 `::before` 上,遮罩只挖框。層疊不變:`::before` 是第一個定位子層,進度條(absolute)仍畫在它上面;
50
+ * 而且洞裡根本沒有框,進度條與框誰畫在上面都不影響結果(CSS UI 4 把 outline 的疊放順序留給瀏覽器自己決定,
51
+ * 「The stacking of the rendering of these outlines is explicitly left up to implementations」)。
52
+ * 這裡只有位置與遮罩,**不含觸發條件**:FileItem 自己的列由整列隱形鈕觸發、FileUpload 的清單列由列自己的
53
+ * `:focus-visible` 觸發,各自在使用端寫。線寬、顏色、往內 2px、圓角全部照舊來自 `focus-ring-inset`
54
+ * (`ds-canonical/references/focus-canonical.md`「框怎麼畫」),不是第四種幾何。
55
+ */
56
+ export declare const FILE_ITEM_RING_LAYER_CLASS = "before:absolute before:inset-0 before:rounded-[inherit] before:pointer-events-none before:[mask:var(--file-item-ring-cutout)]";
57
+ /**
58
+ * @internal
59
+ * 框圖層的遮罩(`--file-item-ring-cutout`)。列底沒有貼著進度條時回 `undefined` —— 呼叫端據此照舊把框畫在列上。
60
+ * 遮罩 = 三塊保留區的聯集:上半部整條 + 左段 + 右段。挖掉的是「進度條那一段(兩端各多 BAR_RING_GAP_PX)的下半部」,
61
+ * 框在那個範圍裡只有底邊,所以挖掉的只有底邊那一段。露出來的是**真正在後面的東西**(列自己的滑過色、卡片、面板、頁面),
62
+ * 不需要知道底色是什麼(與 `avatar.tsx` 頭像堆疊「挖空,不是外圈」同一個理由:深色的 `--surface` 本身半透明,
63
+ * 墊任何固定底色都會在某種容器上錯色)。
64
+ */
65
+ export declare function fileItemRingCutoutStyle({ mode, surface, status, }: Pick<FileItemProps, 'mode' | 'surface' | 'status'>): React.CSSProperties | undefined;
42
66
  declare const FileItem: React.ForwardRefExoticComponent<FileItemProps & React.RefAttributes<HTMLDivElement>>;
43
67
  export declare const fileItemMeta: {
44
68
  readonly component: "FileItem";
@@ -49,7 +73,7 @@ export declare const fileItemMeta: {
49
73
  readonly tokens: {
50
74
  readonly bg: readonly ["bg-secondary", "bg-surface"];
51
75
  readonly fg: readonly ["text-fg-muted", "text-fg-secondary"];
52
- readonly ring: readonly [];
76
+ readonly ring: readonly ["focus-ring-inset"];
53
77
  };
54
78
  };
55
79
  export { FileItem };
@@ -1 +1 @@
1
- {"version":3,"file":"file-item.d.ts","sourceRoot":"","sources":["../../../src/components/FileItem/file-item.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA6C9B,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACxF,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACzB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAA;IACnC,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mGAAmG;IACnG,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAGD,QAAA,MAAM,QAAQ,sFA2Qb,CAAA;AAKD,eAAO,MAAM,YAAY;;;;;;;;;;;CAef,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"file-item.d.ts","sourceRoot":"","sources":["../../../src/components/FileItem/file-item.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA+C9B,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACxF,IAAI,EAAE,MAAM,CAAA;IACZ;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACzB;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAA;IACnC,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mGAAmG;IACnG,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;IACvB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAkBD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,0BAA0B,kIAC0F,CAAA;AAEjI;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,IAAgB,EAChB,OAAgB,EAChB,MAAM,GACP,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC,GAAG,KAAK,CAAC,aAAa,GAAG,SAAS,CAUtF;AAGD,QAAA,MAAM,QAAQ,sFAsVb,CAAA;AAKD,eAAO,MAAM,YAAY;;;;;;;;;;;CAef,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -6,6 +6,7 @@ import { Avatar } from "../Avatar/avatar.js";
6
6
  import { Button } from "../Button/button.js";
7
7
  import { ProgressBar } from "../ProgressBar/progress-bar.js";
8
8
  import { ItemSuffix, ItemPrefix, ItemContent } from "../../patterns/element-anatomy/item-anatomy.js";
9
+ import { STACK_GAP_PX } from "../../tokens/uiSize/stack-gap.js";
9
10
  const STATUS_ICON = {
10
11
  completed: { icon: CircleCheck, color: "text-success" },
11
12
  error: { icon: XCircle, color: "text-error" }
@@ -17,6 +18,24 @@ const PROGRESS_STATUS_MAP = {
17
18
  };
18
19
  const AVATAR_SIZE = 48;
19
20
  const ICON_PX = 16;
21
+ function compactBarInset(surface) {
22
+ const padX = surface === "upload-manager" ? "var(--layout-space-loose)" : "12px";
23
+ return { padX, left: `calc(${padX} + ${ICON_PX}px + 0.5rem)`, right: padX };
24
+ }
25
+ const BAR_RING_GAP_PX = STACK_GAP_PX;
26
+ const FILE_ITEM_RING_LAYER_CLASS = "before:absolute before:inset-0 before:rounded-[inherit] before:pointer-events-none before:[mask:var(--file-item-ring-cutout)]";
27
+ function fileItemRingCutoutStyle({
28
+ mode = "compact",
29
+ surface = "form",
30
+ status
31
+ }) {
32
+ if (mode !== "compact" || surface === "upload-manager" || !status) return void 0;
33
+ const { left, right } = compactBarInset(surface);
34
+ const keep = "linear-gradient(#000 0 0)";
35
+ return {
36
+ ["--file-item-ring-cutout"]: `${keep} top / 100% 50% no-repeat, ${keep} left / calc(${left} - ${BAR_RING_GAP_PX}px) 100% no-repeat, ${keep} right / calc(${right} - ${BAR_RING_GAP_PX}px) 100% no-repeat`
37
+ };
38
+ }
20
39
  const FileItem = React.forwardRef(
21
40
  ({
22
41
  name,
@@ -39,7 +58,7 @@ const FileItem = React.forwardRef(
39
58
  const statusConfig = status && status !== "uploading" ? STATUS_ICON[status] : null;
40
59
  const progressWidth = status === "completed" ? 100 : progress;
41
60
  const showDesc = isRich ? !!description : status === "error" && !!description;
42
- const hoverClass = onClick ? "cursor-pointer" : "";
61
+ const isUploadManager = surface === "upload-manager";
43
62
  const progressBar = hasStatus ? /* @__PURE__ */ jsx(
44
63
  ProgressBar,
45
64
  {
@@ -63,7 +82,7 @@ const FileItem = React.forwardRef(
63
82
  {
64
83
  size: ICON_PX,
65
84
  className: cn(
66
- "shrink-0 transition-opacity motion-reduce:duration-0",
85
+ "shrink-0",
67
86
  statusConfig.color,
68
87
  // 2026-07-05 D4:鍵盤 focus 同步觸發 swap(:has(:focus-visible),對齊 item-anatomy SUFFIX_HOVER_REVEAL_BY_GROUP SSOT)
69
88
  hoverAction && "group-hover/row:opacity-0 group-has-[:focus-visible]/row:opacity-0"
@@ -83,7 +102,7 @@ const FileItem = React.forwardRef(
83
102
  e.stopPropagation();
84
103
  hoverAction.onClick();
85
104
  },
86
- className: "absolute inset-0 opacity-0 group-hover/row:opacity-100 group-has-[:focus-visible]/row:opacity-100 transition-opacity motion-reduce:duration-0"
105
+ className: "absolute inset-0 opacity-0 group-hover/row:opacity-100 group-has-[:focus-visible]/row:opacity-100"
87
106
  }
88
107
  )
89
108
  ]
@@ -108,7 +127,15 @@ const FileItem = React.forwardRef(
108
127
  "%"
109
128
  ] }),
110
129
  statusSlot,
111
- actions
130
+ actions && /* @__PURE__ */ jsx(
131
+ "span",
132
+ {
133
+ "data-unbounded": "true",
134
+ className: "inline-flex items-center gap-2",
135
+ onClick: (e) => e.stopPropagation(),
136
+ children: actions
137
+ }
138
+ )
112
139
  ]
113
140
  }
114
141
  );
@@ -125,7 +152,6 @@ const FileItem = React.forwardRef(
125
152
  suffix
126
153
  ] });
127
154
  const rowA11y = {};
128
- const compactStaticBg = !progressBar ? "bg-secondary" : "";
129
155
  const keyboardPrimaryAction = onClick ? /* @__PURE__ */ jsx(
130
156
  "button",
131
157
  {
@@ -148,16 +174,30 @@ const FileItem = React.forwardRef(
148
174
  // hover 底色瞬間切換,不做過渡(user 2026-09-10 拍板「第三題改成全部瞬間」;SSOT = tokens/motion/motion.spec.md「hover 回饋不做過渡」)
149
175
  "group/row relative flex items-start gap-2 w-full text-body leading-compact",
150
176
  // 2026-09-07 H1g:限定只接下面那顆隱形整列鈕(keyboardPrimaryAction)。
151
- // 原本裸寫 `has-[:focus-visible]` 不分對象,trailing action 的 <Button> 自帶
152
- // ring(button.tsx:66)被聚焦時整列也跟著畫 → 一次互動兩個焦點框,
153
- // 違反 focus-canonical「一個項目只有一個指示器」。
154
- "has-[[data-row-focus-target]:focus-visible]:ring-2 has-[[data-row-focus-target]:focus-visible]:ring-ring",
177
+ // 原本裸寫 `has-[:focus-visible]` 不分對象,trailing action 的 <Button> 被聚焦時整列也跟著畫 →
178
+ // 一次互動兩個焦點框,違反 focus-canonical「一個項目只有一個指示器」。當時 <Button> 自帶
179
+ // ring;2026-09-16 a7b2be94 起它不再自帶焦點 class、改吃全域外描邊,但限定的理由不變。
180
+ // 幾何(2026-09-24 user 拍板「可以照你建議內描邊」):**內描邊**。原本寫的 `ring-2 ring-ring`
181
+ // 是 2026-09-07 就退役的第二套機制,只因閘的舊 regex 只認裸寫的 `focus-visible:ring-2`、
182
+ // 不認這裡的 `has-[…:focus-visible]:` 括號變體才活到今天(該洞同日已補,見
183
+ // scripts/focus-geometry-invariant.mjs R2)。
184
+ // **理由是結構性的**:拿到焦點的是下面那顆 `opacity-0` 的隱形整列鈕,它自己畫不出框,
185
+ // 指示器改畫在列上 —— 這是 focus-canonical「刻意不畫的唯一合法理由是指示器畫在別的元素上,
186
+ // 而且必須指得出承擔者」認可的形狀,承擔者就是本行所在的這個列 div。全域外描邊只作用在
187
+ // 「被聚焦的那個元素」身上,套不到非焦點的列;能掛在列上的只有 focus-ring-inset 與填色專用的
188
+ // focus-ring-inset-emphasis,列不是主色填色 → focus-ring-inset。
189
+ // **不是**靠四周淨空不足,也**不是**引用 item-anatomy「選中 × 互動疊加」表那句「列撐滿容器寬度,
190
+ // 左右沒有 2px 可以往外長」(那格的消費者清單沒有 FileItem):表單的列有圓角、列間 4–12px;
191
+ // 上傳管理器的列 2026-09-25 起鋪滿面板寬、列間 0(B12)—— 兩種幾何都用內描邊,理由只有上面那條結構性的
192
+ // (2026-09-24 審查抓到舊句把「淨空」當理由,勿寫回)。
193
+ // 也**不是**因為捲動容器會裁切 —— 捲動與否明文不進判準。
194
+ "has-[[data-row-focus-target]:focus-visible]:focus-ring-inset",
155
195
  // surface=form → border card(自立輪廓);surface=upload-manager → 無邊框(box 自身是容器,
156
- // avatar 作 item 邊界)。2026-06-03 codify rich-borderless(原僅 spec 旁註,consumer 自己移除)。
157
- // 2026-06-03 圖五:upload-manager rich 拿掉 px+py(卡片移除後 py 多餘,列高靠 avatar 48 的 content minHeight;
158
- // 容器 + gap 控制間距)。form 保留 px-3 py-3 卡片內距。
159
- surface === "upload-manager" ? "rounded-md" : "px-3 py-3 border border-divider rounded-md bg-surface",
160
- hoverClass,
196
+ // avatar 作 item 邊界)。2026-06-03 codify rich-borderless(原僅 spec 旁註,consumer 自己移除)。form 保留 px-3 py-3 卡片內距。
197
+ surface === "upload-manager" ? "px-[var(--layout-space-loose)] py-[calc(var(--layout-space-tight)/2)]" : "px-3 py-3 border border-divider rounded-md bg-surface",
198
+ onClick && "cursor-pointer",
199
+ // 滑過(B12,見上方「滑過底色」段):上傳列平常透明 → 換成 neutral-hover;表單卡片平常是「底」bg-surface → 疊一層
200
+ onClick && (surface === "upload-manager" ? "hover:bg-neutral-hover" : "hover:bg-interaction-hover"),
161
201
  className
162
202
  ),
163
203
  onClick,
@@ -184,21 +224,36 @@ const FileItem = React.forwardRef(
184
224
  }
185
225
  );
186
226
  }
187
- const compactPadX = surface === "upload-manager" ? 0 : 12;
227
+ const { padX: compactPadX, left: compactBarLeft, right: compactBarRight } = compactBarInset(surface);
228
+ const compactBarBottom = isUploadManager ? "calc(var(--layout-space-tight) / 2)" : "0px";
229
+ const compactPadBlock = isUploadManager ? { paddingTop: "calc(var(--layout-space-tight) / 2)", paddingBottom: "calc(var(--layout-space-tight) / 2 + 0.5rem)" } : void 0;
230
+ const ringCutout = fileItemRingCutoutStyle({ mode, surface, status });
188
231
  return /* @__PURE__ */ jsxs(
189
232
  "div",
190
233
  {
191
234
  ref,
192
235
  className: cn(
193
236
  // hover 底色瞬間切換,不做過渡(user 2026-09-10 拍板「第三題改成全部瞬間」;SSOT = tokens/motion/motion.spec.md「hover 回饋不做過渡」)
194
- "group/row relative flex items-start gap-2 py-2 w-full text-body leading-compact rounded-md",
195
- compactStaticBg,
196
- // 2026-09-07 H1g:同 rich —— 只接隱形整列鈕,不接自帶 ring 的 trailing <Button>
197
- "has-[[data-row-focus-target]:focus-visible]:ring-2 has-[[data-row-focus-target]:focus-visible]:ring-ring",
198
- hoverClass,
237
+ "group/row relative flex items-start gap-2 w-full text-body leading-compact",
238
+ // form 的列是圓角膠囊 / 圓角列;upload-manager 的列鋪滿面板寬 → 不加圓角(同 rich,AI 推導),上下內距見上方 compactPadBlock
239
+ !isUploadManager && "py-2 rounded-md",
240
+ !hasStatus && "bg-secondary",
241
+ // 2026-09-07 H1g:同 rich —— 只接隱形整列鈕,不接同樣會畫框的 trailing <Button>;
242
+ // 幾何同 rich 的內描邊(結構性理由見上方那段)。
243
+ // **列底貼著進度條時,框畫在框圖層 ::before**(2026-09-26,file-item.spec.md「焦點框 × 貼著列底的進度條」)。
244
+ // 進度條是 absolute,本來就畫在框的**上面**,正好落在內描邊底邊那 2px 上 —— 但它沒有「蓋住」框:
245
+ // 軌道 --secondary 是半透明,框的藍從軌道透出來;填色 --info 又與框 --ring 同為 blue-6,與框黏成一條
246
+ // (實測聚焦時填色對軌道 1.10:1,平常 4.55:1;深色 1.17 / 4.04)。框圖層在進度條那一段(兩端各多 2px 縫)
247
+ // 挖空,露出真正的底:聚焦時進度條與平常逐像素相同,進度條的頭尾與框之間各隔一道底色的縫。
248
+ // upload-manager 的 bar 離列底 tight/2、碰不到框 → ringCutout 為 undefined,框照舊畫在列上。
249
+ ringCutout ? [FILE_ITEM_RING_LAYER_CLASS, "has-[[data-row-focus-target]:focus-visible]:before:focus-ring-inset"] : "has-[[data-row-focus-target]:focus-visible]:focus-ring-inset",
250
+ onClick && "cursor-pointer",
251
+ // 滑過(B12,見上方「滑過底色」段):有進度條的列平常透明 → 換成 neutral-hover;
252
+ // 靜態小膠囊平常是 bg-secondary → 換成它自己的下一階 secondary-hover(不借透明底的配對)
253
+ onClick && (hasStatus ? "hover:bg-neutral-hover" : "hover:bg-secondary-hover"),
199
254
  className
200
255
  ),
201
- style: { paddingInline: compactPadX },
256
+ style: { paddingInline: compactPadX, ...compactPadBlock, ...ringCutout },
202
257
  onClick,
203
258
  ...rowA11y,
204
259
  ...props,
@@ -209,8 +264,8 @@ const FileItem = React.forwardRef(
209
264
  progressBar && /* @__PURE__ */ jsx(
210
265
  "div",
211
266
  {
212
- className: "absolute bottom-0",
213
- style: { left: `calc(${compactPadX}px + ${ICON_PX}px + 0.5rem)`, right: compactPadX },
267
+ className: "absolute",
268
+ style: { left: compactBarLeft, right: compactBarRight, bottom: compactBarBottom },
214
269
  children: progressBar
215
270
  }
216
271
  )
@@ -229,11 +284,13 @@ const fileItemMeta = {
229
284
  tokens: {
230
285
  bg: ["bg-secondary", "bg-surface"],
231
286
  fg: ["text-fg-muted", "text-fg-secondary"],
232
- ring: []
287
+ ring: ["focus-ring-inset"]
233
288
  }
234
289
  };
235
290
  export {
291
+ FILE_ITEM_RING_LAYER_CLASS,
236
292
  FileItem,
237
- fileItemMeta
293
+ fileItemMeta,
294
+ fileItemRingCutoutStyle
238
295
  };
239
296
  //# sourceMappingURL=file-item.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-item.js","sources":["../../../src/components/FileItem/file-item.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.\nimport * as React from 'react'\nimport { Paperclip, CircleCheck, XCircle, Download, RotateCw } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Avatar } from '@/design-system/components/Avatar/avatar'\nimport { Button } from '@/design-system/components/Button/button'\nimport { ProgressBar } from '@/design-system/components/ProgressBar/progress-bar'\nimport { ItemContent, ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n/**\n * FileItem — 檔案顯示 / 上傳進度\n *\n * Typography: 兩 mode 統一 scanning — text-body (14px) + leading-compact (1.3)(詳 spec「Typography」段,2026-04-23)\n *\n * 兩種 mode(精簡 vs 完整內容呈現):\n *\n * compact(★ default): Paperclip 16px 在左。右側 content + bar。\n * padding 詳 spec「Padding」表(form: px-3 py-2;surface=upload-manager: px-0 保留 py-2)。\n * description 只有 error 才顯示。\n * bar 跟文字左邊對齊(在 icon 右邊的 column 內)。\n *\n * rich: Avatar 48px square 在左(顯示檔案內容縮圖)。右側 content + bar。\n * 多行 description(size / status message)。\n * 有 bar → justify-between(bar 底部對齊 avatar)\n * 無 bar → justify-center(文字垂直置中對齊 avatar)\n *\n * status 可選。不傳 = 已上傳檔案(無 bar,可點擊下載)。\n * onClick → 只加 cursor-pointer(**永不顯示 hover-bg**;FileItem 三型態皆 permanent-anchored,詳 spec「Hover 行為 canonical」)。\n */\n\nconst STATUS_ICON = {\n completed: { icon: CircleCheck, color: 'text-success' },\n error: { icon: XCircle, color: 'text-error' },\n} as const\n\n// ProgressBar status 映射:uploading=inProgress(藍) / completed=success(綠) / error=error(紅)\n// 與 ProgressBar 元件的 status prop 對齊,不需再維護 PROGRESS_COLOR 本地 map。\nconst PROGRESS_STATUS_MAP = {\n uploading: 'inProgress',\n completed: 'success',\n error: 'error',\n} as const\n\nconst AVATAR_SIZE = 48\nconst ICON_PX = 16\n\nexport interface FileItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n name: string\n /**\n * 兩種呈現 mode(精簡 vs 完整):\n * - `compact`(預設):paperclip + filename 單行 inline\n * - `rich`:縮圖 + 檔名 + size + status + progress 的完整 card 呈現\n */\n mode?: 'compact' | 'rich'\n /**\n * 清單所在的 surface context(2026-06-03 codify rich-borderless):\n * - `form`(預設):rich = border card(自立輪廓,Slack/Notion/Linear attachment 慣例)\n * - `upload-manager`:rich = **無邊框**(Google Drive/Dropbox 上傳管理面板 —— 面板自身已是容器,\n * card border 多餘 = 雙層容器);avatar 作每筆 item 視覺邊界。compact 的進度條/灰底不受 surface 影響\n * (由 status 決定)。\n * surface-driven(非 status-driven):避免 form 內 rich 上傳中變無邊框、存好變 card 的邊框閃爍。\n * 列間 gap 由 List wrapper canonical 決定(form rich 8px / upload-manager rich 12px tight / compact 4px,見 spec)。\n */\n surface?: 'form' | 'upload-manager'\n status?: 'uploading' | 'completed' | 'error'\n progress?: number\n /** rich mode: 檔案大小、狀態訊息。compact: 只有 error 才顯示。 ReactNode 支援 inline clickable link(如「View log」)。 */\n description?: React.ReactNode\n thumbnailSrc?: string\n actions?: React.ReactNode\n onClick?: () => void\n /** 整列 primary action 的 accessible name;預設 `開啟 {name}`。 */\n actionAriaLabel?: string\n /**\n * Hover 動作(passive 狀態 icon 變互動 button 的 UX):\n * - `onDownload`:有值時,`status=\"completed\"` 的綠 ✓ icon 在 row hover 時\n * 換成 Download ↓ button;click 觸發 onDownload。無值保持 passive 綠 ✓。\n * - `onRetry`:有值時,`status=\"error\"` 的紅 ✗ icon 在 row hover 時換成 RotateCw ⟲\n * button;click 觸發 onRetry。無值保持 passive 紅 ✗。\n *\n * 世界級對照:Gmail / Slack / Dropbox 附件的 passive 狀態 → hover 變 action\n * 的 UX,使用者知道檔案狀態且能立即行動。\n */\n onDownload?: () => void\n onRetry?: () => void\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst FileItem = React.forwardRef<HTMLDivElement, FileItemProps>(\n (\n {\n name,\n mode = 'compact',\n surface = 'form',\n status,\n progress = 0,\n description,\n thumbnailSrc,\n actions,\n onClick,\n actionAriaLabel = `開啟 ${name}`,\n onDownload,\n onRetry,\n className,\n ...props\n },\n ref,\n ) => {\n const isRich = mode === 'rich'\n const hasStatus = !!status\n const statusConfig = status && status !== 'uploading' ? STATUS_ICON[status] : null\n const progressWidth = status === 'completed' ? 100 : progress\n\n // compact 只有 error 才顯示 description\n const showDesc = isRich ? !!description : (status === 'error' && !!description)\n\n // Hover 行為 canonical(2026-04-23 user 校準):**FileItem 永不顯示 hover-bg**。\n // 各型態都有永久 visual anchor:rich surface=form = border card / rich surface=upload-manager\n // = avatar 48 thumbnail 作 item 邊界(無邊框)/ compact 無 status = bg-secondary /\n // compact 有 status = 底部 progress bar(分隔線型 affordance)——再加 hover-bg 是\n // double-emphasis,視覺雜。世界級共識(Slack / Notion / Figma / Gmail 皆無 hover-bg):\n // permanent-anchored 元件 hover 只靠 cursor + action icon fade / border highlight,\n // 不靠 row bg。onClick 存在時只給 `cursor-pointer`,affordance 靠 cursor + 點擊行為本身。\n const hoverClass = onClick ? 'cursor-pointer' : ''\n\n // 消費 ProgressBar 元件(SSOT);不再自 roll bar。\n // compact mode 用 2px(極密集 row layout),rich mode 用預設 4px。這是 FileItem\n // 私有 composition 細節;ProgressBar 公開 API 維持單一 4px、沒有 height/size 軸。\n // a11y(2026-04-25 axe aria-progressbar-name):aria-label 用 file name 作 context。\n const progressBar = hasStatus ? (\n <ProgressBar\n value={progressWidth}\n status={PROGRESS_STATUS_MAP[status!]}\n className={isRich ? undefined : '!h-0.5'}\n aria-label={`${name} 上傳進度`}\n />\n ) : null\n\n // suffix 對齊 label 第一行(item-anatomy「24px 閾值對齊規則」小 suffix canonical):\n // icons 16 ≤ 24 屬小 suffix,統一 h-[1lh] inline(由 ItemSuffix primitive 提供),\n // 不因 desc wrap 改公式。兩 mode 同公式,跟 item-anatomy 一致。\n\n // Status slot 幾何(2026-04-23 user 統一):rich + compact 都用 `var(--field-height-xs)`(24)\n // 容器,裡面 Button xs iconOnly variant=\"text\"(auto data-unbounded)。\n // Compact 不影響 row 高度 = suffix wrapper 的 data-unbounded CSS 讓 Button layout\n // 收斂到 1lh(同 compact row 內容高),視覺/touch target 仍 24。\n const slotHw = 'var(--field-height-xs)'\n\n const hoverAction =\n status === 'completed' && onDownload ? { icon: Download, onClick: onDownload, label: `下載 ${name}` } :\n status === 'error' && onRetry ? { icon: RotateCw, onClick: onRetry, label: `重試 ${name}` } :\n null\n\n const statusSlot = statusConfig ? (\n <span\n data-unbounded=\"true\"\n className=\"relative inline-flex items-center justify-center shrink-0\"\n style={{ width: slotHw, height: slotHw }}\n >\n {/* Passive 狀態 icon:預設可見;若有 hover-swap,row-hover 時淡出 */}\n <statusConfig.icon\n size={ICON_PX}\n className={cn(\n 'shrink-0 transition-opacity motion-reduce:duration-0',\n statusConfig.color,\n // 2026-07-05 D4:鍵盤 focus 同步觸發 swap(:has(:focus-visible),對齊 item-anatomy SUFFIX_HOVER_REVEAL_BY_GROUP SSOT)\n hoverAction && 'group-hover/row:opacity-0 group-has-[:focus-visible]/row:opacity-0',\n )}\n aria-hidden\n />\n {/* Active action:row-hover 時淡入(rich + compact 同 Button xs 統一) */}\n {hoverAction && (\n <Button\n variant=\"text\"\n size=\"xs\"\n iconOnly\n startIcon={hoverAction.icon}\n aria-label={hoverAction.label}\n onClick={(e) => { e.stopPropagation(); hoverAction.onClick() }}\n className=\"absolute inset-0 opacity-0 group-hover/row:opacity-100 group-has-[:focus-visible]/row:opacity-100 transition-opacity motion-reduce:duration-0\"\n />\n )}\n </span>\n ) : null\n\n // 2026-07-16 dim 39/DA3:消費 ItemSuffix primitive(照 Notice 2026-06-15 已遷模式)。\n // ItemSuffix base geometry(h-[1lh] shrink-0 ml-auto flex items-center gap-2)= 原手刻\n // div 的 flex items-center gap-2 shrink-0 h-[1lh];多出的 ml-auto 為 no-op(左鄰\n // ItemContent 是 flex-1,已把 suffix 推到右緣)→ 像素相等。hoverReveal 預設 false,\n // 不干擾本檔自有的 statusSlot hover-swap 機制(group-hover/row 系)。\n const suffix = (\n <ItemSuffix\n className={cn(\n // data-unbounded chrome-canonical trick:let Button xs (24) live inside h-[1lh]\n // wrapper(compact ~18.2 / rich ~18.2 scanning)without pushing row height。\n // 視覺/hit area 仍 24,layout footprint 收斂到 1lh。同 overlay-surface\n // 的 SurfaceHeader dismiss canonical(2026-04-22 v5)。\n // **child selector `[&>[data-unbounded]]`(非 descendant)**:只針對 suffix\n // wrapper **直接子元素**(statusSlot span、actions Button)套 margin,\n // 避免 status slot 內部 hover-swap Button(nested)也套造成 layout 跳動。\n '[&>[data-unbounded]]:my-[calc((1lh-var(--field-height-xs))/2)]',\n )}\n >\n {status === 'uploading' && isRich && (\n <span className=\"text-fg-secondary tabular-nums\">{progress}%</span>\n )}\n {statusSlot}\n {actions}\n </ItemSuffix>\n )\n\n // content row — 消費 ItemContent primitive(封裝 label + desc + mt-gap token SSOT)。\n // 兩 mode 共用:primitive 改 → 兩 mode 同步,不需 grep。\n // typography:scanning mode(2026-04-23 user 指示)—— label body(14/1.3) + desc caption(12/1.3);\n // row 本身加 `leading-compact` 配合 scanning idiom(同 MenuItem row)。\n const contentRow = (\n <div className=\"flex items-start gap-2\">\n <ItemContent\n label={name}\n description={showDesc ? description : undefined}\n mode=\"scanning\"\n descriptionTone={status === 'error' ? 'error' : 'secondary'}\n />\n {suffix}\n </div>\n )\n\n // a11y nested-interactive contract:row 含 hover-swap / trailing action buttons,故 row\n // 本身不可設 role=button + tabIndex。Primary keyboard path 由下方 sibling native button\n // 承接;mouse 仍由 row onClick 承接,兩者皆呼叫同一 callback。\n const rowA11y = {}\n\n // Compact 靜態背景(AR20):無進度條 → 顯示 `bg-secondary`(= neutral-3)作「檔案已上傳 /\n // 靜態列表」視覺區隔,跟「上傳中(有 progress bar)」對照。hover 不改 bg(見上方\n // hoverClass canonical:FileItem 永不顯示 hover-bg)。\n // **為什麼 bg-secondary 不 bg-neutral-3**:`bg-neutral-3` 不是合法 Tailwind utility\n // (primitive token `--color-neutral-3` 沒經 `@theme inline` 橋接);`bg-secondary`\n // 是 semantic token 橋接的 utility(見 `tokens/color/semantic.css`@theme inline),\n // 底色同樣指向 `--color-neutral-3`。對齊 Badge low / ProgressBar track SSOT。\n const compactStaticBg = !progressBar ? 'bg-secondary' : ''\n // Primary row action 與 trailing actions 是 sibling controls,不把整列設成 role=button,\n // 因此不會形成 nested-interactive。透明 full-row button 只接 keyboard/focus;pointer\n // 仍由既有 row onClick 接手,保持 hit area 與 consumer callback contract 不變。\n const keyboardPrimaryAction = onClick ? (\n <button\n type=\"button\"\n aria-label={actionAriaLabel}\n // 整列焦點框的唯一觸發者(見上方兩處 has-[[data-row-focus-target]:focus-visible])。\n // 它自己不畫框(opacity-0),指示器畫在列上 —— focus-canonical 認可的「指示器畫在別的元素上」。\n data-row-focus-target=\"\"\n className=\"absolute inset-0 opacity-0 pointer-events-none\"\n onClick={(event) => {\n event.stopPropagation()\n onClick()\n }}\n />\n ) : null\n\n // ── rich(含縮圖完整呈現)——AR17 canonical:surface=form 加邊框 card / surface=upload-manager 無邊框 ──\n // Rich surface=form 是「檔案 card」風格,外框讓每個 row 視覺上是獨立 card(Slack / Notion /\n // Linear attachment 慣例);surface=upload-manager 無邊框,avatar 作 item 邊界(面板自身是容器,\n // 見 file-item.spec.md「邊框 / 背景」表)\n if (isRich) {\n return (\n <div\n ref={ref}\n className={cn(\n // hover 底色瞬間切換,不做過渡(user 2026-09-10 拍板「第三題改成全部瞬間」;SSOT = tokens/motion/motion.spec.md「hover 回饋不做過渡」)\n 'group/row relative flex items-start gap-2 w-full text-body leading-compact',\n // 2026-09-07 H1g:限定只接下面那顆隱形整列鈕(keyboardPrimaryAction)。\n // 原本裸寫 `has-[:focus-visible]` 不分對象,trailing action 的 <Button> 自帶\n // ring(button.tsx:66)被聚焦時整列也跟著畫 → 一次互動兩個焦點框,\n // 違反 focus-canonical「一個項目只有一個指示器」。\n 'has-[[data-row-focus-target]:focus-visible]:ring-2 has-[[data-row-focus-target]:focus-visible]:ring-ring',\n // surface=form → border card(自立輪廓);surface=upload-manager → 無邊框(box 自身是容器,\n // avatar 作 item 邊界)。2026-06-03 codify rich-borderless(原僅 spec 旁註,consumer 自己移除)。\n // 2026-06-03 圖五:upload-manager rich 拿掉 px+py(卡片移除後 py 多餘,列高靠 avatar 48 的 content minHeight;\n // 容器 + gap 控制間距)。form 保留 px-3 py-3 卡片內距。\n surface === 'upload-manager' ? 'rounded-md' : 'px-3 py-3 border border-divider rounded-md bg-surface',\n hoverClass,\n className,\n )}\n onClick={onClick}\n {...rowA11y}\n {...props}\n >\n {keyboardPrimaryAction}\n <Avatar src={thumbnailSrc} alt={name} size={AVATAR_SIZE} shape=\"square\" className=\"shrink-0\" />\n {/* Rich layout invariant(2026-04-23 user 校準):\n - content col minHeight = AVATAR_SIZE(48),確保 1-line desc 時內容 ≥ avatar 高\n - `justify-between`(有 bar)/`justify-center`(無 bar):\n * 1-line desc:label 頂 + progress bar 底 **自動對齊 avatar 頂/底**\n * 無 bar:content 垂直 center 對齊 avatar 中\n - `gap-2`:desc ↔ progress bar **至少 8px gap**(multi-line desc 時 bar 溢出仍保 8px)\n - row `items-start`:avatar top-align 作視覺引導(tight-stack box 內 item 邊界) */}\n <div\n className={cn(\n 'flex flex-col flex-1 min-w-0 gap-2',\n progressBar ? 'justify-between' : 'justify-center',\n )}\n style={{ minHeight: AVATAR_SIZE }}\n >\n {contentRow}\n {progressBar}\n </div>\n </div>\n )\n }\n\n // ── compact: py-2, bar absolute 底部 ──\n // 左右 padding 單一來源(SSOT):form=12px(= px-3);upload-manager=0(由面板提供 L/R)。\n // progress bar 是 absolute 定位,其 left/right 必須跟此值「同源」—— 否則 surface 一拿掉 padding,\n // bar 的 offset 沒同步就會對齊跑掉(2026-06-03 圖五 bug:原本 left/right 寫死 0.75rem 假設 px-3)。\n const compactPadX = surface === 'upload-manager' ? 0 : 12\n return (\n <div\n ref={ref}\n className={cn(\n // hover 底色瞬間切換,不做過渡(user 2026-09-10 拍板「第三題改成全部瞬間」;SSOT = tokens/motion/motion.spec.md「hover 回饋不做過渡」)\n 'group/row relative flex items-start gap-2 py-2 w-full text-body leading-compact rounded-md',\n compactStaticBg,\n // 2026-09-07 H1g:同 rich —— 只接隱形整列鈕,不接自帶 ring 的 trailing <Button>\n 'has-[[data-row-focus-target]:focus-visible]:ring-2 has-[[data-row-focus-target]:focus-visible]:ring-ring',\n hoverClass,\n className,\n )}\n style={{ paddingInline: compactPadX }}\n onClick={onClick}\n {...rowA11y}\n {...props}\n >\n {keyboardPrimaryAction}\n <ItemPrefix>\n <Paperclip size={ICON_PX} className=\"shrink-0 text-fg-muted\" aria-hidden />\n </ItemPrefix>\n {/* Compact 共用 contentRow(via ItemContent primitive SSOT)—— 先前 inline\n hand-craft 導致 compact label↔desc gap 跟 rich 不同步。shared contentRow\n 保證兩 mode 修 primitive 一處全同步。 */}\n <div className=\"flex flex-col flex-1 min-w-0\">\n {contentRow}\n </div>\n\n {/* ProgressBar: absolute 底部。left/right 與 compactPadX 同源:\n left = padX + icon + gap-2(0.5rem)對齊 label 首字;right = padX 收在 row 內緣。 */}\n {progressBar && (\n <div\n className=\"absolute bottom-0\"\n style={{ left: `calc(${compactPadX}px + ${ICON_PX}px + 0.5rem)`, right: compactPadX }}\n >\n {progressBar}\n </div>\n )}\n </div>\n )\n },\n)\nFileItem.displayName = 'FileItem'\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 fileItemMeta = {\n component: 'FileItem',\n family: 2,\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default'],\n tokens: {\n bg: ['bg-secondary', 'bg-surface'],\n fg: ['text-fg-muted', 'text-fg-secondary'],\n ring: [],\n },\n} as const\n\nexport { FileItem }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-item.js","sources":["../../../src/components/FileItem/file-item.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.\nimport * as React from 'react'\nimport { Paperclip, CircleCheck, XCircle, Download, RotateCw } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Avatar } from '@/design-system/components/Avatar/avatar'\nimport { Button } from '@/design-system/components/Button/button'\nimport { ProgressBar } from '@/design-system/components/ProgressBar/progress-bar'\nimport { ItemContent, ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { STACK_GAP_PX } from '@/design-system/tokens/uiSize/stack-gap'\n\n/**\n * FileItem — 檔案顯示 / 上傳進度\n *\n * Typography: 兩 mode 統一 scanning — text-body (14px) + leading-compact (1.3)(詳 spec「Typography」段,2026-04-23)\n *\n * 兩種 mode(精簡 vs 完整內容呈現):\n *\n * compact(★ default): Paperclip 16px 在左。右側 content + bar。\n * padding 詳 spec「Padding」表(form: px-3 py-2;surface=upload-manager: 列自帶左右 loose、上下 tight/2,\n * 面板 body 左右 0 —— 2026-09-25 待辦總帳 B12,可點的列滑過底色鋪到面板邊)。\n * description 只有 error 才顯示。\n * bar 跟文字左邊對齊(在 icon 右邊的 column 內)。\n *\n * rich: Avatar 48px square 在左(顯示檔案內容縮圖)。右側 content + bar。\n * 多行 description(size / status message)。\n * 有 bar → justify-between(bar 底部對齊 avatar)\n * 無 bar → justify-center(文字垂直置中對齊 avatar)\n *\n * status 可選。不傳 = 已上傳檔案(無 bar,可點擊下載)。\n * onClick → cursor-pointer + 滑過底色(只有點了會有反應的才加,依平常底色配對;詳 spec「滑過」段,待辦總帳 B12)。\n */\n\nconst STATUS_ICON = {\n completed: { icon: CircleCheck, color: 'text-success' },\n error: { icon: XCircle, color: 'text-error' },\n} as const\n\n// ProgressBar status 映射:uploading=inProgress(藍) / completed=success(綠) / error=error(紅)\n// 與 ProgressBar 元件的 status prop 對齊,不需再維護 PROGRESS_COLOR 本地 map。\nconst PROGRESS_STATUS_MAP = {\n uploading: 'inProgress',\n completed: 'success',\n error: 'error',\n} as const\n\nconst AVATAR_SIZE = 48\nconst ICON_PX = 16\n\nexport interface FileItemProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {\n name: string\n /**\n * 兩種呈現 mode(精簡 vs 完整):\n * - `compact`(預設):paperclip + filename 單行 inline\n * - `rich`:縮圖 + 檔名 + size + status + progress 的完整 card 呈現\n */\n mode?: 'compact' | 'rich'\n /**\n * 清單所在的 surface context(2026-06-03 codify rich-borderless):\n * - `form`(預設):rich = border card(自立輪廓,Slack/Notion/Linear attachment 慣例)\n * - `upload-manager`:rich = **無邊框**(Google Drive/Dropbox 上傳管理面板 —— 面板自身已是容器,\n * card border 多餘 = 雙層容器);avatar 作每筆 item 視覺邊界。compact 的進度條/灰底不受 surface 影響\n * (由 status 決定)。\n * surface-driven(非 status-driven):避免 form 內 rich 上傳中變無邊框、存好變 card 的邊框閃爍。\n * 列間 gap 由 List wrapper canonical 決定(form rich 8px / form compact 4px / upload-manager 0 —— 列自帶上下 tight/2,\n * 列間 ink 距仍 12,2026-09-25 待辦總帳 B12;見 spec)。\n */\n surface?: 'form' | 'upload-manager'\n status?: 'uploading' | 'completed' | 'error'\n progress?: number\n /** rich mode: 檔案大小、狀態訊息。compact: 只有 error 才顯示。 ReactNode 支援 inline clickable link(如「View log」)。 */\n description?: React.ReactNode\n thumbnailSrc?: string\n actions?: React.ReactNode\n onClick?: () => void\n /** 整列 primary action 的 accessible name;預設 `開啟 {name}`。 */\n actionAriaLabel?: string\n /**\n * Hover 動作(passive 狀態 icon 變互動 button 的 UX):\n * - `onDownload`:有值時,`status=\"completed\"` 的綠 ✓ icon 在 row hover 時\n * 換成 Download ↓ button;click 觸發 onDownload。無值保持 passive 綠 ✓。\n * - `onRetry`:有值時,`status=\"error\"` 的紅 ✗ icon 在 row hover 時換成 RotateCw ⟲\n * button;click 觸發 onRetry。無值保持 passive 紅 ✗。\n *\n * 世界級對照:Gmail / Slack / Dropbox 附件的 passive 狀態 → hover 變 action\n * 的 UX,使用者知道檔案狀態且能立即行動。\n */\n onDownload?: () => void\n onRetry?: () => void\n}\n\n// ── compact 進度條的左右位置(單一來源)──\n// 進度條本身(下方 compact 分支)與焦點框的挖空(fileItemRingCutoutStyle)都從這裡取,內距一改兩者一起動\n// (2026-06-03 圖五 bug:bar 的 left / right 寫死、內距一改就對不齊)。\n// form:左右 12px(= px-3)。upload-manager(2026-09-25 待辦總帳 B12):左右 loose(= 原本面板給的值,文字 x 不變)。\n// left = 內距 + icon + gap-2(0.5rem)→ 對齊 label 首字;right = 內距 → 收在列內緣。\nfunction compactBarInset(surface: FileItemProps['surface']) {\n const padX = surface === 'upload-manager' ? 'var(--layout-space-loose)' : '12px'\n return { padX, left: `calc(${padX} + ${ICON_PX}px + 0.5rem)`, right: padX }\n}\n\n/**\n * 焦點框在進度條兩端留的縫(px)= DS 通用的「疊在一起的兩樣東西」之間的縫(`tokens/uiSize/stack-gap.ts`,\n * 全域外描邊的 outline-offset、頭像堆疊的縫、步驟條外圈的縫都是同一個 token)。\n */\nconst BAR_RING_GAP_PX = STACK_GAP_PX\n\n/**\n * @internal\n * 焦點框的「框圖層」:與列同形同大的 `::before`(file-item.spec.md「焦點框 × 貼著列底的進度條」)。\n * 只在**列底貼著進度條**時用 —— form 的 compact 列有 status 時。upload-manager 的進度條離列底 tight/2、\n * rich 的進度條在內容區,都碰不到框,照舊把框畫在列上。\n * 為什麼要另一層:進度條住在列裡。框若畫在列上,列是進度條的祖先,遮罩會連進度條一起挖掉;\n * 畫在 `::before` 上,遮罩只挖框。層疊不變:`::before` 是第一個定位子層,進度條(absolute)仍畫在它上面;\n * 而且洞裡根本沒有框,進度條與框誰畫在上面都不影響結果(CSS UI 4 把 outline 的疊放順序留給瀏覽器自己決定,\n * 「The stacking of the rendering of these outlines is explicitly left up to implementations」)。\n * 這裡只有位置與遮罩,**不含觸發條件**:FileItem 自己的列由整列隱形鈕觸發、FileUpload 的清單列由列自己的\n * `:focus-visible` 觸發,各自在使用端寫。線寬、顏色、往內 2px、圓角全部照舊來自 `focus-ring-inset`\n * (`ds-canonical/references/focus-canonical.md`「框怎麼畫」),不是第四種幾何。\n */\nexport const FILE_ITEM_RING_LAYER_CLASS =\n 'before:absolute before:inset-0 before:rounded-[inherit] before:pointer-events-none before:[mask:var(--file-item-ring-cutout)]'\n\n/**\n * @internal\n * 框圖層的遮罩(`--file-item-ring-cutout`)。列底沒有貼著進度條時回 `undefined` —— 呼叫端據此照舊把框畫在列上。\n * 遮罩 = 三塊保留區的聯集:上半部整條 + 左段 + 右段。挖掉的是「進度條那一段(兩端各多 BAR_RING_GAP_PX)的下半部」,\n * 框在那個範圍裡只有底邊,所以挖掉的只有底邊那一段。露出來的是**真正在後面的東西**(列自己的滑過色、卡片、面板、頁面),\n * 不需要知道底色是什麼(與 `avatar.tsx` 頭像堆疊「挖空,不是外圈」同一個理由:深色的 `--surface` 本身半透明,\n * 墊任何固定底色都會在某種容器上錯色)。\n */\nexport function fileItemRingCutoutStyle({\n mode = 'compact',\n surface = 'form',\n status,\n}: Pick<FileItemProps, 'mode' | 'surface' | 'status'>): React.CSSProperties | undefined {\n if (mode !== 'compact' || surface === 'upload-manager' || !status) return undefined\n const { left, right } = compactBarInset(surface)\n const keep = 'linear-gradient(#000 0 0)' // 遮罩只看不透明度;顏色無意義\n return {\n ['--file-item-ring-cutout' as string]:\n `${keep} top / 100% 50% no-repeat, ` +\n `${keep} left / calc(${left} - ${BAR_RING_GAP_PX}px) 100% no-repeat, ` +\n `${keep} right / calc(${right} - ${BAR_RING_GAP_PX}px) 100% no-repeat`,\n }\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst FileItem = React.forwardRef<HTMLDivElement, FileItemProps>(\n (\n {\n name,\n mode = 'compact',\n surface = 'form',\n status,\n progress = 0,\n description,\n thumbnailSrc,\n actions,\n onClick,\n actionAriaLabel = `開啟 ${name}`,\n onDownload,\n onRetry,\n className,\n ...props\n },\n ref,\n ) => {\n const isRich = mode === 'rich'\n const hasStatus = !!status\n const statusConfig = status && status !== 'uploading' ? STATUS_ICON[status] : null\n const progressWidth = status === 'completed' ? 100 : progress\n\n // compact 只有 error 才顯示 description\n const showDesc = isRich ? !!description : (status === 'error' && !!description)\n\n // 滑過底色(2026-09-25 待辦總帳 B12;取代 2026-04-23「FileItem 永不顯示 hover-bg」)。\n // user 原話:「要點了會有反應的才加,並確保加上去之後不會有任何視覺奇怪的地方,且按鈕的互動樣式也是自然疊加上去吧?用再亮一層這樣的措辭是否不夠精準?」\n // → 只有傳了 onClick 的列 / 卡才有滑過底色;沒傳就沒有(✓→下載鈕的換位照舊,那顆鈕有自己的滑過色)。\n // 換上什麼色依「平常底色」配對(tokens/color/color.spec.md「Hover 換色配對總則」),直接寫在下方各 mode 的 cn() 裡、\n // 跟靜止底同一次呼叫 —— scripts/hover-own-pair-invariant.mjs 才看得到這一對:\n // rich + form 卡片 bg-surface(「底」)→ 底不換,疊一層 bg-interaction-hover\n // compact 小膠囊 bg-secondary → 換成自己的下一階 bg-secondary-hover\n // 透明的列(compact 有進度條、upload-manager 的列)→ 換成 bg-neutral-hover\n // 不加按住(active:)那一階:FileItem「列按下深一階」是待辦總帳 N4 / F 模型 D3(2),尚未提問(AI 推導:不先替 user 決定)。\n // 列內按鈕(刪除、✓→下載)滑過時換上自己的 neutral-hover(半透明),自然疊在列的滑過色上,不寫特例\n // (color.spec.md「巢狀滑過」段)。\n const isUploadManager = surface === 'upload-manager'\n\n // 消費 ProgressBar 元件(SSOT);不再自 roll bar。\n // compact mode 用 2px(極密集 row layout),rich mode 用預設 4px。這是 FileItem\n // 私有 composition 細節;ProgressBar 公開 API 維持單一 4px、沒有 height/size 軸。\n // a11y(2026-04-25 axe aria-progressbar-name):aria-label 用 file name 作 context。\n const progressBar = hasStatus ? (\n <ProgressBar\n value={progressWidth}\n status={PROGRESS_STATUS_MAP[status!]}\n className={isRich ? undefined : '!h-0.5'}\n aria-label={`${name} 上傳進度`}\n />\n ) : null\n\n // suffix 對齊 label 第一行(item-anatomy「24px 閾值對齊規則」小 suffix canonical):\n // icons 16 ≤ 24 屬小 suffix,統一 h-[1lh] inline(由 ItemSuffix primitive 提供),\n // 不因 desc wrap 改公式。兩 mode 同公式,跟 item-anatomy 一致。\n\n // Status slot 幾何(2026-04-23 user 統一):rich + compact 都用 `var(--field-height-xs)`(24)\n // 容器,裡面 Button xs iconOnly variant=\"text\"(auto data-unbounded)。\n // Compact 不影響 row 高度 = suffix wrapper 的 data-unbounded CSS 讓 Button layout\n // 收斂到 1lh(同 compact row 內容高),視覺與命中區仍 24(命中 ≡ 可視,見\n // ds-canonical/references/hit-area-canonical.md;2026-09-24 把原文的「touch target」正名為命中區)。\n const slotHw = 'var(--field-height-xs)'\n\n const hoverAction =\n status === 'completed' && onDownload ? { icon: Download, onClick: onDownload, label: `下載 ${name}` } :\n status === 'error' && onRetry ? { icon: RotateCw, onClick: onRetry, label: `重試 ${name}` } :\n null\n\n const statusSlot = statusConfig ? (\n <span\n data-unbounded=\"true\"\n className=\"relative inline-flex items-center justify-center shrink-0\"\n style={{ width: slotHw, height: slotHw }}\n >\n {/* Passive 狀態 icon:預設可見;若有 hover-swap,row-hover 時瞬間隱藏、換上操作鈕(不淡出;\n tokens/motion/motion.spec.md「hover 回饋不做過渡」,2026-09-26 延伸到滑過才出現的按鈕,待辦總帳 L9 / N4(3)) */}\n <statusConfig.icon\n size={ICON_PX}\n className={cn(\n 'shrink-0',\n statusConfig.color,\n // 2026-07-05 D4:鍵盤 focus 同步觸發 swap(:has(:focus-visible),對齊 item-anatomy SUFFIX_HOVER_REVEAL_BY_GROUP SSOT)\n hoverAction && 'group-hover/row:opacity-0 group-has-[:focus-visible]/row:opacity-0',\n )}\n aria-hidden\n />\n {/* Active action:row-hover 時瞬間出現(不淡入,同上;rich + compact 同 Button xs 統一) */}\n {hoverAction && (\n <Button\n variant=\"text\"\n size=\"xs\"\n iconOnly\n startIcon={hoverAction.icon}\n aria-label={hoverAction.label}\n onClick={(e) => { e.stopPropagation(); hoverAction.onClick() }}\n className=\"absolute inset-0 opacity-0 group-hover/row:opacity-100 group-has-[:focus-visible]/row:opacity-100\"\n />\n )}\n </span>\n ) : null\n\n // 2026-07-16 dim 39/DA3:消費 ItemSuffix primitive(照 Notice 2026-06-15 已遷模式)。\n // ItemSuffix base geometry(h-[1lh] shrink-0 ml-auto flex items-center gap-2)= 原手刻\n // div 的 flex items-center gap-2 shrink-0 h-[1lh];多出的 ml-auto 為 no-op(左鄰\n // ItemContent 是 flex-1,已把 suffix 推到右緣)→ 像素相等。hoverReveal 預設 false,\n // 不干擾本檔自有的 statusSlot hover-swap 機制(group-hover/row 系)。\n const suffix = (\n <ItemSuffix\n className={cn(\n // data-unbounded chrome-canonical trick:let Button xs (24) live inside h-[1lh]\n // wrapper(compact ~18.2 / rich ~18.2 scanning)without pushing row height。\n // 視覺/hit area 仍 24,layout footprint 收斂到 1lh。同 overlay-surface\n // 的 SurfaceHeader dismiss canonical(2026-04-22 v5)。\n // **child selector `[&>[data-unbounded]]`(非 descendant)**:只針對 suffix\n // wrapper **直接子元素**(statusSlot span、actions Button)套 margin,\n // 避免 status slot 內部 hover-swap Button(nested)也套造成 layout 跳動。\n '[&>[data-unbounded]]:my-[calc((1lh-var(--field-height-xs))/2)]',\n )}\n >\n {status === 'uploading' && isRich && (\n <span className=\"text-fg-secondary tabular-nums\">{progress}%</span>\n )}\n {statusSlot}\n {/* **動作鈕不搶整列 click,由元件自己吃掉,不要求 consumer 每次記得**(2026-09-24)。\n Canonical 早就寫了:`patterns/element-anatomy/item-anatomy.spec.md`「suffix 可以塞什麼」表的 Inline Action 列\n 「明確點擊靶子 ≤ 24px,`stopPropagation` 避免搶 row click」。\n 但先前只有 FileItem **自家**的 hover-swap 鈕做到(本檔 statusSlot 裡 `hoverAction` 那顆 Button 的 `stopPropagation`),consumer 從 `actions`\n 傳進來的鈕沒有任何人做 —— 於是「點刪除 → 整列 onClick 也跟著跑 → 檔案被開起來」\n 在我們自己的示範裡活到今天(實測:`已上傳` 這則點刪除鈕,FileViewer 就開)。\n 同一列同時有整列 onClick 和 trailing action 時,這是**必然**會犯的錯,所以答案不是\n 在文件裡要 consumer 記得,而是元件內部把邊界劃好(同 `agent-panel.tsx` 選項卡裡「其他(自由輸入)」輸入框的\n `stopPropagation` / `data-table.tsx` 選取欄 `cellEl` 裡 Checkbox 與 RadioGroupItem 的 `stopPropagation`)。\n **只包 `actions`、不包整個 suffix**:suffix 裡的 `{progress}%` 與被動狀態圖示是唯讀\n metadata,item-anatomy「suffix 可以塞什麼」表明寫唯讀 metadata「不搶 row click target」\n = 點它仍該開整列,所以那兩個不進這層。\n `data-unbounded` 掛在**這一層**:上面那條 `[&>[data-unbounded]]` 只認 ItemSuffix 的\n **直接**子元素;包一層之後負 margin 的承接者換成本層,否則 24 高的鈕會把 compact 列撐高。\n 實測 compact / rich / upload-manager 三則的列高、suffix 高、鈕的座標與尺寸改前改後逐項相同。 */}\n {actions && (\n <span\n data-unbounded=\"true\"\n className=\"inline-flex items-center gap-2\"\n onClick={(e) => e.stopPropagation()}\n >\n {actions}\n </span>\n )}\n </ItemSuffix>\n )\n\n // content row — 消費 ItemContent primitive(封裝 label + desc + mt-gap token SSOT)。\n // 兩 mode 共用:primitive 改 → 兩 mode 同步,不需 grep。\n // typography:scanning mode(2026-04-23 user 指示)—— label body(14/1.3) + desc caption(12/1.3);\n // row 本身加 `leading-compact` 配合 scanning idiom(同 MenuItem row)。\n const contentRow = (\n <div className=\"flex items-start gap-2\">\n <ItemContent\n label={name}\n description={showDesc ? description : undefined}\n mode=\"scanning\"\n descriptionTone={status === 'error' ? 'error' : 'secondary'}\n />\n {suffix}\n </div>\n )\n\n // a11y nested-interactive contract:row 含 hover-swap / trailing action buttons,故 row\n // 本身不可設 role=button + tabIndex。Primary keyboard path 由下方 sibling native button\n // 承接;mouse 仍由 row onClick 承接,兩者皆呼叫同一 callback。\n const rowA11y = {}\n\n // Compact 靜態背景(AR20):無 status(= 無進度條)→ `bg-secondary`(= neutral-3)作「檔案已上傳 /\n // 靜態列表」視覺區隔,跟「上傳中(有 progress bar)」對照;寫在下方 compact 的 cn() 裡(`!hasStatus &&`),\n // 跟它的滑過配對同一次呼叫(見上方「滑過底色」段)。\n // **為什麼用 semantic 的 bg-secondary、不直接寫 neutral 第 3 階的 primitive 名**:primitive token\n // `--color-neutral-3` 沒經 `@theme inline` 橋接,拿它當 utility 會 silent 失效;`bg-secondary` 是 semantic\n // token 橋接的 utility(見 `tokens/color/semantic.css`@theme inline),底色同樣指向 `--color-neutral-3`。\n // 對齊 Badge low / ProgressBar track SSOT。\n // Primary row action 與 trailing actions 是 sibling controls,不把整列設成 role=button,\n // 因此不會形成 nested-interactive。透明 full-row button 只接 keyboard/focus;pointer\n // 仍由既有 row onClick 接手,保持 hit area 與 consumer callback contract 不變。\n const keyboardPrimaryAction = onClick ? (\n <button\n type=\"button\"\n aria-label={actionAriaLabel}\n // 整列焦點框的唯一觸發者(見上方兩處 has-[[data-row-focus-target]:focus-visible])。\n // 它自己不畫框(opacity-0),指示器畫在列上 —— focus-canonical 認可的「指示器畫在別的元素上」。\n data-row-focus-target=\"\"\n className=\"absolute inset-0 opacity-0 pointer-events-none\"\n onClick={(event) => {\n event.stopPropagation()\n onClick()\n }}\n />\n ) : null\n\n // ── rich(含縮圖完整呈現)——AR17 canonical:surface=form 加邊框 card / surface=upload-manager 無邊框 ──\n // Rich surface=form 是「檔案 card」風格,外框讓每個 row 視覺上是獨立 card(Slack / Notion /\n // Linear attachment 慣例);surface=upload-manager 無邊框,avatar 作 item 邊界(面板自身是容器,\n // 見 file-item.spec.md「邊框 / 背景」表)\n if (isRich) {\n return (\n <div\n ref={ref}\n className={cn(\n // hover 底色瞬間切換,不做過渡(user 2026-09-10 拍板「第三題改成全部瞬間」;SSOT = tokens/motion/motion.spec.md「hover 回饋不做過渡」)\n 'group/row relative flex items-start gap-2 w-full text-body leading-compact',\n // 2026-09-07 H1g:限定只接下面那顆隱形整列鈕(keyboardPrimaryAction)。\n // 原本裸寫 `has-[:focus-visible]` 不分對象,trailing action 的 <Button> 被聚焦時整列也跟著畫 →\n // 一次互動兩個焦點框,違反 focus-canonical「一個項目只有一個指示器」。當時 <Button> 自帶\n // ring;2026-09-16 a7b2be94 起它不再自帶焦點 class、改吃全域外描邊,但限定的理由不變。\n // 幾何(2026-09-24 user 拍板「可以照你建議內描邊」):**內描邊**。原本寫的 `ring-2 ring-ring`\n // 是 2026-09-07 就退役的第二套機制,只因閘的舊 regex 只認裸寫的 `focus-visible:ring-2`、\n // 不認這裡的 `has-[…:focus-visible]:` 括號變體才活到今天(該洞同日已補,見\n // scripts/focus-geometry-invariant.mjs R2)。\n // **理由是結構性的**:拿到焦點的是下面那顆 `opacity-0` 的隱形整列鈕,它自己畫不出框,\n // 指示器改畫在列上 —— 這是 focus-canonical「刻意不畫的唯一合法理由是指示器畫在別的元素上,\n // 而且必須指得出承擔者」認可的形狀,承擔者就是本行所在的這個列 div。全域外描邊只作用在\n // 「被聚焦的那個元素」身上,套不到非焦點的列;能掛在列上的只有 focus-ring-inset 與填色專用的\n // focus-ring-inset-emphasis,列不是主色填色 → focus-ring-inset。\n // **不是**靠四周淨空不足,也**不是**引用 item-anatomy「選中 × 互動疊加」表那句「列撐滿容器寬度,\n // 左右沒有 2px 可以往外長」(那格的消費者清單沒有 FileItem):表單的列有圓角、列間 4–12px;\n // 上傳管理器的列 2026-09-25 起鋪滿面板寬、列間 0(B12)—— 兩種幾何都用內描邊,理由只有上面那條結構性的\n // (2026-09-24 審查抓到舊句把「淨空」當理由,勿寫回)。\n // 也**不是**因為捲動容器會裁切 —— 捲動與否明文不進判準。\n 'has-[[data-row-focus-target]:focus-visible]:focus-ring-inset',\n // surface=form → border card(自立輪廓);surface=upload-manager → 無邊框(box 自身是容器,\n // avatar 作 item 邊界)。2026-06-03 codify rich-borderless(原僅 spec 旁註,consumer 自己移除)。form 保留 px-3 py-3 卡片內距。\n surface === 'upload-manager'\n // 上傳管理器的列(2026-09-25 待辦總帳 B12,推翻 2026-06-03「左右拿掉交給容器」):可點的列滑過底色要鋪到\n // 面板左右邊,所以左右 gutter 改由列自己帶、面板 body 給 0(判準 = overlay-surface.spec.md「誰負責左右 gutter」);\n // 值 = 原本面板給的 loose → 縮圖與文字的 x 不變。上下各 tight/2、面板 body 上下也給 tight/2、列間 0 ——\n // 邊緣→縮圖、縮圖→縮圖仍是 tight,滑過底色上下各留 tight/2、不貼縮圖。\n // 不加圓角:列鋪滿面板寬,圓角碰到面板的直邊會缺角(同 MenuItem 滿版列;AI 推導)。\n ? 'px-[var(--layout-space-loose)] py-[calc(var(--layout-space-tight)/2)]'\n : 'px-3 py-3 border border-divider rounded-md bg-surface',\n onClick && 'cursor-pointer',\n // 滑過(B12,見上方「滑過底色」段):上傳列平常透明 → 換成 neutral-hover;表單卡片平常是「底」bg-surface → 疊一層\n onClick && (surface === 'upload-manager' ? 'hover:bg-neutral-hover' : 'hover:bg-interaction-hover'),\n className,\n )}\n onClick={onClick}\n {...rowA11y}\n {...props}\n >\n {keyboardPrimaryAction}\n <Avatar src={thumbnailSrc} alt={name} size={AVATAR_SIZE} shape=\"square\" className=\"shrink-0\" />\n {/* Rich layout invariant(2026-04-23 user 校準):\n - content col minHeight = AVATAR_SIZE(48),確保 1-line desc 時內容 ≥ avatar 高\n - `justify-between`(有 bar)/`justify-center`(無 bar):\n * 1-line desc:label 頂 + progress bar 底 **自動對齊 avatar 頂/底**\n * 無 bar:content 垂直 center 對齊 avatar 中\n - `gap-2`:desc ↔ progress bar **至少 8px gap**(multi-line desc 時 bar 溢出仍保 8px)\n - row `items-start`:avatar top-align 作視覺引導(tight-stack box 內 item 邊界) */}\n <div\n className={cn(\n 'flex flex-col flex-1 min-w-0 gap-2',\n progressBar ? 'justify-between' : 'justify-center',\n )}\n style={{ minHeight: AVATAR_SIZE }}\n >\n {contentRow}\n {progressBar}\n </div>\n </div>\n )\n }\n\n // ── compact: bar absolute 底部 ──\n // 內距單一來源(SSOT):progress bar 是 absolute 定位,其 left / right / bottom 必須跟列的內距「同源」——\n // 左右取自 compactBarInset(與焦點框的挖空共用,見檔案上方),上下見下:\n // form:上下 py-2,bar 貼列底。\n // upload-manager(2026-09-25 待辦總帳 B12,推翻 2026-06-03 的「左右 0、交給面板」):可點的列滑過底色要鋪到面板\n // 左右邊,所以左右改由列自己帶 loose(= 原本面板給的值,文字 x 不變)、面板 body 給 0。\n // 上 tight/2、下 tight/2 + 0.5rem(0.5rem = 原 py-2 下緣那 8:文字↔bar 6 + bar 2),bar 離列底 tight/2;\n // 面板 body 上下也給 tight/2、列間 0 → 邊緣→文字、bar→下一列文字、bar→邊緣仍全是 tight(與 06-03 同值),\n // 滑過底色則上下各留 tight/2,bar 不貼底色邊。\n const { padX: compactPadX, left: compactBarLeft, right: compactBarRight } = compactBarInset(surface)\n const compactBarBottom = isUploadManager ? 'calc(var(--layout-space-tight) / 2)' : '0px'\n const compactPadBlock = isUploadManager\n ? { paddingTop: 'calc(var(--layout-space-tight) / 2)', paddingBottom: 'calc(var(--layout-space-tight) / 2 + 0.5rem)' }\n : undefined\n // 列底貼著進度條(form + 有 status)→ 框改畫在框圖層、進度條那段挖空;否則 undefined,框照舊畫在列上(見下方 className)\n const ringCutout = fileItemRingCutoutStyle({ mode, surface, status })\n return (\n <div\n ref={ref}\n className={cn(\n // hover 底色瞬間切換,不做過渡(user 2026-09-10 拍板「第三題改成全部瞬間」;SSOT = tokens/motion/motion.spec.md「hover 回饋不做過渡」)\n 'group/row relative flex items-start gap-2 w-full text-body leading-compact',\n // form 的列是圓角膠囊 / 圓角列;upload-manager 的列鋪滿面板寬 → 不加圓角(同 rich,AI 推導),上下內距見上方 compactPadBlock\n !isUploadManager && 'py-2 rounded-md',\n !hasStatus && 'bg-secondary',\n // 2026-09-07 H1g:同 rich —— 只接隱形整列鈕,不接同樣會畫框的 trailing <Button>;\n // 幾何同 rich 的內描邊(結構性理由見上方那段)。\n // **列底貼著進度條時,框畫在框圖層 ::before**(2026-09-26,file-item.spec.md「焦點框 × 貼著列底的進度條」)。\n // 進度條是 absolute,本來就畫在框的**上面**,正好落在內描邊底邊那 2px 上 —— 但它沒有「蓋住」框:\n // 軌道 --secondary 是半透明,框的藍從軌道透出來;填色 --info 又與框 --ring 同為 blue-6,與框黏成一條\n // (實測聚焦時填色對軌道 1.10:1,平常 4.55:1;深色 1.17 / 4.04)。框圖層在進度條那一段(兩端各多 2px 縫)\n // 挖空,露出真正的底:聚焦時進度條與平常逐像素相同,進度條的頭尾與框之間各隔一道底色的縫。\n // upload-manager 的 bar 離列底 tight/2、碰不到框 → ringCutout 為 undefined,框照舊畫在列上。\n ringCutout\n ? [FILE_ITEM_RING_LAYER_CLASS, 'has-[[data-row-focus-target]:focus-visible]:before:focus-ring-inset']\n : 'has-[[data-row-focus-target]:focus-visible]:focus-ring-inset',\n onClick && 'cursor-pointer',\n // 滑過(B12,見上方「滑過底色」段):有進度條的列平常透明 → 換成 neutral-hover;\n // 靜態小膠囊平常是 bg-secondary → 換成它自己的下一階 secondary-hover(不借透明底的配對)\n onClick && (hasStatus ? 'hover:bg-neutral-hover' : 'hover:bg-secondary-hover'),\n className,\n )}\n style={{ paddingInline: compactPadX, ...compactPadBlock, ...ringCutout }}\n onClick={onClick}\n {...rowA11y}\n {...props}\n >\n {keyboardPrimaryAction}\n <ItemPrefix>\n <Paperclip size={ICON_PX} className=\"shrink-0 text-fg-muted\" aria-hidden />\n </ItemPrefix>\n {/* Compact 共用 contentRow(via ItemContent primitive SSOT)—— 先前 inline\n hand-craft 導致 compact label↔desc gap 跟 rich 不同步。shared contentRow\n 保證兩 mode 修 primitive 一處全同步。 */}\n <div className=\"flex flex-col flex-1 min-w-0\">\n {contentRow}\n </div>\n\n {/* ProgressBar: absolute 底部。left / right 取自 compactBarInset(與焦點框的挖空同源),bottom 與列內距同源:\n left = padX + icon + gap-2(0.5rem)對齊 label 首字;right = padX 收在 row 內緣;\n bottom = form 0(貼列底,聚焦時框在這一段挖空,見上方 className)/ upload-manager tight/2(B12,見上方內距段)。 */}\n {progressBar && (\n <div\n className=\"absolute\"\n style={{ left: compactBarLeft, right: compactBarRight, bottom: compactBarBottom }}\n >\n {progressBar}\n </div>\n )}\n </div>\n )\n },\n)\nFileItem.displayName = 'FileItem'\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 fileItemMeta = {\n component: 'FileItem',\n family: 2,\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default'],\n tokens: {\n bg: ['bg-secondary', 'bg-surface'],\n fg: ['text-fg-muted', 'text-fg-secondary'],\n ring: ['focus-ring-inset'],\n },\n} as const\n\nexport { FileItem }\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
- import { FileItem, fileItemMeta } from "./file-item.js";
1
+ import { FILE_ITEM_RING_LAYER_CLASS, FileItem, fileItemMeta, fileItemRingCutoutStyle } from "./file-item.js";
2
2
  export {
3
+ FILE_ITEM_RING_LAYER_CLASS,
3
4
  FileItem,
4
- fileItemMeta
5
+ fileItemMeta,
6
+ fileItemRingCutoutStyle
5
7
  };
6
8
  //# sourceMappingURL=index.js.map
@@ -110,7 +110,7 @@ export declare const fileUploadMeta: {
110
110
  readonly tokens: {
111
111
  readonly bg: readonly ["bg-surface", "bg-disabled"];
112
112
  readonly fg: readonly [];
113
- readonly ring: readonly ["ring-ring"];
113
+ readonly ring: readonly ["--ring"];
114
114
  };
115
115
  };
116
116
  export { FileUpload };
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.d.ts","sourceRoot":"","sources":["../../../src/components/FileUpload/file-upload.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;IAC5C,oCAAoC;IACpC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC3F,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAA;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC/B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC1B,yFAAyF;IACzF,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,4EAA4E;IAC5E,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAC3C;AAYD,QAAA,MAAM,UAAU,wFAoQf,CAAA;AA0BD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;CAiBjB,CAAA;AAEV,OAAO,EAAE,UAAU,EAAE,CAAA"}
1
+ {"version":3,"file":"file-upload.d.ts","sourceRoot":"","sources":["../../../src/components/FileUpload/file-upload.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAkB9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,OAAO,CAAA;IAC5C,oCAAoC;IACpC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,kCAAkC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC;IAC3F,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAA;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAA;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IAC/B,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gCAAgC;IAChC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAA;IAC1B,yFAAyF;IACzF,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,4EAA4E;IAC5E,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAC3C;AA6BD,QAAA,MAAM,UAAU,wFA2Wf,CAAA;AA0BD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;CAiBjB,CAAA;AAEV,OAAO,EAAE,UAAU,EAAE,CAAA"}