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

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 (481) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  50. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  51. package/dist/components/DataTable/data-table-filter-panel.js +3 -4
  52. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  53. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  54. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  55. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  56. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  57. package/dist/components/DataTable/data-table.d.ts +1 -1
  58. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  59. package/dist/components/DataTable/data-table.js +44 -32
  60. package/dist/components/DataTable/data-table.js.map +1 -1
  61. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  62. package/dist/components/DatePicker/date-picker.js +4 -4
  63. package/dist/components/DatePicker/date-picker.js.map +1 -1
  64. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  65. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  66. package/dist/components/DescriptionList/description-list.js +6 -6
  67. package/dist/components/DescriptionList/description-list.js.map +1 -1
  68. package/dist/components/Dialog/dialog.d.ts +2 -2
  69. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  70. package/dist/components/Dialog/dialog.js.map +1 -1
  71. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  72. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  73. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  74. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  75. package/dist/components/Field/field-context.d.ts +16 -10
  76. package/dist/components/Field/field-context.d.ts.map +1 -1
  77. package/dist/components/Field/field-context.js.map +1 -1
  78. package/dist/components/Field/field-types.d.ts +2 -2
  79. package/dist/components/Field/field-types.d.ts.map +1 -1
  80. package/dist/components/Field/field-types.js.map +1 -1
  81. package/dist/components/Field/field-wrapper.d.ts +20 -4
  82. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  83. package/dist/components/Field/field-wrapper.js +30 -31
  84. package/dist/components/Field/field-wrapper.js.map +1 -1
  85. package/dist/components/Field/field.d.ts +1 -1
  86. package/dist/components/Field/field.d.ts.map +1 -1
  87. package/dist/components/Field/field.js +25 -3
  88. package/dist/components/Field/field.js.map +1 -1
  89. package/dist/components/Field/use-form-validation.d.ts +1 -1
  90. package/dist/components/Field/use-form-validation.js.map +1 -1
  91. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  92. package/dist/components/FileItem/file-item.js +2 -5
  93. package/dist/components/FileItem/file-item.js.map +1 -1
  94. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  95. package/dist/components/FileUpload/file-upload.js +5 -1
  96. package/dist/components/FileUpload/file-upload.js.map +1 -1
  97. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  98. package/dist/components/FileViewer/file-viewer.js +2 -1
  99. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  100. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  101. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  102. package/dist/components/HoverCard/hover-card.js +4 -2
  103. package/dist/components/HoverCard/hover-card.js.map +1 -1
  104. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  105. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  106. package/dist/components/InlineEdit/inline-edit.js +104 -62
  107. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  108. package/dist/components/Input/input.d.ts +1 -1
  109. package/dist/components/Input/input.d.ts.map +1 -1
  110. package/dist/components/Input/input.js +6 -6
  111. package/dist/components/Input/input.js.map +1 -1
  112. package/dist/components/LinkInput/link-input.d.ts +5 -5
  113. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  114. package/dist/components/LinkInput/link-input.js +3 -3
  115. package/dist/components/LinkInput/link-input.js.map +1 -1
  116. package/dist/components/Notice/notice.d.ts +17 -1
  117. package/dist/components/Notice/notice.d.ts.map +1 -1
  118. package/dist/components/Notice/notice.js +7 -1
  119. package/dist/components/Notice/notice.js.map +1 -1
  120. package/dist/components/NumberInput/number-input.d.ts +1 -1
  121. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  122. package/dist/components/NumberInput/number-input.js +12 -1
  123. package/dist/components/NumberInput/number-input.js.map +1 -1
  124. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  125. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  126. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  127. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  128. package/dist/components/PeoplePicker/people-picker.js +7 -5
  129. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  130. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  131. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  132. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  133. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  134. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  135. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  136. package/dist/components/RadioGroup/radio-group.js +1 -1
  137. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  138. package/dist/components/Rating/rating.d.ts.map +1 -1
  139. package/dist/components/Rating/rating.js +4 -0
  140. package/dist/components/Rating/rating.js.map +1 -1
  141. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  142. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  143. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  144. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  145. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  146. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  147. package/dist/components/Select/select.d.ts +16 -6
  148. package/dist/components/Select/select.d.ts.map +1 -1
  149. package/dist/components/Select/select.js +17 -5
  150. package/dist/components/Select/select.js.map +1 -1
  151. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  152. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  153. package/dist/components/SelectMenu/select-menu.js +17 -3
  154. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  155. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  156. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  157. package/dist/components/Sheet/sheet.d.ts +2 -2
  158. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  159. package/dist/components/Sheet/sheet.js.map +1 -1
  160. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  161. package/dist/components/Sidebar/sidebar.js +2 -2
  162. package/dist/components/Sidebar/sidebar.js.map +1 -1
  163. package/dist/components/Slider/slider.d.ts.map +1 -1
  164. package/dist/components/Slider/slider.js +6 -3
  165. package/dist/components/Slider/slider.js.map +1 -1
  166. package/dist/components/Steps/steps.d.ts +6 -4
  167. package/dist/components/Steps/steps.d.ts.map +1 -1
  168. package/dist/components/Steps/steps.js +19 -5
  169. package/dist/components/Steps/steps.js.map +1 -1
  170. package/dist/components/Switch/switch.d.ts +4 -4
  171. package/dist/components/Switch/switch.d.ts.map +1 -1
  172. package/dist/components/Switch/switch.js +3 -1
  173. package/dist/components/Switch/switch.js.map +1 -1
  174. package/dist/components/Tabs/tabs.d.ts +1 -1
  175. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  176. package/dist/components/Tabs/tabs.js +73 -23
  177. package/dist/components/Tabs/tabs.js.map +1 -1
  178. package/dist/components/Tag/tag.d.ts +3 -1
  179. package/dist/components/Tag/tag.d.ts.map +1 -1
  180. package/dist/components/Tag/tag.js +2 -2
  181. package/dist/components/Tag/tag.js.map +1 -1
  182. package/dist/components/Textarea/textarea.d.ts +4 -4
  183. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  184. package/dist/components/Textarea/textarea.js +15 -15
  185. package/dist/components/Textarea/textarea.js.map +1 -1
  186. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  187. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  188. package/dist/components/TimePicker/time-picker.js +8 -5
  189. package/dist/components/TimePicker/time-picker.js.map +1 -1
  190. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  191. package/dist/components/Tooltip/tooltip.js +27 -23
  192. package/dist/components/Tooltip/tooltip.js.map +1 -1
  193. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  194. package/dist/components/TreeView/tree-view.js +16 -0
  195. package/dist/components/TreeView/tree-view.js.map +1 -1
  196. package/dist/index.d.ts +7 -7
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +6 -13
  199. package/dist/index.js.map +1 -1
  200. package/dist/lib/drag-visual.d.ts +2 -2
  201. package/dist/lib/drag-visual.js.map +1 -1
  202. package/dist/lib/utils.d.ts +1 -0
  203. package/dist/lib/utils.d.ts.map +1 -1
  204. package/dist/lib/utils.js +21 -1
  205. package/dist/lib/utils.js.map +1 -1
  206. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  207. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  208. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  209. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  210. package/dist/tokens/categorical-color.d.ts +3 -3
  211. package/dist/tokens/categorical-color.d.ts.map +1 -1
  212. package/dist/tokens/categorical-color.js +2 -2
  213. package/dist/tokens/categorical-color.js.map +1 -1
  214. package/ds-canonical/fork/AGENTS.md +213 -0
  215. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  216. package/ds-canonical/fork/codex/hooks.json +16 -0
  217. package/ds-canonical/fork/governance.lock +22 -7
  218. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  219. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  220. package/ds-canonical/fork/manifest.json +10 -1
  221. package/ds-canonical/fork/preamble.md +3 -2
  222. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  223. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  224. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  225. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  226. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  227. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +19 -2
  228. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  229. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  230. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  232. package/ds-canonical/references/certified-surfaces.md +20 -0
  233. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  234. package/ds-canonical/references/principle-dim-map.json +20 -2
  235. package/ds-canonical/references/props-naming.md +2 -1
  236. package/ds-canonical/references/ssot-index.md +2 -2
  237. package/ds-canonical/references/story-baseline-registry.json +2 -2
  238. package/ds-canonical/rules/story-rules.md +1 -1
  239. package/ds-canonical/rules/ui-development.md +2 -1
  240. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  241. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  242. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  243. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  244. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  245. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  246. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  247. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  248. package/ds-story-manifest.json +21 -21
  249. package/llms-full.txt +3 -3
  250. package/llms.txt +1 -1
  251. package/package.json +2 -1
  252. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  253. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  254. package/src/components/Accordion/accordion.spec.md +10 -1
  255. package/src/components/Accordion/accordion.stories.tsx +10 -5
  256. package/src/components/Accordion/accordion.tsx +7 -2
  257. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  258. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  259. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  260. package/src/components/AppShell/app-shell.spec.md +4 -0
  261. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  262. package/src/components/Avatar/avatar.tsx +1 -1
  263. package/src/components/Badge/badge.spec.md +2 -2
  264. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  265. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  266. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  267. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  268. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  269. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  270. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  271. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  272. package/src/components/Button/button-group.tsx +4 -4
  273. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  274. package/src/components/Button/button.principles.stories.tsx +1 -1
  275. package/src/components/Button/button.spec.md +2 -2
  276. package/src/components/Button/button.stories.tsx +22 -28
  277. package/src/components/Button/button.tsx +2 -1
  278. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  279. package/src/components/Calendar/calendar.spec.md +1 -1
  280. package/src/components/Carousel/carousel.spec.md +17 -1
  281. package/src/components/Carousel/carousel.tsx +93 -42
  282. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  283. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  284. package/src/components/Checkbox/checkbox.spec.md +12 -3
  285. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  286. package/src/components/Checkbox/checkbox.tsx +79 -19
  287. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  288. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  289. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  290. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  291. package/src/components/Combobox/combobox.spec.md +6 -2
  292. package/src/components/Combobox/combobox.stories.tsx +9 -36
  293. package/src/components/Combobox/combobox.tsx +42 -27
  294. package/src/components/Command/command.spec.md +3 -3
  295. package/src/components/Command/command.tsx +9 -2
  296. package/src/components/DataTable/cell-registry.tsx +75 -76
  297. package/src/components/DataTable/column-types.ts +4 -17
  298. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  299. package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
  300. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  301. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  302. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  303. package/src/components/DataTable/data-table.css +2 -3
  304. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  305. package/src/components/DataTable/data-table.spec.md +8 -7
  306. package/src/components/DataTable/data-table.stories.tsx +39 -29
  307. package/src/components/DataTable/data-table.tsx +90 -67
  308. package/src/components/DataTable/filter-operators.spec.md +2 -0
  309. package/src/components/DateGrid/date-grid.spec.md +1 -1
  310. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  311. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  312. package/src/components/DatePicker/date-picker.spec.md +10 -9
  313. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  314. package/src/components/DatePicker/date-picker.tsx +13 -13
  315. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  316. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  317. package/src/components/DescriptionList/description-list.spec.md +12 -12
  318. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  319. package/src/components/DescriptionList/description-list.tsx +10 -10
  320. package/src/components/Dialog/dialog.tsx +4 -1
  321. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  322. package/src/components/Empty/empty.spec.md +0 -1
  323. package/src/components/Field/field-context.ts +17 -11
  324. package/src/components/Field/field-controls.spec.md +46 -37
  325. package/src/components/Field/field-types.ts +14 -12
  326. package/src/components/Field/field-wrapper.tsx +59 -43
  327. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  328. package/src/components/Field/field.principles.stories.tsx +5 -28
  329. package/src/components/Field/field.spec.md +5 -4
  330. package/src/components/Field/field.stories.tsx +103 -72
  331. package/src/components/Field/field.tsx +36 -4
  332. package/src/components/Field/form-validation.spec.md +4 -0
  333. package/src/components/Field/use-form-validation.ts +1 -1
  334. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  335. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  336. package/src/components/FileItem/file-item.tsx +10 -8
  337. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  338. package/src/components/FileUpload/file-upload.spec.md +3 -2
  339. package/src/components/FileUpload/file-upload.tsx +5 -1
  340. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  342. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  343. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  344. package/src/components/FileViewer/file-viewer.tsx +3 -2
  345. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  346. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  347. package/src/components/HoverCard/hover-card.spec.md +2 -2
  348. package/src/components/HoverCard/hover-card.tsx +4 -2
  349. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  350. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  351. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  352. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  353. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  354. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  355. package/src/components/Input/input.principles.stories.tsx +3 -3
  356. package/src/components/Input/input.spec.md +4 -4
  357. package/src/components/Input/input.stories.tsx +3 -3
  358. package/src/components/Input/input.tsx +13 -13
  359. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  360. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  361. package/src/components/LinkInput/link-input.spec.md +6 -2
  362. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  363. package/src/components/LinkInput/link-input.tsx +21 -19
  364. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  365. package/src/components/Notice/notice.tsx +8 -2
  366. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  367. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  368. package/src/components/NumberInput/number-input.spec.md +6 -6
  369. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  370. package/src/components/NumberInput/number-input.tsx +17 -5
  371. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  372. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  373. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  374. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  375. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  376. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  377. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  378. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  379. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  380. package/src/components/PeoplePicker/person-display.tsx +3 -3
  381. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  382. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  383. package/src/components/Popover/popover.spec.md +4 -2
  384. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  385. package/src/components/ProfileCard/profile-card.tsx +1 -1
  386. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  387. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  388. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  389. package/src/components/README.md +1 -0
  390. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  391. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  392. package/src/components/RadioGroup/radio-group.tsx +19 -14
  393. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  394. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  395. package/src/components/Rating/rating.spec.md +2 -2
  396. package/src/components/Rating/rating.stories.tsx +4 -18
  397. package/src/components/Rating/rating.tsx +5 -1
  398. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  399. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  400. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  401. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  402. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  403. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  404. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  405. package/src/components/Select/select.principles.stories.tsx +3 -3
  406. package/src/components/Select/select.spec.md +10 -1
  407. package/src/components/Select/select.stories.tsx +41 -27
  408. package/src/components/Select/select.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  410. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  411. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  412. package/src/components/SelectMenu/select-menu.tsx +38 -5
  413. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  414. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  415. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  416. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  417. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  418. package/src/components/Sheet/sheet.tsx +4 -1
  419. package/src/components/Sidebar/sidebar.tsx +1 -1
  420. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  421. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  422. package/src/components/Slider/slider.spec.md +13 -1
  423. package/src/components/Slider/slider.stories.tsx +44 -32
  424. package/src/components/Slider/slider.tsx +13 -4
  425. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  426. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  427. package/src/components/Steps/steps.spec.md +4 -2
  428. package/src/components/Steps/steps.stories.tsx +4 -56
  429. package/src/components/Steps/steps.tsx +31 -7
  430. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  431. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  432. package/src/components/Switch/switch.spec.md +4 -4
  433. package/src/components/Switch/switch.stories.tsx +3 -3
  434. package/src/components/Switch/switch.tsx +16 -10
  435. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  436. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  437. package/src/components/Tabs/tabs.spec.md +5 -2
  438. package/src/components/Tabs/tabs.stories.tsx +36 -44
  439. package/src/components/Tabs/tabs.tsx +101 -36
  440. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  441. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  442. package/src/components/Tag/tag.spec.md +4 -1
  443. package/src/components/Tag/tag.tsx +5 -3
  444. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  445. package/src/components/Textarea/textarea.spec.md +5 -5
  446. package/src/components/Textarea/textarea.tsx +24 -24
  447. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  448. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  449. package/src/components/TimePicker/time-picker.spec.md +6 -5
  450. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  451. package/src/components/TimePicker/time-picker.tsx +24 -14
  452. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  453. package/src/components/Toast/toast.stories.tsx +1 -1
  454. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  455. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  456. package/src/components/Tooltip/tooltip.spec.md +9 -3
  457. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  458. package/src/components/Tooltip/tooltip.tsx +12 -2
  459. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  460. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  461. package/src/components/TreeView/tree-view.spec.md +8 -6
  462. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  463. package/src/components/TreeView/tree-view.tsx +36 -0
  464. package/src/index.ts +13 -10
  465. package/src/lib/drag-visual.ts +2 -2
  466. package/src/lib/utils.ts +19 -0
  467. package/src/patterns/action-bar/action-bar.spec.md +1 -0
  468. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  469. package/src/patterns/element-anatomy/item-anatomy.spec.md +4 -0
  470. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  471. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  472. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  473. package/src/tokens/categorical-color.ts +5 -5
  474. package/src/tokens/color/color.spec.md +4 -4
  475. package/src/tokens/color/primitives.css +9 -2
  476. package/src/tokens/motion/motion.spec.md +6 -7
  477. package/src/tokens/opacity/opacity.spec.md +1 -1
  478. package/src/tokens/orphan-tokens.spec.md +1 -1
  479. package/src/tokens/typography/typography.spec.md +2 -0
  480. package/src/tokens/uiSize/uiSize.css +5 -0
  481. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"steps.js","sources":["../../../src/components/Steps/steps.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — foundational composite(Steps + StepItem + orientation/state/connector 邏輯緊密耦合,拆檔會讓 props drilling 複雜化超過可讀 gain)\nimport * as React from 'react'\nimport { Check, ChevronDown, X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n// ── Types ─────────────────────────────────────────────────────────────────\n\nexport type StepsSize = 'sm' | 'md' | 'lg'\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport type StepsOrientation = 'vertical' | 'horizontal'\nexport type StepsExpansion = 'follow-active' | 'multiple'\nexport type StepContentState = 'upcoming' | 'reachable' | 'current' | 'completed' | 'error'\n\n// ── Constants ─────────────────────────────────────────────────────────────\n\nconst INDICATOR_SIZE: Record<StepsSize, number> = {\n sm: 8,\n md: 24,\n lg: 32,\n}\n\nconst INDICATOR_ICON_SIZE: Record<StepsSize, number> = {\n sm: 0,\n md: 16,\n lg: 20,\n}\n\nconst SM_HIT_AREA = 24\n\nconst INDICATOR_BOX_WIDTH: Record<StepsSize, number> = {\n sm: SM_HIT_AREA,\n md: INDICATOR_SIZE.md,\n lg: INDICATOR_SIZE.lg,\n}\n\n// ── Outer ring (box-shadow, zero layout impact) ───────────────────────────\n\nconst RING_GAP_PX = 2\nconst RING_WIDTH_PX = 2\n\nfunction getOuterRingShadow(ringColor: string): string {\n return `0 0 0 ${RING_GAP_PX}px var(--surface), 0 0 0 ${RING_GAP_PX + RING_WIDTH_PX}px ${ringColor}`\n}\n\nfunction resolveRingColor(state: StepContentState, linear: boolean): string {\n if (state === 'error') return 'var(--error-hover)'\n if (state === 'current' && !linear) return 'var(--border-hover)'\n return 'var(--info-hover)'\n}\n\n// ── Contexts ──────────────────────────────────────────────────────────────\n\ninterface StepsContextValue {\n value: string | undefined\n completedValues: Set<string>\n errorValues: Set<string>\n reachableValues: Set<string>\n linear: boolean\n size: StepsSize\n orientation: StepsOrientation\n expansion: StepsExpansion\n expandedSet: Set<string>\n setValue: (value: string) => void\n toggleExpanded: (value: string) => void\n total: number\n}\n\nconst StepsContext = React.createContext<StepsContextValue | null>(null)\n\nfunction useStepsContext(): StepsContextValue {\n const ctx = React.useContext(StepsContext)\n if (!ctx) throw new Error('Steps compound components must be rendered inside <Steps>')\n return ctx\n}\n\ninterface StepItemContextValue {\n value: string\n state: StepContentState\n focused: boolean\n disabled: boolean\n clickable: boolean\n expanded: boolean\n isLast: boolean\n activate: () => void\n}\n\nconst StepItemContext = React.createContext<StepItemContextValue | null>(null)\n\nfunction useStepItemContext(): StepItemContextValue {\n const ctx = React.useContext(StepItemContext)\n if (!ctx) throw new Error('StepLabel / StepDescription / StepContent must be inside <StepItem>')\n return ctx\n}\n\nconst StepIndexContext = React.createContext<number>(0)\n\n// ── Pure helpers ──────────────────────────────────────────────────────────\n\nfunction computeState(\n itemValue: string,\n value: string | undefined,\n completedValues: Set<string>,\n errorValues: Set<string>,\n reachableValues: Set<string>,\n linear: boolean,\n override: StepContentState | undefined,\n): StepContentState {\n if (override) return override\n if (errorValues.has(itemValue)) return 'error'\n if (completedValues.has(itemValue)) return 'completed'\n if (itemValue === value) return 'current'\n if (linear && reachableValues.has(itemValue)) return 'reachable'\n return 'upcoming'\n}\n\nfunction isClickable(\n state: StepContentState,\n linear: boolean,\n disabled: boolean,\n): boolean {\n if (disabled) return false\n if (!linear) return true\n return state !== 'upcoming'\n}\n\nfunction normalizeExpanded(\n defaultExpanded: 'all' | 'none' | string[] | undefined,\n allValues: string[],\n): Set<string> {\n if (defaultExpanded === 'all') return new Set(allValues)\n if (!defaultExpanded || defaultExpanded === 'none') return new Set()\n return new Set(defaultExpanded)\n}\n\nfunction computeReachableValues(\n childValues: string[],\n completedValues: string[],\n): Set<string> {\n const completed = new Set(completedValues)\n const reachable = new Set(completed)\n for (const v of childValues) {\n if (!completed.has(v)) {\n reachable.add(v)\n break\n }\n }\n return reachable\n}\n\n// ── Steps root ────────────────────────────────────────────────────────────\n\nconst stepsRootVariants = cva('list-none p-0 m-0', {\n variants: {\n orientation: {\n vertical: 'flex flex-col',\n horizontal: 'flex flex-row items-start gap-3',\n },\n },\n defaultVariants: { orientation: 'vertical' },\n})\n\nexport interface StepsProps\n extends Omit<React.HTMLAttributes<HTMLOListElement>, 'onChange' | 'defaultValue'>,\n VariantProps<typeof stepsRootVariants> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n completedValues?: string[]\n errorValues?: string[]\n linear?: boolean\n size?: StepsSize\n orientation?: StepsOrientation\n expansion?: StepsExpansion\n defaultExpanded?: 'all' | 'none' | string[]\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Steps = React.forwardRef<HTMLOListElement, StepsProps>(\n (\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n completedValues = [],\n errorValues = [],\n linear = true,\n size = 'md',\n orientation = 'vertical',\n expansion = 'follow-active',\n defaultExpanded,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const [internalValue, setInternalValue] = React.useState<string | undefined>(defaultValue)\n const isControlled = valueProp !== undefined\n const value = isControlled ? valueProp : internalValue\n\n const setValue = React.useCallback(\n (next: string) => {\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n const childValues = React.useMemo(() => {\n const vals: string[] = []\n React.Children.forEach(children, child => {\n if (\n React.isValidElement(child) &&\n typeof child.props === 'object' &&\n child.props &&\n 'value' in child.props\n ) {\n vals.push(String((child.props as { value: string }).value))\n }\n })\n return vals\n }, [children])\n\n const reachableValues = React.useMemo(\n () => computeReachableValues(childValues, completedValues),\n [childValues, completedValues],\n )\n\n const [expandedSet, setExpandedSet] = React.useState<Set<string>>(() =>\n normalizeExpanded(defaultExpanded, childValues),\n )\n\n const toggleExpanded = React.useCallback((itemValue: string) => {\n setExpandedSet(prev => {\n const next = new Set(prev)\n if (next.has(itemValue)) next.delete(itemValue)\n else next.add(itemValue)\n return next\n })\n }, [])\n\n const stepCount = React.Children.count(children)\n\n const ctxValue = React.useMemo<StepsContextValue>(\n () => ({\n value,\n completedValues: new Set(completedValues),\n errorValues: new Set(errorValues),\n reachableValues,\n linear,\n size,\n orientation,\n expansion,\n expandedSet,\n setValue,\n toggleExpanded,\n total: stepCount,\n }),\n [value, completedValues, errorValues, reachableValues, linear, size, orientation, expansion, expandedSet, setValue, toggleExpanded, stepCount],\n )\n\n // Interleave horizontal connectors between items\n const count = stepCount\n const itemsWithIndex: React.ReactNode[] = []\n\n React.Children.forEach(children, (child, index) => {\n if (!React.isValidElement(child)) {\n itemsWithIndex.push(child)\n return\n }\n const isLast = index === count - 1\n const cloned = React.cloneElement(\n child as React.ReactElement<StepItemInjectedProps>,\n { __isLast: isLast },\n )\n itemsWithIndex.push(\n <StepIndexContext.Provider key={`item-${index}`} value={index + 1}>\n {cloned}\n </StepIndexContext.Provider>,\n )\n // Horizontal connectors are now INSIDE each StepItem (Ant Design pattern),\n // not between items. No interleaving needed.\n })\n\n return (\n <StepsContext.Provider value={ctxValue}>\n <ol\n ref={ref}\n data-orientation={orientation}\n data-size={size}\n className={cn(stepsRootVariants({ orientation }), className)}\n {...props}\n >\n {itemsWithIndex}\n </ol>\n </StepsContext.Provider>\n )\n },\n)\nSteps.displayName = 'Steps'\n\n// ── StepItem ──────────────────────────────────────────────────────────────\n\ninterface StepItemInjectedProps {\n __isLast?: boolean\n}\n\nexport interface StepItemProps\n extends Omit<React.HTMLAttributes<HTMLLIElement>, 'value'>,\n StepItemInjectedProps {\n value: string\n state?: 'error'\n disabled?: boolean\n}\n\nconst stepItemVariants = cva('group/step-item outline-none', {\n variants: {\n orientation: {\n // pb-6 on li provides spacing for next item; connector is absolute within li\n vertical: 'relative flex flex-col',\n // Ant Design pattern:flex-1 等寬(最後一步用 last: 覆蓋成自然寬度)。\n // Connector 在 item 內部(不是 items 之間的獨立元素)。\n horizontal: 'flex-1 min-w-0 last:flex-none last:shrink-0',\n },\n size: {\n sm: 'text-body',\n md: 'text-body',\n lg: 'text-body-lg',\n },\n },\n defaultVariants: { orientation: 'vertical', size: 'md' },\n})\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepItem = React.forwardRef<HTMLLIElement, StepItemProps>(\n ({ value, state: stateOverride, disabled = false, children, className, __isLast = false, ...props }, ref) => {\n const steps = useStepsContext()\n const state = computeState(\n value,\n steps.value,\n steps.completedValues,\n steps.errorValues,\n steps.reachableValues,\n steps.linear,\n stateOverride,\n )\n const focused = value === steps.value\n const clickable = isClickable(state, steps.linear, disabled)\n const expanded =\n steps.expansion === 'follow-active' ? focused : steps.expandedSet.has(value)\n\n const activate = React.useCallback(() => {\n if (!clickable) return\n // 永遠更新 focus(value),multiple 模式額外 toggle 展開\n steps.setValue(value)\n if (steps.expansion === 'multiple') {\n steps.toggleExpanded(value)\n }\n }, [clickable, steps, value])\n\n const itemCtx = React.useMemo<StepItemContextValue>(() => ({\n value,\n state,\n focused,\n disabled,\n clickable,\n expanded,\n isLast: __isLast,\n activate,\n }), [value, state, focused, disabled, clickable, expanded, __isLast, activate])\n\n const isVertical = steps.orientation === 'vertical'\n\n return (\n <StepItemContext.Provider value={itemCtx}>\n <li\n ref={ref}\n data-state={state}\n data-focused={focused || undefined}\n data-disabled={disabled || undefined}\n data-clickable={clickable || undefined}\n aria-current={focused ? 'step' : undefined}\n aria-disabled={disabled || undefined}\n className={cn(\n stepItemVariants({ orientation: steps.orientation, size: steps.size }),\n isVertical && !__isLast && 'pb-6',\n !clickable && 'cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <StepItemLayout>{children}</StepItemLayout>\n </li>\n </StepItemContext.Provider>\n )\n },\n)\nStepItem.displayName = 'StepItem'\n\n// ── StepItem internal layout ─────────────────────────────────────────────\n\nfunction StepItemLayout({ children }: { children: React.ReactNode }) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n\n let labelNode: React.ReactNode = null\n let descNode: React.ReactNode = null\n let contentNode: React.ReactNode = null\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) return\n if (child.type === StepLabel) labelNode = child\n else if (child.type === StepDescription) descNode = child\n else if (child.type === StepContent) contentNode = child\n })\n\n if (steps.orientation === 'horizontal') {\n return <HorizontalLayout label={labelNode} description={descNode} />\n }\n return (\n <VerticalLayout label={labelNode} description={descNode} content={contentNode} isLast={item.isLast} />\n )\n}\n\n// ── Clickable header ─────────────────────────────────────────────────────\n\n// SR-only 狀態文字 map(2026-06-01 #25 a11y:indicator 是 aria-hidden 純視覺,故「第 N 步/共 M 步/狀態」\n// 需經 sr-only span 給螢幕報讀器。對齊 Carbon ProgressIndicator `--assistive-text`(已完成/進行中/未開始)慣例)\nconst STEP_STATUS_TEXT: Record<StepContentState, string> = {\n completed: '已完成',\n current: '進行中',\n error: '錯誤',\n reachable: '未開始',\n upcoming: '未開始',\n}\n\nfunction StepItemHeader({ children, className, style, contentId }: { children: React.ReactNode; className?: string; style?: React.CSSProperties; contentId?: string }) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const index = React.useContext(StepIndexContext)\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!item.clickable) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n item.activate()\n }\n }\n return (\n <div\n role={item.clickable ? 'button' : undefined}\n tabIndex={item.clickable ? 0 : undefined}\n onClick={item.clickable ? item.activate : undefined}\n onKeyDown={item.clickable ? onKeyDown : undefined}\n aria-disabled={item.disabled || undefined}\n // 2026-07-05 D4 修:step 有 content 的可點 header(role=button)必帶 aria-expanded —\n // WAI-ARIA disclosure pattern trigger 最低要求(multiple 模式 toggle;follow-active 亦\n // 同步反映展開狀態)。aria-controls 只在 content 實際 render(展開)時輸出,避免\n // dangling id reference(content 收合時不在 DOM)。\n aria-expanded={item.clickable && contentId ? item.expanded : undefined}\n aria-controls={item.clickable && contentId && item.expanded ? contentId : undefined}\n className={cn(\n // leading-compact:scanning-family header 行高 = 1.3(item-anatomy.spec.md:776 掃描模式 label 行高)。\n // 設在 header 而非 li 根 → prefix h-[1lh] + 水平 connector h-[1lh] + label(StepLabel 亦 leading-compact)\n // 全用 1.3 對齊;li 根 text-body(1.5,steps.tsx:329-331)留給展開 content 的 reading 行高,不被\n // scanning 波及(避免 改A壞B)。對齊 MenuItem 把 leading-compact 放 row 容器之原則(item-anatomy.tsx:144-146)。\n 'outline-none leading-compact',\n item.clickable\n ? 'cursor-pointer rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'\n : 'cursor-not-allowed',\n className,\n )}\n style={style}\n >\n <span className=\"sr-only\">{`第 ${index} 步,共 ${steps.total} 步,${STEP_STATUS_TEXT[item.state]}`}</span>\n {children}\n </div>\n )\n}\n\n// ── Vertical layout ──────────────────────────────────────────────────────\n\nfunction VerticalLayout({\n label,\n description,\n content,\n isLast,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n content: React.ReactNode\n isLast: boolean\n}) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const showContent = !!content && item.expanded\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n // 2026-07-05 D4 修:content 區 id 供 header aria-controls 指向(disclosure 配線)\n const contentId = React.useId()\n\n return (\n <>\n <StepItemHeader className=\"flex items-start gap-3\" contentId={content ? contentId : undefined}>\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT);\n width = INDICATOR_BOX_WIDTH 固定欄寬,base justify-center 讓 sm dot 在欄內置中 */}\n <ItemPrefix style={{ width: indicatorBox }}>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"flex-1 min-w-0 flex items-start gap-2\">\n <div className=\"flex-1 min-w-0 flex flex-col\">\n {label}\n {description}\n </div>\n {/* Row suffix slot — 消費 item-anatomy <ItemSuffix>(h-[1lh] 對齊 label 第一行);\n text col 是 flex-1 → base ml-auto 惰性,8px 間距由父層 gap-2 提供(= MenuItem 父層 gap idiom)*/}\n {steps.expansion === 'multiple' && !!content && (\n <ItemSuffix aria-hidden>\n <ChevronDown\n size={16}\n className={cn(\n 'text-fg-muted transition-transform duration-150',\n item.expanded && 'rotate-180',\n )}\n />\n </ItemSuffix>\n )}\n </div>\n </StepItemHeader>\n {showContent && (\n <div id={contentId} className=\"flex items-start gap-3 mt-3\">\n <div className=\"shrink-0\" style={{ width: indicatorBox }} />\n <div className=\"flex-1 min-w-0\">{content}</div>\n </div>\n )}\n {!isLast && <VerticalConnectorLine />}\n </>\n )\n}\n\n// ── Vertical connector ───────────────────────────────────────────────────\n\nfunction VerticalConnectorLine() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const isBlue = item.state === 'completed'\n const radius = INDICATOR_SIZE[steps.size] / 2\n const gap = 8\n\n return (\n <div\n aria-hidden\n className={cn(\n // leading-compact:connector 的 0.5lh 須跟 scanning label 同行高(1.3)→ 起點對齊 circle 中心\n // (circle 對齊 label 第一行;label 已 leading-compact)。否則 connector 繼承 li 根 1.5 → 0.5lh 偏大 → 起點偏低。\n 'absolute w-px leading-compact',\n isBlue ? 'bg-info' : 'bg-border',\n )}\n style={{\n left: INDICATOR_BOX_WIDTH[steps.size] / 2,\n top: `calc(0.5lh + ${radius}px + ${gap}px)`,\n bottom: `calc(${radius}px - 0.5lh + ${gap}px)`,\n }}\n />\n )\n}\n\n// ── Horizontal layout (Ant Design pattern) ──────────────────────────────\n//\n// Connector 在 **item 內部**(不是 items 之間的獨立元素):\n// Step (flex-1): [indicator][gap][label][gap][──connector──]\n// Last step: [indicator][gap][label] (無 connector)\n//\n// Root: flex-row gap-3 → gap 只在 step items 之間\n// Step items: flex-1 等寬(最後一步 flex-none 自然寬度)\n//\n// 等距保證:\n// label→connector gap = item 內 flex gap-3 = 12px\n// connector→next circle = root gap-3 = 12px\n// 兩邊都是 12px ✓\n//\n// Description 在 step item 內(connector 下方),wrap 到 item 寬度 = 最長到連結線尾段 ✓\n\nfunction HorizontalLayout({\n label,\n description,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n}) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const isBlue = item.state === 'completed'\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n\n return (\n <>\n {/* Row 1: indicator + label + connector(在同一個 flex row) */}\n <StepItemHeader className=\"flex items-start gap-3\">\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT)*/}\n <ItemPrefix>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"shrink-0 min-w-0\">{label}</div>\n {/* Connector 在 item 內部,flex-1 填滿剩餘寬度 */}\n {!item.isLast && (\n <div className=\"h-[1lh] flex-1 flex items-center min-w-4\" aria-hidden>\n <div className={cn('h-px w-full', isBlue ? 'bg-info' : 'bg-border')} />\n </div>\n )}\n </StepItemHeader>\n {/* Row 2: description — 在 item 寬度內 wrap(含 connector 佔的空間) */}\n {description && (\n <div className=\"min-w-0\" style={{ paddingLeft: indicatorBox + 12 }}>\n {description}\n </div>\n )}\n </>\n )\n}\n\n// ── StepIndicator ────────────────────────────────────────────────────────\n\nfunction StepIndicator() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const { size, linear } = steps\n const { state, focused, disabled } = item\n\n if (size === 'sm') return <SmIndicator state={state} focused={focused} disabled={disabled} linear={linear} />\n return <MdLgIndicator size={size} state={state} focused={focused} disabled={disabled} linear={linear} />\n}\n\n// ── sm indicator: 8px dot in 24px hit area ───────────────────────────────\n\nfunction SmIndicator({\n state,\n focused,\n disabled,\n linear,\n}: {\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n // sm current (linear) and reachable: hollow ring\n const isHollow = (state === 'current' && linear) || state === 'reachable'\n\n let dotStyle: React.CSSProperties\n if (isHollow) {\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: 'transparent',\n border: '2px solid var(--info-hover)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n } else {\n const dotBg =\n state === 'completed' ? 'var(--info)'\n : state === 'error' ? 'var(--error)'\n : state === 'current' && !linear ? 'var(--fg-disabled)'\n : 'var(--fg-disabled)' // upcoming + non-linear fallback\n\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: dotBg,\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n }\n\n return (\n <span\n aria-hidden\n className=\"relative inline-flex items-center justify-center shrink-0\"\n style={{ width: SM_HIT_AREA, height: SM_HIT_AREA }}\n >\n <span\n className={cn('block rounded-full', disabled && 'opacity-disabled')}\n style={dotStyle}\n />\n </span>\n )\n}\n\n// ── md/lg indicator: filled circle with number/icon ──────────────────────\n\nfunction MdLgIndicator({\n size,\n state,\n focused,\n disabled,\n linear,\n}: {\n size: StepsSize\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n const diameter = INDICATOR_SIZE[size]\n const iconPx = INDICATOR_ICON_SIZE[size]\n\n let fillBg: string\n let contentColor: string\n\n switch (state) {\n case 'error':\n fillBg = 'var(--error)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'completed':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'current':\n if (linear) {\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n case 'reachable':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n default: // upcoming\n if (linear) {\n fillBg = 'var(--muted)'\n contentColor = 'var(--fg-disabled)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n }\n\n return (\n <span\n aria-hidden\n className={cn(\n 'relative inline-flex items-center justify-center shrink-0 rounded-full',\n 'font-medium leading-none transition-colors',\n disabled && 'opacity-disabled',\n )}\n style={{\n width: diameter,\n height: diameter,\n background: fillBg,\n color: contentColor,\n // 2026-06-11 R2:對齊 spec canonical「indicator 數字與 label 同級」(steps.spec.md 狀態表 md=14/lg=16;spec 明文「之前寫小一號(md=12,lg=14)是錯的」)\n fontSize: size === 'lg' ? 'var(--font-body-lg-size)' : 'var(--font-body-size)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }}\n >\n <IndicatorContent state={state} iconPx={iconPx} />\n </span>\n )\n}\n\nfunction IndicatorContent({ state, iconPx }: { state: StepContentState; iconPx: number }) {\n if (state === 'completed') return <Check size={iconPx} strokeWidth={2.5} />\n if (state === 'error') return <X size={iconPx} strokeWidth={2.5} />\n return <StepNumber />\n}\n\nfunction StepNumber() {\n const index = React.useContext(StepIndexContext)\n return <span>{index}</span>\n}\n\n// ── StepLabel ────────────────────────────────────────────────────────────\n\nexport interface StepLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepLabel = React.forwardRef<HTMLSpanElement, StepLabelProps>(\n ({ className, children, ...props }, ref) => {\n const { size } = useStepsContext()\n const { state, focused, disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // leading-compact:scanning-family label 行高 = 1.3(item-anatomy.spec.md:776);text-body utility\n // 自帶 lh:1.5,須顯式 leading-compact 蓋回 1.3,跟 MenuItem label(實測 14px/18px=1.3)一致。\n 'font-medium break-words leading-compact',\n size === 'lg' ? 'text-body-lg' : 'text-body',\n disabled\n ? 'text-fg-disabled'\n : state === 'error'\n ? 'text-error-text'\n : focused\n ? 'text-foreground'\n : 'text-fg-secondary',\n className,\n )}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepLabel.displayName = 'StepLabel'\n\n// ── StepDescription ──────────────────────────────────────────────────────\n\nexport interface StepDescriptionProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst StepDescription = React.forwardRef<HTMLSpanElement, StepDescriptionProps>(\n ({ className, children, style, ...props }, ref) => {\n const { size } = useStepsContext()\n const { disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // Steps 跟 MenuItem 同 scanning-family:sm/md = scanning(body+caption),lg = scanning-lg(body-lg+body-compact)\n size === 'lg'\n ? 'mt-[var(--item-gap-label-desc-scanning-lg)]'\n : 'mt-[var(--item-gap-label-desc-scanning)]',\n 'leading-compact break-words',\n disabled ? 'text-fg-disabled' : 'text-fg-secondary',\n className,\n )}\n style={{\n fontSize: size === 'lg' ? 'var(--font-body-size)' : 'var(--font-caption-size)',\n ...style,\n }}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepDescription.displayName = 'StepDescription'\n\n// ── StepContent ──────────────────────────────────────────────────────────\n\nexport interface StepContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst StepContent = React.forwardRef<HTMLDivElement, StepContentProps>(\n ({ className, children, ...props }, ref) => {\n const { orientation } = useStepsContext()\n if (orientation === 'horizontal') return null\n return (\n <div\n ref={ref}\n className={cn('text-body text-foreground min-w-0', className)}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\nStepContent.displayName = 'StepContent'\n\n// ── Exports ──────────────────────────────────────────────────────────────\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 stepsMeta = {\n component: 'Steps',\n family: 2,\n variants: {},\n sizes: {\n sm: { px: 8, when: 'Sidebar / 緊湊 onboarding;indicator 8px dot' },\n md: { px: 24, when: '預設 — wizard / checkout / 註冊主流程;indicator 24px circle' },\n lg: { px: 32, when: 'Marketing 流程展示 / 重要 onboarding;indicator 32px circle' },\n },\n states: ['upcoming', 'reachable', 'current', 'completed', 'error'], // 2026-06-11 R2:content-state 模型(spec 狀態表),非 Phase-1 boilerplate 互動 states,\n tokens: {\n bg: ['bg-info'],\n fg: ['--fg-disabled', '--foreground', '--on-emphasis', 'text-error-text', 'text-fg-disabled', 'text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { Steps, StepItem, StepLabel, StepDescription, StepContent, stepsRootVariants, stepItemVariants }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"steps.js","sources":["../../../src/components/Steps/steps.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — foundational composite(Steps + StepItem + orientation/state/connector 邏輯緊密耦合,拆檔會讓 props drilling 複雜化超過可讀 gain)\nimport * as React from 'react'\nimport { Check, ChevronDown, X } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n// ── Types ─────────────────────────────────────────────────────────────────\n\nexport type StepsSize = 'sm' | 'md' | 'lg'\n// code-quality-allow: dead-export — public API surface — consumer-exposed for future use\nexport type StepsOrientation = 'vertical' | 'horizontal'\nexport type StepsExpansion = 'follow-active' | 'multiple'\nexport type StepContentState = 'upcoming' | 'reachable' | 'current' | 'completed' | 'error'\n\n// ── Constants ─────────────────────────────────────────────────────────────\n\nconst INDICATOR_SIZE: Record<StepsSize, number> = {\n sm: 8,\n md: 24,\n lg: 32,\n}\n\nconst INDICATOR_ICON_SIZE: Record<StepsSize, number> = {\n sm: 0,\n md: 16,\n lg: 20,\n}\n\nconst SM_HIT_AREA = 24\n\nconst INDICATOR_BOX_WIDTH: Record<StepsSize, number> = {\n sm: SM_HIT_AREA,\n md: INDICATOR_SIZE.md,\n lg: INDICATOR_SIZE.lg,\n}\n\n// ── Outer ring (box-shadow, zero layout impact) ───────────────────────────\n\nconst RING_GAP_PX = 2\nconst RING_WIDTH_PX = 2\n\nfunction getOuterRingShadow(ringColor: string): string {\n return `0 0 0 ${RING_GAP_PX}px var(--surface), 0 0 0 ${RING_GAP_PX + RING_WIDTH_PX}px ${ringColor}`\n}\n\nfunction resolveRingColor(state: StepContentState, linear: boolean): string {\n if (state === 'error') return 'var(--error-hover)'\n if (state === 'current' && !linear) return 'var(--border-hover)'\n return 'var(--info-hover)'\n}\n\n// ── Contexts ──────────────────────────────────────────────────────────────\n\ninterface StepsContextValue {\n value: string | undefined\n completedValues: Set<string>\n errorValues: Set<string>\n reachableValues: Set<string>\n linear: boolean\n size: StepsSize\n orientation: StepsOrientation\n expansion: StepsExpansion\n expandedSet: Set<string>\n setValue: (value: string) => void\n toggleExpanded: (value: string) => void\n total: number\n}\n\nconst StepsContext = React.createContext<StepsContextValue | null>(null)\n\nfunction useStepsContext(): StepsContextValue {\n const ctx = React.useContext(StepsContext)\n if (!ctx) throw new Error('Steps compound components must be rendered inside <Steps>')\n return ctx\n}\n\ninterface StepItemContextValue {\n value: string\n state: StepContentState\n focused: boolean\n disabled: boolean\n clickable: boolean\n expanded: boolean\n isLast: boolean\n activate: () => void\n}\n\nconst StepItemContext = React.createContext<StepItemContextValue | null>(null)\n\nfunction useStepItemContext(): StepItemContextValue {\n const ctx = React.useContext(StepItemContext)\n if (!ctx) throw new Error('StepLabel / StepDescription / StepContent must be inside <StepItem>')\n return ctx\n}\n\nconst StepIndexContext = React.createContext<number>(0)\n\n// ── Pure helpers ──────────────────────────────────────────────────────────\n\nfunction computeState(\n itemValue: string,\n value: string | undefined,\n completedValues: Set<string>,\n errorValues: Set<string>,\n reachableValues: Set<string>,\n linear: boolean,\n override: StepContentState | undefined,\n): StepContentState {\n if (override) return override\n if (errorValues.has(itemValue)) return 'error'\n if (completedValues.has(itemValue)) return 'completed'\n if (itemValue === value) return 'current'\n if (linear && reachableValues.has(itemValue)) return 'reachable'\n return 'upcoming'\n}\n\nfunction isClickable(\n state: StepContentState,\n linear: boolean,\n disabled: boolean,\n): boolean {\n if (disabled) return false\n if (!linear) return true\n return state !== 'upcoming'\n}\n\nfunction normalizeExpanded(\n defaultExpanded: 'all' | 'none' | string[] | undefined,\n allValues: string[],\n): Set<string> {\n if (defaultExpanded === 'all') return new Set(allValues)\n if (!defaultExpanded || defaultExpanded === 'none') return new Set()\n return new Set(defaultExpanded)\n}\n\nfunction computeReachableValues(\n childValues: string[],\n completedValues: string[],\n): Set<string> {\n const completed = new Set(completedValues)\n const reachable = new Set(completed)\n for (const v of childValues) {\n if (!completed.has(v)) {\n reachable.add(v)\n break\n }\n }\n return reachable\n}\n\n// ── Steps root ────────────────────────────────────────────────────────────\n\nconst stepsRootVariants = cva('list-none p-0 m-0', {\n variants: {\n orientation: {\n vertical: 'flex flex-col',\n horizontal: 'flex flex-row items-start gap-3',\n },\n },\n defaultVariants: { orientation: 'vertical' },\n})\n\nexport interface StepsProps\n extends Omit<React.HTMLAttributes<HTMLOListElement>, 'onChange' | 'defaultValue'>,\n VariantProps<typeof stepsRootVariants> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n completedValues?: string[]\n errorValues?: string[]\n linear?: boolean\n size?: StepsSize\n orientation?: StepsOrientation\n expansion?: StepsExpansion\n defaultExpanded?: 'all' | 'none' | string[]\n /** Controlled 展開集合(2026-07-18 user 拍板補完整雙向控制,對齊 TreeView expandedIds + Radix/MUI/Ant Accordion)。\n * 傳入則由 consumer 掌控展開狀態(與 `defaultExpanded` 二選一);toggle 時經 `onExpandedChange` 回寫。 */\n expanded?: string[]\n /** Controlled 展開變更回呼(展開/收合 step 時觸發,回傳新的展開值陣列)。 */\n onExpandedChange?: (expanded: string[]) => void\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Steps = React.forwardRef<HTMLOListElement, StepsProps>(\n (\n {\n value: valueProp,\n defaultValue,\n onValueChange,\n completedValues = [],\n errorValues = [],\n linear = true,\n size = 'md',\n orientation = 'vertical',\n expansion = 'follow-active',\n defaultExpanded,\n expanded: expandedProp,\n onExpandedChange,\n className,\n children,\n ...props\n },\n ref,\n ) => {\n const [internalValue, setInternalValue] = React.useState<string | undefined>(defaultValue)\n const isControlled = valueProp !== undefined\n const value = isControlled ? valueProp : internalValue\n\n const setValue = React.useCallback(\n (next: string) => {\n if (!isControlled) setInternalValue(next)\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n const childValues = React.useMemo(() => {\n const vals: string[] = []\n React.Children.forEach(children, child => {\n if (\n React.isValidElement(child) &&\n typeof child.props === 'object' &&\n child.props &&\n 'value' in child.props\n ) {\n vals.push(String((child.props as { value: string }).value))\n }\n })\n return vals\n }, [children])\n\n const reachableValues = React.useMemo(\n () => computeReachableValues(childValues, completedValues),\n [childValues, completedValues],\n )\n\n // Controlled(expandedProp 傳入)/ uncontrolled(defaultExpanded 初值)dual-mode(2026-07-18)。\n const isExpandedControlled = expandedProp !== undefined\n const [expandedInternal, setExpandedInternal] = React.useState<Set<string>>(() =>\n normalizeExpanded(defaultExpanded, childValues),\n )\n const expandedSet = isExpandedControlled ? new Set(expandedProp) : expandedInternal\n\n const toggleExpanded = React.useCallback((itemValue: string) => {\n const compute = (prev: Set<string>) => {\n const next = new Set(prev)\n if (next.has(itemValue)) next.delete(itemValue)\n else next.add(itemValue)\n return next\n }\n if (isExpandedControlled) {\n onExpandedChange?.([...compute(new Set(expandedProp))])\n } else {\n setExpandedInternal(prev => {\n const next = compute(prev)\n onExpandedChange?.([...next])\n return next\n })\n }\n }, [isExpandedControlled, expandedProp, onExpandedChange])\n\n const stepCount = React.Children.count(children)\n\n const ctxValue = React.useMemo<StepsContextValue>(\n () => ({\n value,\n completedValues: new Set(completedValues),\n errorValues: new Set(errorValues),\n reachableValues,\n linear,\n size,\n orientation,\n expansion,\n expandedSet,\n setValue,\n toggleExpanded,\n total: stepCount,\n }),\n [value, completedValues, errorValues, reachableValues, linear, size, orientation, expansion, expandedSet, setValue, toggleExpanded, stepCount],\n )\n\n // Interleave horizontal connectors between items\n const count = stepCount\n const itemsWithIndex: React.ReactNode[] = []\n\n React.Children.forEach(children, (child, index) => {\n if (!React.isValidElement(child)) {\n itemsWithIndex.push(child)\n return\n }\n const isLast = index === count - 1\n const cloned = React.cloneElement(\n child as React.ReactElement<StepItemInjectedProps>,\n { __isLast: isLast },\n )\n itemsWithIndex.push(\n <StepIndexContext.Provider key={`item-${index}`} value={index + 1}>\n {cloned}\n </StepIndexContext.Provider>,\n )\n // Horizontal connectors are now INSIDE each StepItem (Ant Design pattern),\n // not between items. No interleaving needed.\n })\n\n return (\n <StepsContext.Provider value={ctxValue}>\n <ol\n ref={ref}\n data-orientation={orientation}\n data-size={size}\n className={cn(stepsRootVariants({ orientation }), className)}\n {...props}\n >\n {itemsWithIndex}\n </ol>\n </StepsContext.Provider>\n )\n },\n)\nSteps.displayName = 'Steps'\n\n// ── StepItem ──────────────────────────────────────────────────────────────\n\n// Steps 內部 cloneElement 注入用的私有 props — 刻意「不」併入公開 StepItemProps:\n// dunder 內部欄位不進 root API(consumer 無合法理由手動控制末項 connector / 間距),\n// 也就不會被 barrel 匯出成公開型別。StepItem render body 以 intersection cast 內部讀取。\ninterface StepItemInjectedProps {\n __isLast?: boolean\n}\n\nexport interface StepItemProps\n extends Omit<React.HTMLAttributes<HTMLLIElement>, 'value'> {\n value: string\n state?: 'error'\n disabled?: boolean\n}\n\nconst stepItemVariants = cva('group/step-item outline-none', {\n variants: {\n orientation: {\n // pb-6 on li provides spacing for next item; connector is absolute within li\n vertical: 'relative flex flex-col',\n // Ant Design pattern:flex-1 等寬(最後一步用 last: 覆蓋成自然寬度)。\n // Connector 在 item 內部(不是 items 之間的獨立元素)。\n horizontal: 'flex-1 min-w-0 last:flex-none last:shrink-0',\n },\n size: {\n sm: 'text-body',\n md: 'text-body',\n lg: 'text-body-lg',\n },\n },\n defaultVariants: { orientation: 'vertical', size: 'md' },\n})\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepItem = React.forwardRef<HTMLLIElement, StepItemProps>(\n ({ value, state: stateOverride, disabled = false, children, className, ...restProps }, ref) => {\n // __isLast 由 Steps root 經 cloneElement 私下注入(見 StepItemInjectedProps);以 intersection\n // cast 從 rest 讀出後解構掉,確保 dunder 不落到 DOM li,也不必污染公開 StepItemProps。\n const { __isLast = false, ...props } = restProps as typeof restProps & StepItemInjectedProps\n const steps = useStepsContext()\n const state = computeState(\n value,\n steps.value,\n steps.completedValues,\n steps.errorValues,\n steps.reachableValues,\n steps.linear,\n stateOverride,\n )\n const focused = value === steps.value\n const clickable = isClickable(state, steps.linear, disabled)\n const expanded =\n steps.expansion === 'follow-active' ? focused : steps.expandedSet.has(value)\n\n const activate = React.useCallback(() => {\n if (!clickable) return\n // 永遠更新 focus(value),multiple 模式額外 toggle 展開\n steps.setValue(value)\n if (steps.expansion === 'multiple') {\n steps.toggleExpanded(value)\n }\n }, [clickable, steps, value])\n\n const itemCtx = React.useMemo<StepItemContextValue>(() => ({\n value,\n state,\n focused,\n disabled,\n clickable,\n expanded,\n isLast: __isLast,\n activate,\n }), [value, state, focused, disabled, clickable, expanded, __isLast, activate])\n\n const isVertical = steps.orientation === 'vertical'\n\n return (\n <StepItemContext.Provider value={itemCtx}>\n <li\n ref={ref}\n data-state={state}\n data-focused={focused || undefined}\n data-disabled={disabled || undefined}\n data-clickable={clickable || undefined}\n aria-current={focused ? 'step' : undefined}\n aria-disabled={disabled || undefined}\n className={cn(\n stepItemVariants({ orientation: steps.orientation, size: steps.size }),\n isVertical && !__isLast && 'pb-6',\n !clickable && 'cursor-not-allowed',\n className,\n )}\n {...props}\n >\n <StepItemLayout>{children}</StepItemLayout>\n </li>\n </StepItemContext.Provider>\n )\n },\n)\nStepItem.displayName = 'StepItem'\n\n// ── StepItem internal layout ─────────────────────────────────────────────\n\nfunction StepItemLayout({ children }: { children: React.ReactNode }) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n\n let labelNode: React.ReactNode = null\n let descNode: React.ReactNode = null\n let contentNode: React.ReactNode = null\n React.Children.forEach(children, child => {\n if (!React.isValidElement(child)) return\n if (child.type === StepLabel) labelNode = child\n else if (child.type === StepDescription) descNode = child\n else if (child.type === StepContent) contentNode = child\n })\n\n if (steps.orientation === 'horizontal') {\n return <HorizontalLayout label={labelNode} description={descNode} />\n }\n return (\n <VerticalLayout label={labelNode} description={descNode} content={contentNode} isLast={item.isLast} />\n )\n}\n\n// ── Clickable header ─────────────────────────────────────────────────────\n\n// SR-only 狀態文字 map(2026-06-01 #25 a11y:indicator 是 aria-hidden 純視覺,故「第 N 步/共 M 步/狀態」\n// 需經 sr-only span 給螢幕報讀器。對齊 Carbon ProgressIndicator `--assistive-text`(已完成/進行中/未開始)慣例)\nconst STEP_STATUS_TEXT: Record<StepContentState, string> = {\n completed: '已完成',\n current: '進行中',\n error: '錯誤',\n reachable: '未開始',\n upcoming: '未開始',\n}\n\nfunction StepItemHeader({ children, className, style, contentId }: { children: React.ReactNode; className?: string; style?: React.CSSProperties; contentId?: string }) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const index = React.useContext(StepIndexContext)\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!item.clickable) return\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n item.activate()\n }\n }\n return (\n <div\n role={item.clickable ? 'button' : undefined}\n tabIndex={item.clickable ? 0 : undefined}\n onClick={item.clickable ? item.activate : undefined}\n onKeyDown={item.clickable ? onKeyDown : undefined}\n aria-disabled={item.disabled || undefined}\n // 2026-07-05 D4 修:step 有 content 的可點 header(role=button)必帶 aria-expanded —\n // WAI-ARIA disclosure pattern trigger 最低要求(multiple 模式 toggle;follow-active 亦\n // 同步反映展開狀態)。aria-controls 只在 content 實際 render(展開)時輸出,避免\n // dangling id reference(content 收合時不在 DOM)。\n aria-expanded={item.clickable && contentId ? item.expanded : undefined}\n aria-controls={item.clickable && contentId && item.expanded ? contentId : undefined}\n className={cn(\n // leading-compact:scanning-family header 行高 = 1.3(item-anatomy.spec.md:776 掃描模式 label 行高)。\n // 設在 header 而非 li 根 → prefix h-[1lh] + 水平 connector h-[1lh] + label(StepLabel 亦 leading-compact)\n // 全用 1.3 對齊;li 根 text-body(1.5,steps.tsx:329-331)留給展開 content 的 reading 行高,不被\n // scanning 波及(避免 改A壞B)。對齊 MenuItem 把 leading-compact 放 row 容器之原則(item-anatomy.tsx:144-146)。\n 'outline-none leading-compact',\n item.clickable\n ? 'cursor-pointer rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring'\n : 'cursor-not-allowed',\n className,\n )}\n style={style}\n >\n <span className=\"sr-only\">{`第 ${index} 步,共 ${steps.total} 步,${STEP_STATUS_TEXT[item.state]}`}</span>\n {children}\n </div>\n )\n}\n\n// ── Vertical layout ──────────────────────────────────────────────────────\n\nfunction VerticalLayout({\n label,\n description,\n content,\n isLast,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n content: React.ReactNode\n isLast: boolean\n}) {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const showContent = !!content && item.expanded\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n // 2026-07-05 D4 修:content 區 id 供 header aria-controls 指向(disclosure 配線)\n const contentId = React.useId()\n\n return (\n <>\n <StepItemHeader className=\"flex items-start gap-3\" contentId={content ? contentId : undefined}>\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT);\n width = INDICATOR_BOX_WIDTH 固定欄寬,base justify-center 讓 sm dot 在欄內置中 */}\n <ItemPrefix style={{ width: indicatorBox }}>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"flex-1 min-w-0 flex items-start gap-2\">\n <div className=\"flex-1 min-w-0 flex flex-col\">\n {label}\n {description}\n </div>\n {/* Row suffix slot — 消費 item-anatomy <ItemSuffix>(h-[1lh] 對齊 label 第一行);\n text col 是 flex-1 → base ml-auto 惰性,8px 間距由父層 gap-2 提供(= MenuItem 父層 gap idiom)*/}\n {steps.expansion === 'multiple' && !!content && (\n <ItemSuffix aria-hidden>\n <ChevronDown\n size={16}\n className={cn(\n 'text-fg-muted transition-transform duration-150',\n item.expanded && 'rotate-180',\n )}\n />\n </ItemSuffix>\n )}\n </div>\n </StepItemHeader>\n {showContent && (\n <div id={contentId} className=\"flex items-start gap-3 mt-3\">\n <div className=\"shrink-0\" style={{ width: indicatorBox }} />\n <div className=\"flex-1 min-w-0\">{content}</div>\n </div>\n )}\n {!isLast && <VerticalConnectorLine />}\n </>\n )\n}\n\n// ── Vertical connector ───────────────────────────────────────────────────\n\nfunction VerticalConnectorLine() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const isBlue = item.state === 'completed'\n const radius = INDICATOR_SIZE[steps.size] / 2\n const gap = 8\n\n return (\n <div\n aria-hidden\n className={cn(\n // leading-compact:connector 的 0.5lh 須跟 scanning label 同行高(1.3)→ 起點對齊 circle 中心\n // (circle 對齊 label 第一行;label 已 leading-compact)。否則 connector 繼承 li 根 1.5 → 0.5lh 偏大 → 起點偏低。\n 'absolute w-px leading-compact',\n isBlue ? 'bg-info' : 'bg-border',\n )}\n style={{\n left: INDICATOR_BOX_WIDTH[steps.size] / 2,\n top: `calc(0.5lh + ${radius}px + ${gap}px)`,\n bottom: `calc(${radius}px - 0.5lh + ${gap}px)`,\n }}\n />\n )\n}\n\n// ── Horizontal layout (Ant Design pattern) ──────────────────────────────\n//\n// Connector 在 **item 內部**(不是 items 之間的獨立元素):\n// Step (flex-1): [indicator][gap][label][gap][──connector──]\n// Last step: [indicator][gap][label] (無 connector)\n//\n// Root: flex-row gap-3 → gap 只在 step items 之間\n// Step items: flex-1 等寬(最後一步 flex-none 自然寬度)\n//\n// 等距保證:\n// label→connector gap = item 內 flex gap-3 = 12px\n// connector→next circle = root gap-3 = 12px\n// 兩邊都是 12px ✓\n//\n// Description 在 step item 內(connector 下方),wrap 到 item 寬度 = 最長到連結線尾段 ✓\n\nfunction HorizontalLayout({\n label,\n description,\n}: {\n label: React.ReactNode\n description: React.ReactNode\n}) {\n const item = useStepItemContext()\n const steps = useStepsContext()\n const isBlue = item.state === 'completed'\n const indicatorBox = INDICATOR_BOX_WIDTH[steps.size]\n\n return (\n <>\n {/* Row 1: indicator + label + connector(在同一個 flex row) */}\n <StepItemHeader className=\"flex items-start gap-3\">\n {/* Row prefix slot — 消費 item-anatomy <ItemPrefix>(h-[1lh] 對齊 label 第一行 SSOT)*/}\n <ItemPrefix>\n <StepIndicator />\n </ItemPrefix>\n <div className=\"shrink-0 min-w-0\">{label}</div>\n {/* Connector 在 item 內部,flex-1 填滿剩餘寬度 */}\n {!item.isLast && (\n <div className=\"h-[1lh] flex-1 flex items-center min-w-4\" aria-hidden>\n <div className={cn('h-px w-full', isBlue ? 'bg-info' : 'bg-border')} />\n </div>\n )}\n </StepItemHeader>\n {/* Row 2: description — 在 item 寬度內 wrap(含 connector 佔的空間) */}\n {description && (\n <div className=\"min-w-0\" style={{ paddingLeft: indicatorBox + 12 }}>\n {description}\n </div>\n )}\n </>\n )\n}\n\n// ── StepIndicator ────────────────────────────────────────────────────────\n\nfunction StepIndicator() {\n const steps = useStepsContext()\n const item = useStepItemContext()\n const { size, linear } = steps\n const { state, focused, disabled } = item\n\n if (size === 'sm') return <SmIndicator state={state} focused={focused} disabled={disabled} linear={linear} />\n return <MdLgIndicator size={size} state={state} focused={focused} disabled={disabled} linear={linear} />\n}\n\n// ── sm indicator: 8px dot in 24px hit area ───────────────────────────────\n\nfunction SmIndicator({\n state,\n focused,\n disabled,\n linear,\n}: {\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n // sm current (linear) and reachable: hollow ring\n const isHollow = (state === 'current' && linear) || state === 'reachable'\n\n let dotStyle: React.CSSProperties\n if (isHollow) {\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: 'transparent',\n border: '2px solid var(--info-hover)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n } else {\n const dotBg =\n state === 'completed' ? 'var(--info)'\n : state === 'error' ? 'var(--error)'\n : state === 'current' && !linear ? 'var(--fg-disabled)'\n : 'var(--fg-disabled)' // upcoming + non-linear fallback\n\n dotStyle = {\n width: INDICATOR_SIZE.sm,\n height: INDICATOR_SIZE.sm,\n background: dotBg,\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }\n }\n\n return (\n <span\n aria-hidden\n className=\"relative inline-flex items-center justify-center shrink-0\"\n style={{ width: SM_HIT_AREA, height: SM_HIT_AREA }}\n >\n <span\n className={cn('block rounded-full', disabled && 'opacity-disabled')}\n style={dotStyle}\n />\n </span>\n )\n}\n\n// ── md/lg indicator: filled circle with number/icon ──────────────────────\n\nfunction MdLgIndicator({\n size,\n state,\n focused,\n disabled,\n linear,\n}: {\n size: StepsSize\n state: StepContentState\n focused: boolean\n disabled: boolean\n linear: boolean\n}) {\n const diameter = INDICATOR_SIZE[size]\n const iconPx = INDICATOR_ICON_SIZE[size]\n\n let fillBg: string\n let contentColor: string\n\n switch (state) {\n case 'error':\n fillBg = 'var(--error)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'completed':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n case 'current':\n if (linear) {\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n case 'reachable':\n fillBg = 'var(--info)'\n contentColor = 'var(--on-emphasis)'\n break\n default: // upcoming\n if (linear) {\n fillBg = 'var(--muted)'\n contentColor = 'var(--fg-disabled)'\n } else {\n fillBg = 'var(--secondary)'\n contentColor = 'var(--foreground)'\n }\n break\n }\n\n return (\n <span\n aria-hidden\n className={cn(\n 'relative inline-flex items-center justify-center shrink-0 rounded-full',\n 'font-medium leading-none transition-colors',\n disabled && 'opacity-disabled',\n )}\n style={{\n width: diameter,\n height: diameter,\n background: fillBg,\n color: contentColor,\n // 2026-06-11 R2:對齊 spec canonical「indicator 數字與 label 同級」(steps.spec.md 狀態表 md=14/lg=16;spec 明文「之前寫小一號(md=12,lg=14)是錯的」)\n fontSize: size === 'lg' ? 'var(--font-body-lg-size)' : 'var(--font-body-size)',\n boxShadow: focused ? getOuterRingShadow(resolveRingColor(state, linear)) : undefined,\n }}\n >\n <IndicatorContent state={state} iconPx={iconPx} />\n </span>\n )\n}\n\nfunction IndicatorContent({ state, iconPx }: { state: StepContentState; iconPx: number }) {\n if (state === 'completed') return <Check size={iconPx} strokeWidth={2.5} />\n if (state === 'error') return <X size={iconPx} strokeWidth={2.5} />\n return <StepNumber />\n}\n\nfunction StepNumber() {\n const index = React.useContext(StepIndexContext)\n return <span>{index}</span>\n}\n\n// ── StepLabel ────────────────────────────────────────────────────────────\n\nexport interface StepLabelProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst StepLabel = React.forwardRef<HTMLSpanElement, StepLabelProps>(\n ({ className, children, ...props }, ref) => {\n const { size } = useStepsContext()\n const { state, focused, disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // leading-compact:scanning-family label 行高 = 1.3(item-anatomy.spec.md:776);text-body utility\n // 自帶 lh:1.5,須顯式 leading-compact 蓋回 1.3,跟 MenuItem label(實測 14px/18px=1.3)一致。\n 'font-medium break-words leading-compact',\n size === 'lg' ? 'text-body-lg' : 'text-body',\n disabled\n ? 'text-fg-disabled'\n : state === 'error'\n ? 'text-error-text'\n : focused\n ? 'text-foreground'\n : 'text-fg-secondary',\n className,\n )}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepLabel.displayName = 'StepLabel'\n\n// ── StepDescription ──────────────────────────────────────────────────────\n\nexport interface StepDescriptionProps extends React.HTMLAttributes<HTMLSpanElement> {}\n\nconst StepDescription = React.forwardRef<HTMLSpanElement, StepDescriptionProps>(\n ({ className, children, style, ...props }, ref) => {\n const { size } = useStepsContext()\n const { disabled } = useStepItemContext()\n\n return (\n <span\n ref={ref}\n className={cn(\n // Steps 跟 MenuItem 同 scanning-family:sm/md = scanning(body+caption),lg = scanning-lg(body-lg+body-compact)\n size === 'lg'\n ? 'mt-[var(--item-gap-label-desc-scanning-lg)]'\n : 'mt-[var(--item-gap-label-desc-scanning)]',\n 'leading-compact break-words',\n disabled ? 'text-fg-disabled' : 'text-fg-secondary',\n className,\n )}\n style={{\n fontSize: size === 'lg' ? 'var(--font-body-size)' : 'var(--font-caption-size)',\n ...style,\n }}\n {...props}\n >\n {children}\n </span>\n )\n },\n)\nStepDescription.displayName = 'StepDescription'\n\n// ── StepContent ──────────────────────────────────────────────────────────\n\nexport interface StepContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nconst StepContent = React.forwardRef<HTMLDivElement, StepContentProps>(\n ({ className, children, ...props }, ref) => {\n const { orientation } = useStepsContext()\n if (orientation === 'horizontal') return null\n return (\n <div\n ref={ref}\n className={cn('text-body text-foreground min-w-0', className)}\n {...props}\n >\n {children}\n </div>\n )\n },\n)\nStepContent.displayName = 'StepContent'\n\n// ── Exports ──────────────────────────────────────────────────────────────\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 stepsMeta = {\n component: 'Steps',\n family: 2,\n variants: {},\n sizes: {\n sm: { px: 8, when: 'Sidebar / 緊湊 onboarding;indicator 8px dot' },\n md: { px: 24, when: '預設 — wizard / checkout / 註冊主流程;indicator 24px circle' },\n lg: { px: 32, when: 'Marketing 流程展示 / 重要 onboarding;indicator 32px circle' },\n },\n states: ['upcoming', 'reachable', 'current', 'completed', 'error'], // 2026-06-11 R2:content-state 模型(spec 狀態表),非 Phase-1 boilerplate 互動 states,\n tokens: {\n bg: ['bg-info'],\n fg: ['--fg-disabled', '--foreground', '--on-emphasis', 'text-error-text', 'text-fg-disabled', 'text-fg-muted', 'text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { Steps, StepItem, StepLabel, StepDescription, StepContent, stepsRootVariants, stepItemVariants }\n"],"names":[],"mappings":"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"}
@@ -45,7 +45,7 @@ import type { FieldMode, FieldVariant } from '../../components/Field/field-types
45
45
  declare const switchVariants: (props?: ({
46
46
  size?: "sm" | "md" | "lg" | null | undefined;
47
47
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
48
- export interface SwitchProps extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>, VariantProps<typeof switchVariants> {
48
+ export interface SwitchProps extends Omit<React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>, 'asChild' | 'children'>, VariantProps<typeof switchVariants> {
49
49
  /**
50
50
  * Inline label。提供時 Switch 自動包一個 <label> 並連結 htmlFor,
51
51
  * 套用 text-body / text-foreground / disabled 色 的 codified 樣式。
@@ -61,15 +61,15 @@ export interface SwitchProps extends React.ComponentPropsWithoutRef<typeof Switc
61
61
  /**
62
62
  * readonly 模式:standalone = 鎖定互動但維持 ON/OFF 視覺;Field 內 = 灰框 + 勾/叉 icon。
63
63
  * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。
64
- * DataTable cell 非編輯態用 mode="display"(勾/叉 icon),非 readOnly。
64
+ * DataTable cell 非編輯態用 mode="view"(勾/叉 icon),非 readOnly。
65
65
  */
66
66
  readOnly?: boolean;
67
67
  /**
68
68
  * Field mode(2026-05-05 Phase B3 align):
69
69
  * edit — 一般可互動 Switch(預設)
70
- * display — **純展示**:渲染 勾/叉 icon(無互動 primitive、無 input chrome);
70
+ * view — **純展示**:渲染 勾/叉 icon(無互動 primitive、無 input chrome);
71
71
  * 對齊 Carbon read-only / DataTable boolean cell。
72
- * `display` 完全無 toggle 形體;`readonly` 視場景(field-types.ts)。
72
+ * `view` 完全無 toggle 形體;`readonly` 視場景(field-types.ts)。
73
73
  * readonly — standalone 同 readOnly prop(保留視覺鎖互動);Field 內 = 灰框 + 勾/叉 icon
74
74
  * disabled — 同 disabled prop
75
75
  */
@@ -1 +1 @@
1
- {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../../src/components/Switch/switch.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAA;AAE1D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAK3F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,QAAA,MAAM,cAAc;;8EA6BnB,CAAA;AAgBD,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,EAClE,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAED,QAAA,MAAM,MAAM,uFAiNX,CAAA;AAKD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBb,CAAA;AAEV,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../../src/components/Switch/switch.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAA;AAE1D,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAK3F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,QAAA,MAAM,cAAc;;8EA6BnB,CAAA;AAgBD,MAAM,WAAW,WAKf,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC,EAChG,YAAY,CAAC,OAAO,cAAc,CAAC;IACrC;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;OAIG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAED,QAAA,MAAM,MAAM,uFAmNX,CAAA;AAKD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuBb,CAAA;AAEV,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA"}
@@ -91,8 +91,10 @@ const Switch = React.forwardRef(
91
91
  asChild: _asChild,
92
92
  children: _children,
93
93
  ...restDomProps
94
+ // asChild/children 已從 SwitchProps 型別 Omit(見型別註解);此處 cast 保留 runtime strip
95
+ // (防 any-cast consumer 洩漏到 primitive),與 RadioGroup 同款防禦。
94
96
  } = props;
95
- if (resolvedMode === "display") {
97
+ if (resolvedMode === "view") {
96
98
  const isChecked = checkedProp === true;
97
99
  return /* @__PURE__ */ jsx("span", { ...restDomProps, ref, className: "inline-flex", children: /* @__PURE__ */ jsx(BooleanValueIcon, { checked: isChecked, size: resolvedBoxSize }) });
98
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"switch.js","sources":["../../../src/components/Switch/switch.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 * as SwitchPrimitives from '@radix-ui/react-switch'\nimport { Check } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'\nimport { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from '@/design-system/components/Field/field-context'\nimport { fieldWrapperStyles } from '@/design-system/components/Field/field-wrapper'\nimport { BooleanValueIcon } from '@/design-system/components/SelectionControl/boolean-value'\n\n/**\n * Switch — 開關控件\n *\n * ── 結構 ──\n * Track(pill 形容器)→ Thumb(白色圓 + 2px border + check icon)\n * Track 寬 = 2 × 高,thumb 直徑 = track 高度\n *\n * ── 尺寸(sm = md)──\n * sm/md: track 20×40, thumb 20, 白色圓 16, check 12(= checkbox sm/md)\n * lg: track 24×48, thumb 24, 白色圓 20, check 16(= checkbox lg)\n *\n * ── 視覺狀態 ──\n * OFF: track border (neutral-5), thumb 白色 + 2px border-border(neutral-5,與 OFF track 同色)無 check\n * ON: track primary, thumb 白色 + 2px primary border + primary check icon\n * disabled: opacity-disabled(整體透明度)\n * readOnly(standalone): 視覺同一般態,但 pointer-events-none + aria-readonly\n * readOnly(Field 內): 渲染 readonly 灰框 + 勾/叉 icon(2026-06-12 拍板,= Input readonly 同視覺語言)\n *\n * ── label / description / readOnly ──\n * Switch 可以透過 `label` 和 `description` props 在元件內直接渲染緊鄰的文字,\n * 樣式全部 codify 在元件內(text-body、foreground/fg-secondary、disabled 色)。\n *\n * 單獨使用時:\n * <Switch label=\"啟用通知\" description=\"收到新訊息時提醒\" />\n *\n * Form 內使用(在 <Field> context 內):\n * <Field>\n * <FieldLabel>啟用通知</FieldLabel>\n * <Switch /> ← label/description prop 會被自動忽略\n * <FieldDescription>收到新訊息時提醒</FieldDescription>\n * </Field>\n *\n * Field context 透過 useFieldContext() 偵測,避免雙層 label。\n *\n * readOnly 模式:\n * <Switch readOnly checked={true} label=\"...\" />\n * standalone:視覺維持 ON/OFF 正確狀態,但無法互動、不在 tab order 內、寫入 aria-readonly。\n * Field 內:渲染 readonly 灰框 + 勾/叉 icon(不渲染 toggle;見 forwardRef 內 readonly 分支)。\n * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。\n */\n\nconst switchVariants = cva(\n [\n 'group peer inline-flex shrink-0 cursor-pointer items-center rounded-full',\n 'transition-colors duration-150',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'disabled:cursor-not-allowed disabled:opacity-disabled',\n // readOnly:鎖定互動但視覺正常\n 'data-[readonly=true]:pointer-events-none data-[readonly=true]:cursor-default',\n // OFF → ON 背景色\n 'data-[state=unchecked]:bg-border',\n 'data-[state=checked]:bg-primary',\n // 選中之上的 hover = 同色相升 hover 階(2026-07-06 user 掃出 Switch 是「藍色選中家族」\n // 唯一漏網:Checkbox checked hover 早有同款、Ant Switch checked hover = colorPrimaryHover\n // 源碼實錘;順修 meta states 宣稱 'hover' 但 code 原本零 hover 樣式的 claim-vs-code 落差)。\n // unchecked hover:border(n-5)→ border-hover(n-6)深一階,對齊 Checkbox 未選 hover\n // 加深一階慣例 + Ant unchecked hover(colorTextTertiary 加深)同方向。\n 'data-[state=unchecked]:hover:bg-border-hover',\n 'data-[state=checked]:hover:bg-primary-hover',\n ],\n {\n variants: {\n size: {\n sm: 'h-5 w-10', // 20×40\n md: 'h-5 w-10', // 20×40\n lg: 'h-6 w-12', // 24×48\n },\n },\n defaultVariants: { size: 'md' },\n }\n)\n\nconst SPECS: Record<string, { thumb: number; check: number; checkStroke: number }> = {\n // checkStroke:16px 以下 icon 視覺不夠顯眼 → 加粗 stroke 補償(跟 Checkbox 共用原則,\n // 見 checkbox.tsx 的 checkStrokeWidth 註解)。12px 用 3.5(render ≈ 1.75px 線寬,比 Lucide\n // 預設的 1px render 明顯更粗,視覺跟 16px 預設 stroke 的 1.33px 有足夠區別),16px 用 2.5\n // (render ≈ 1.67px,比預設 1.33px 稍粗讓 toggle check 夠顯眼)。跨 size 配對值由 checkbox.tsx 共用。\n // 2026-05-18 簡化 per user 視覺證 + Checkbox 同步(3.5 → 3 sm/md):effective render 差\n // 0.08px 視覺看不出,保留 compensation 主旨但不過度差異化。\n // 2026-07-04 刪 dead field translate:整檔零消費,實際位移 SSOT = Thumb className\n // translate-x-5(20px)/ translate-x-6(24px)(見下方 Thumb),消除雙住所漂移風險。\n sm: { thumb: 20, check: 12, checkStroke: 3 },\n md: { thumb: 20, check: 12, checkStroke: 3 },\n lg: { thumb: 24, check: 16, checkStroke: 2.5 },\n}\n\nexport interface SwitchProps\n extends React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>,\n VariantProps<typeof switchVariants> {\n /**\n * Inline label。提供時 Switch 自動包一個 <label> 並連結 htmlFor,\n * 套用 text-body / text-foreground / disabled 色 的 codified 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldLabel 接管)。\n */\n label?: React.ReactNode\n /**\n * Inline description(secondary 文字)。須與 label 搭配使用,\n * 單獨設定 description 無效果。套用 text-body / text-fg-secondary 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldDescription 接管)。\n */\n description?: React.ReactNode\n /**\n * readonly 模式:standalone = 鎖定互動但維持 ON/OFF 視覺;Field 內 = 灰框 + 勾/叉 icon。\n * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。\n * DataTable cell 非編輯態用 mode=\"display\"(勾/叉 icon),非 readOnly。\n */\n readOnly?: boolean\n /**\n * Field mode(2026-05-05 Phase B3 align):\n * edit — 一般可互動 Switch(預設)\n * display — **純展示**:渲染 勾/叉 icon(無互動 primitive、無 input chrome);\n * 對齊 Carbon read-only / DataTable boolean cell。\n * `display` 完全無 toggle 形體;`readonly` 視場景(field-types.ts)。\n * readonly — standalone 同 readOnly prop(保留視覺鎖互動);Field 內 = 灰框 + 勾/叉 icon\n * disabled — 同 disabled prop\n */\n mode?: FieldMode\n /**\n * Visual chrome — Switch 本體無 input wrapper variant,本 prop 對 Switch 主體無視覺影響;\n * 為對齊 Field 4-mode + chrome 透傳契約而保留(M19 一致性)。\n */\n variant?: FieldVariant\n}\n\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitives.Root>,\n SwitchProps\n>(\n (\n {\n className,\n size,\n label,\n description,\n readOnly = false,\n disabled: disabledProp,\n mode,\n // chrome 對 Switch 主體無視覺影響(無 input wrapper)— 接收純為 prop 一致性;destructure 防 leak 到 DOM。\n variant: _chrome,\n id: idProp,\n ...props\n },\n ref\n ) => {\n const sizeKey = size ?? 'md'\n const spec = SPECS[sizeKey]\n\n // Field context 偵測:在 Field 內時忽略自己的 label/description,避免雙層\n // 2026-05-31 #35:hooks(useFieldContext / useId)必在任何 conditional return 前呼叫(Rules of Hooks)。\n // 原 mode='display' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。\n const fieldCtx = useFieldContext()\n // 2026-06-08 SSOT:<Field disabled>/<Field mode> cascade(原 disabled/mode 直傳 prop,漏 fieldCtx)\n const disabled = useResolvedFieldDisabled(disabledProp)\n const resolvedMode = useResolvedFieldMode({ mode, disabled, readOnly })\n const effectiveReadOnly = readOnly || resolvedMode === 'readonly'\n // mode='disabled' 直傳(無 Field ctx 的 cell 場景)必須落到真 disabled chrome(同 Checkbox 2026-06-12 修)\n const effectiveDisabled = disabled || resolvedMode === 'disabled'\n // readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)\n const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'\n const insideField = fieldCtx?.hasFieldWrapper === true\n const effectiveLabel = insideField ? undefined : label\n const effectiveDescription = insideField ? undefined : description\n\n // 在 horizontal Field 內自動齊右(iOS / macOS Settings canonical):\n // horizontal Field 的 layout 是 label(固定寬)| control area(fill),Switch 作為\n // trailing control 應靠右(對齊 horizontal DescriptionItem 的「label 左 / value 右」模式)。\n // 世界級對照:iOS Settings / macOS System Settings / GitHub Settings / Figma prefs\n // 一律 switch 齊右 — 視覺掃描快、對齊一致。\n const alignRightInField =\n insideField && fieldCtx?.orientation === 'horizontal' ? 'ml-auto' : ''\n\n // Id 連結:優先使用 prop,再退到 Field context 的 id,最後用 useId 生成\n const generatedId = React.useId()\n const inputId = idProp ?? fieldCtx?.id ?? generatedId\n\n // 2026-07-04 修:display / readonly-in-Field 分支的裸 span/div 原丟棄剩餘 props\n // (id/data-*/aria-*)且不轉發 forwardRef ref → consumer 的 aria-label 等靜默失效。\n // 抽出 Radix 專屬 non-DOM props,其餘 DOM props 於兩分支 spread 轉發(與 Checkbox/\n // RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。\n const {\n checked: checkedProp,\n defaultChecked: defaultCheckedProp,\n onCheckedChange: _onCheckedChange,\n required: _required,\n name: _name,\n value: _value,\n asChild: _asChild,\n children: _children,\n ...restDomProps\n } = props\n\n // ── mode='display'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────\n // 純展示模式:無互動 toggle、渲染 Check / X icon。與 Checkbox display 對齊(同 boolean primitive,\n // 共用 SelectionControl/boolean-value.tsx SSOT — 勾/叉 icon + 中性 foreground 色)。\n if (resolvedMode === 'display') {\n const isChecked = checkedProp === true\n return (\n <span {...restDomProps} ref={ref as React.Ref<HTMLSpanElement>} className=\"inline-flex\">\n <BooleanValueIcon checked={isChecked} size={resolvedBoxSize} />\n </span>\n )\n }\n\n // ── mode='readonly' in Field(2026-06-12 拍板「灰框 + 勾/叉」,與 Checkbox 同款;2026-07-09 glyph → Check/X icon)──\n // Field 內 readonly boolean = fieldWrapperStyles readonly 灰框(= Input readonly 同源)\n // + 勾/叉 icon 值語言;standalone readOnly(settings list)維持原樣鎖互動。詳 checkbox.tsx 同段註解。\n if (effectiveReadOnly && insideField) {\n const isChecked = (checkedProp ?? defaultCheckedProp) === true\n const boxSize = resolvedBoxSize\n return (\n <div\n {...(restDomProps as React.HTMLAttributes<HTMLDivElement>)}\n ref={ref as React.Ref<HTMLDivElement>}\n role=\"switch\"\n aria-checked={isChecked}\n aria-readonly=\"true\"\n aria-labelledby={fieldCtx?.labelId}\n aria-invalid={fieldCtx?.invalid || undefined}\n data-readonly=\"true\"\n tabIndex={0}\n className={cn(\n fieldWrapperStyles({ size: boxSize, mode: 'readonly', variant: 'default' }),\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n >\n <BooleanValueIcon checked={isChecked} size={boxSize} />\n </div>\n )\n }\n\n const rootEl = (\n <SwitchPrimitives.Root\n id={inputId}\n className={cn(switchVariants({ size }), alignRightInField, className)}\n ref={ref}\n disabled={effectiveDisabled}\n aria-readonly={effectiveReadOnly || undefined}\n data-readonly={effectiveReadOnly || undefined}\n tabIndex={effectiveReadOnly ? -1 : undefined}\n aria-describedby={fieldCtx?.descriptionId}\n {...props}\n // 2026-07-05 D4 修:readOnly 鎖互動補 label 繞道 — <label htmlFor> 的 synthetic click\n // 不是 pointer event,cva pointer-events-none 攔不到,點 label 文字仍 toggle。\n // preventDefault 讓 Radix composeEventHandlers(checkForDefaultPrevented)跳過內部 toggle;\n // 必列在 {...props} 之後才不被 consumer onClick 覆蓋(與 Checkbox/RadioGroupItem 同修)。\n onClick={(event) => {\n if (effectiveReadOnly) {\n event.preventDefault()\n return\n }\n props.onClick?.(event)\n }}\n >\n <SwitchPrimitives.Thumb\n className={cn(\n 'pointer-events-none flex items-center justify-center rounded-full bg-on-emphasis border-2',\n 'transition-all duration-150',\n 'data-[state=unchecked]:translate-x-0 data-[state=unchecked]:border-border',\n 'data-[state=checked]:border-primary',\n sizeKey === 'lg' ? 'data-[state=checked]:translate-x-6' : 'data-[state=checked]:translate-x-5',\n )}\n style={{ width: spec.thumb, height: spec.thumb }}\n >\n {/* Check icon — Radix Thumb inherits data-state from Root */}\n <Check\n size={spec.check}\n strokeWidth={spec.checkStroke}\n className=\"text-primary opacity-0 transition-opacity duration-150 group-data-[state=checked]:opacity-100\"\n aria-hidden\n />\n </SwitchPrimitives.Thumb>\n </SwitchPrimitives.Root>\n )\n\n // 無 label → 只渲染 switch 本體\n if (effectiveLabel == null) return rootEl\n\n // 有 label → 包 <label> + codified 樣式\n // Switch 慣例:label 在左、switch 在右(對齊 iOS / Polaris / Material 標準)\n // label 行第一行對齊 switch 中線:容器用 items-start + switch 包 h-[1lh] flex-center\n return (\n <label\n htmlFor={inputId}\n // 2026-07-05 D4 修:readOnly 時在 label 端取消 synthetic activation(第一道防線;\n // Root onClick guard 為第二道 — 兩道對齊 finding suggestion 防 consumer 自寫 label 繞過)。\n onClick={(event) => {\n if (effectiveReadOnly) event.preventDefault()\n }}\n className={cn(\n 'inline-flex items-start gap-3 select-none',\n effectiveDisabled ? 'cursor-not-allowed' : readOnly ? 'cursor-default' : 'cursor-pointer'\n )}\n >\n {/* Label↔desc gap typography-mode-aware:\n sm/md = reading(body+body 14/1.5),lg = reading-lg(body-lg+body 14/1.5) */}\n <span\n className={cn(\n 'flex-1 min-w-0 flex flex-col',\n sizeKey === 'lg'\n ? 'gap-[var(--item-gap-label-desc-reading-lg)]'\n : 'gap-[var(--item-gap-label-desc-reading)]',\n )}\n >\n <span\n className={cn(\n // Reading mode 字級:lg → text-body-lg (16px),sm/md → text-body (14px)\n sizeKey === 'lg' ? 'text-body-lg' : 'text-body',\n effectiveDisabled ? 'text-fg-disabled' : 'text-foreground'\n )}\n >\n {effectiveLabel}\n </span>\n {effectiveDescription != null && (\n <span\n className={cn(\n effectiveDisabled ? 'text-fg-disabled' : 'text-fg-secondary'\n )}\n // Reading mode description:**最小 14px**(spec 14→14px, 16→14px),lh 預設 1.5。\n // 用 inline style 直接繞過 tailwind-merge 對 text-body / text-fg-* 的潛在衝突。\n style={{ fontSize: 'var(--font-body-size)' }}\n >\n {effectiveDescription}\n </span>\n )}\n </span>\n {/* @row-slot-handcraft-allow: Field 控件的 1lh 首行對齊 wrapper(selection-control 家族 Checkbox/RadioGroup 同構),非 row item slot,不消費 MenuItem */}\n <span className=\"h-[1lh] flex items-center shrink-0\">\n {rootEl}\n </span>\n </label>\n )\n }\n)\nSwitch.displayName = SwitchPrimitives.Root.displayName\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 switchMeta = {\n component: 'Switch',\n family: null, // self-contained primitive(對齊 spec frontmatter self-contained + body L31;非 Family 4)\n variants: {\n\n },\n sizes: {\n sm: { fieldHeight: 28, iconSize: 12, typography: 'body' },\n md: { fieldHeight: 32, iconSize: 12, typography: 'body' },\n lg: { fieldHeight: 36, iconSize: 16, typography: 'body-lg' },\n },\n // 2026-07-04 修 stale meta:移除 'active' — switchVariants / Thumb 無 active-state 樣式\n // (cva 只有 unchecked/checked/disabled/readonly/focus-visible;對照 checkboxMeta 正確不含 active)\n // 'checked' = ON 持續態(bg-primary;2026-07-07 meta 詞彙統一補列,toggle 家族用 'checked')\n states: ['default', 'hover', 'checked', 'focus-visible', 'disabled'],\n tokens: {\n // 2026-07-04 補齊漏列:bg-border = OFF track(cva data-[state=unchecked]:bg-border)、\n // bg-on-emphasis = Thumb 白圓(Thumb className)— 兩者 code 實際消費,meta 原漏列\n bg: ['bg-border', 'bg-on-emphasis', 'bg-primary'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground', 'text-primary'],\n ring: ['ring-ring'],\n },\n defaultSize: 'md',\n} as const\n\nexport { Switch, switchVariants }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"switch.js","sources":["../../../src/components/Switch/switch.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 * as SwitchPrimitives from '@radix-ui/react-switch'\nimport { Check } from 'lucide-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant } from '@/design-system/components/Field/field-types'\nimport { useFieldContext, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldSize } from '@/design-system/components/Field/field-context'\nimport { fieldWrapperStyles } from '@/design-system/components/Field/field-wrapper'\nimport { BooleanValueIcon } from '@/design-system/components/SelectionControl/boolean-value'\n\n/**\n * Switch — 開關控件\n *\n * ── 結構 ──\n * Track(pill 形容器)→ Thumb(白色圓 + 2px border + check icon)\n * Track 寬 = 2 × 高,thumb 直徑 = track 高度\n *\n * ── 尺寸(sm = md)──\n * sm/md: track 20×40, thumb 20, 白色圓 16, check 12(= checkbox sm/md)\n * lg: track 24×48, thumb 24, 白色圓 20, check 16(= checkbox lg)\n *\n * ── 視覺狀態 ──\n * OFF: track border (neutral-5), thumb 白色 + 2px border-border(neutral-5,與 OFF track 同色)無 check\n * ON: track primary, thumb 白色 + 2px primary border + primary check icon\n * disabled: opacity-disabled(整體透明度)\n * readOnly(standalone): 視覺同一般態,但 pointer-events-none + aria-readonly\n * readOnly(Field 內): 渲染 readonly 灰框 + 勾/叉 icon(2026-06-12 拍板,= Input readonly 同視覺語言)\n *\n * ── label / description / readOnly ──\n * Switch 可以透過 `label` 和 `description` props 在元件內直接渲染緊鄰的文字,\n * 樣式全部 codify 在元件內(text-body、foreground/fg-secondary、disabled 色)。\n *\n * 單獨使用時:\n * <Switch label=\"啟用通知\" description=\"收到新訊息時提醒\" />\n *\n * Form 內使用(在 <Field> context 內):\n * <Field>\n * <FieldLabel>啟用通知</FieldLabel>\n * <Switch /> ← label/description prop 會被自動忽略\n * <FieldDescription>收到新訊息時提醒</FieldDescription>\n * </Field>\n *\n * Field context 透過 useFieldContext() 偵測,避免雙層 label。\n *\n * readOnly 模式:\n * <Switch readOnly checked={true} label=\"...\" />\n * standalone:視覺維持 ON/OFF 正確狀態,但無法互動、不在 tab order 內、寫入 aria-readonly。\n * Field 內:渲染 readonly 灰框 + 勾/叉 icon(不渲染 toggle;見 forwardRef 內 readonly 分支)。\n * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。\n */\n\nconst switchVariants = cva(\n [\n 'group peer inline-flex shrink-0 cursor-pointer items-center rounded-full',\n 'transition-colors duration-150',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n 'disabled:cursor-not-allowed disabled:opacity-disabled',\n // readOnly:鎖定互動但視覺正常\n 'data-[readonly=true]:pointer-events-none data-[readonly=true]:cursor-default',\n // OFF → ON 背景色\n 'data-[state=unchecked]:bg-border',\n 'data-[state=checked]:bg-primary',\n // 選中之上的 hover = 同色相升 hover 階(2026-07-06 user 掃出 Switch 是「藍色選中家族」\n // 唯一漏網:Checkbox checked hover 早有同款、Ant Switch checked hover = colorPrimaryHover\n // 源碼實錘;順修 meta states 宣稱 'hover' 但 code 原本零 hover 樣式的 claim-vs-code 落差)。\n // unchecked hover:border(n-5)→ border-hover(n-6)深一階,對齊 Checkbox 未選 hover\n // 加深一階慣例 + Ant unchecked hover(colorTextTertiary 加深)同方向。\n 'data-[state=unchecked]:hover:bg-border-hover',\n 'data-[state=checked]:hover:bg-primary-hover',\n ],\n {\n variants: {\n size: {\n sm: 'h-5 w-10', // 20×40\n md: 'h-5 w-10', // 20×40\n lg: 'h-6 w-12', // 24×48\n },\n },\n defaultVariants: { size: 'md' },\n }\n)\n\nconst SPECS: Record<string, { thumb: number; check: number; checkStroke: number }> = {\n // checkStroke:16px 以下 icon 視覺不夠顯眼 → 加粗 stroke 補償(跟 Checkbox 共用原則,\n // 見 checkbox.tsx 的 checkStrokeWidth 註解)。12px 用 3.5(render ≈ 1.75px 線寬,比 Lucide\n // 預設的 1px render 明顯更粗,視覺跟 16px 預設 stroke 的 1.33px 有足夠區別),16px 用 2.5\n // (render ≈ 1.67px,比預設 1.33px 稍粗讓 toggle check 夠顯眼)。跨 size 配對值由 checkbox.tsx 共用。\n // 2026-05-18 簡化 per user 視覺證 + Checkbox 同步(3.5 → 3 sm/md):effective render 差\n // 0.08px 視覺看不出,保留 compensation 主旨但不過度差異化。\n // 2026-07-04 刪 dead field translate:整檔零消費,實際位移 SSOT = Thumb className\n // translate-x-5(20px)/ translate-x-6(24px)(見下方 Thumb),消除雙住所漂移風險。\n sm: { thumb: 20, check: 12, checkStroke: 3 },\n md: { thumb: 20, check: 12, checkStroke: 3 },\n lg: { thumb: 24, check: 16, checkStroke: 2.5 },\n}\n\nexport interface SwitchProps\n // asChild / children 從公開型別 Omit(2026-07-18 決策2):Switch 固定 anatomy —\n // 恆渲染 Thumb + BooleanValueIcon,非 Slot host;children 被固定 Thumb 靜默覆蓋,\n // asChild(Radix Slot 單子節點)破壞 track/thumb 結構(CLAUDE.md 失敗記憶「asChild ? Slot」)。\n // 對齊 Checkbox 同款收窄(sibling selection control)。\n extends Omit<React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>, 'asChild' | 'children'>,\n VariantProps<typeof switchVariants> {\n /**\n * Inline label。提供時 Switch 自動包一個 <label> 並連結 htmlFor,\n * 套用 text-body / text-foreground / disabled 色 的 codified 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldLabel 接管)。\n */\n label?: React.ReactNode\n /**\n * Inline description(secondary 文字)。須與 label 搭配使用,\n * 單獨設定 description 無效果。套用 text-body / text-fg-secondary 樣式。\n * 在 <Field> context 內時此 prop 會被忽略(由 FieldDescription 接管)。\n */\n description?: React.ReactNode\n /**\n * readonly 模式:standalone = 鎖定互動但維持 ON/OFF 視覺;Field 內 = 灰框 + 勾/叉 icon。\n * 與 disabled 的差異:readonly 不降色(可讀),disabled 降色(弱化)。\n * DataTable cell 非編輯態用 mode=\"view\"(勾/叉 icon),非 readOnly。\n */\n readOnly?: boolean\n /**\n * Field mode(2026-05-05 Phase B3 align):\n * edit — 一般可互動 Switch(預設)\n * view — **純展示**:渲染 勾/叉 icon(無互動 primitive、無 input chrome);\n * 對齊 Carbon read-only / DataTable boolean cell。\n * `view` 完全無 toggle 形體;`readonly` 視場景(field-types.ts)。\n * readonly — standalone 同 readOnly prop(保留視覺鎖互動);Field 內 = 灰框 + 勾/叉 icon\n * disabled — 同 disabled prop\n */\n mode?: FieldMode\n /**\n * Visual chrome — Switch 本體無 input wrapper variant,本 prop 對 Switch 主體無視覺影響;\n * 為對齊 Field 4-mode + chrome 透傳契約而保留(M19 一致性)。\n */\n variant?: FieldVariant\n}\n\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitives.Root>,\n SwitchProps\n>(\n (\n {\n className,\n size,\n label,\n description,\n readOnly = false,\n disabled: disabledProp,\n mode,\n // chrome 對 Switch 主體無視覺影響(無 input wrapper)— 接收純為 prop 一致性;destructure 防 leak 到 DOM。\n variant: _chrome,\n id: idProp,\n ...props\n },\n ref\n ) => {\n const sizeKey = size ?? 'md'\n const spec = SPECS[sizeKey]\n\n // Field context 偵測:在 Field 內時忽略自己的 label/description,避免雙層\n // 2026-05-31 #35:hooks(useFieldContext / useId)必在任何 conditional return 前呼叫(Rules of Hooks)。\n // 原 mode='view' early return 寫在 hooks 之上 → runtime 切 mode 會 hook count 不一致 crash;已下移至 hooks 後。\n const fieldCtx = useFieldContext()\n // 2026-06-08 SSOT:<Field disabled>/<Field mode> cascade(原 disabled/mode 直傳 prop,漏 fieldCtx)\n const disabled = useResolvedFieldDisabled(disabledProp)\n const resolvedMode = useResolvedFieldMode({ mode, disabled, readOnly })\n const effectiveReadOnly = readOnly || resolvedMode === 'readonly'\n // mode='disabled' 直傳(無 Field ctx 的 cell 場景)必須落到真 disabled chrome(同 Checkbox 2026-06-12 修)\n const effectiveDisabled = disabled || resolvedMode === 'disabled'\n // readonly 灰框 size:走 SSOT resolver(prop > ctx > 'md',field-context.ts:150-161)\n const resolvedBoxSize = useResolvedFieldSize(size ?? undefined, 'md') as 'sm' | 'md' | 'lg'\n const insideField = fieldCtx?.hasFieldWrapper === true\n const effectiveLabel = insideField ? undefined : label\n const effectiveDescription = insideField ? undefined : description\n\n // 在 horizontal Field 內自動齊右(iOS / macOS Settings canonical):\n // horizontal Field 的 layout 是 label(固定寬)| control area(fill),Switch 作為\n // trailing control 應靠右(對齊 horizontal DescriptionItem 的「label 左 / value 右」模式)。\n // 世界級對照:iOS Settings / macOS System Settings / GitHub Settings / Figma prefs\n // 一律 switch 齊右 — 視覺掃描快、對齊一致。\n const alignRightInField =\n insideField && fieldCtx?.orientation === 'horizontal' ? 'ml-auto' : ''\n\n // Id 連結:優先使用 prop,再退到 Field context 的 id,最後用 useId 生成\n const generatedId = React.useId()\n const inputId = idProp ?? fieldCtx?.id ?? generatedId\n\n // 2026-07-04 修:view / readonly-in-Field 分支的裸 span/div 原丟棄剩餘 props\n // (id/data-*/aria-*)且不轉發 forwardRef ref → consumer 的 aria-label 等靜默失效。\n // 抽出 Radix 專屬 non-DOM props,其餘 DOM props 於兩分支 spread 轉發(與 Checkbox/\n // RadioGroup 同修);edit 主路徑不受影響(rootEl 仍 spread 完整 props)。\n const {\n checked: checkedProp,\n defaultChecked: defaultCheckedProp,\n onCheckedChange: _onCheckedChange,\n required: _required,\n name: _name,\n value: _value,\n asChild: _asChild,\n children: _children,\n ...restDomProps\n // asChild/children 已從 SwitchProps 型別 Omit(見型別註解);此處 cast 保留 runtime strip\n // (防 any-cast consumer 洩漏到 primitive),與 RadioGroup 同款防禦。\n } = props as SwitchProps & { asChild?: boolean; children?: React.ReactNode }\n\n // ── mode='view'(下移至所有 hooks 之後,per #35 Rules of Hooks)──────────\n // 純展示模式:無互動 toggle、渲染 Check / X icon。與 Checkbox view 對齊(同 boolean primitive,\n // 共用 SelectionControl/boolean-value.tsx SSOT — 勾/叉 icon + 中性 foreground 色)。\n if (resolvedMode === 'view') {\n const isChecked = checkedProp === true\n return (\n <span {...restDomProps} ref={ref as React.Ref<HTMLSpanElement>} className=\"inline-flex\">\n <BooleanValueIcon checked={isChecked} size={resolvedBoxSize} />\n </span>\n )\n }\n\n // ── mode='readonly' in Field(2026-06-12 拍板「灰框 + 勾/叉」,與 Checkbox 同款;2026-07-09 glyph → Check/X icon)──\n // Field 內 readonly boolean = fieldWrapperStyles readonly 灰框(= Input readonly 同源)\n // + 勾/叉 icon 值語言;standalone readOnly(settings list)維持原樣鎖互動。詳 checkbox.tsx 同段註解。\n if (effectiveReadOnly && insideField) {\n const isChecked = (checkedProp ?? defaultCheckedProp) === true\n const boxSize = resolvedBoxSize\n return (\n <div\n {...(restDomProps as React.HTMLAttributes<HTMLDivElement>)}\n ref={ref as React.Ref<HTMLDivElement>}\n role=\"switch\"\n aria-checked={isChecked}\n aria-readonly=\"true\"\n aria-labelledby={fieldCtx?.labelId}\n aria-invalid={fieldCtx?.invalid || undefined}\n data-readonly=\"true\"\n tabIndex={0}\n className={cn(\n fieldWrapperStyles({ size: boxSize, mode: 'readonly', variant: 'default' }),\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n className,\n )}\n >\n <BooleanValueIcon checked={isChecked} size={boxSize} />\n </div>\n )\n }\n\n const rootEl = (\n <SwitchPrimitives.Root\n id={inputId}\n className={cn(switchVariants({ size }), alignRightInField, className)}\n ref={ref}\n disabled={effectiveDisabled}\n aria-readonly={effectiveReadOnly || undefined}\n data-readonly={effectiveReadOnly || undefined}\n tabIndex={effectiveReadOnly ? -1 : undefined}\n aria-describedby={fieldCtx?.descriptionId}\n {...props}\n // 2026-07-05 D4 修:readOnly 鎖互動補 label 繞道 — <label htmlFor> 的 synthetic click\n // 不是 pointer event,cva pointer-events-none 攔不到,點 label 文字仍 toggle。\n // preventDefault 讓 Radix composeEventHandlers(checkForDefaultPrevented)跳過內部 toggle;\n // 必列在 {...props} 之後才不被 consumer onClick 覆蓋(與 Checkbox/RadioGroupItem 同修)。\n onClick={(event) => {\n if (effectiveReadOnly) {\n event.preventDefault()\n return\n }\n props.onClick?.(event)\n }}\n >\n <SwitchPrimitives.Thumb\n className={cn(\n 'pointer-events-none flex items-center justify-center rounded-full bg-on-emphasis border-2',\n 'transition-all duration-150',\n 'data-[state=unchecked]:translate-x-0 data-[state=unchecked]:border-border',\n 'data-[state=checked]:border-primary',\n sizeKey === 'lg' ? 'data-[state=checked]:translate-x-6' : 'data-[state=checked]:translate-x-5',\n )}\n style={{ width: spec.thumb, height: spec.thumb }}\n >\n {/* Check icon — Radix Thumb inherits data-state from Root */}\n <Check\n size={spec.check}\n strokeWidth={spec.checkStroke}\n className=\"text-primary opacity-0 transition-opacity duration-150 group-data-[state=checked]:opacity-100\"\n aria-hidden\n />\n </SwitchPrimitives.Thumb>\n </SwitchPrimitives.Root>\n )\n\n // 無 label → 只渲染 switch 本體\n if (effectiveLabel == null) return rootEl\n\n // 有 label → 包 <label> + codified 樣式\n // Switch 慣例:label 在左、switch 在右(對齊 iOS / Polaris / Material 標準)\n // label 行第一行對齊 switch 中線:容器用 items-start + switch 包 h-[1lh] flex-center\n return (\n <label\n htmlFor={inputId}\n // 2026-07-05 D4 修:readOnly 時在 label 端取消 synthetic activation(第一道防線;\n // Root onClick guard 為第二道 — 兩道對齊 finding suggestion 防 consumer 自寫 label 繞過)。\n onClick={(event) => {\n if (effectiveReadOnly) event.preventDefault()\n }}\n className={cn(\n 'inline-flex items-start gap-3 select-none',\n effectiveDisabled ? 'cursor-not-allowed' : readOnly ? 'cursor-default' : 'cursor-pointer'\n )}\n >\n {/* Label↔desc gap typography-mode-aware:\n sm/md = reading(body+body 14/1.5),lg = reading-lg(body-lg+body 14/1.5) */}\n <span\n className={cn(\n 'flex-1 min-w-0 flex flex-col',\n sizeKey === 'lg'\n ? 'gap-[var(--item-gap-label-desc-reading-lg)]'\n : 'gap-[var(--item-gap-label-desc-reading)]',\n )}\n >\n <span\n className={cn(\n // Reading mode 字級:lg → text-body-lg (16px),sm/md → text-body (14px)\n sizeKey === 'lg' ? 'text-body-lg' : 'text-body',\n effectiveDisabled ? 'text-fg-disabled' : 'text-foreground'\n )}\n >\n {effectiveLabel}\n </span>\n {effectiveDescription != null && (\n <span\n className={cn(\n effectiveDisabled ? 'text-fg-disabled' : 'text-fg-secondary'\n )}\n // Reading mode description:**最小 14px**(spec 14→14px, 16→14px),lh 預設 1.5。\n // 用 inline style 直接繞過 tailwind-merge 對 text-body / text-fg-* 的潛在衝突。\n style={{ fontSize: 'var(--font-body-size)' }}\n >\n {effectiveDescription}\n </span>\n )}\n </span>\n {/* @row-slot-handcraft-allow: Field 控件的 1lh 首行對齊 wrapper(selection-control 家族 Checkbox/RadioGroup 同構),非 row item slot,不消費 MenuItem */}\n <span className=\"h-[1lh] flex items-center shrink-0\">\n {rootEl}\n </span>\n </label>\n )\n }\n)\nSwitch.displayName = SwitchPrimitives.Root.displayName\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 switchMeta = {\n component: 'Switch',\n family: null, // self-contained primitive(對齊 spec frontmatter self-contained + body L31;非 Family 4)\n variants: {\n\n },\n sizes: {\n sm: { fieldHeight: 28, iconSize: 12, typography: 'body' },\n md: { fieldHeight: 32, iconSize: 12, typography: 'body' },\n lg: { fieldHeight: 36, iconSize: 16, typography: 'body-lg' },\n },\n // 2026-07-04 修 stale meta:移除 'active' — switchVariants / Thumb 無 active-state 樣式\n // (cva 只有 unchecked/checked/disabled/readonly/focus-visible;對照 checkboxMeta 正確不含 active)\n // 'checked' = ON 持續態(bg-primary;2026-07-07 meta 詞彙統一補列,toggle 家族用 'checked')\n states: ['default', 'hover', 'checked', 'focus-visible', 'disabled'],\n tokens: {\n // 2026-07-04 補齊漏列:bg-border = OFF track(cva data-[state=unchecked]:bg-border)、\n // bg-on-emphasis = Thumb 白圓(Thumb className)— 兩者 code 實際消費,meta 原漏列\n bg: ['bg-border', 'bg-on-emphasis', 'bg-primary'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground', 'text-primary'],\n ring: ['ring-ring'],\n },\n defaultSize: 'md',\n} as const\n\nexport { Switch, switchVariants }\n"],"names":[],"mappings":"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"}
@@ -45,7 +45,7 @@ declare const TabsList: React.ForwardRefExoticComponent<TabsListProps & React.Re
45
45
  declare const tabsTriggerVariants: (props?: ({
46
46
  size?: "sm" | "md" | "lg" | null | undefined;
47
47
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
48
- interface TabsTriggerProps extends React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger> {
48
+ interface TabsTriggerProps extends Omit<React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>, 'asChild'> {
49
49
  /** 左側 icon(LucideIcon) */
50
50
  startIcon?: LucideIcon;
51
51
  /** 右側 badge(通常是計數指示器) */
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/tabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAkB9C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,KAAK,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAClC,KAAK,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAU9C,UAAU,SAAU,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC;CAAG;AA2CxF,QAAA,MAAM,IAAI,kFAkCR,CAAA;AAiBF,UAAU,aACR,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC;IACjE,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,QAAA,MAAM,QAAQ,sFAmCZ,CAAA;AA0MF,QAAA,MAAM,mBAAmB;;8EA4CxB,CAAA;AAED,UAAU,gBACR,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC;IACpE,0BAA0B;IAC1B,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,yBAAyB;IACzB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC/B;AAED,QAAA,MAAM,WAAW,4FAiDf,CAAA;AAIF,QAAA,MAAM,WAAW,0JAkBf,CAAA;AAKF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoBX,CAAA;AAEV,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAA;AACxE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAA"}
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../../src/components/Tabs/tabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAA;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAkB9C;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,KAAK,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAClC,KAAK,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAmB9C,UAAU,SAAU,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC;CAAG;AA2CxF,QAAA,MAAM,IAAI,kFAkCR,CAAA;AAiBF,UAAU,aACR,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC;IACjE,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;CACxB;AAED,QAAA,MAAM,QAAQ,sFA8CZ,CAAA;AA0MF,QAAA,MAAM,mBAAmB;;8EA4CxB,CAAA;AAED,UAAU,gBAIR,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IACrF,0BAA0B;IAC1B,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,yBAAyB;IACzB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;OAIG;IACH,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC/B;AAED,QAAA,MAAM,WAAW,4FA0Ff,CAAA;AAIF,QAAA,MAAM,WAAW,0JAkBf,CAAA;AAKF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoBX,CAAA;AAEV,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,CAAA;AACxE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAA"}
@@ -1,5 +1,6 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
+ import { createPortal } from "react-dom";
3
4
  import * as TabsPrimitive from "@radix-ui/react-tabs";
4
5
  import { cva } from "class-variance-authority";
5
6
  import { cn } from "../../lib/utils.js";
@@ -8,6 +9,7 @@ import { useScrollByPage, buildFadeMask, ARROW_BUTTON_WIDTH, OverflowScrollArrow
8
9
  import { ICON_SIZE } from "../../patterns/element-anatomy/item-anatomy.js";
9
10
  import { useScrollEdges } from "../../hooks/use-overflow-items.js";
10
11
  const TabsContext = React.createContext({ size: "md" });
12
+ const TabsActionOverlayContext = React.createContext(null);
11
13
  const TabsValueContext = React.createContext({});
12
14
  function getElementRef(element) {
13
15
  var _a, _b;
@@ -67,21 +69,27 @@ const TABS_LIST_BASE = [
67
69
  ].join(" ");
68
70
  const TabsList = React.forwardRef(({ className, size = "sm", overflow = "none", children, ...props }, ref) => {
69
71
  const tabsSizeContext = React.useMemo(() => ({ size }), [size]);
72
+ const [overlayEl, setOverlayEl] = React.useState(null);
73
+ let listNode;
70
74
  if (overflow === "scroll") {
71
- return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(ScrollTabsList, { ref, className, ...props, children }) });
72
- }
73
- if (overflow === "menu") {
74
- return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(MenuTabsList, { ref, className, ...props, children }) });
75
+ listNode = /* @__PURE__ */ jsx(ScrollTabsList, { ref, className, ...props, children });
76
+ } else if (overflow === "menu") {
77
+ listNode = /* @__PURE__ */ jsx(MenuTabsList, { ref, className, ...props, children });
78
+ } else {
79
+ listNode = /* @__PURE__ */ jsx(
80
+ TabsPrimitive.List,
81
+ {
82
+ ref,
83
+ className: cn(TABS_LIST_BASE, "w-full", className),
84
+ ...props,
85
+ children
86
+ }
87
+ );
75
88
  }
76
- return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(
77
- TabsPrimitive.List,
78
- {
79
- ref,
80
- className: cn(TABS_LIST_BASE, "w-full", className),
81
- ...props,
82
- children
83
- }
84
- ) });
89
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: tabsSizeContext, children: /* @__PURE__ */ jsx(TabsActionOverlayContext.Provider, { value: overlayEl, children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
90
+ listNode,
91
+ /* @__PURE__ */ jsx("div", { ref: setOverlayEl, className: "pointer-events-none absolute inset-0 z-10" })
92
+ ] }) }) });
85
93
  });
86
94
  TabsList.displayName = "TabsList";
87
95
  const ScrollTabsList = React.forwardRef(({ className, children, ...props }, ref) => {
@@ -268,14 +276,48 @@ const tabsTriggerVariants = cva(
268
276
  );
269
277
  const TabsTrigger = React.forwardRef(({ className, startIcon: StartIcon, badge, endIcon: EndIcon, inlineAction, children, ...props }, ref) => {
270
278
  const { size } = React.useContext(TabsContext);
279
+ const overlayEl = React.useContext(TabsActionOverlayContext);
271
280
  const iconSize = ICON_SIZE[size];
272
281
  const hasSuffix = badge != null || EndIcon !== void 0;
273
282
  const hasAction = inlineAction != null;
274
283
  const actionPaddingRight = hasAction ? iconSize + (hasSuffix ? 4 : 8) : void 0;
284
+ const triggerElRef = React.useRef(null);
285
+ const setTriggerRef = React.useCallback(
286
+ (el) => {
287
+ triggerElRef.current = el;
288
+ if (typeof ref === "function") ref(el);
289
+ else if (ref) ref.current = el;
290
+ },
291
+ [ref]
292
+ );
293
+ const [actionPos, setActionPos] = React.useState(null);
294
+ React.useLayoutEffect(() => {
295
+ if (!hasAction || !overlayEl) return;
296
+ const el = triggerElRef.current;
297
+ if (!el) return;
298
+ const compute = () => {
299
+ var _a;
300
+ const t = (_a = triggerElRef.current) == null ? void 0 : _a.getBoundingClientRect();
301
+ const o = overlayEl.getBoundingClientRect();
302
+ if (!t) return;
303
+ setActionPos({ left: t.right - o.left, top: t.top - o.top, height: t.height });
304
+ };
305
+ compute();
306
+ const ro = new ResizeObserver(compute);
307
+ ro.observe(el);
308
+ ro.observe(overlayEl);
309
+ window.addEventListener("resize", compute);
310
+ window.addEventListener("scroll", compute, true);
311
+ return () => {
312
+ ro.disconnect();
313
+ window.removeEventListener("resize", compute);
314
+ window.removeEventListener("scroll", compute, true);
315
+ };
316
+ }, [hasAction, overlayEl]);
275
317
  const trigger = /* @__PURE__ */ jsxs(
276
318
  TabsPrimitive.Trigger,
277
319
  {
278
- ref,
320
+ ref: setTriggerRef,
279
321
  className: cn(tabsTriggerVariants({ size }), className),
280
322
  style: hasAction ? { paddingRight: actionPaddingRight } : void 0,
281
323
  ...props,
@@ -290,14 +332,22 @@ const TabsTrigger = React.forwardRef(({ className, startIcon: StartIcon, badge,
290
332
  }
291
333
  );
292
334
  if (!hasAction) return trigger;
293
- return (
294
- // sibling 佈局 wrapper:span(relative)內 trigger + 絕對定位 action。
295
- // Radix roving focus 用 collection context 收 trigger,不要求 trigger 是 List 直接子層。
296
- /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", children: [
297
- trigger,
298
- /* @__PURE__ */ jsx("span", { className: "absolute top-1/2 -translate-y-1/2 right-0 inline-flex items-center", children: inlineAction })
299
- ] })
300
- );
335
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
336
+ trigger,
337
+ overlayEl && actionPos && createPortal(
338
+ // action portal 到 overlay(tablist 外);left=trigger.right + `-translate-x-full` action
339
+ // 右緣對齊 trigger 右緣;top/height + items-center → 垂直置中(同原 right-0 + top-1/2 幾何)。
340
+ /* @__PURE__ */ jsx(
341
+ "span",
342
+ {
343
+ className: "pointer-events-auto absolute inline-flex -translate-x-full items-center",
344
+ style: { left: actionPos.left, top: actionPos.top, height: actionPos.height },
345
+ children: inlineAction
346
+ }
347
+ ),
348
+ overlayEl
349
+ )
350
+ ] });
301
351
  });
302
352
  TabsTrigger.displayName = "TabsTrigger";
303
353
  const TabsContent = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(