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

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 (622) hide show
  1. package/CLAUDE.md +8 -8
  2. package/README.md +3 -2
  3. package/dist/components/Alert/alert.js.map +1 -1
  4. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
  5. package/dist/components/AppShell/app-shell.d.ts +1 -1
  6. package/dist/components/AppShell/app-shell.d.ts.map +1 -1
  7. package/dist/components/AppShell/app-shell.js +22 -2
  8. package/dist/components/AppShell/app-shell.js.map +1 -1
  9. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  10. package/dist/components/Avatar/avatar.js +4 -4
  11. package/dist/components/Avatar/avatar.js.map +1 -1
  12. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  13. package/dist/components/Breadcrumb/breadcrumb.js +1 -1
  14. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  15. package/dist/components/Button/button.d.ts +2 -2
  16. package/dist/components/Button/button.d.ts.map +1 -1
  17. package/dist/components/Button/button.js +12 -3
  18. package/dist/components/Button/button.js.map +1 -1
  19. package/dist/components/Calendar/calendar.d.ts +13 -5
  20. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  21. package/dist/components/Calendar/calendar.js +7 -1
  22. package/dist/components/Calendar/calendar.js.map +1 -1
  23. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  24. package/dist/components/Carousel/carousel.js +8 -3
  25. package/dist/components/Carousel/carousel.js.map +1 -1
  26. package/dist/components/Chart/chart.d.ts.map +1 -1
  27. package/dist/components/Chart/chart.js +1 -0
  28. package/dist/components/Chart/chart.js.map +1 -1
  29. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  30. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  31. package/dist/components/Checkbox/checkbox.js +8 -4
  32. package/dist/components/Checkbox/checkbox.js.map +1 -1
  33. package/dist/components/Chip/chip.d.ts +1 -1
  34. package/dist/components/Chip/chip.d.ts.map +1 -1
  35. package/dist/components/Chip/chip.js.map +1 -1
  36. package/dist/components/Coachmark/coachmark.d.ts +10 -3
  37. package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
  38. package/dist/components/Coachmark/coachmark.js.map +1 -1
  39. package/dist/components/Combobox/combobox.d.ts +5 -1
  40. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  41. package/dist/components/Combobox/combobox.js +30 -13
  42. package/dist/components/Combobox/combobox.js.map +1 -1
  43. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  44. package/dist/components/DataTable/cell-registry.js +53 -62
  45. package/dist/components/DataTable/cell-registry.js.map +1 -1
  46. package/dist/components/DataTable/column-types.d.ts +10 -4
  47. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  48. package/dist/components/DataTable/column-types.js.map +1 -1
  49. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +1 -1
  50. package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
  51. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
  52. package/dist/components/DataTable/data-table-filter-group.d.ts +47 -0
  53. package/dist/components/DataTable/data-table-filter-group.d.ts.map +1 -0
  54. package/dist/components/DataTable/data-table-filter-group.js +154 -0
  55. package/dist/components/DataTable/data-table-filter-group.js.map +1 -0
  56. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  57. package/dist/components/DataTable/data-table-filter-panel.js +285 -0
  58. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
  59. package/dist/components/DataTable/data-table-filter-value-picker.d.ts +29 -0
  60. package/dist/components/DataTable/data-table-filter-value-picker.d.ts.map +1 -0
  61. package/dist/components/DataTable/data-table-filter-value-picker.js +187 -0
  62. package/dist/components/DataTable/data-table-filter-value-picker.js.map +1 -0
  63. package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
  64. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  65. package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
  66. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  67. package/dist/components/DataTable/data-table-sort-manager.js +140 -0
  68. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
  69. package/dist/components/DataTable/data-table.d.ts +5 -6
  70. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  71. package/dist/components/DataTable/data-table.js +36 -15
  72. package/dist/components/DataTable/data-table.js.map +1 -1
  73. package/dist/components/DataTable/filter-operators.js +140 -0
  74. package/dist/components/DataTable/filter-operators.js.map +1 -0
  75. package/dist/components/DataTable/filter-tree.js +312 -0
  76. package/dist/components/DataTable/filter-tree.js.map +1 -0
  77. package/dist/components/DataTable/index.d.ts +3 -0
  78. package/dist/components/DataTable/index.d.ts.map +1 -1
  79. package/dist/components/DataTable/index.js +12 -1
  80. package/dist/components/DataTable/index.js.map +1 -1
  81. package/dist/components/DataTable/lib/column-meta.js +25 -0
  82. package/dist/components/DataTable/lib/column-meta.js.map +1 -0
  83. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  84. package/dist/components/DateGrid/date-grid.js +3 -1
  85. package/dist/components/DateGrid/date-grid.js.map +1 -1
  86. package/dist/components/DatePicker/date-picker.d.ts +7 -1
  87. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  88. package/dist/components/DatePicker/date-picker.js +105 -74
  89. package/dist/components/DatePicker/date-picker.js.map +1 -1
  90. package/dist/components/Dialog/dialog.d.ts +20 -3
  91. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  92. package/dist/components/Dialog/dialog.js +38 -20
  93. package/dist/components/Dialog/dialog.js.map +1 -1
  94. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  95. package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
  96. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  97. package/dist/components/Field/field-context.d.ts +45 -5
  98. package/dist/components/Field/field-context.d.ts.map +1 -1
  99. package/dist/components/Field/field-context.js +19 -0
  100. package/dist/components/Field/field-context.js.map +1 -1
  101. package/dist/components/Field/field-edit-keys.d.ts +21 -0
  102. package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
  103. package/dist/components/Field/field-edit-keys.js +19 -0
  104. package/dist/components/Field/field-edit-keys.js.map +1 -0
  105. package/dist/components/Field/field-types.d.ts +20 -1
  106. package/dist/components/Field/field-types.d.ts.map +1 -1
  107. package/dist/components/Field/field-types.js.map +1 -1
  108. package/dist/components/Field/field-wrapper.d.ts +3 -2
  109. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  110. package/dist/components/Field/field-wrapper.js +38 -39
  111. package/dist/components/Field/field-wrapper.js.map +1 -1
  112. package/dist/components/Field/field.d.ts +2 -1
  113. package/dist/components/Field/field.d.ts.map +1 -1
  114. package/dist/components/Field/field.js.map +1 -1
  115. package/dist/components/Field/index.d.ts +1 -0
  116. package/dist/components/Field/index.d.ts.map +1 -1
  117. package/dist/components/Field/index.js +2 -0
  118. package/dist/components/Field/index.js.map +1 -1
  119. package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
  120. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  121. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  122. package/dist/components/FileItem/file-item.js +1 -1
  123. package/dist/components/FileItem/file-item.js.map +1 -1
  124. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  125. package/dist/components/FileUpload/file-upload.js.map +1 -1
  126. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  127. package/dist/components/FileViewer/file-viewer.js +7 -2
  128. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  129. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
  130. package/dist/components/FileViewer/image-renderer.js +22 -1
  131. package/dist/components/FileViewer/image-renderer.js.map +1 -1
  132. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  133. package/dist/components/HoverCard/hover-card.js +5 -3
  134. package/dist/components/HoverCard/hover-card.js.map +1 -1
  135. package/dist/components/InlineEdit/index.d.ts +2 -0
  136. package/dist/components/InlineEdit/index.d.ts.map +1 -0
  137. package/dist/components/InlineEdit/index.js +5 -0
  138. package/dist/components/InlineEdit/index.js.map +1 -0
  139. package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
  140. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
  141. package/dist/components/InlineEdit/inline-edit.js +164 -0
  142. package/dist/components/InlineEdit/inline-edit.js.map +1 -0
  143. package/dist/components/Input/input.d.ts +6 -11
  144. package/dist/components/Input/input.d.ts.map +1 -1
  145. package/dist/components/Input/input.js +43 -13
  146. package/dist/components/Input/input.js.map +1 -1
  147. package/dist/components/LinkInput/link-input.d.ts +2 -2
  148. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  149. package/dist/components/LinkInput/link-input.js +6 -5
  150. package/dist/components/LinkInput/link-input.js.map +1 -1
  151. package/dist/components/Menu/menu-item.d.ts +14 -2
  152. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  153. package/dist/components/Menu/menu-item.js +25 -3
  154. package/dist/components/Menu/menu-item.js.map +1 -1
  155. package/dist/components/NumberInput/number-input.d.ts +3 -3
  156. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  157. package/dist/components/NumberInput/number-input.js +6 -5
  158. package/dist/components/NumberInput/number-input.js.map +1 -1
  159. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  160. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
  161. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  162. package/dist/components/Pagination/pagination.js +1 -1
  163. package/dist/components/Pagination/pagination.js.map +1 -1
  164. package/dist/components/PeoplePicker/index.js +7 -1
  165. package/dist/components/PeoplePicker/index.js.map +1 -1
  166. package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
  167. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  168. package/dist/components/PeoplePicker/people-picker.js +23 -10
  169. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  170. package/dist/components/PeoplePicker/person-display.d.ts +6 -3
  171. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  172. package/dist/components/PeoplePicker/person-display.js +19 -14
  173. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  174. package/dist/components/Popover/popover.d.ts.map +1 -1
  175. package/dist/components/Popover/popover.js +3 -1
  176. package/dist/components/Popover/popover.js.map +1 -1
  177. package/dist/components/ProfileCard/profile-card.d.ts +2 -2
  178. package/dist/components/ProfileCard/profile-card.js +3 -3
  179. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  180. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  181. package/dist/components/RadioGroup/radio-group.js +15 -9
  182. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  183. package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
  184. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  185. package/dist/components/ScrollArea/scroll-area.js +6 -3
  186. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  187. package/dist/components/Select/select.d.ts +46 -5
  188. package/dist/components/Select/select.d.ts.map +1 -1
  189. package/dist/components/Select/select.js +109 -28
  190. package/dist/components/Select/select.js.map +1 -1
  191. package/dist/components/SelectMenu/select-menu.d.ts +3 -1
  192. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  193. package/dist/components/SelectMenu/select-menu.js +8 -1
  194. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  195. package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
  196. package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
  197. package/dist/components/SelectionControl/boolean-value.js +23 -0
  198. package/dist/components/SelectionControl/boolean-value.js.map +1 -0
  199. package/dist/components/SelectionControl/index.d.ts +1 -0
  200. package/dist/components/SelectionControl/index.d.ts.map +1 -1
  201. package/dist/components/SelectionControl/index.js +2 -0
  202. package/dist/components/SelectionControl/index.js.map +1 -1
  203. package/dist/components/Sheet/index.js +2 -1
  204. package/dist/components/Sheet/sheet.d.ts +7 -1
  205. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  206. package/dist/components/Sheet/sheet.js +5 -2
  207. package/dist/components/Sheet/sheet.js.map +1 -1
  208. package/dist/components/Sidebar/sidebar.d.ts +9 -4
  209. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  210. package/dist/components/Sidebar/sidebar.js +8 -10
  211. package/dist/components/Sidebar/sidebar.js.map +1 -1
  212. package/dist/components/Slider/slider.d.ts.map +1 -1
  213. package/dist/components/Slider/slider.js.map +1 -1
  214. package/dist/components/Switch/switch.d.ts +6 -6
  215. package/dist/components/Switch/switch.d.ts.map +1 -1
  216. package/dist/components/Switch/switch.js +3 -2
  217. package/dist/components/Switch/switch.js.map +1 -1
  218. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  219. package/dist/components/Tabs/tabs.js +15 -1
  220. package/dist/components/Tabs/tabs.js.map +1 -1
  221. package/dist/components/Textarea/textarea.d.ts +2 -2
  222. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  223. package/dist/components/Textarea/textarea.js +50 -42
  224. package/dist/components/Textarea/textarea.js.map +1 -1
  225. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  226. package/dist/components/TimePicker/time-columns.js +42 -38
  227. package/dist/components/TimePicker/time-columns.js.map +1 -1
  228. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  229. package/dist/components/TimePicker/time-picker.js +8 -6
  230. package/dist/components/TimePicker/time-picker.js.map +1 -1
  231. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  232. package/dist/components/Tooltip/tooltip.js +7 -5
  233. package/dist/components/Tooltip/tooltip.js.map +1 -1
  234. package/dist/components/TreeView/tree-view.d.ts +56 -1
  235. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  236. package/dist/components/TreeView/tree-view.js +211 -12
  237. package/dist/components/TreeView/tree-view.js.map +1 -1
  238. package/dist/index.d.ts +115 -58
  239. package/dist/index.d.ts.map +1 -1
  240. package/dist/index.js +95 -108
  241. package/dist/index.js.map +1 -1
  242. package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
  243. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  244. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  245. package/dist/tokens/categorical-color.js +15 -0
  246. package/dist/tokens/categorical-color.js.map +1 -1
  247. package/dist/tokens/motion/motion.d.ts +7 -6
  248. package/dist/tokens/motion/motion.d.ts.map +1 -1
  249. package/dist/tokens/motion/motion.js +6 -6
  250. package/dist/tokens/motion/motion.js.map +1 -1
  251. package/dist/tokens/motion/overlay-motion.d.ts +19 -0
  252. package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
  253. package/dist/tokens/motion/overlay-motion.js +9 -0
  254. package/dist/tokens/motion/overlay-motion.js.map +1 -0
  255. package/dist/tokens/uiSize/icon-size.js +5 -0
  256. package/dist/tokens/uiSize/icon-size.js.map +1 -0
  257. package/ds-canonical/fork/governance.lock +31 -19
  258. package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
  259. package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
  260. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
  261. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
  262. package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
  263. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
  264. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
  265. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
  266. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
  267. package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
  268. package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
  269. package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  270. package/ds-canonical/fork/manifest.json +15 -0
  271. package/ds-canonical/fork/preamble.md +20 -18
  272. package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
  273. package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
  274. package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
  275. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
  276. package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
  277. package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
  278. package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
  279. package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
  280. package/ds-canonical/hooks/README.md +1 -1
  281. package/ds-canonical/hooks/block_prototype_imports.py +15 -4
  282. package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
  283. package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
  284. package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
  285. package/ds-canonical/hooks/check_datatable_invariants.sh +6 -3
  286. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
  287. package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
  288. package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
  289. package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
  290. package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
  291. package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
  292. package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
  293. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
  294. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
  295. package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
  296. package/ds-canonical/hooks/check_story_determinism.sh +2 -0
  297. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
  298. package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  299. package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
  300. package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
  301. package/ds-canonical/hooks/stop_self_audit.sh +31 -0
  302. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
  303. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
  304. package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
  305. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
  306. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
  307. package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
  308. package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
  309. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
  310. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
  311. package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
  312. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
  313. package/ds-canonical/references/build-ui-canonicals.md +2 -1
  314. package/ds-canonical/references/failure-class-registry.json +145 -0
  315. package/ds-canonical/references/governance-audit-coverage.md +33 -0
  316. package/ds-canonical/references/item-anatomy-recipe.md +2 -2
  317. package/ds-canonical/references/scenario-definition.md +6 -9
  318. package/ds-canonical/references/ssot-consultation.md +2 -2
  319. package/ds-canonical/references/ssot-index.md +5 -4
  320. package/ds-canonical/references/story-baseline-registry.json +8 -2
  321. package/ds-canonical/references/structural-token-retention.md +6 -9
  322. package/ds-canonical/rules/meta-patterns.md +8 -8
  323. package/ds-canonical/rules/self-verify.md +4 -3
  324. package/ds-canonical/rules/story-rules.md +2 -2
  325. package/ds-canonical/rules/ui-development.md +2 -2
  326. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
  327. package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
  328. package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
  329. package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
  330. package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
  331. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  332. package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
  333. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
  334. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
  335. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
  336. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
  337. package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
  338. package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
  339. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
  340. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
  341. package/ds-canonical/skills/governance-health/SKILL.md +1 -1
  342. package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
  343. package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
  344. package/ds-canonical/skills/new-component/SKILL.md +5 -5
  345. package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
  346. package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
  347. package/ds-canonical/skills/propose-options/SKILL.md +3 -3
  348. package/ds-canonical/skills/prototype/SKILL.md +1 -1
  349. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
  350. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
  351. package/ds-canonical/skills/story-writing/SKILL.md +3 -3
  352. package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
  353. package/ds-story-manifest.json +29 -20
  354. package/llms-full.txt +22 -1
  355. package/llms.txt +5 -4
  356. package/package.json +7 -3
  357. package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
  358. package/src/components/Accordion/accordion.stories.tsx +16 -1
  359. package/src/components/Alert/alert.principles.stories.tsx +1 -1
  360. package/src/components/Alert/alert.spec.md +8 -10
  361. package/src/components/Alert/alert.stories.tsx +28 -28
  362. package/src/components/Alert/alert.tsx +1 -1
  363. package/src/components/AppShell/_demo-helpers.tsx +6 -3
  364. package/src/components/AppShell/app-shell.spec.md +4 -4
  365. package/src/components/AppShell/app-shell.tsx +28 -2
  366. package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
  367. package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
  368. package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
  369. package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
  370. package/src/components/Avatar/avatar.spec.md +2 -2
  371. package/src/components/Avatar/avatar.stories.tsx +8 -6
  372. package/src/components/Avatar/avatar.tsx +13 -5
  373. package/src/components/Badge/badge.principles.stories.tsx +1 -1
  374. package/src/components/Badge/badge.spec.md +2 -0
  375. package/src/components/Badge/badge.stories.tsx +4 -2
  376. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
  377. package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
  378. package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
  379. package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
  380. package/src/components/Button/button.principles.stories.tsx +1 -1
  381. package/src/components/Button/button.spec.md +2 -2
  382. package/src/components/Button/button.tsx +18 -3
  383. package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
  384. package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
  385. package/src/components/Calendar/calendar.spec.md +5 -4
  386. package/src/components/Calendar/calendar.stories.tsx +7 -4
  387. package/src/components/Calendar/calendar.tsx +26 -7
  388. package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
  389. package/src/components/Carousel/carousel.spec.md +2 -2
  390. package/src/components/Carousel/carousel.tsx +11 -3
  391. package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
  392. package/src/components/Chart/chart.principles.stories.tsx +1 -1
  393. package/src/components/Chart/chart.stories.tsx +2 -8
  394. package/src/components/Chart/chart.tsx +3 -0
  395. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
  396. package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
  397. package/src/components/Checkbox/checkbox.spec.md +13 -26
  398. package/src/components/Checkbox/checkbox.stories.tsx +11 -8
  399. package/src/components/Checkbox/checkbox.tsx +18 -13
  400. package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
  401. package/src/components/Chip/chip.principles.stories.tsx +1 -1
  402. package/src/components/Chip/chip.spec.md +5 -4
  403. package/src/components/Chip/chip.tsx +5 -1
  404. package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
  405. package/src/components/CircularProgress/circular-progress.spec.md +3 -3
  406. package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
  407. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
  408. package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
  409. package/src/components/Coachmark/coachmark.spec.md +5 -5
  410. package/src/components/Coachmark/coachmark.stories.tsx +3 -1
  411. package/src/components/Coachmark/coachmark.tsx +10 -3
  412. package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
  413. package/src/components/Combobox/combobox.tsx +53 -19
  414. package/src/components/Command/command.anatomy.stories.tsx +2 -2
  415. package/src/components/Command/command.principles.stories.tsx +1 -1
  416. package/src/components/Command/command.stories.tsx +42 -10
  417. package/src/components/DataTable/cell-registry.tsx +86 -63
  418. package/src/components/DataTable/column-types.ts +10 -1
  419. package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
  420. package/src/components/DataTable/data-table-filter-group.tsx +231 -0
  421. package/src/components/DataTable/data-table-filter-panel.tsx +16 -430
  422. package/src/components/DataTable/data-table-filter-value-picker.tsx +237 -0
  423. package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
  424. package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
  425. package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
  426. package/src/components/DataTable/data-table.spec.md +33 -13
  427. package/src/components/DataTable/data-table.stories.tsx +16 -17
  428. package/src/components/DataTable/data-table.tsx +107 -61
  429. package/src/components/DataTable/filter-operators.spec.md +3 -3
  430. package/src/components/DataTable/index.ts +3 -0
  431. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
  432. package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
  433. package/src/components/DateGrid/date-grid.spec.md +1 -1
  434. package/src/components/DateGrid/date-grid.tsx +3 -1
  435. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
  436. package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
  437. package/src/components/DatePicker/date-picker.spec.md +3 -3
  438. package/src/components/DatePicker/date-picker.stories.tsx +4 -5
  439. package/src/components/DatePicker/date-picker.tsx +99 -45
  440. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
  441. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  442. package/src/components/DescriptionList/description-list.spec.md +3 -3
  443. package/src/components/DescriptionList/description-list.stories.tsx +7 -6
  444. package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
  445. package/src/components/Dialog/dialog.spec.md +9 -0
  446. package/src/components/Dialog/dialog.stories.tsx +66 -5
  447. package/src/components/Dialog/dialog.tsx +60 -25
  448. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
  449. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
  450. package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
  451. package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
  452. package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
  453. package/src/components/Empty/empty.spec.md +2 -2
  454. package/src/components/Field/field-context.ts +69 -5
  455. package/src/components/Field/field-controls.spec.md +62 -8
  456. package/src/components/Field/field-edit-keys.ts +66 -0
  457. package/src/components/Field/field-types.ts +58 -9
  458. package/src/components/Field/field-wrapper.tsx +50 -42
  459. package/src/components/Field/field.anatomy.stories.tsx +9 -6
  460. package/src/components/Field/field.spec.md +1 -1
  461. package/src/components/Field/field.stories.tsx +1 -1
  462. package/src/components/Field/field.tsx +2 -1
  463. package/src/components/Field/form-validation.spec.md +3 -3
  464. package/src/components/Field/index.ts +1 -0
  465. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
  466. package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
  467. package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
  468. package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
  469. package/src/components/FileItem/file-item.spec.md +5 -8
  470. package/src/components/FileItem/file-item.stories.tsx +36 -25
  471. package/src/components/FileItem/file-item.tsx +8 -6
  472. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
  473. package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
  474. package/src/components/FileUpload/file-upload.spec.md +1 -1
  475. package/src/components/FileUpload/file-upload.tsx +1 -1
  476. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
  477. package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
  478. package/src/components/FileViewer/file-viewer.spec.md +30 -12
  479. package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
  480. package/src/components/FileViewer/file-viewer.tsx +12 -4
  481. package/src/components/FileViewer/image-renderer.tsx +35 -7
  482. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
  483. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
  484. package/src/components/HoverCard/hover-card.spec.md +5 -5
  485. package/src/components/HoverCard/hover-card.stories.tsx +16 -16
  486. package/src/components/HoverCard/hover-card.tsx +5 -3
  487. package/src/components/InlineEdit/index.ts +5 -0
  488. package/src/components/InlineEdit/inline-edit.spec.md +149 -0
  489. package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
  490. package/src/components/InlineEdit/inline-edit.tsx +287 -0
  491. package/src/components/Input/input.anatomy.stories.tsx +8 -7
  492. package/src/components/Input/input.principles.stories.tsx +2 -12
  493. package/src/components/Input/input.spec.md +13 -18
  494. package/src/components/Input/input.tsx +69 -22
  495. package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
  496. package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
  497. package/src/components/LinkInput/link-input.tsx +11 -10
  498. package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
  499. package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
  500. package/src/components/Menu/menu-item.spec.md +22 -15
  501. package/src/components/Menu/menu-item.stories.tsx +39 -11
  502. package/src/components/Menu/menu-item.tsx +38 -4
  503. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  504. package/src/components/Notice/notice.spec.md +16 -3
  505. package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
  506. package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
  507. package/src/components/NumberInput/number-input.spec.md +4 -4
  508. package/src/components/NumberInput/number-input.tsx +19 -12
  509. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
  510. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
  511. package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
  512. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
  513. package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
  514. package/src/components/Pagination/pagination.spec.md +1 -1
  515. package/src/components/Pagination/pagination.stories.tsx +2 -6
  516. package/src/components/Pagination/pagination.tsx +1 -1
  517. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
  518. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
  519. package/src/components/PeoplePicker/people-picker.spec.md +6 -6
  520. package/src/components/PeoplePicker/people-picker.tsx +56 -16
  521. package/src/components/PeoplePicker/person-display.tsx +32 -16
  522. package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
  523. package/src/components/Popover/popover.tsx +3 -1
  524. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
  525. package/src/components/ProfileCard/profile-card.spec.md +3 -3
  526. package/src/components/ProfileCard/profile-card.tsx +6 -6
  527. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
  528. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
  529. package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
  530. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
  531. package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
  532. package/src/components/RadioGroup/radio-group.tsx +41 -15
  533. package/src/components/Rating/rating.spec.md +11 -3
  534. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  535. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  536. package/src/components/ScrollArea/scroll-area.spec.md +7 -3
  537. package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
  538. package/src/components/ScrollArea/scroll-area.tsx +17 -4
  539. package/src/components/Select/select.anatomy.stories.tsx +3 -3
  540. package/src/components/Select/select.spec.md +29 -17
  541. package/src/components/Select/select.stories.tsx +33 -0
  542. package/src/components/Select/select.tsx +190 -36
  543. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
  544. package/src/components/SelectMenu/select-menu.spec.md +15 -7
  545. package/src/components/SelectMenu/select-menu.tsx +16 -3
  546. package/src/components/SelectionControl/boolean-value.tsx +39 -0
  547. package/src/components/SelectionControl/index.ts +1 -0
  548. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
  549. package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
  550. package/src/components/SelectionControl/selection-item.spec.md +3 -3
  551. package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
  552. package/src/components/Separator/separator.spec.md +2 -2
  553. package/src/components/Separator/separator.stories.tsx +6 -27
  554. package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
  555. package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
  556. package/src/components/Sheet/sheet.spec.md +2 -2
  557. package/src/components/Sheet/sheet.tsx +9 -5
  558. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
  559. package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
  560. package/src/components/Sidebar/sidebar.spec.md +13 -15
  561. package/src/components/Sidebar/sidebar.stories.tsx +8 -7
  562. package/src/components/Sidebar/sidebar.tsx +37 -25
  563. package/src/components/Skeleton/skeleton.stories.tsx +4 -11
  564. package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
  565. package/src/components/Slider/slider.principles.stories.tsx +2 -2
  566. package/src/components/Slider/slider.spec.md +5 -5
  567. package/src/components/Slider/slider.tsx +3 -1
  568. package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
  569. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  570. package/src/components/Steps/steps.spec.md +1 -1
  571. package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
  572. package/src/components/Switch/switch.principles.stories.tsx +4 -4
  573. package/src/components/Switch/switch.spec.md +8 -8
  574. package/src/components/Switch/switch.stories.tsx +9 -24
  575. package/src/components/Switch/switch.tsx +17 -13
  576. package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
  577. package/src/components/Tabs/tabs.spec.md +1 -1
  578. package/src/components/Tabs/tabs.tsx +21 -1
  579. package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
  580. package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
  581. package/src/components/Textarea/textarea.spec.md +4 -4
  582. package/src/components/Textarea/textarea.tsx +72 -46
  583. package/src/components/TimePicker/time-columns.tsx +6 -2
  584. package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
  585. package/src/components/TimePicker/time-picker.spec.md +3 -3
  586. package/src/components/TimePicker/time-picker.tsx +16 -10
  587. package/src/components/Toast/toast.stories.tsx +7 -4
  588. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
  589. package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
  590. package/src/components/Tooltip/tooltip.spec.md +1 -1
  591. package/src/components/Tooltip/tooltip.stories.tsx +4 -39
  592. package/src/components/Tooltip/tooltip.tsx +8 -6
  593. package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
  594. package/src/components/TreeView/tree-view.spec.md +42 -11
  595. package/src/components/TreeView/tree-view.stories.tsx +1 -0
  596. package/src/components/TreeView/tree-view.tsx +322 -17
  597. package/src/index.ts +588 -60
  598. package/src/patterns/action-bar/action-bar.spec.md +9 -0
  599. package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
  600. package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
  601. package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
  602. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
  603. package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
  604. package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
  605. package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
  606. package/src/styles/tokens.css +3 -0
  607. package/src/tokens/README.md +1 -1
  608. package/src/tokens/color/color.spec.md +4 -4
  609. package/src/tokens/color/color.stories.tsx +3 -3
  610. package/src/tokens/density/density.stories.tsx +16 -3
  611. package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
  612. package/src/tokens/motion/motion.css +33 -21
  613. package/src/tokens/motion/motion.spec.md +32 -15
  614. package/src/tokens/motion/motion.stories.tsx +58 -5
  615. package/src/tokens/motion/motion.ts +7 -6
  616. package/src/tokens/motion/overlay-motion.ts +26 -0
  617. package/src/tokens/orphan-tokens.spec.md +4 -4
  618. package/src/tokens/token-system.spec.md +1 -0
  619. package/src/tokens/uiSize/uiSize.css +1 -1
  620. package/src/tokens/uiSize/uiSize.spec.md +1 -1
  621. package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
  622. package/src/tokens/utility-registry.json +160 -23
@@ -23,7 +23,7 @@ import type { LucideIcon } from 'lucide-react';
23
23
  * ── 詳見 chip.spec.md ──
24
24
  */
25
25
  declare const chipVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
26
- export interface ChipProps extends React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> {
26
+ export interface ChipProps extends Omit<React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item>, 'asChild'> {
27
27
  /** 左側 icon(LucideIcon),最多一個 */
28
28
  startIcon?: LucideIcon;
29
29
  /** 右側 badge(通常是計數指示器)*/
@@ -1 +1 @@
1
- {"version":3,"file":"chip.d.ts","sourceRoot":"","sources":["../../../src/components/Chip/chip.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,oBAAoB,MAAM,8BAA8B,CAAA;AAEpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAiB9C;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,QAAA,MAAM,YAAY,oFAkCjB,CAAA;AAED,MAAM,WAAW,SACf,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC;IACxE,+BAA+B;IAC/B,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,wBAAwB;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,uCAAuC;IACvC,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB;AAED,QAAA,MAAM,IAAI,qFAsBR,CAAA;AAKF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAExD,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,wBAAwB,CACzD,OAAO,oBAAoB,CAAC,IAAI,CACjC,GAAG;IACF,qDAAqD;IACrD,MAAM,CAAC,EAAE,eAAe,CAAA;CACzB,CAAA;AAED,QAAA,MAAM,SAAS,uFA2Bd,CAAA;AAwOD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;CAeX,CAAA;AAEV,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"chip.d.ts","sourceRoot":"","sources":["../../../src/components/Chip/chip.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,oBAAoB,MAAM,8BAA8B,CAAA;AAEpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAiB9C;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,QAAA,MAAM,YAAY,oFAkCjB,CAAA;AAED,MAAM,WAAW,SAKf,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,oBAAoB,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IACzF,+BAA+B;IAC/B,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,wBAAwB;IACxB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,uCAAuC;IACvC,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB;AAED,QAAA,MAAM,IAAI,qFAsBR,CAAA;AAKF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAA;AAExD,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC,wBAAwB,CACzD,OAAO,oBAAoB,CAAC,IAAI,CACjC,GAAG;IACF,qDAAqD;IACrD,MAAM,CAAC,EAAE,eAAe,CAAA;CACzB,CAAA;AAED,QAAA,MAAM,SAAS,uFA2Bd,CAAA;AAwOD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;CAeX,CAAA;AAEV,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"chip.js","sources":["../../../src/components/Chip/chip.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 ToggleGroupPrimitive from '@radix-ui/react-toggle-group'\nimport { cva } from 'class-variance-authority'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuCheckboxItem,\n} from '@/design-system/components/DropdownMenu/dropdown-menu'\nimport {\n useScrollEdges,\n useScrollByPage,\n buildFadeMask,\n ARROW_BUTTON_WIDTH,\n OverflowScrollArrow,\n OverflowMenuTriggerButton,\n} from '@/design-system/patterns/horizontal-overflow/horizontal-overflow'\n\n/**\n * Chip — Material Design Filter Chip\n *\n * 基於 Radix ToggleGroup,橋接設計系統 token。\n * 必須在 <ChipGroup> 內使用。\n *\n * ── 內部結構(鏡射 Button)──\n * [startIcon?] [<span px-1>label</span>] [<span gap-1>badge? + endIcon?</span>]\n *\n * ── Size ──\n * 單一 size = h-field-sm(28/32 density-aware)\n * 對齊 Material 3 / Atlassian / Polaris 世界級共識\n *\n * ── State ──\n * default bg-surface border-border text-fg-secondary\n * hover border-border-hover text-foreground(對齊 Input / SegmentedControl)\n * selected bg-surface(不變) border-primary text-primary\n * disabled cursor-not-allowed text-fg-disabled\n *\n * ── 詳見 chip.spec.md ──\n */\n\n// ── Chip item ────────────────────────────────────────────────────────────────\n\nconst chipVariants = cva(\n [\n 'inline-flex items-center justify-center',\n 'h-field-sm px-3 gap-1',\n 'rounded-full border border-border',\n // 預設文字: text-fg-secondary (neutral-8) — 對齊 SegmentedControl / Tabs 未選狀態\n 'bg-surface text-fg-secondary',\n 'text-body leading-compact font-medium whitespace-nowrap',\n 'transition-colors duration-150',\n 'cursor-pointer select-none',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n // hover(未選):border 加深一階 + 文字轉深,對齊 Input / SegmentedControl hover\n 'hover:border-border-hover hover:text-foreground',\n // selected: 文字 + 邊框都用 primary base,底色維持 bg-surface 不變\n // ── pill 風格 canonical 選中規則,跟 SegmentedControl 完全一致(SSOT = semantic.css「選中狀態」段):\n // primary base 同時染文字和線條;底色不改 (不用 primary-subtle)。\n // 2026-07-06 user 拍板:持續選中 hover 階 → base — Ant(pagination/tabs/input focus 全 base)/\n // Atlassian(selected = brand 同顆)/ Material 3(active tab = primary)三家實錘「瞬時弱、持續強」;\n // hover 階專屬瞬時態(hover/預覽),持續選中站 base。\n 'data-[state=on]:border-primary data-[state=on]:text-primary',\n // 選中之上的 hover = 同色相升 hover 階(2026-07-06 user 拍板;Button pressed hover\n // data-[state=on]:hover:text-primary-hover 家族 + Ant active 頁 hover = colorPrimaryHover\n // 同派)。原本靠 CSS 平手 source-order 讓選中「碰巧」贏過未選 hover(靜止無回饋)= 脆弱,\n // 顯式宣告一併解掉。\n 'data-[state=on]:hover:border-primary-hover data-[state=on]:hover:text-primary-hover',\n // disabled:cursor-not-allowed + 鎖 hover 不變色\n // 不用 pointer-events-none(否則 cursor-not-allowed 不會顯示)\n 'disabled:cursor-not-allowed disabled:text-fg-disabled',\n 'disabled:hover:border-border disabled:hover:text-fg-disabled',\n // disabled × selected 疊加(2026-07-07 user 拍板統一;M24 state > emphasis:disabled 全滅,\n // 選中的 primary 描邊/染字一併退場——原本只滅字不滅框 = 半滅,Checkbox checked+disabled 全滅同族)\n 'data-[state=on]:disabled:border-border data-[state=on]:disabled:text-fg-disabled',\n 'data-[state=on]:disabled:hover:border-border data-[state=on]:disabled:hover:text-fg-disabled',\n ]\n)\n\nexport interface ChipProps\n extends React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> {\n /** 左側 icon(LucideIcon),最多一個 */\n startIcon?: LucideIcon\n /** 右側 badge(通常是計數指示器)*/\n badge?: React.ReactNode\n /** 右側 icon(少見,通常是 ChevronDown 指示可展開)*/\n endIcon?: LucideIcon\n}\n\nconst Chip = React.forwardRef<\n React.ElementRef<typeof ToggleGroupPrimitive.Item>,\n ChipProps\n>(({ className, startIcon: StartIcon, badge, endIcon: EndIcon, children, ...props }, ref) => {\n const hasSuffix = badge != null || EndIcon !== undefined\n\n return (\n <ToggleGroupPrimitive.Item\n ref={ref}\n className={cn(chipVariants(), className)}\n {...props}\n >\n {StartIcon && <StartIcon size={16} aria-hidden />}\n {children != null && <span className=\"px-1\">{children}</span>}\n {hasSuffix && (\n <span className=\"inline-flex items-center gap-1\">\n {badge}\n {EndIcon && <EndIcon size={16} aria-hidden />}\n </span>\n )}\n </ToggleGroupPrimitive.Item>\n )\n})\nChip.displayName = 'Chip'\n\n// ── ChipGroup ────────────────────────────────────────────────────────────────\n\nexport type ChipGroupLayout = 'wrap' | 'scroll' | 'menu'\n\nexport type ChipGroupProps = React.ComponentPropsWithoutRef<\n typeof ToggleGroupPrimitive.Root\n> & {\n /** Overflow 處理模式。預設 `wrap`(塞不下換行)。詳見 chip.spec.md */\n layout?: ChipGroupLayout\n}\n\nconst ChipGroup = React.forwardRef<HTMLDivElement, ChipGroupProps>(\n ({ layout = 'wrap', className, children, ...props }, ref) => {\n if (layout === 'scroll') {\n return (\n <ScrollChipGroup ref={ref} className={className} {...props}>\n {children}\n </ScrollChipGroup>\n )\n }\n if (layout === 'menu') {\n return (\n <MenuChipGroup ref={ref} className={className} {...props}>\n {children}\n </MenuChipGroup>\n )\n }\n // wrap(預設)\n return (\n <ToggleGroupPrimitive.Root\n ref={ref}\n className={cn('flex flex-wrap gap-2', className)}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Root>\n )\n }\n)\nChipGroup.displayName = 'ChipGroup'\n\n// ── Scroll / Menu modes ──\n// Fade mask / arrows / menu trigger 全部從 horizontal-overflow pattern module 取用。\n// 詳見 `patterns/horizontal-overflow/horizontal-overflow.spec.md`。\n//\n// Canonical 規則:所有 overflow affordance 一律是 Button text sm iconOnly,\n// 不論在 Chip / Tab / Step / SegmentedControl。Chip menu trigger 曾經用\n// chip-shape 圓形 button,已改回 text button 對齊 mental model。\n\n// ── ScrollChipGroup ──────────────────────────────────────────────────────────\n\nconst ScrollChipGroup = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>\n>(({ className, children, ...props }, ref) => {\n const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n const scrollByPage = useScrollByPage(scrollRef)\n const maskImage = buildFadeMask({\n canScroll,\n atStart,\n atEnd,\n reserveArrowWidth: ARROW_BUTTON_WIDTH,\n })\n\n return (\n <div className=\"relative\">\n <div\n ref={scrollRef}\n className=\"overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n style={{ maskImage, WebkitMaskImage: maskImage }}\n >\n <ToggleGroupPrimitive.Root\n ref={ref}\n className={cn('flex flex-nowrap gap-2 w-fit', className)}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Root>\n </div>\n {!atStart && canScroll && (\n <OverflowScrollArrow direction=\"left\" onClick={() => scrollByPage('left')} />\n )}\n {!atEnd && canScroll && (\n <OverflowScrollArrow direction=\"right\" onClick={() => scrollByPage('right')} />\n )}\n </div>\n )\n})\nScrollChipGroup.displayName = 'ScrollChipGroup'\n\n// ── MenuChipGroup ────────────────────────────────────────────────────────────\n// Show-all navigator pattern (Chrome tab dropdown / VS Code editor tabs):\n// - Menu 永遠顯示全部 chips,每個都用 DropdownMenuCheckboxItem + checked 反映 selection\n// - 點 menu item = toggle selection + scrollIntoView,把該 chip 捲到中央\n// - 不用動態 overflow 計算,menu 內容穩定\n//\n// Menu trigger 使用 canonical `<OverflowMenuTriggerButton>`(= Button text sm iconOnly\n// + ChevronDown),跟 Tabs menu trigger 完全同一套——overflow affordance 屬於工具層,\n// 不該用 chip 自己的視覺語言(圓形 outlined)去渲染,否則 mental model 錯誤(使用者\n// 會誤以為是第 N+1 個可選 chip)。\n//\n// 過去 Chip menu trigger 曾用 `chipVariants() + aspect-square + p-0` 做成圓形 pill,\n// 已按 `horizontal-overflow.spec.md` 的 canonical 規則改回 text button。\n//\n// Fade mask 仍保留(reserveArrowWidth: 0),軟化內容硬邊。\n\n// ── getElementRef(Radix Slot idiom)──────────────────────────────────────────\n// 讀取 child element 既有 ref 而不觸發 React dev deprecation warning:\n// React ≤18 ref 在 element.ref;React 19 起移到 element.props.ref,錯誤側讀取會 fire warning\n// (以 getter 上的 isReactWarning 標記)。抄 Radix UI Slot 的偵測法:\n// https://github.com/radix-ui/primitives/blob/main/packages/react/slot/src/slot.tsx(getElementRef)\n// react-compose-refs 僅為 transitive dep(非 package.json 直接依賴),不直接 import — 最小 local 實作。\nfunction getElementRef(element: React.ReactElement): React.Ref<HTMLElement> | undefined {\n // React <=18 dev:props.ref 掛 isReactWarning getter → 真 ref 在 element.ref\n let getter = Object.getOwnPropertyDescriptor(element.props, 'ref')?.get\n let mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning\n if (mayWarn) return (element as unknown as { ref?: React.Ref<HTMLElement> }).ref\n // React 19 dev:element.ref 掛 isReactWarning getter → 真 ref 在 props.ref\n getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get\n mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning\n if (mayWarn) return (element.props as { ref?: React.Ref<HTMLElement> }).ref\n // production:兩處擇一\n return (\n (element.props as { ref?: React.Ref<HTMLElement> }).ref ??\n (element as unknown as { ref?: React.Ref<HTMLElement> }).ref ??\n undefined\n )\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst MenuChipGroup = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>\n>(({ className, children, ...props }, ref) => {\n const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n\n // Local ref map — 追蹤每個 chip 的 DOM 元素供 scrollIntoView 使用。\n // 不用 useOverflowIndices 因為 menu 永遠顯示全部, 不需要動態 overflow 計算。\n // code-quality-allow: long-function — helper fn 結構緊密,拆 sub-fn 會跨 fn 傳 state 反而複雜\n const itemRefs = React.useRef<Map<number, HTMLElement>>(new Map())\n // 2026-05-16 audit codex Round 6:capture rAF + cancel on unmount(defensive hygiene)\n const scrollRafIdRef = React.useRef<number>(0)\n React.useEffect(() => () => { if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current) }, [])\n const registerItem = React.useCallback(\n (index: number) => (el: HTMLElement | null) => {\n if (el) itemRefs.current.set(index, el)\n else itemRefs.current.delete(index)\n },\n []\n )\n\n const menuMaskImage = buildFadeMask({ canScroll, atStart, atEnd, reserveArrowWidth: 0 })\n\n const items = React.useMemo(\n () => React.Children.toArray(children).filter(React.isValidElement) as React.ReactElement[],\n [children]\n )\n\n const groupType = (props as { type?: 'single' | 'multiple' }).type ?? 'single'\n const groupValue = (props as { value?: string | string[] }).value\n const groupOnValueChange = (\n props as { onValueChange?: (value: string | string[]) => void }\n ).onValueChange\n\n // code-quality-allow: long-function — helper fn 結構緊密,拆 sub-fn 會跨 fn 傳 state 反而複雜\n const isSelected = React.useCallback(\n (chipValue: string): boolean => {\n if (groupType === 'multiple') {\n return Array.isArray(groupValue) && groupValue.includes(chipValue)\n }\n return groupValue === chipValue\n },\n [groupType, groupValue]\n )\n\n // code-quality-allow: long-function — multi / single / none selection mode each has 事務性 branch,拆 fn 會跨 fn 傳 chipValue/index/groupOnValueChange state 反而難讀\n const toggleFromMenu = React.useCallback(\n (chipValue: string, index: number) => {\n if (!groupOnValueChange) {\n if (import.meta.env?.DEV) {\n console.warn(\n '[ChipGroup] layout=\"menu\" 需要 controlled 使用(請傳 value + onValueChange),否則 menu items 無法同步主 chip 選擇狀態。'\n )\n }\n return\n }\n if (groupType === 'multiple') {\n const current = (Array.isArray(groupValue) ? groupValue : []) as string[]\n const next = current.includes(chipValue)\n ? current.filter((v) => v !== chipValue)\n : [...current, chipValue]\n ;(groupOnValueChange as (v: string[]) => void)(next)\n } else {\n ;(groupOnValueChange as (v: string) => void)(chipValue)\n }\n // scrollIntoView: 讓剛選中的 chip 出現在視圖中央\n if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current)\n scrollRafIdRef.current = requestAnimationFrame(() => {\n scrollRafIdRef.current = 0\n itemRefs.current.get(index)?.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' })\n })\n },\n [groupType, groupValue, groupOnValueChange]\n )\n\n // 2026-07-05 fix(deep-audit A.1b):原 cloneElement 直接以 registerItem 覆寫 child ref,\n // consumer 傳給 Chip 的自有 ref 在 menu layout 會被靜默取代。改 compose — 同時餵\n // registerItem(scrollIntoView 用)與 child 原 ref(對齊 Radix compose-refs idiom)。\n const enhancedItems = items.map((child, i) => {\n const childRef = getElementRef(child)\n return React.cloneElement(\n child as React.ReactElement<{ ref?: React.Ref<HTMLElement> }>,\n {\n ref: (el: HTMLElement | null) => {\n registerItem(i)(el)\n if (typeof childRef === 'function') childRef(el)\n else if (childRef) (childRef as React.MutableRefObject<HTMLElement | null>).current = el\n },\n }\n )\n })\n\n return (\n <div className=\"flex items-center gap-2\">\n <div\n ref={scrollRef}\n className=\"flex-1 min-w-0 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n style={{ maskImage: menuMaskImage, WebkitMaskImage: menuMaskImage }}\n >\n <ToggleGroupPrimitive.Root\n ref={ref}\n className={cn('flex flex-nowrap gap-2 w-fit', className)}\n {...props}\n >\n {enhancedItems}\n </ToggleGroupPrimitive.Root>\n </div>\n {canScroll && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <OverflowMenuTriggerButton\n aria-label={`選項選單(共 ${items.length} 個)`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {items.map((chip, index) => {\n const chipProps = chip.props as { value?: string; children?: React.ReactNode; disabled?: boolean }\n const chipValue = chipProps.value\n if (typeof chipValue !== 'string') return null\n return (\n <DropdownMenuCheckboxItem\n key={chipValue}\n checked={isSelected(chipValue)}\n disabled={chipProps.disabled}\n onCheckedChange={() => toggleFromMenu(chipValue, index)}\n >\n {chipProps.children}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n )\n})\nMenuChipGroup.displayName = 'MenuChipGroup'\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 chipMeta = {\n component: 'Chip',\n family: 3,\n // 2026-07-04 audit 填 Phase 2:Chip 單一視覺無 variant 軸(variants 留空為 intentional,非漏填)\n variants: {},\n sizes: {\n // 單一尺寸:h-field-sm(28/32 依 density)、icon 16、text-body、px-3(cva 真值)\n sm: { fieldHeight: 28, iconSize: 16, typography: 'body' },\n },\n states: ['default', 'hover', 'selected', 'focus-visible', 'disabled'], // selected = data-[state=on](primary base,2026-07-06 拍板);cva 無 active 樣式\n tokens: {\n bg: ['bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground', 'text-primary'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Chip, ChipGroup, chipVariants }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chip.js","sources":["../../../src/components/Chip/chip.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 ToggleGroupPrimitive from '@radix-ui/react-toggle-group'\nimport { cva } from 'class-variance-authority'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuCheckboxItem,\n} from '@/design-system/components/DropdownMenu/dropdown-menu'\nimport {\n useScrollEdges,\n useScrollByPage,\n buildFadeMask,\n ARROW_BUTTON_WIDTH,\n OverflowScrollArrow,\n OverflowMenuTriggerButton,\n} from '@/design-system/patterns/horizontal-overflow/horizontal-overflow'\n\n/**\n * Chip — Material Design Filter Chip\n *\n * 基於 Radix ToggleGroup,橋接設計系統 token。\n * 必須在 <ChipGroup> 內使用。\n *\n * ── 內部結構(鏡射 Button)──\n * [startIcon?] [<span px-1>label</span>] [<span gap-1>badge? + endIcon?</span>]\n *\n * ── Size ──\n * 單一 size = h-field-sm(28/32 density-aware)\n * 對齊 Material 3 / Atlassian / Polaris 世界級共識\n *\n * ── State ──\n * default bg-surface border-border text-fg-secondary\n * hover border-border-hover text-foreground(對齊 Input / SegmentedControl)\n * selected bg-surface(不變) border-primary text-primary\n * disabled cursor-not-allowed text-fg-disabled\n *\n * ── 詳見 chip.spec.md ──\n */\n\n// ── Chip item ────────────────────────────────────────────────────────────────\n\nconst chipVariants = cva(\n [\n 'inline-flex items-center justify-center',\n 'h-field-sm px-3 gap-1',\n 'rounded-full border border-border',\n // 預設文字: text-fg-secondary (neutral-8) — 對齊 SegmentedControl / Tabs 未選狀態\n 'bg-surface text-fg-secondary',\n 'text-body leading-compact font-medium whitespace-nowrap',\n 'transition-colors duration-150',\n 'cursor-pointer select-none',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1',\n // hover(未選):border 加深一階 + 文字轉深,對齊 Input / SegmentedControl hover\n 'hover:border-border-hover hover:text-foreground',\n // selected: 文字 + 邊框都用 primary base,底色維持 bg-surface 不變\n // ── pill 風格 canonical 選中規則,跟 SegmentedControl 完全一致(SSOT = semantic.css「選中狀態」段):\n // primary base 同時染文字和線條;底色不改 (不用 primary-subtle)。\n // 2026-07-06 user 拍板:持續選中 hover 階 → base — Ant(pagination/tabs/input focus 全 base)/\n // Atlassian(selected = brand 同顆)/ Material 3(active tab = primary)三家實錘「瞬時弱、持續強」;\n // hover 階專屬瞬時態(hover/預覽),持續選中站 base。\n 'data-[state=on]:border-primary data-[state=on]:text-primary',\n // 選中之上的 hover = 同色相升 hover 階(2026-07-06 user 拍板;Button pressed hover\n // data-[state=on]:hover:text-primary-hover 家族 + Ant active 頁 hover = colorPrimaryHover\n // 同派)。原本靠 CSS 平手 source-order 讓選中「碰巧」贏過未選 hover(靜止無回饋)= 脆弱,\n // 顯式宣告一併解掉。\n 'data-[state=on]:hover:border-primary-hover data-[state=on]:hover:text-primary-hover',\n // disabled:cursor-not-allowed + 鎖 hover 不變色\n // 不用 pointer-events-none(否則 cursor-not-allowed 不會顯示)\n 'disabled:cursor-not-allowed disabled:text-fg-disabled',\n 'disabled:hover:border-border disabled:hover:text-fg-disabled',\n // disabled × selected 疊加(2026-07-07 user 拍板統一;M24 state > emphasis:disabled 全滅,\n // 選中的 primary 描邊/染字一併退場——原本只滅字不滅框 = 半滅,Checkbox checked+disabled 全滅同族)\n 'data-[state=on]:disabled:border-border data-[state=on]:disabled:text-fg-disabled',\n 'data-[state=on]:disabled:hover:border-border data-[state=on]:disabled:hover:text-fg-disabled',\n ]\n)\n\nexport interface ChipProps\n // 2026-07-14 dim-9 修:Omit 'asChild' — chip.spec.md 禁止事項明載「❌ 用 asChild——不支援」,\n // 且內部固定渲染 {icon}{label}{suffix} 多 children 結構,asChild(Radix Slot 要求單一\n // element child)會 runtime throw(CLAUDE.md 失敗記憶「asChild ? Slot : Native」條)。\n // 型別層 Omit 讓誤用在編譯期失敗,對齊 spec-vs-type 一致。\n extends Omit<React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item>, 'asChild'> {\n /** 左側 icon(LucideIcon),最多一個 */\n startIcon?: LucideIcon\n /** 右側 badge(通常是計數指示器)*/\n badge?: React.ReactNode\n /** 右側 icon(少見,通常是 ChevronDown 指示可展開)*/\n endIcon?: LucideIcon\n}\n\nconst Chip = React.forwardRef<\n React.ElementRef<typeof ToggleGroupPrimitive.Item>,\n ChipProps\n>(({ className, startIcon: StartIcon, badge, endIcon: EndIcon, children, ...props }, ref) => {\n const hasSuffix = badge != null || EndIcon !== undefined\n\n return (\n <ToggleGroupPrimitive.Item\n ref={ref}\n className={cn(chipVariants(), className)}\n {...props}\n >\n {StartIcon && <StartIcon size={16} aria-hidden />}\n {children != null && <span className=\"px-1\">{children}</span>}\n {hasSuffix && (\n <span className=\"inline-flex items-center gap-1\">\n {badge}\n {EndIcon && <EndIcon size={16} aria-hidden />}\n </span>\n )}\n </ToggleGroupPrimitive.Item>\n )\n})\nChip.displayName = 'Chip'\n\n// ── ChipGroup ────────────────────────────────────────────────────────────────\n\nexport type ChipGroupLayout = 'wrap' | 'scroll' | 'menu'\n\nexport type ChipGroupProps = React.ComponentPropsWithoutRef<\n typeof ToggleGroupPrimitive.Root\n> & {\n /** Overflow 處理模式。預設 `wrap`(塞不下換行)。詳見 chip.spec.md */\n layout?: ChipGroupLayout\n}\n\nconst ChipGroup = React.forwardRef<HTMLDivElement, ChipGroupProps>(\n ({ layout = 'wrap', className, children, ...props }, ref) => {\n if (layout === 'scroll') {\n return (\n <ScrollChipGroup ref={ref} className={className} {...props}>\n {children}\n </ScrollChipGroup>\n )\n }\n if (layout === 'menu') {\n return (\n <MenuChipGroup ref={ref} className={className} {...props}>\n {children}\n </MenuChipGroup>\n )\n }\n // wrap(預設)\n return (\n <ToggleGroupPrimitive.Root\n ref={ref}\n className={cn('flex flex-wrap gap-2', className)}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Root>\n )\n }\n)\nChipGroup.displayName = 'ChipGroup'\n\n// ── Scroll / Menu modes ──\n// Fade mask / arrows / menu trigger 全部從 horizontal-overflow pattern module 取用。\n// 詳見 `patterns/horizontal-overflow/horizontal-overflow.spec.md`。\n//\n// Canonical 規則:所有 overflow affordance 一律是 Button text sm iconOnly,\n// 不論在 Chip / Tab / Step / SegmentedControl。Chip menu trigger 曾經用\n// chip-shape 圓形 button,已改回 text button 對齊 mental model。\n\n// ── ScrollChipGroup ──────────────────────────────────────────────────────────\n\nconst ScrollChipGroup = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>\n>(({ className, children, ...props }, ref) => {\n const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n const scrollByPage = useScrollByPage(scrollRef)\n const maskImage = buildFadeMask({\n canScroll,\n atStart,\n atEnd,\n reserveArrowWidth: ARROW_BUTTON_WIDTH,\n })\n\n return (\n <div className=\"relative\">\n <div\n ref={scrollRef}\n className=\"overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n style={{ maskImage, WebkitMaskImage: maskImage }}\n >\n <ToggleGroupPrimitive.Root\n ref={ref}\n className={cn('flex flex-nowrap gap-2 w-fit', className)}\n {...props}\n >\n {children}\n </ToggleGroupPrimitive.Root>\n </div>\n {!atStart && canScroll && (\n <OverflowScrollArrow direction=\"left\" onClick={() => scrollByPage('left')} />\n )}\n {!atEnd && canScroll && (\n <OverflowScrollArrow direction=\"right\" onClick={() => scrollByPage('right')} />\n )}\n </div>\n )\n})\nScrollChipGroup.displayName = 'ScrollChipGroup'\n\n// ── MenuChipGroup ────────────────────────────────────────────────────────────\n// Show-all navigator pattern (Chrome tab dropdown / VS Code editor tabs):\n// - Menu 永遠顯示全部 chips,每個都用 DropdownMenuCheckboxItem + checked 反映 selection\n// - 點 menu item = toggle selection + scrollIntoView,把該 chip 捲到中央\n// - 不用動態 overflow 計算,menu 內容穩定\n//\n// Menu trigger 使用 canonical `<OverflowMenuTriggerButton>`(= Button text sm iconOnly\n// + ChevronDown),跟 Tabs menu trigger 完全同一套——overflow affordance 屬於工具層,\n// 不該用 chip 自己的視覺語言(圓形 outlined)去渲染,否則 mental model 錯誤(使用者\n// 會誤以為是第 N+1 個可選 chip)。\n//\n// 過去 Chip menu trigger 曾用 `chipVariants() + aspect-square + p-0` 做成圓形 pill,\n// 已按 `horizontal-overflow.spec.md` 的 canonical 規則改回 text button。\n//\n// Fade mask 仍保留(reserveArrowWidth: 0),軟化內容硬邊。\n\n// ── getElementRef(Radix Slot idiom)──────────────────────────────────────────\n// 讀取 child element 既有 ref 而不觸發 React dev deprecation warning:\n// React ≤18 ref 在 element.ref;React 19 起移到 element.props.ref,錯誤側讀取會 fire warning\n// (以 getter 上的 isReactWarning 標記)。抄 Radix UI Slot 的偵測法:\n// https://github.com/radix-ui/primitives/blob/main/packages/react/slot/src/slot.tsx(getElementRef)\n// react-compose-refs 僅為 transitive dep(非 package.json 直接依賴),不直接 import — 最小 local 實作。\nfunction getElementRef(element: React.ReactElement): React.Ref<HTMLElement> | undefined {\n // React <=18 dev:props.ref 掛 isReactWarning getter → 真 ref 在 element.ref\n let getter = Object.getOwnPropertyDescriptor(element.props, 'ref')?.get\n let mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning\n if (mayWarn) return (element as unknown as { ref?: React.Ref<HTMLElement> }).ref\n // React 19 dev:element.ref 掛 isReactWarning getter → 真 ref 在 props.ref\n getter = Object.getOwnPropertyDescriptor(element, 'ref')?.get\n mayWarn = getter && 'isReactWarning' in getter && getter.isReactWarning\n if (mayWarn) return (element.props as { ref?: React.Ref<HTMLElement> }).ref\n // production:兩處擇一\n return (\n (element.props as { ref?: React.Ref<HTMLElement> }).ref ??\n (element as unknown as { ref?: React.Ref<HTMLElement> }).ref ??\n undefined\n )\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst MenuChipGroup = React.forwardRef<\n HTMLDivElement,\n React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>\n>(({ className, children, ...props }, ref) => {\n const { scrollRef, atStart, atEnd, canScroll } = useScrollEdges<HTMLDivElement>()\n\n // Local ref map — 追蹤每個 chip 的 DOM 元素供 scrollIntoView 使用。\n // 不用 useOverflowIndices 因為 menu 永遠顯示全部, 不需要動態 overflow 計算。\n // code-quality-allow: long-function — helper fn 結構緊密,拆 sub-fn 會跨 fn 傳 state 反而複雜\n const itemRefs = React.useRef<Map<number, HTMLElement>>(new Map())\n // 2026-05-16 audit codex Round 6:capture rAF + cancel on unmount(defensive hygiene)\n const scrollRafIdRef = React.useRef<number>(0)\n React.useEffect(() => () => { if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current) }, [])\n const registerItem = React.useCallback(\n (index: number) => (el: HTMLElement | null) => {\n if (el) itemRefs.current.set(index, el)\n else itemRefs.current.delete(index)\n },\n []\n )\n\n const menuMaskImage = buildFadeMask({ canScroll, atStart, atEnd, reserveArrowWidth: 0 })\n\n const items = React.useMemo(\n () => React.Children.toArray(children).filter(React.isValidElement) as React.ReactElement[],\n [children]\n )\n\n const groupType = (props as { type?: 'single' | 'multiple' }).type ?? 'single'\n const groupValue = (props as { value?: string | string[] }).value\n const groupOnValueChange = (\n props as { onValueChange?: (value: string | string[]) => void }\n ).onValueChange\n\n // code-quality-allow: long-function — helper fn 結構緊密,拆 sub-fn 會跨 fn 傳 state 反而複雜\n const isSelected = React.useCallback(\n (chipValue: string): boolean => {\n if (groupType === 'multiple') {\n return Array.isArray(groupValue) && groupValue.includes(chipValue)\n }\n return groupValue === chipValue\n },\n [groupType, groupValue]\n )\n\n // code-quality-allow: long-function — multi / single / none selection mode each has 事務性 branch,拆 fn 會跨 fn 傳 chipValue/index/groupOnValueChange state 反而難讀\n const toggleFromMenu = React.useCallback(\n (chipValue: string, index: number) => {\n if (!groupOnValueChange) {\n if (import.meta.env?.DEV) {\n console.warn(\n '[ChipGroup] layout=\"menu\" 需要 controlled 使用(請傳 value + onValueChange),否則 menu items 無法同步主 chip 選擇狀態。'\n )\n }\n return\n }\n if (groupType === 'multiple') {\n const current = (Array.isArray(groupValue) ? groupValue : []) as string[]\n const next = current.includes(chipValue)\n ? current.filter((v) => v !== chipValue)\n : [...current, chipValue]\n ;(groupOnValueChange as (v: string[]) => void)(next)\n } else {\n ;(groupOnValueChange as (v: string) => void)(chipValue)\n }\n // scrollIntoView: 讓剛選中的 chip 出現在視圖中央\n if (scrollRafIdRef.current) cancelAnimationFrame(scrollRafIdRef.current)\n scrollRafIdRef.current = requestAnimationFrame(() => {\n scrollRafIdRef.current = 0\n itemRefs.current.get(index)?.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' })\n })\n },\n [groupType, groupValue, groupOnValueChange]\n )\n\n // 2026-07-05 fix(deep-audit A.1b):原 cloneElement 直接以 registerItem 覆寫 child ref,\n // consumer 傳給 Chip 的自有 ref 在 menu layout 會被靜默取代。改 compose — 同時餵\n // registerItem(scrollIntoView 用)與 child 原 ref(對齊 Radix compose-refs idiom)。\n const enhancedItems = items.map((child, i) => {\n const childRef = getElementRef(child)\n return React.cloneElement(\n child as React.ReactElement<{ ref?: React.Ref<HTMLElement> }>,\n {\n ref: (el: HTMLElement | null) => {\n registerItem(i)(el)\n if (typeof childRef === 'function') childRef(el)\n else if (childRef) (childRef as React.MutableRefObject<HTMLElement | null>).current = el\n },\n }\n )\n })\n\n return (\n <div className=\"flex items-center gap-2\">\n <div\n ref={scrollRef}\n className=\"flex-1 min-w-0 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\n style={{ maskImage: menuMaskImage, WebkitMaskImage: menuMaskImage }}\n >\n <ToggleGroupPrimitive.Root\n ref={ref}\n className={cn('flex flex-nowrap gap-2 w-fit', className)}\n {...props}\n >\n {enhancedItems}\n </ToggleGroupPrimitive.Root>\n </div>\n {canScroll && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <OverflowMenuTriggerButton\n aria-label={`選項選單(共 ${items.length} 個)`}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n {items.map((chip, index) => {\n const chipProps = chip.props as { value?: string; children?: React.ReactNode; disabled?: boolean }\n const chipValue = chipProps.value\n if (typeof chipValue !== 'string') return null\n return (\n <DropdownMenuCheckboxItem\n key={chipValue}\n checked={isSelected(chipValue)}\n disabled={chipProps.disabled}\n onCheckedChange={() => toggleFromMenu(chipValue, index)}\n >\n {chipProps.children}\n </DropdownMenuCheckboxItem>\n )\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n )\n})\nMenuChipGroup.displayName = 'MenuChipGroup'\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 chipMeta = {\n component: 'Chip',\n family: 3,\n // 2026-07-04 audit 填 Phase 2:Chip 單一視覺無 variant 軸(variants 留空為 intentional,非漏填)\n variants: {},\n sizes: {\n // 單一尺寸:h-field-sm(28/32 依 density)、icon 16、text-body、px-3(cva 真值)\n sm: { fieldHeight: 28, iconSize: 16, typography: 'body' },\n },\n states: ['default', 'hover', 'selected', 'focus-visible', 'disabled'], // selected = data-[state=on](primary base,2026-07-06 拍板);cva 無 active 樣式\n tokens: {\n bg: ['bg-surface'],\n fg: ['text-fg-disabled', 'text-fg-secondary', 'text-foreground', 'text-primary'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Chip, ChipGroup, chipVariants }\n"],"names":[],"mappings":"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"}
@@ -21,7 +21,9 @@ import * as React from 'react';
21
21
  * 同樣規則)。CTA = `isLastStep ? 'Done' : 'Next'`
22
22
  * 4. **抑制 CTA 自動 focus,焦點落在 content 容器** — `onOpenAutoFocus` preventDefault
23
23
  * 後 focus content 容器本身(非第一個 CTA),避免使用者還在讀 body 時按 Enter 誤推進;
24
- * Tab 第一下即達 content 內第一個 CTA。焦點不可停在 trigger:non-modal Popover
24
+ * Tab 才移到 content 內按鈕:**單步無 header** 時第一個 tabbable 即推進 CTA;**有 header
25
+ * (kind / headerTitle 會渲 PopoverHeader 右上 Close X)或多步** 時 DOM 順序上 Close X /
26
+ * Previous / Skip 在推進 CTA 之前,需多按幾下 Tab。焦點不可停在 trigger:non-modal Popover 下
25
27
  * 焦點在 DismissableLayer 外按 Tab 會觸發 focus-outside dismiss 誤關閉
26
28
  * (2026-07-05 D4;對齊 dialog.tsx handleOpenAutoFocus `?? content` fallback,見 spec「A11y 預設」)。
27
29
  *
@@ -39,8 +41,13 @@ export interface CoachmarkProps extends Omit<React.HTMLAttributes<HTMLDivElement
39
41
  /** 預設打開(uncontrolled initial state)— 2026-05-15 audit Dim 26 V1 fix per user verbatim「A:1」approval */
40
42
  defaultOpen?: boolean;
41
43
  onOpenChange?: (open: boolean) => void;
42
- /** 觸發 anchor 元素。通常傳 trigger element;Coachmark 浮層會定位於此 */
43
- children: React.ReactNode;
44
+ /**
45
+ * 觸發 anchor 元素——**必為單一 React element**(內部走 `<PopoverTrigger asChild>` =
46
+ * Radix Slot 契約;傳 string / fragment / 多元素會 `React.Children.only` runtime 炸,
47
+ * 見 CLAUDE.md 失敗記憶索引「asChild + Slot」條)。與 Popover / Tooltip / HoverCard
48
+ * 同一錨點契約;型別收緊為 ReactElement 讓契約在 compile 期顯現。
49
+ */
50
+ children: React.ReactElement;
44
51
  /** 頂部 media 區(圖片 / illustration / video 等);不傳則無 media */
45
52
  image?: React.ReactNode;
46
53
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"coachmark.d.ts","sourceRoot":"","sources":["../../../src/components/Coachmark/coachmark.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAe9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACtG,2BAA2B;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,sGAAsG;IACtG,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,yDAAyD;IACzD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,yDAAyD;IACzD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK,CAAC,SAAS,CAAA;IAChD,eAAe;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,gCAAgC;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,gDAAgD;IAChD,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AASD,QAAA,MAAM,SAAS,uFA2Id,CAAA;AAKD,eAAO,MAAM,aAAa;;;;;;;;;;;CAehB,CAAA;AAEV,OAAO,EAAE,SAAS,EAAE,CAAA"}
1
+ {"version":3,"file":"coachmark.d.ts","sourceRoot":"","sources":["../../../src/components/Coachmark/coachmark.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAe9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,UAAU,aAAa;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IACtG,2BAA2B;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,sGAAsG;IACtG,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;;OAKG;IACH,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAA;IAC5B,yDAAyD;IACzD,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,KAAK,CAAC,SAAS,CAAA;IAChD,eAAe;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB,gCAAgC;IAChC,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,gDAAgD;IAChD,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AASD,QAAA,MAAM,SAAS,uFA2Id,CAAA;AAKD,eAAO,MAAM,aAAa;;;;;;;;;;;CAehB,CAAA;AAEV,OAAO,EAAE,SAAS,EAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"coachmark.js","sources":["../../../src/components/Coachmark/coachmark.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 { cn } from '@/lib/utils'\nimport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverBody,\n PopoverFooter,\n PopoverHeader,\n PopoverTitle,\n} from '@/design-system/components/Popover/popover'\nimport { Button } from '@/design-system/components/Button/button'\nimport { AspectRatio } from '@/design-system/components/AspectRatio/aspect-ratio'\nimport { OVERLAY_SIDE_OFFSET } from '@/design-system/tokens/elevation/overlay-geometry'\n\n/**\n * Coachmark — 功能介紹 / onboarding tour 的浮層卡片\n *\n * 世界級對照:Apple HIG「Coachmark」(Apple 命名原處)/ Material「Feature Discovery」/\n * Ant Design `<Tour>` / Shepherd.js / react-joyride / Intercom Product Tours。\n *\n * 本元件 = **Popover 的 composition pattern**,consume 相同 overlay-surface SSOT:\n * - Header(可選,多步驟建議傳 `kind=\"tips\" | \"new-features\" | 自訂 title`,\n * single-step 預設無 header 避免視覺過重)\n * - Media 區(圖 / 截圖 / illustration,full-width 邊緣對齊,由 AspectRatio 管比例)\n * - Body(SurfaceBody padding):title + description 左對齊\n * - Footer(SurfaceFooter padding,但 justify-between):step 計數左 / actions 右\n *\n * ── 單 vs 多步驟 canonical(世界級行為規則) ──\n * 1. **Single step**(無 `onPrev` 且 `isLastStep`):CTA 文字 = `doneLabel ?? '知道了'`\n * (Apple HIG / Intercom 慣例;不用 \"Next\" 因為沒有下一步)\n * 2. **Multi step 第一步**(無 `onPrev`,有 `onNext`):CTA = \"Next\",Skip 顯示\n * 3. **Multi step 中間 / 最後步**(有 `onPrev`):**Skip 不顯示**(使用者已投入進度,\n * 再給 Skip 會讓「放棄」入口與「回上一步」衝突 — Linear / Pendo / Shepherd.js\n * 同樣規則)。CTA = `isLastStep ? 'Done' : 'Next'`\n * 4. **抑制 CTA 自動 focus,焦點落在 content 容器** — `onOpenAutoFocus` preventDefault\n * 後 focus content 容器本身(非第一個 CTA),避免使用者還在讀 body 時按 Enter 誤推進;\n * Tab 第一下即達 content 內第一個 CTA。焦點不可停在 trigger:non-modal Popover 下\n * 焦點在 DismissableLayer 外按 Tab 會觸發 focus-outside dismiss 誤關閉\n * (2026-07-05 D4;對齊 dialog.tsx handleOpenAutoFocus `?? content` fallback,見 spec「A11y 預設」)。\n *\n * ── 為什麼 Body+Footer 消費 overlay-surface ──\n * 避免 padding token 漂移:Dialog / Popover / Coachmark 三者共用同一套 Header/Body/Footer\n * padding(px-loose / py-tight),改 Dialog 就三邊自動跟進。\n */\n\ninterface CoachmarkStep {\n current: number\n total: number\n}\n\nexport interface CoachmarkProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title'> {\n /** 控制顯示(controlled mode)*/\n open?: boolean\n /** 預設打開(uncontrolled initial state)— 2026-05-15 audit Dim 26 V1 fix per user verbatim「A:1」approval */\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /** 觸發 anchor 元素。通常傳 trigger element;Coachmark 浮層會定位於此 */\n children: React.ReactNode\n /** 頂部 media 區(圖片 / illustration / video 等);不傳則無 media */\n image?: React.ReactNode\n /**\n * Media 區域的長寬比(ratio = 寬 / 高)。預設 `16/9`(onboarding feature tour\n * 世界級 convention — Intercom / Pendo / Shepherd.js)。其他常用:`4/3` 產品截圖 /\n * `1/1` 方圖 / `3/4` 直式 portrait。消費獨立的 `AspectRatio` primitive 元件。\n */\n mediaRatio?: number\n /**\n * 頂部 header 類型(多步驟 tour 建議傳)。\n * - `'tips'` → header title = \"使用技巧\"\n * - `'new-features'` → header title = \"新功能介紹\"\n * - `ReactNode` → 自訂 title(string / JSX)\n * - undefined → 無 header(單步驟常用)\n */\n kind?: 'tips' | 'new-features' | React.ReactNode\n /** 標題(bold) */\n title?: React.ReactNode\n /** 說明文字(normal weight,多行 OK) */\n description?: React.ReactNode\n /** 步驟計數(2 of 3);若需多步導覽 consumer 自行管理 current */\n step?: CoachmarkStep\n /** Skip 按鈕 callback;不傳則不顯示 Skip。多步驟中間 / 最後步自動隱藏(有 onPrev 時) */\n onSkip?: () => void\n /** Next 按鈕 callback;不傳則不顯示 Next */\n onNext?: () => void\n /** Previous 按鈕 callback(多步 tour 第 2+ 步顯示);不傳則不顯示 */\n onPrev?: () => void\n /**\n * 最後一步 flag。影響 primary CTA 文字:\n * - single step(無 onPrev 且 isLastStep):CTA = `doneLabel ?? '知道了'`\n * - multi-step 最後步(有 onPrev 且 isLastStep):CTA = 'Done'\n * - 其他:CTA = 'Next'\n */\n isLastStep?: boolean\n /** 自訂單步驟完成 CTA 文字(預設 `'知道了'`)。僅 single-step 使用 */\n doneLabel?: string\n /** 浮層定位(對齊 Popover props) */\n side?: 'top' | 'right' | 'bottom' | 'left'\n align?: 'start' | 'center' | 'end'\n sideOffset?: number\n /** 外殼寬度(預設 w-80 = 320px,比一般 Popover 寬,因要放 media + 文字) */\n className?: string\n}\n\n// i18n-allow: DS-internal kind → title 預設對照表;consumer 透過 `title` prop 直接覆寫\nconst KIND_TITLE: Record<'tips' | 'new-features', string> = {\n tips: '使用技巧',\n 'new-features': '新功能介紹',\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Coachmark = React.forwardRef<HTMLDivElement, CoachmarkProps>(\n (\n {\n open,\n defaultOpen,\n onOpenChange,\n children,\n image,\n mediaRatio = 16 / 9,\n kind,\n title,\n description,\n step,\n onSkip,\n onNext,\n onPrev,\n isLastStep = false,\n doneLabel = '知道了', // i18n-allow: DS default; consumer override via doneLabel prop\n side = 'bottom',\n align = 'center',\n sideOffset = OVERLAY_SIDE_OFFSET,\n className,\n ...props\n },\n ref,\n ) => {\n // 單/多步驟行為推導\n const isSingleStep = isLastStep && !onPrev\n // canonical(spec.md CTA 語義表 L116):有 onPrev → 不顯示 Skip;**單步驟也不顯示 Skip**\n // (單步「skip」與「知道了」語義重複 = 同一個關閉動作,雙關閉鍵造成困惑;對齊 Apple HIG / Intercom / Pendo 單步 tip 僅一個完成鍵)\n const showSkip = Boolean(onSkip) && !onPrev && !isSingleStep\n const nextLabel = isSingleStep ? doneLabel : isLastStep ? 'Done' : 'Next'\n\n const hasFooterContent = Boolean(step || showSkip || onNext || onPrev)\n const stepText = step ? `${step.current} of ${step.total}` : null\n\n // Header title 解析\n const headerTitle =\n kind === 'tips' || kind === 'new-features'\n ? KIND_TITLE[kind as 'tips' | 'new-features']\n : kind\n\n // 2026-05-31 #6 / 2026-07-05 改消費 Popover 自動接線:PopoverContent(role=dialog)accessible name 三層 —\n // 1. headerTitle → <PopoverTitle> 掛載時由 popover.tsx PopoverTitleContext 自動接 aria-labelledby(免手動)\n // 2. 無 header 但有 body 主 title(<h3> 非 PopoverTitle,自動接線接不到)→ 仍手動接 aria-labelledby\n // 3. 皆無 → aria-label fallback\n const bodyTitleId = React.useId()\n const bodyTitleLabelledBy = !headerTitle && title ? bodyTitleId : undefined\n\n return (\n <Popover open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n ref={ref}\n side={side}\n align={align}\n sideOffset={sideOffset}\n className={cn('w-80 p-0 overflow-hidden', className)}\n // 禁止 Radix 開啟時自動 focus 第一個 focusable(預設會 focus Prev / Skip / Next),\n // Coachmark 的 CTA 不該被 auto-focus 偷觸發(user 可能還在讀 body,按 Enter 就推進)。\n // 2026-07-05 D4:preventDefault 後必 focus content 容器本身(FocusScope 容器自帶 tabIndex=-1)——\n // 焦點若停在 trigger(DismissableLayer 外),non-modal Popover 按 Tab 即觸發 focus-outside\n // dismiss 直接關閉,CTA 鍵盤永遠到不了;focus 容器後 Tab 第一下即達第一個 CTA,Enter 按在\n // 容器上無動作(原「不誤推進」意圖保留;對齊 dialog.tsx handleOpenAutoFocus `?? content` fallback)。\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n ;(e.currentTarget as HTMLElement).focus({ preventScroll: true })\n }}\n aria-labelledby={bodyTitleLabelledBy}\n aria-label={headerTitle || title ? undefined : '提示'}\n {...props}\n >\n {headerTitle && (\n // Header title 走 `<PopoverTitle>` 共用 Popover typography canonical(text-body font-medium)。\n // **不 hideClose** — 對齊 Popover / Dialog / 所有 overlay 家族 canonical:header 必有 dismiss X\n // (user 可隨時關閉,跟 Skip / Done 是不同入口,canonical 重複不冗)\n <PopoverHeader>\n <PopoverTitle>{headerTitle}</PopoverTitle>\n </PopoverHeader>\n )}\n\n {image && (\n <AspectRatio ratio={mediaRatio} className=\"w-full overflow-hidden bg-muted\">\n {image}\n </AspectRatio>\n )}\n\n {(title || description) && (\n // 對齊 Dialog / Popover canonical:body 左對齊(不中置)\n // Why: Coachmark 雖是 onboarding / feature discovery,但文字可讀性 > 視覺焦點;\n // 中文 / 長句中置會「每行起點不同」造成閱讀鋸齒,左對齊最穩。\n // 世界級參考:Notion / Linear / Figma onboarding tour 皆左對齊;Intercom Messenger 亦如是。\n <PopoverBody className=\"flex flex-col\">\n {title && (\n <h3 id={!headerTitle ? bodyTitleId : undefined} className=\"text-body-lg font-medium text-foreground\">{title}</h3>\n )}\n {description && (\n // title(body-lg 16)+ desc(body 14)→ reading-lg token(label tier 決定)\n // 對齊 Dialog / Sheet canonical;移除原 gap-1(4px)drift\n <p className=\"mt-[var(--item-gap-label-desc-reading-lg)] text-body text-fg-secondary\">{description}</p>\n )}\n </PopoverBody>\n )}\n\n {hasFooterContent && (\n // 專屬 Coachmark canonical:footer 無上方分隔線(media + body + footer 視覺一氣呵成,\n // 不像 Dialog 需要 header/footer 分隔強化結構)。override SurfaceFooter default border-t\n <PopoverFooter className=\"justify-between !border-t-0\">\n {stepText ? (\n // step 文字走 text-body 跟 body content 字體一致\n <span className=\"text-body text-fg-secondary tabular-nums\">\n {stepText}\n </span>\n ) : (\n <span aria-hidden /> /* 保持 justify-between space */\n )}\n <div className=\"flex items-center gap-2\">\n {onPrev && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={onPrev}>\n Previous\n </Button>\n )}\n {showSkip && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={onSkip}>\n Skip\n </Button>\n )}\n {onNext && (\n <Button variant=\"primary\" size=\"sm\" onClick={onNext}>\n {nextLabel}\n </Button>\n )}\n </div>\n </PopoverFooter>\n )}\n </PopoverContent>\n </Popover>\n )\n },\n)\nCoachmark.displayName = 'Coachmark'\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 coachmarkMeta = {\n component: 'Coachmark',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default'], // 純 Popover composition — 無自有 hover / active / disabled 視覺(spec「邊界狀態」)\n tokens: {\n bg: ['bg-muted'],\n fg: ['text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { Coachmark }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coachmark.js","sources":["../../../src/components/Coachmark/coachmark.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 { cn } from '@/lib/utils'\nimport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverBody,\n PopoverFooter,\n PopoverHeader,\n PopoverTitle,\n} from '@/design-system/components/Popover/popover'\nimport { Button } from '@/design-system/components/Button/button'\nimport { AspectRatio } from '@/design-system/components/AspectRatio/aspect-ratio'\nimport { OVERLAY_SIDE_OFFSET } from '@/design-system/tokens/elevation/overlay-geometry'\n\n/**\n * Coachmark — 功能介紹 / onboarding tour 的浮層卡片\n *\n * 世界級對照:Apple HIG「Coachmark」(Apple 命名原處)/ Material「Feature Discovery」/\n * Ant Design `<Tour>` / Shepherd.js / react-joyride / Intercom Product Tours。\n *\n * 本元件 = **Popover 的 composition pattern**,consume 相同 overlay-surface SSOT:\n * - Header(可選,多步驟建議傳 `kind=\"tips\" | \"new-features\" | 自訂 title`,\n * single-step 預設無 header 避免視覺過重)\n * - Media 區(圖 / 截圖 / illustration,full-width 邊緣對齊,由 AspectRatio 管比例)\n * - Body(SurfaceBody padding):title + description 左對齊\n * - Footer(SurfaceFooter padding,但 justify-between):step 計數左 / actions 右\n *\n * ── 單 vs 多步驟 canonical(世界級行為規則) ──\n * 1. **Single step**(無 `onPrev` 且 `isLastStep`):CTA 文字 = `doneLabel ?? '知道了'`\n * (Apple HIG / Intercom 慣例;不用 \"Next\" 因為沒有下一步)\n * 2. **Multi step 第一步**(無 `onPrev`,有 `onNext`):CTA = \"Next\",Skip 顯示\n * 3. **Multi step 中間 / 最後步**(有 `onPrev`):**Skip 不顯示**(使用者已投入進度,\n * 再給 Skip 會讓「放棄」入口與「回上一步」衝突 — Linear / Pendo / Shepherd.js\n * 同樣規則)。CTA = `isLastStep ? 'Done' : 'Next'`\n * 4. **抑制 CTA 自動 focus,焦點落在 content 容器** — `onOpenAutoFocus` preventDefault\n * 後 focus content 容器本身(非第一個 CTA),避免使用者還在讀 body 時按 Enter 誤推進;\n * 按 Tab 才移到 content 內按鈕:**單步無 header** 時第一個 tabbable 即推進 CTA;**有 header\n * (kind / headerTitle 會渲 PopoverHeader 右上 Close X)或多步** 時 DOM 順序上 Close X /\n * Previous / Skip 在推進 CTA 之前,需多按幾下 Tab。焦點不可停在 trigger:non-modal Popover 下\n * 焦點在 DismissableLayer 外按 Tab 會觸發 focus-outside dismiss 誤關閉\n * (2026-07-05 D4;對齊 dialog.tsx handleOpenAutoFocus `?? content` fallback,見 spec「A11y 預設」)。\n *\n * ── 為什麼 Body+Footer 消費 overlay-surface ──\n * 避免 padding token 漂移:Dialog / Popover / Coachmark 三者共用同一套 Header/Body/Footer\n * padding(px-loose / py-tight),改 Dialog 就三邊自動跟進。\n */\n\ninterface CoachmarkStep {\n current: number\n total: number\n}\n\nexport interface CoachmarkProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'title'> {\n /** 控制顯示(controlled mode)*/\n open?: boolean\n /** 預設打開(uncontrolled initial state)— 2026-05-15 audit Dim 26 V1 fix per user verbatim「A:1」approval */\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n /**\n * 觸發 anchor 元素——**必為單一 React element**(內部走 `<PopoverTrigger asChild>` =\n * Radix Slot 契約;傳 string / fragment / 多元素會 `React.Children.only` runtime 炸,\n * 見 CLAUDE.md 失敗記憶索引「asChild + Slot」條)。與 Popover / Tooltip / HoverCard\n * 同一錨點契約;型別收緊為 ReactElement 讓契約在 compile 期顯現。\n */\n children: React.ReactElement\n /** 頂部 media 區(圖片 / illustration / video 等);不傳則無 media */\n image?: React.ReactNode\n /**\n * Media 區域的長寬比(ratio = 寬 / 高)。預設 `16/9`(onboarding feature tour\n * 世界級 convention — Intercom / Pendo / Shepherd.js)。其他常用:`4/3` 產品截圖 /\n * `1/1` 方圖 / `3/4` 直式 portrait。消費獨立的 `AspectRatio` primitive 元件。\n */\n mediaRatio?: number\n /**\n * 頂部 header 類型(多步驟 tour 建議傳)。\n * - `'tips'` → header title = \"使用技巧\"\n * - `'new-features'` → header title = \"新功能介紹\"\n * - `ReactNode` → 自訂 title(string / JSX)\n * - undefined → 無 header(單步驟常用)\n */\n kind?: 'tips' | 'new-features' | React.ReactNode\n /** 標題(bold) */\n title?: React.ReactNode\n /** 說明文字(normal weight,多行 OK) */\n description?: React.ReactNode\n /** 步驟計數(2 of 3);若需多步導覽 consumer 自行管理 current */\n step?: CoachmarkStep\n /** Skip 按鈕 callback;不傳則不顯示 Skip。多步驟中間 / 最後步自動隱藏(有 onPrev 時) */\n onSkip?: () => void\n /** Next 按鈕 callback;不傳則不顯示 Next */\n onNext?: () => void\n /** Previous 按鈕 callback(多步 tour 第 2+ 步顯示);不傳則不顯示 */\n onPrev?: () => void\n /**\n * 最後一步 flag。影響 primary CTA 文字:\n * - single step(無 onPrev 且 isLastStep):CTA = `doneLabel ?? '知道了'`\n * - multi-step 最後步(有 onPrev 且 isLastStep):CTA = 'Done'\n * - 其他:CTA = 'Next'\n */\n isLastStep?: boolean\n /** 自訂單步驟完成 CTA 文字(預設 `'知道了'`)。僅 single-step 使用 */\n doneLabel?: string\n /** 浮層定位(對齊 Popover props) */\n side?: 'top' | 'right' | 'bottom' | 'left'\n align?: 'start' | 'center' | 'end'\n sideOffset?: number\n /** 外殼寬度(預設 w-80 = 320px,比一般 Popover 寬,因要放 media + 文字) */\n className?: string\n}\n\n// i18n-allow: DS-internal kind → title 預設對照表;consumer 透過 `title` prop 直接覆寫\nconst KIND_TITLE: Record<'tips' | 'new-features', string> = {\n tips: '使用技巧',\n 'new-features': '新功能介紹',\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst Coachmark = React.forwardRef<HTMLDivElement, CoachmarkProps>(\n (\n {\n open,\n defaultOpen,\n onOpenChange,\n children,\n image,\n mediaRatio = 16 / 9,\n kind,\n title,\n description,\n step,\n onSkip,\n onNext,\n onPrev,\n isLastStep = false,\n doneLabel = '知道了', // i18n-allow: DS default; consumer override via doneLabel prop\n side = 'bottom',\n align = 'center',\n sideOffset = OVERLAY_SIDE_OFFSET,\n className,\n ...props\n },\n ref,\n ) => {\n // 單/多步驟行為推導\n const isSingleStep = isLastStep && !onPrev\n // canonical(spec.md CTA 語義表 L116):有 onPrev → 不顯示 Skip;**單步驟也不顯示 Skip**\n // (單步「skip」與「知道了」語義重複 = 同一個關閉動作,雙關閉鍵造成困惑;對齊 Apple HIG / Intercom / Pendo 單步 tip 僅一個完成鍵)\n const showSkip = Boolean(onSkip) && !onPrev && !isSingleStep\n const nextLabel = isSingleStep ? doneLabel : isLastStep ? 'Done' : 'Next'\n\n const hasFooterContent = Boolean(step || showSkip || onNext || onPrev)\n const stepText = step ? `${step.current} of ${step.total}` : null\n\n // Header title 解析\n const headerTitle =\n kind === 'tips' || kind === 'new-features'\n ? KIND_TITLE[kind as 'tips' | 'new-features']\n : kind\n\n // 2026-05-31 #6 / 2026-07-05 改消費 Popover 自動接線:PopoverContent(role=dialog)accessible name 三層 —\n // 1. headerTitle → <PopoverTitle> 掛載時由 popover.tsx PopoverTitleContext 自動接 aria-labelledby(免手動)\n // 2. 無 header 但有 body 主 title(<h3> 非 PopoverTitle,自動接線接不到)→ 仍手動接 aria-labelledby\n // 3. 皆無 → aria-label fallback\n const bodyTitleId = React.useId()\n const bodyTitleLabelledBy = !headerTitle && title ? bodyTitleId : undefined\n\n return (\n <Popover open={open} defaultOpen={defaultOpen} onOpenChange={onOpenChange}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n ref={ref}\n side={side}\n align={align}\n sideOffset={sideOffset}\n className={cn('w-80 p-0 overflow-hidden', className)}\n // 禁止 Radix 開啟時自動 focus 第一個 focusable(預設會 focus Prev / Skip / Next),\n // Coachmark 的 CTA 不該被 auto-focus 偷觸發(user 可能還在讀 body,按 Enter 就推進)。\n // 2026-07-05 D4:preventDefault 後必 focus content 容器本身(FocusScope 容器自帶 tabIndex=-1)——\n // 焦點若停在 trigger(DismissableLayer 外),non-modal Popover 按 Tab 即觸發 focus-outside\n // dismiss 直接關閉,CTA 鍵盤永遠到不了;focus 容器後 Tab 第一下即達第一個 CTA,Enter 按在\n // 容器上無動作(原「不誤推進」意圖保留;對齊 dialog.tsx handleOpenAutoFocus `?? content` fallback)。\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n ;(e.currentTarget as HTMLElement).focus({ preventScroll: true })\n }}\n aria-labelledby={bodyTitleLabelledBy}\n aria-label={headerTitle || title ? undefined : '提示'}\n {...props}\n >\n {headerTitle && (\n // Header title 走 `<PopoverTitle>` 共用 Popover typography canonical(text-body font-medium)。\n // **不 hideClose** — 對齊 Popover / Dialog / 所有 overlay 家族 canonical:header 必有 dismiss X\n // (user 可隨時關閉,跟 Skip / Done 是不同入口,canonical 重複不冗)\n <PopoverHeader>\n <PopoverTitle>{headerTitle}</PopoverTitle>\n </PopoverHeader>\n )}\n\n {image && (\n <AspectRatio ratio={mediaRatio} className=\"w-full overflow-hidden bg-muted\">\n {image}\n </AspectRatio>\n )}\n\n {(title || description) && (\n // 對齊 Dialog / Popover canonical:body 左對齊(不中置)\n // Why: Coachmark 雖是 onboarding / feature discovery,但文字可讀性 > 視覺焦點;\n // 中文 / 長句中置會「每行起點不同」造成閱讀鋸齒,左對齊最穩。\n // 世界級參考:Notion / Linear / Figma onboarding tour 皆左對齊;Intercom Messenger 亦如是。\n <PopoverBody className=\"flex flex-col\">\n {title && (\n <h3 id={!headerTitle ? bodyTitleId : undefined} className=\"text-body-lg font-medium text-foreground\">{title}</h3>\n )}\n {description && (\n // title(body-lg 16)+ desc(body 14)→ reading-lg token(label tier 決定)\n // 對齊 Dialog / Sheet canonical;移除原 gap-1(4px)drift\n <p className=\"mt-[var(--item-gap-label-desc-reading-lg)] text-body text-fg-secondary\">{description}</p>\n )}\n </PopoverBody>\n )}\n\n {hasFooterContent && (\n // 專屬 Coachmark canonical:footer 無上方分隔線(media + body + footer 視覺一氣呵成,\n // 不像 Dialog 需要 header/footer 分隔強化結構)。override SurfaceFooter default border-t\n <PopoverFooter className=\"justify-between !border-t-0\">\n {stepText ? (\n // step 文字走 text-body 跟 body content 字體一致\n <span className=\"text-body text-fg-secondary tabular-nums\">\n {stepText}\n </span>\n ) : (\n <span aria-hidden /> /* 保持 justify-between space */\n )}\n <div className=\"flex items-center gap-2\">\n {onPrev && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={onPrev}>\n Previous\n </Button>\n )}\n {showSkip && (\n <Button variant=\"tertiary\" size=\"sm\" onClick={onSkip}>\n Skip\n </Button>\n )}\n {onNext && (\n <Button variant=\"primary\" size=\"sm\" onClick={onNext}>\n {nextLabel}\n </Button>\n )}\n </div>\n </PopoverFooter>\n )}\n </PopoverContent>\n </Popover>\n )\n },\n)\nCoachmark.displayName = 'Coachmark'\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 coachmarkMeta = {\n component: 'Coachmark',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: ['default'], // 純 Popover composition — 無自有 hover / active / disabled 視覺(spec「邊界狀態」)\n tokens: {\n bg: ['bg-muted'],\n fg: ['text-fg-secondary', 'text-foreground'],\n ring: [],\n },\n} as const\n\nexport { Coachmark }\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
2
+ import type { FieldMode, FieldVariant, FieldWidth } from '../../components/Field/field-types';
3
3
  import { type SelectMenuOption } from '../../components/SelectMenu/select-menu';
4
4
  /**
5
5
  * Combobox option schema(2026-05-10 post-Issue-4 audit unify):**explicit extends
@@ -26,6 +26,10 @@ export interface ComboboxProps {
26
26
  mode?: FieldMode;
27
27
  /** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */
28
28
  variant?: FieldVariant;
29
+ /** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮:value 寬 + slot 元素寬 + gap +
30
+ * field 內 padding;chrome 與互動不變。場景 = detail pane inline metadata。
31
+ * SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */
32
+ width?: FieldWidth;
29
33
  error?: boolean;
30
34
  size?: 'sm' | 'md' | 'lg';
31
35
  options: ComboboxOption[];
@@ -1 +1 @@
1
- {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/Combobox/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAM3F,OAAO,EAAwD,KAAK,gBAAgB,EAAE,MAAM,mDAAmD,CAAA;AAc/I;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAe,SAAQ,gBAAgB;CAEvD;AAgLD,KAAK,qBAAqB,GAAG,QAAQ,GAAG,KAAK,CAAA;AA8I7C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,uFAAuF;IACvF,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW;IACX,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;kGAE8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;gDAC4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mFAAmF;IACnF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;IAC/F;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7E;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;sEAGkE;IAClE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAkXD,QAAA,MAAM,QAAQ,sFAab,CAAA;AAKD,eAAO,MAAM,YAAY;;;;;;;;;;;CAgBf,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../../src/components/Combobox/combobox.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAwB,UAAU,EAAE,MAAM,8CAA8C,CAAA;AAM7H,OAAO,EAAwD,KAAK,gBAAgB,EAAE,MAAM,mDAAmD,CAAA;AAc/I;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,cAAe,SAAQ,gBAAgB;CAEvD;AAgLD,KAAK,qBAAqB,GAAG,QAAQ,GAAG,KAAK,CAAA;AA+I7C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,uFAAuF;IACvF,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB;;iEAE6D;IAC7D,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IACpC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,WAAW;IACX,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;kGAE8F;IAC9F,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,qCAAqC;IACrC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;gDAC4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,mFAAmF;IACnF,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;IAC/F;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7E;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B;;;sEAGkE;IAClE,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AA+YD,QAAA,MAAM,QAAQ,sFAab,CAAA;AAKD,eAAO,MAAM,YAAY;;;;;;;;;;;CAgBf,CAAA;AAEV,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -2,8 +2,8 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { X, ChevronDown } from "lucide-react";
4
4
  import { cn } from "../../lib/utils.js";
5
- import { nakedCellRowModeAlign, fieldWrapperStyles, EMPTY_DISPLAY, fieldDisplayTextClass } from "../Field/field-wrapper.js";
6
- import { useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldVariant, useResolvedFieldMode, useFieldContext, useResolvedFieldInvalid } from "../Field/field-context.js";
5
+ import { nakedCellRowModeAlign, fieldWrapperStyles, fieldDisplayTextClass } from "../Field/field-wrapper.js";
6
+ import { useResolvedFieldSize, useFieldContext, useResolvedFieldDisabled, useResolvedFieldVariant, useResolvedFieldMode, useResolvedFieldInvalid, useFieldEmptyDisplay, fieldEmptyColorClass } from "../Field/field-context.js";
7
7
  import { Tag } from "../Tag/tag.js";
8
8
  import { ItemSuffix, ItemInlineAction, ICON_SIZE } from "../../patterns/element-anatomy/item-anatomy.js";
9
9
  import { OverflowIndicator } from "../OverflowIndicator/overflow-indicator.js";
@@ -153,8 +153,9 @@ function ComboboxTagStack({
153
153
  containerRef: externalRef,
154
154
  disabled = false
155
155
  }) {
156
+ const emptyDisplay = useFieldEmptyDisplay();
156
157
  const ownRef = React.useRef(null);
157
- if (!value || value.length === 0) return /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY });
158
+ if (!value || value.length === 0) return /* @__PURE__ */ jsx("span", { className: fieldEmptyColorClass(disabled ? "disabled" : "display"), children: emptyDisplay });
158
159
  const items = value.map((v) => {
159
160
  var _a;
160
161
  return { value: v, label: ((_a = options == null ? void 0 : options.find((o) => o.value === v)) == null ? void 0 : _a.label) ?? v };
@@ -177,6 +178,7 @@ const getIconSize = (size) => ICON_SIZE[size];
177
178
  function ReadonlyMultiSelect({
178
179
  mode,
179
180
  variant: variantProp,
181
+ width,
180
182
  size,
181
183
  options,
182
184
  value,
@@ -185,6 +187,7 @@ function ReadonlyMultiSelect({
185
187
  showDisplayEndIcon = false
186
188
  }) {
187
189
  const resolvedMode = mode ?? "readonly";
190
+ const emptyDisplay = useFieldEmptyDisplay();
188
191
  const variant = variantProp ?? "default";
189
192
  const sz = size ?? "md";
190
193
  const iconSize = sz === "lg" ? 20 : 16;
@@ -193,16 +196,16 @@ function ReadonlyMultiSelect({
193
196
  const hasTags = ((value == null ? void 0 : value.length) ?? 0) > 0;
194
197
  if (resolvedMode === "display") {
195
198
  if (!showDisplayEndIcon) {
196
- if (!hasTags) return /* @__PURE__ */ jsx("span", { className: cn(fieldDisplayTextClass(sz), "text-fg-muted", className), children: EMPTY_DISPLAY });
199
+ if (!hasTags) return /* @__PURE__ */ jsx("span", { className: cn(fieldDisplayTextClass(sz), fieldEmptyColorClass(resolvedMode), className), children: emptyDisplay });
197
200
  return /* @__PURE__ */ jsx(ComboboxTagStack, { value, options, tagSize: sz, wrap });
198
201
  }
199
202
  return /* @__PURE__ */ jsxs(
200
203
  "div",
201
204
  {
202
- className: cn(fieldWrapperStyles({ mode: "display", variant, size: sz }), hasTags && tagPadding[sz], className),
205
+ className: cn(fieldWrapperStyles({ mode: "display", variant, width, size: sz }), hasTags && tagPadding[sz], className),
203
206
  "data-field-mode": "display",
204
207
  children: [
205
- hasTags ? /* @__PURE__ */ jsx(ComboboxTagStack, { value, options, tagSize: sz, wrap }) : /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0", "text-fg-muted"), children: EMPTY_DISPLAY }),
208
+ hasTags ? /* @__PURE__ */ jsx(ComboboxTagStack, { value, options, tagSize: sz, wrap }) : /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0", fieldEmptyColorClass(resolvedMode)), children: emptyDisplay }),
206
209
  /* @__PURE__ */ jsx(ItemSuffix, { className: "pointer-events-none", children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: "shrink-0 text-fg-muted", "aria-hidden": true }) })
207
210
  ]
208
211
  }
@@ -213,7 +216,7 @@ function ReadonlyMultiSelect({
213
216
  {
214
217
  ref: containerRef,
215
218
  className: cn(
216
- fieldWrapperStyles({ mode: resolvedMode, variant, size: sz }),
219
+ fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }),
217
220
  hasTags && tagPadding[sz],
218
221
  // 2026-05-18 #6A Round 1 Step 1/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:451):
219
222
  // readonly/disabled path 對齊 L293 display wrapper 已 ship 的 overflow-hidden fix。
@@ -237,7 +240,7 @@ function ReadonlyMultiSelect({
237
240
  containerRef,
238
241
  disabled: resolvedMode === "disabled"
239
242
  }
240
- ) : /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY }),
243
+ ) : /* @__PURE__ */ jsx("span", { className: fieldEmptyColorClass(resolvedMode), children: emptyDisplay }),
241
244
  (variant === "naked" ? !!showDisplayEndIcon : resolvedMode === "disabled") && /* @__PURE__ */ jsx(ItemSuffix, { className: cn("pointer-events-none", wrap && "self-start"), style: wrap ? { height: tagHeight } : void 0, children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: cn("shrink-0", resolvedMode === "disabled" ? "text-fg-disabled" : "text-fg-muted"), "aria-hidden": true }) })
242
245
  ]
243
246
  }
@@ -246,6 +249,7 @@ function ReadonlyMultiSelect({
246
249
  function NativeCombobox({
247
250
  mode,
248
251
  variant: variantProp,
252
+ width,
249
253
  error = false,
250
254
  size = "md",
251
255
  options,
@@ -257,8 +261,10 @@ function NativeCombobox({
257
261
  wrap = false,
258
262
  clearable = false,
259
263
  showDisplayEndIcon = false,
260
- __triggerRef
264
+ __triggerRef,
265
+ "aria-label": ariaLabel
261
266
  }) {
267
+ const fieldCtx = useFieldContext();
262
268
  const disabled = useResolvedFieldDisabled(disabledProp);
263
269
  const variant = useResolvedFieldVariant(variantProp);
264
270
  const resolvedMode = useResolvedFieldMode({ mode, disabled });
@@ -271,7 +277,7 @@ function NativeCombobox({
271
277
  const selectRef = React.useRef(null);
272
278
  const tagAreaRef = React.useRef(null);
273
279
  if (resolvedMode !== "edit") {
274
- return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, size, options, value, wrap, className, showDisplayEndIcon });
280
+ return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, width, size, options, value, wrap, className, showDisplayEndIcon });
275
281
  }
276
282
  const items = value.map((v) => {
277
283
  var _a;
@@ -285,6 +291,13 @@ function NativeCombobox({
285
291
  ref: selectRef,
286
292
  value: "",
287
293
  onChange: (e) => handleAdd(e.target.value),
294
+ id: fieldCtx == null ? void 0 : fieldCtx.id,
295
+ "aria-label": ariaLabel,
296
+ "aria-labelledby": ariaLabel ? void 0 : fieldCtx == null ? void 0 : fieldCtx.labelId,
297
+ "aria-invalid": error || void 0,
298
+ "aria-required": (fieldCtx == null ? void 0 : fieldCtx.required) || void 0,
299
+ "aria-describedby": fieldCtx == null ? void 0 : fieldCtx.descriptionId,
300
+ "aria-errormessage": error ? fieldCtx == null ? void 0 : fieldCtx.errorId : void 0,
288
301
  className: cn(
289
302
  "bg-transparent outline-none border-none p-0 text-[inherit] font-[inherit] leading-[inherit] text-fg-muted cursor-pointer appearance-none",
290
303
  value.length > 0 ? "absolute inset-0 w-full h-full opacity-0 z-0 cursor-pointer" : "relative z-10 flex-1 min-w-20"
@@ -300,7 +313,7 @@ function NativeCombobox({
300
313
  {
301
314
  ref: __triggerRef,
302
315
  className: cn(
303
- fieldWrapperStyles({ mode: "edit", variant, size, error }),
316
+ fieldWrapperStyles({ mode: "edit", variant, width, size, error }),
304
317
  value.length > 0 && tagPadding[size],
305
318
  "relative",
306
319
  wrap && "items-start py-1",
@@ -382,6 +395,7 @@ function NativeCombobox({
382
395
  function CustomCombobox({
383
396
  mode,
384
397
  variant: variantProp,
398
+ width,
385
399
  error: errorProp = false,
386
400
  size = "md",
387
401
  options,
@@ -459,7 +473,7 @@ function CustomCombobox({
459
473
  [filteredOptions]
460
474
  );
461
475
  if (resolvedMode !== "edit") {
462
- return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, size, options, value, wrap, className, showDisplayEndIcon });
476
+ return /* @__PURE__ */ jsx(ReadonlyMultiSelect, { mode: resolvedMode, variant, width, size, options, value, wrap, className, showDisplayEndIcon });
463
477
  }
464
478
  const chevronEl = /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: cn("shrink-0 text-fg-muted transition-transform", open && "rotate-180"), "aria-hidden": true });
465
479
  const trigger = /* @__PURE__ */ jsxs(
@@ -473,12 +487,13 @@ function CustomCombobox({
473
487
  "aria-controls": listboxId,
474
488
  tabIndex: 0,
475
489
  "aria-label": ariaLabel,
490
+ "aria-labelledby": ariaLabel ? void 0 : fieldCtx == null ? void 0 : fieldCtx.labelId,
476
491
  "aria-invalid": error || void 0,
477
492
  "aria-required": (fieldCtx == null ? void 0 : fieldCtx.required) || void 0,
478
493
  "aria-describedby": fieldCtx == null ? void 0 : fieldCtx.descriptionId,
479
494
  "aria-errormessage": error ? fieldCtx == null ? void 0 : fieldCtx.errorId : void 0,
480
495
  className: cn(
481
- fieldWrapperStyles({ mode: "edit", variant, size, error }),
496
+ fieldWrapperStyles({ mode: "edit", variant, width, size, error }),
482
497
  value.length > 0 && tagPadding[size],
483
498
  "relative cursor-pointer",
484
499
  wrap && "items-start py-1",
@@ -490,6 +505,8 @@ function CustomCombobox({
490
505
  "data-field-mode": "edit",
491
506
  "data-error": error ? "" : void 0,
492
507
  onKeyDown: (e) => {
508
+ var _a, _b;
509
+ if ((e.key === "Enter" || e.key === " ") && e.target !== e.currentTarget && ((_b = (_a = e.target).closest) == null ? void 0 : _b.call(_a, 'button, a, [role="button"]'))) return;
493
510
  if (open && forwardKeyToListbox(listboxId, e)) return;
494
511
  if (e.key === "Enter" || e.key === " ") {
495
512
  if (!open) {