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

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 (477) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  50. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  51. package/dist/components/DataTable/data-table-filter-panel.js +3 -4
  52. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  53. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  54. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  55. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  56. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  57. package/dist/components/DataTable/data-table.d.ts +1 -1
  58. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  59. package/dist/components/DataTable/data-table.js +44 -32
  60. package/dist/components/DataTable/data-table.js.map +1 -1
  61. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  62. package/dist/components/DatePicker/date-picker.js +4 -4
  63. package/dist/components/DatePicker/date-picker.js.map +1 -1
  64. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  65. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  66. package/dist/components/DescriptionList/description-list.js +6 -6
  67. package/dist/components/DescriptionList/description-list.js.map +1 -1
  68. package/dist/components/Dialog/dialog.d.ts +2 -2
  69. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  70. package/dist/components/Dialog/dialog.js.map +1 -1
  71. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  72. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  73. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  74. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  75. package/dist/components/Field/field-context.d.ts +16 -10
  76. package/dist/components/Field/field-context.d.ts.map +1 -1
  77. package/dist/components/Field/field-context.js.map +1 -1
  78. package/dist/components/Field/field-types.d.ts +2 -2
  79. package/dist/components/Field/field-types.d.ts.map +1 -1
  80. package/dist/components/Field/field-types.js.map +1 -1
  81. package/dist/components/Field/field-wrapper.d.ts +20 -4
  82. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  83. package/dist/components/Field/field-wrapper.js +30 -31
  84. package/dist/components/Field/field-wrapper.js.map +1 -1
  85. package/dist/components/Field/field.d.ts +1 -1
  86. package/dist/components/Field/field.d.ts.map +1 -1
  87. package/dist/components/Field/field.js +25 -3
  88. package/dist/components/Field/field.js.map +1 -1
  89. package/dist/components/Field/use-form-validation.d.ts +1 -1
  90. package/dist/components/Field/use-form-validation.js.map +1 -1
  91. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  92. package/dist/components/FileItem/file-item.js +2 -5
  93. package/dist/components/FileItem/file-item.js.map +1 -1
  94. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  95. package/dist/components/FileUpload/file-upload.js +5 -1
  96. package/dist/components/FileUpload/file-upload.js.map +1 -1
  97. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  98. package/dist/components/FileViewer/file-viewer.js +2 -1
  99. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  100. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  101. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  102. package/dist/components/HoverCard/hover-card.js +4 -2
  103. package/dist/components/HoverCard/hover-card.js.map +1 -1
  104. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  105. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  106. package/dist/components/InlineEdit/inline-edit.js +104 -62
  107. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  108. package/dist/components/Input/input.d.ts +1 -1
  109. package/dist/components/Input/input.d.ts.map +1 -1
  110. package/dist/components/Input/input.js +6 -6
  111. package/dist/components/Input/input.js.map +1 -1
  112. package/dist/components/LinkInput/link-input.d.ts +5 -5
  113. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  114. package/dist/components/LinkInput/link-input.js +3 -3
  115. package/dist/components/LinkInput/link-input.js.map +1 -1
  116. package/dist/components/Notice/notice.d.ts +17 -1
  117. package/dist/components/Notice/notice.d.ts.map +1 -1
  118. package/dist/components/Notice/notice.js +7 -1
  119. package/dist/components/Notice/notice.js.map +1 -1
  120. package/dist/components/NumberInput/number-input.d.ts +1 -1
  121. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  122. package/dist/components/NumberInput/number-input.js +12 -1
  123. package/dist/components/NumberInput/number-input.js.map +1 -1
  124. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  125. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  126. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  127. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  128. package/dist/components/PeoplePicker/people-picker.js +7 -5
  129. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  130. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  131. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  132. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  133. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  134. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  135. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  136. package/dist/components/RadioGroup/radio-group.js +1 -1
  137. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  138. package/dist/components/Rating/rating.d.ts.map +1 -1
  139. package/dist/components/Rating/rating.js +4 -0
  140. package/dist/components/Rating/rating.js.map +1 -1
  141. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  142. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  143. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  144. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  145. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  146. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  147. package/dist/components/Select/select.d.ts +16 -6
  148. package/dist/components/Select/select.d.ts.map +1 -1
  149. package/dist/components/Select/select.js +17 -5
  150. package/dist/components/Select/select.js.map +1 -1
  151. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  152. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  153. package/dist/components/SelectMenu/select-menu.js +17 -3
  154. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  155. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  156. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  157. package/dist/components/Sheet/sheet.d.ts +2 -2
  158. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  159. package/dist/components/Sheet/sheet.js.map +1 -1
  160. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  161. package/dist/components/Sidebar/sidebar.js +2 -2
  162. package/dist/components/Sidebar/sidebar.js.map +1 -1
  163. package/dist/components/Slider/slider.d.ts.map +1 -1
  164. package/dist/components/Slider/slider.js +6 -3
  165. package/dist/components/Slider/slider.js.map +1 -1
  166. package/dist/components/Steps/steps.d.ts +6 -4
  167. package/dist/components/Steps/steps.d.ts.map +1 -1
  168. package/dist/components/Steps/steps.js +19 -5
  169. package/dist/components/Steps/steps.js.map +1 -1
  170. package/dist/components/Switch/switch.d.ts +4 -4
  171. package/dist/components/Switch/switch.d.ts.map +1 -1
  172. package/dist/components/Switch/switch.js +3 -1
  173. package/dist/components/Switch/switch.js.map +1 -1
  174. package/dist/components/Tabs/tabs.d.ts +1 -1
  175. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  176. package/dist/components/Tabs/tabs.js +73 -23
  177. package/dist/components/Tabs/tabs.js.map +1 -1
  178. package/dist/components/Tag/tag.d.ts +3 -1
  179. package/dist/components/Tag/tag.d.ts.map +1 -1
  180. package/dist/components/Tag/tag.js +2 -2
  181. package/dist/components/Tag/tag.js.map +1 -1
  182. package/dist/components/Textarea/textarea.d.ts +4 -4
  183. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  184. package/dist/components/Textarea/textarea.js +15 -15
  185. package/dist/components/Textarea/textarea.js.map +1 -1
  186. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  187. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  188. package/dist/components/TimePicker/time-picker.js +8 -5
  189. package/dist/components/TimePicker/time-picker.js.map +1 -1
  190. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  191. package/dist/components/Tooltip/tooltip.js +27 -23
  192. package/dist/components/Tooltip/tooltip.js.map +1 -1
  193. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  194. package/dist/components/TreeView/tree-view.js +16 -0
  195. package/dist/components/TreeView/tree-view.js.map +1 -1
  196. package/dist/index.d.ts +7 -7
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +6 -13
  199. package/dist/index.js.map +1 -1
  200. package/dist/lib/drag-visual.d.ts +2 -2
  201. package/dist/lib/drag-visual.js.map +1 -1
  202. package/dist/lib/utils.d.ts +1 -0
  203. package/dist/lib/utils.d.ts.map +1 -1
  204. package/dist/lib/utils.js +21 -1
  205. package/dist/lib/utils.js.map +1 -1
  206. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  207. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  208. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  209. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  210. package/dist/tokens/categorical-color.d.ts +3 -3
  211. package/dist/tokens/categorical-color.d.ts.map +1 -1
  212. package/dist/tokens/categorical-color.js +2 -2
  213. package/dist/tokens/categorical-color.js.map +1 -1
  214. package/ds-canonical/fork/AGENTS.md +213 -0
  215. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  216. package/ds-canonical/fork/codex/hooks.json +16 -0
  217. package/ds-canonical/fork/governance.lock +22 -7
  218. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  219. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  220. package/ds-canonical/fork/manifest.json +10 -1
  221. package/ds-canonical/fork/preamble.md +3 -2
  222. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  223. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  224. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  225. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  226. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  227. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
  228. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  229. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  230. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  232. package/ds-canonical/references/certified-surfaces.md +20 -0
  233. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  234. package/ds-canonical/references/principle-dim-map.json +20 -2
  235. package/ds-canonical/references/props-naming.md +2 -1
  236. package/ds-canonical/references/ssot-index.md +2 -2
  237. package/ds-canonical/references/story-baseline-registry.json +2 -2
  238. package/ds-canonical/rules/story-rules.md +1 -1
  239. package/ds-canonical/rules/ui-development.md +2 -1
  240. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  241. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  242. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  243. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  244. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  245. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  246. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  247. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  248. package/ds-story-manifest.json +21 -21
  249. package/llms-full.txt +3 -3
  250. package/llms.txt +1 -1
  251. package/package.json +2 -1
  252. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  253. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  254. package/src/components/Accordion/accordion.spec.md +10 -1
  255. package/src/components/Accordion/accordion.stories.tsx +10 -5
  256. package/src/components/Accordion/accordion.tsx +7 -2
  257. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  258. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  259. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  260. package/src/components/AppShell/app-shell.spec.md +4 -0
  261. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  262. package/src/components/Avatar/avatar.tsx +1 -1
  263. package/src/components/Badge/badge.spec.md +2 -2
  264. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  265. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  266. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  267. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  268. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  269. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  270. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  271. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  272. package/src/components/Button/button-group.tsx +4 -4
  273. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  274. package/src/components/Button/button.principles.stories.tsx +1 -1
  275. package/src/components/Button/button.spec.md +2 -2
  276. package/src/components/Button/button.stories.tsx +22 -28
  277. package/src/components/Button/button.tsx +2 -1
  278. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  279. package/src/components/Calendar/calendar.spec.md +1 -1
  280. package/src/components/Carousel/carousel.spec.md +17 -1
  281. package/src/components/Carousel/carousel.tsx +93 -42
  282. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  283. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  284. package/src/components/Checkbox/checkbox.spec.md +12 -3
  285. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  286. package/src/components/Checkbox/checkbox.tsx +79 -19
  287. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  288. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  289. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  290. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  291. package/src/components/Combobox/combobox.spec.md +6 -2
  292. package/src/components/Combobox/combobox.stories.tsx +9 -36
  293. package/src/components/Combobox/combobox.tsx +42 -27
  294. package/src/components/Command/command.spec.md +3 -3
  295. package/src/components/Command/command.tsx +9 -2
  296. package/src/components/DataTable/cell-registry.tsx +75 -76
  297. package/src/components/DataTable/column-types.ts +4 -17
  298. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  299. package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
  300. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  301. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  302. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  303. package/src/components/DataTable/data-table.css +2 -3
  304. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  305. package/src/components/DataTable/data-table.spec.md +7 -7
  306. package/src/components/DataTable/data-table.stories.tsx +39 -29
  307. package/src/components/DataTable/data-table.tsx +90 -67
  308. package/src/components/DataTable/filter-operators.spec.md +2 -0
  309. package/src/components/DateGrid/date-grid.spec.md +1 -1
  310. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  311. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  312. package/src/components/DatePicker/date-picker.spec.md +9 -9
  313. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  314. package/src/components/DatePicker/date-picker.tsx +13 -13
  315. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  316. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  317. package/src/components/DescriptionList/description-list.spec.md +12 -12
  318. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  319. package/src/components/DescriptionList/description-list.tsx +10 -10
  320. package/src/components/Dialog/dialog.tsx +4 -1
  321. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  322. package/src/components/Field/field-context.ts +17 -11
  323. package/src/components/Field/field-controls.spec.md +44 -37
  324. package/src/components/Field/field-types.ts +14 -12
  325. package/src/components/Field/field-wrapper.tsx +59 -43
  326. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  327. package/src/components/Field/field.principles.stories.tsx +5 -28
  328. package/src/components/Field/field.spec.md +4 -4
  329. package/src/components/Field/field.stories.tsx +103 -72
  330. package/src/components/Field/field.tsx +36 -4
  331. package/src/components/Field/form-validation.spec.md +2 -0
  332. package/src/components/Field/use-form-validation.ts +1 -1
  333. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  334. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  335. package/src/components/FileItem/file-item.tsx +10 -8
  336. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  337. package/src/components/FileUpload/file-upload.spec.md +3 -2
  338. package/src/components/FileUpload/file-upload.tsx +5 -1
  339. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  340. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  342. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  343. package/src/components/FileViewer/file-viewer.tsx +3 -2
  344. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  345. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  346. package/src/components/HoverCard/hover-card.spec.md +2 -2
  347. package/src/components/HoverCard/hover-card.tsx +4 -2
  348. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  349. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  350. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  351. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  352. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  353. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  354. package/src/components/Input/input.principles.stories.tsx +3 -3
  355. package/src/components/Input/input.spec.md +4 -4
  356. package/src/components/Input/input.stories.tsx +3 -3
  357. package/src/components/Input/input.tsx +13 -13
  358. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  359. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  360. package/src/components/LinkInput/link-input.spec.md +6 -2
  361. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  362. package/src/components/LinkInput/link-input.tsx +21 -19
  363. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  364. package/src/components/Notice/notice.tsx +8 -2
  365. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  366. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  367. package/src/components/NumberInput/number-input.spec.md +6 -6
  368. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  369. package/src/components/NumberInput/number-input.tsx +17 -5
  370. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  371. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  372. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  373. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  374. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  375. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  376. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  377. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  378. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  379. package/src/components/PeoplePicker/person-display.tsx +3 -3
  380. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  381. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  382. package/src/components/Popover/popover.spec.md +4 -2
  383. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  384. package/src/components/ProfileCard/profile-card.tsx +1 -1
  385. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  386. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  387. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  388. package/src/components/README.md +1 -0
  389. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  390. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  391. package/src/components/RadioGroup/radio-group.tsx +19 -14
  392. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  393. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  394. package/src/components/Rating/rating.spec.md +2 -2
  395. package/src/components/Rating/rating.stories.tsx +4 -18
  396. package/src/components/Rating/rating.tsx +5 -1
  397. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  398. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  399. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  400. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  401. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  402. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  403. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  404. package/src/components/Select/select.principles.stories.tsx +3 -3
  405. package/src/components/Select/select.spec.md +9 -1
  406. package/src/components/Select/select.stories.tsx +41 -27
  407. package/src/components/Select/select.tsx +44 -26
  408. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  410. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  411. package/src/components/SelectMenu/select-menu.tsx +38 -5
  412. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  413. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  414. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  415. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  416. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  417. package/src/components/Sheet/sheet.tsx +4 -1
  418. package/src/components/Sidebar/sidebar.tsx +1 -1
  419. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  420. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  421. package/src/components/Slider/slider.spec.md +13 -1
  422. package/src/components/Slider/slider.stories.tsx +44 -32
  423. package/src/components/Slider/slider.tsx +13 -4
  424. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  425. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  426. package/src/components/Steps/steps.spec.md +4 -2
  427. package/src/components/Steps/steps.stories.tsx +4 -56
  428. package/src/components/Steps/steps.tsx +31 -7
  429. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  430. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  431. package/src/components/Switch/switch.spec.md +4 -4
  432. package/src/components/Switch/switch.stories.tsx +3 -3
  433. package/src/components/Switch/switch.tsx +16 -10
  434. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  435. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  436. package/src/components/Tabs/tabs.spec.md +5 -2
  437. package/src/components/Tabs/tabs.stories.tsx +36 -44
  438. package/src/components/Tabs/tabs.tsx +101 -36
  439. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  440. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  441. package/src/components/Tag/tag.spec.md +3 -1
  442. package/src/components/Tag/tag.tsx +5 -3
  443. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  444. package/src/components/Textarea/textarea.spec.md +5 -5
  445. package/src/components/Textarea/textarea.tsx +24 -24
  446. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  447. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  448. package/src/components/TimePicker/time-picker.spec.md +6 -5
  449. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  450. package/src/components/TimePicker/time-picker.tsx +24 -14
  451. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  452. package/src/components/Toast/toast.stories.tsx +1 -1
  453. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  454. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  455. package/src/components/Tooltip/tooltip.spec.md +9 -3
  456. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  457. package/src/components/Tooltip/tooltip.tsx +12 -2
  458. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  459. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  460. package/src/components/TreeView/tree-view.spec.md +8 -6
  461. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  462. package/src/components/TreeView/tree-view.tsx +36 -0
  463. package/src/index.ts +13 -10
  464. package/src/lib/drag-visual.ts +2 -2
  465. package/src/lib/utils.ts +19 -0
  466. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  467. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  468. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  469. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  470. package/src/tokens/categorical-color.ts +5 -5
  471. package/src/tokens/color/color.spec.md +4 -4
  472. package/src/tokens/color/primitives.css +9 -2
  473. package/src/tokens/opacity/opacity.spec.md +1 -1
  474. package/src/tokens/orphan-tokens.spec.md +1 -1
  475. package/src/tokens/typography/typography.spec.md +2 -0
  476. package/src/tokens/uiSize/uiSize.css +5 -0
  477. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"people-picker.js","sources":["../../../src/components/PeoplePicker/people-picker.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// @placeholder-vocabulary-allow: 2026-07-04 Q4 完成 field-controls.spec.md 共享 contract b — emptyPlaceholder forward 已移除,emptyText 直達 Combobox → SelectMenu emptyText(search-empty 真住所);placeholder 為 trigger empty SSOT。\n// @cell-metric-escape-allow: comment describes RETIRED `tagAreaPaddingLeftPx={8}` magic — current code is surface-guarded (`surface === 'form'` only injects `!px-[var(--field-px)]`; table-cell context untouched, lets naked `!px-[var(--table-cell-px)]` SSOT take over). Hook regex grep'd the comment word, not the live code path. Per (a) fix 2026-05-13 user-approved Path a.\nimport * as React from 'react'\nimport { ChevronDown } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, nakedCellRowModeAlign } from '@/design-system/components/Field/field-wrapper'\nimport { useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'\nimport { ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { useFieldSurface, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant } from '@/design-system/components/Field/field-context'\nimport { Avatar } from '@/design-system/components/Avatar/avatar'\nimport { Tag } from '@/design-system/components/Tag/tag'\nimport { Select as SelectPublic } from '@/design-system/components/Select/select'\nimport { Combobox as ComboboxPublic } from '@/design-system/components/Combobox/combobox'\nimport { PersonDisplay, MultiPersonDisplay, PersonAvatarTag, buildPersonProfileCard, resolvePerson, type PersonValue } from './person-display'\nimport {\n getAvatarStackVisibleCount,\n AVATAR_STACK_AVATAR_PX,\n AVATAR_STACK_OVERFLOW_CHIP_PX,\n} from './avatar-stack-overflow'\nimport type { WithFieldVariantInternal } from '@/design-system/components/Field/field-types'\n\n// ── @internal naked variant forward 通道(2026-07-14 API 策展 E)──────────────────────────\n// naked 已從公開 FieldVariant 拆出(field-types.ts FieldVariantInternal)。PeoplePicker 是\n// Select / Combobox 的 wrapper:cell-registry 傳入的 naked 需原樣 forward 給 primitive\n// (M30 wrapper forward 全 primitive surface)。型別層 widen,純型別、零 runtime。\nconst Select = SelectPublic as WithFieldVariantInternal<typeof SelectPublic>\nconst Combobox = ComboboxPublic as WithFieldVariantInternal<typeof ComboboxPublic>\n// Pure helpers extracted to sibling for file-size budget(2026-05-18,P1 ≤ 500 lines)。\n// 不消費 component closure 的純 constant / 純 mapping function 全部搬走,主檔保留 SSOT-bearing\n// render logic(消費 Combobox / Select / state 等 closure 的部分)。\n// SSOT primitive re-export(backward-compat 對外 import 路徑保持 `./people-picker`)。\nimport {\n PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS,\n getPeoplePickerTagWrapperClass,\n personToSelectOption,\n findPerson,\n} from './people-picker-helpers'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\nexport { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass }\n\n// ── PeoplePicker ────────────────────────────────────────────────────────────\n// **2026-05-07 v15.6 SSOT 重構 v2**:\n//\n// - **single mode** wraps `<Select searchable selectedItemRenderer>`\n// - **multi mode** 兩種 displayMode(consumer 自選),**皆 wrap `<Combobox>`**(同 SSOT,\n// 差別在 tagRenderer 視覺):\n// - **'stack'**(default,baseline 既有視覺)— Avatar 疊合 + `+N` overflow indicator,\n// 不可 wrap。tagRenderer 渲染 avatar stack(visible count 走 shared `avatar-stack-overflow`\n// primitive deterministic formula,2026-05-15 Bug 3 fix;display 路徑 `<MultiPersonDisplay>` 同 primitive)。\n// 對齊 Notion / Linear / Atlassian / Slack 多人 quick-glance idiom。\n// - **'pill'**(opt-in)— 每人 Tag pill,可 wrap。Wrap `<Combobox tagRenderer>`,\n// tagRenderer 用 Tag 元件 `avatar` prop SSOT(不塞 children)。\n// `pillShowAvatar` 控 pill 內是否顯 avatar prefix(default true,false → 純文字 pill)。\n// 對齊 GitHub Reviewers / Combobox tag-input idiom。\n\n// **codex P2 fix(2026-05-07 v15.10)**:`extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>`\n// 讓 consumer 可傳 `id` / `data-testid` / `onBlur` / `onFocus` / `aria-*` 等 HTML root props,\n// component 內部 `...rest` forward 到 trigger 容器(對齊 DS 既有 Combobox / Select 慣例)。\n// `onChange` 衝突走 Omit(本 component 用 PersonValue[] custom signature)。\nexport interface PeoplePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Field mode(edit / display / readonly / disabled),默認 inherit Field context 或 'edit' */\n mode?: FieldMode\n /** Field chrome variant(對齊 Select / Combobox)*/\n variant?: FieldVariant\n /** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮(value 寬 + slot 寬 + gap + 內 padding);\n * chrome 與互動不變。SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */\n width?: FieldWidth\n size?: 'sm' | 'md' | 'lg'\n /** 當前已選的人(單選 PersonValue,多選 PersonValue[])*/\n value?: PersonValue | PersonValue[] | null\n /** 值變更 callback(永遠 emit array — single mode 取 [0] 即 single value)*/\n onChange?: (value: PersonValue[]) => void\n /** 可選人員清單(edit mode 下拉顯示)*/\n people?: PersonValue[]\n /** 2026-05-12 Stream C Issue 4 fix(codex Q3 Cluster C):trigger empty placeholder。\n * Default '請選擇人員'。**禁** 將 `emptyText`(search-empty)當 trigger placeholder 傳。 */\n placeholder?: string\n /** 搜尋框 placeholder — **僅 multi 模式 panel-top search(`searchIn='menu'`,default)生效**。\n * single mode wrap `<Select searchable>` 走 inline-trigger 搜尋,提示取自 `placeholder`\n * (Select 無 searchPlaceholder prop);multi `searchIn='trigger'` inline 搜尋同理走\n * placeholder 規則(spec「Trigger display SSOT canonical table」)。 */\n searchPlaceholder?: string\n /** 搜尋無結果訊息(filtered menu empty)。**僅**用於 SelectMenu `emptyText`(菜單空狀態,\n * 2026-07-04 Q4 接線完成),不轉 trigger placeholder(2026-05-12 Issue 4 semantic fix)。 */\n emptyText?: string\n className?: string\n disabled?: boolean\n /** Initial open state(uncontrolled)*/\n defaultOpen?: boolean\n /** open state 變更 callback */\n onOpenChange?: (open: boolean) => void\n /**\n * Multi mode 顯示樣式(default 'stack')。Single mode 此 prop 忽略。\n * - 'stack' — Avatar 疊合 + `+N`(空間省、不可 wrap;default)\n * - 'pill' — 每人 Tag pill(可 wrap)\n */\n multiDisplay?: 'stack' | 'pill'\n /**\n * `multiDisplay='pill'` 模式下是否顯示 avatar prefix(default true)。\n * 設 false → 純文字 pill,進一步節省空間。對齊 Tag 元件 `avatar` prop SSOT。\n */\n pillShowAvatar?: boolean\n /** Pill 模式下是否允許 wrap(default true)— 對齊 Combobox `wrap` prop */\n pillWrap?: boolean\n /**\n * 搜尋型態(2026-05-12 規則 3 ship,3-mode SSOT 對齊 A1-A5 spec):\n * - `'menu'`(default,backward-compat)— 浮層內搜尋(panel-top search)\n * - `'trigger'`(multi 模式 opt-in)— inline 搜尋(浮層開時 name 拿掉,avatar 後接 input cursor,\n * 類 Combobox inline-trigger idiom)\n * Single mode 永遠 inline-trigger(wrap Select searchable 直接走 inline),此 prop multi 才有意義。\n */\n searchIn?: 'menu' | 'trigger'\n /**\n * Display 是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)\n * — DataTable cell display↔edit 像素級對齊用。預設 false(裸 PersonDisplay,backward compat)。\n * 設 true 時 display 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,\n * 與 edit (Select / Combobox wrapped) 同 DOM 結構,消除 Layer-B padding mismatch。\n */\n showDisplayEndIcon?: boolean\n /** a11y label */\n 'aria-label'?: string\n}\n\nconst PeoplePicker = React.forwardRef<HTMLDivElement, PeoplePickerProps>(function PeoplePicker({\n mode: modeProp,\n variant: variantProp,\n width,\n size: sizeProp,\n value,\n onChange,\n people = [],\n placeholder = '請選擇人員', // i18n-allow: DS default(2026-05-12 Stream C Issue 4)\n searchPlaceholder = '搜尋人員…', // i18n-allow: DS default\n emptyText = '沒有符合的人員', // i18n-allow: DS default — only for SelectMenu noResultsText\n className,\n disabled: disabledProp,\n defaultOpen = false,\n onOpenChange,\n multiDisplay = 'stack',\n pillShowAvatar = true,\n pillWrap = true,\n searchIn = 'menu',\n showDisplayEndIcon = false,\n 'aria-label': ariaLabel,\n ...rest\n}, ref) {\n const surface = useFieldSurface()\n const emptyDisplay = useFieldEmptyDisplay()\n const size = useResolvedFieldSize(sizeProp) // B 組 cascade fix\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-06-08 SSOT:mode/disabled/variant 統一經 helper;修 <Field disabled> 漏 cascade(原只讀 fieldCtx.mode)\n const resolvedMode: FieldMode = useResolvedFieldMode({ mode: modeProp, disabled })\n const resolvedVariant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const isMulti = Array.isArray(value)\n const isEmpty = !value || (isMulti && value.length === 0)\n\n // 2026-07-05 D3 P0 修:以下派生 + 4 hooks 原宣告在 display/readonly/single/pill 四個 early return\n // 之後 — 同一 mounted instance 的 resolvedMode 於 edit↔display/disabled 切換(<Field mode>/<Field\n // disabled> cascade 正是 runtime 翻轉機制)時 hook 數 7→11 變動 → React #310 crash(與 Combobox\n // beta.76 / LinkInput 2026-07-04 同家族)。全部 hoist 到任何 early return 之前(對齊 select.tsx\n // 「所有 hooks 必在 early return 前 call」canonical);effect 加 mode/stack guard,邏輯不變。\n const selectedNames: string[] = !value\n ? []\n : Array.isArray(value)\n ? value.map(v => resolvePerson(v).name)\n : [resolvePerson(value).name]\n\n // SSOT visible count compute via formula primitive + ResizeObserver(multi stack mode 專用)\n const stackContainerRef = React.useRef<HTMLDivElement | null>(null)\n const [stackVisibleCount, setStackVisibleCount] = React.useState<number | undefined>(undefined)\n React.useLayoutEffect(() => {\n if (resolvedMode !== 'edit' || !isMulti || multiDisplay !== 'stack' || selectedNames.length <= 1) {\n setStackVisibleCount(undefined); return\n }\n const root = stackContainerRef.current\n if (!root) return\n // 2026-05-15 ROOT CAUSE FIX(user 抓「之前說的問題都還是存在」):\n // stackContainerRef 透過 mergedStackRef 接 Combobox forwarded ref → root **就是** [role=combobox]\n // div 自己。原 `root.querySelector('[role=combobox]')` 不找 self 永遠 null → trigger=null →\n // tagArea=null → available=0 → setStackVisibleCount(0) → 整 stack 全 overflow → fallback 到\n // Combobox DOM-based useOverflowCount(非 deterministic 那個算法)。修:用 root 自己當 trigger,\n // 從 root 內找 tagArea(flex-1 min-w-0 div)。\n const calc = () => {\n const trigger = root.matches('[role=\"combobox\"]') ? root : root.querySelector<HTMLElement>('[role=\"combobox\"]')\n const tagArea = trigger?.querySelector<HTMLElement>('div[class*=\"flex-1\"][class*=\"min-w-0\"]')\n const available = tagArea?.clientWidth ?? trigger?.clientWidth ?? 0\n const visible = getAvatarStackVisibleCount({\n availablePx: available,\n total: selectedNames.length,\n avatarPx: AVATAR_STACK_AVATAR_PX[size],\n overflowChipPx: AVATAR_STACK_OVERFLOW_CHIP_PX[size],\n })\n setStackVisibleCount(visible)\n }\n calc()\n const ro = new ResizeObserver(calc)\n ro.observe(root)\n return () => ro.disconnect()\n }, [resolvedMode, isMulti, multiDisplay, selectedNames.length, size])\n // Merge ref:forward to parent + capture for ResizeObserver\n const mergedStackRef = React.useCallback((el: HTMLDivElement | null) => {\n stackContainerRef.current = el\n if (typeof ref === 'function') ref(el)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = el\n }, [ref])\n\n // ── mode='display' ────────────────────────────────────────────────────────\n // Default(showDisplayEndIcon=false):裸 PersonDisplay / MultiPersonDisplay — backward compat。\n // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,\n // 與 edit (Select / Combobox wrapped) 同 DOM 結構消除 cell display↔edit 像素偏移。\n if (resolvedMode === 'display') {\n if (!showDisplayEndIcon) {\n if (isEmpty) return <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n return isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured />\n : <PersonDisplay value={value as PersonValue} size={size} />\n }\n // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)\n const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'display', variant: resolvedVariant, width, size }), className)}\n data-field-mode=\"display\"\n >\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign)}>\n {isEmpty\n ? <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n : isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured />\n : <PersonDisplay value={value as PersonValue} size={size} />}\n </span>\n <ItemSuffix className=\"pointer-events-none\">\n <ChevronDown size={iconSize} className=\"shrink-0 text-fg-muted\" aria-hidden />\n </ItemSuffix>\n </div>\n )\n }\n\n // ── readonly / disabled — Field wrapper chrome,Avatar 視覺保留 ───────────\n if (resolvedMode !== 'edit') {\n return (\n <div\n ref={ref}\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: resolvedVariant, width, size }), className)}\n data-field-mode={resolvedMode}\n aria-disabled={resolvedMode === 'disabled' ? true : undefined}\n aria-label={ariaLabel}\n {...rest}\n >\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign, resolvedMode === 'disabled' && 'text-fg-disabled')}>\n {/* 2026-07-14 deep-audit 修:disabled 傳入 → 抑制 Avatar ProfileCard hoverCard + avatar dim\n (spec「disabled:灰化整個 field,不可互動」原被 hoverCard falsify);readonly 保留 hoverCard(純展示仍可查閱) */}\n {isEmpty\n ? <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n : isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured disabled={resolvedMode === 'disabled'} />\n : <PersonDisplay value={value as PersonValue} size={size} disabled={resolvedMode === 'disabled'} />}\n </span>\n {/* 2026-06-26 類型身份 indicator:edit 顯示 / readonly 不顯示 / disabled 保留(fg-disabled,對齊原生 <select disabled>);naked cell 依 showDisplayEndIcon */}\n {(resolvedVariant === 'naked' ? showDisplayEndIcon : resolvedMode === 'disabled') && (\n <ItemSuffix className=\"pointer-events-none\">\n <ChevronDown size={ICON_SIZE[size as 'sm' | 'md' | 'lg']} className={cn('shrink-0', resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted')} aria-hidden />\n </ItemSuffix>\n )}\n </div>\n )\n }\n\n // ── edit mode ─────────────────────────────────────────────────────────────\n // (selectedNames 派生已 hoist 至檔上方 hooks 區,見 D3 P0 修註解)\n\n // ── single mode → wraps Select ────────────────────────────────────────────\n if (!isMulti) {\n const handleSingleChange = (name: string) => onChange?.([findPerson(people, name)])\n return (\n <Select\n ref={ref as React.Ref<HTMLDivElement>}\n // 2026-07-14 deep-audit fix:width 補 forward(原漏傳 → single edit path 忽略公開 width prop;\n // multi pill / stack 皆有傳,對齊 M30 wrapper forward 全 primitive surface)\n width={width}\n size={size}\n variant={resolvedVariant}\n options={people.map(personToSelectOption)}\n value={selectedNames[0] ?? null}\n onChange={handleSingleChange}\n searchable\n placeholder={placeholder}\n // 2026-05-12 Issue 4:placeholder = trigger empty。2026-07-04 Q4:emptyText 走 Select →\n // SelectMenu 接線(search-empty 語意,與 trigger-empty 分離)。\n emptyText={emptyText}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n className={className}\n aria-label={ariaLabel}\n selectedItemRenderer={(opt) => <PersonDisplay value={findPerson(people, opt.value)} size={size} />}\n // **codex P2 forward**:Select 原生屬性走 allowlist(`Pick<SelectHTMLAttributes>`,\n // 2026-07-14 API 策展 D,見 select.tsx SelectProps docblock),event handler element\n // 型別跟 PeoplePicker `HTMLAttributes<HTMLDivElement>` 不一致(`onCopy` / `onChange` 等)。\n // Runtime spread 等效 — DOM 收到 attrs 不挑剔(非 allowlist attrs 落 CustomSelect rest,\n // 續 spread 到 trigger div,runtime 行為不變)。\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // any-allow: rest 含 `onChange: FormEventHandler` 跟 Select onChange signature 衝突 — DOM runtime spread 安全(per codex P2 forward)\n {...(rest as any)}\n />\n )\n }\n\n // ── multi 'pill' → wraps Combobox(對齊 GitHub Reviewers / Combobox idiom)────\n if (multiDisplay === 'pill') {\n const handleMultiChange = (next: string[]) => {\n onChange?.(next.map(name => findPerson(people, name)))\n }\n return (\n <Combobox\n width={width}\n ref={ref as React.Ref<HTMLDivElement>}\n size={size}\n variant={resolvedVariant}\n options={people.map(personToSelectOption)}\n value={selectedNames}\n onChange={handleMultiChange}\n searchable\n // 2026-07-14 deep-audit fix:searchIn 補 forward(原漏傳 → pill 模式永遠 Combobox default 'menu',\n // documented multi opt-in `searchIn='trigger'` silently 無效;stack branch 已傳,對齊 M30 forward 全 surface)\n searchIn={searchIn}\n searchPlaceholder={searchPlaceholder}\n // 2026-05-12 Stream C Issue 4(codex Q3):placeholder = trigger empty hint('請選擇人員')\n // — semantic clean separation。2026-07-04 Q4 拍板完成 1-cycle 承諾:emptyPlaceholder forward\n // 移除,emptyText 改傳 Combobox → SelectMenu emptyText(search-empty 真住所,菜單空狀態)。\n placeholder={placeholder}\n emptyText={emptyText}\n wrap={pillWrap}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n className={className}\n aria-label={ariaLabel}\n // codex P2 forward(see Select branch comment for type-cast rationale)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // any-allow: rest 含 `onChange: FormEventHandler` 跟 Combobox onChange signature 衝突 — DOM runtime spread 安全(per codex P2 forward)\n {...(rest as any)}\n // **Tag SSOT canonical**:用 `avatar` prop(不塞 children),Tag 內部統一\n // wrap 進 16×16 圓形 mask container(per Tag tsx line 175)。\n tagRenderer={(item, onRemove) => {\n const p = resolvePerson(findPerson(people, item.value))\n return (\n <Tag\n key={item.value}\n size={size}\n color=\"neutral\"\n // 2026-05-18 7B' fix(per user 拍板「執行」+ Codex Round 3 共識,paired with Combobox L286):\n // 拿掉 `unbounded` 對齊 Tag canonical max-w-40 cap + 內建 ellipsis。PeoplePicker pill 走\n // Combobox tagRenderer slot,SSOT = Tag primitive 視覺(per codex Round 3 verdict)。\n // 人名 99% < 25 chars 不觸發 cap;極端長名(複數姓 + middle name)觸發 ellipsis 是合理 UX。\n avatar={pillShowAvatar\n ? <Avatar src={p.avatarUrl} alt={p.name} size={16} hoverCard={buildPersonProfileCard(p)} />\n : undefined}\n onRemove={onRemove}\n >\n {p.name}\n </Tag>\n )\n }}\n />\n )\n }\n\n // ── multi 'stack' (default) → wraps Combobox 跟 pill mode 同 SSOT,差別在 tagRenderer 視覺。\n //\n // **2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus)**:visible count 走 shared\n // `avatar-stack-overflow` primitive deterministic formula(取代 Combobox DOM offsetWidth-based\n // useOverflowCount + 60px fallback 不 deterministic),pass override 給 Combobox bypass internal\n // measurement。`MultiPersonDisplay`(display path)同 primitive,display + edit 結果一致。\n // 對齊 user verbatim SSOT「同 cell width 同 overflow 判斷」+ codex Q3 consensus shared primitive。\n const handleMultiChange = (next: string[]) => {\n onChange?.(next.map(name => findPerson(people, name)))\n }\n // ── edit mode ─────────────────────────────────────────────────────────────\n // (selectedNames 派生已 hoist 至檔上方 hooks 區,見 D3 P0 修註解)\n\n return (\n <Combobox\n width={width}\n ref={mergedStackRef}\n size={size}\n variant={resolvedVariant}\n options={people.map(personToSelectOption)}\n value={selectedNames}\n onChange={handleMultiChange}\n searchable\n searchIn={searchIn}\n searchPlaceholder={searchPlaceholder}\n // 2026-05-12 Stream C Issue 4(codex Q3):placeholder = trigger empty('請選擇人員');emptyText = search-empty(僅 backward-compat forward 1 cycle)\n placeholder={placeholder}\n emptyText={emptyText}\n wrap={false}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n // 2026-05-13 (a) fix(user 拍 Path a + Layer A density-drift root-cause):\n // 撤掉 `tagAreaPaddingLeftPx={8}` magic — Combobox `tagPadding[size]` 是 density-dependent\n // calc 公式(`(field-height - icon-size) / 2`),只在 md size + default density 才 = 4px;\n // 其他 size/density 漂 6px / 8px → 4+8=12 spec 公式不成立。\n // (a) fix:form context + 有 tag → 改 inject `!px-[var(--field-px)]`(固定 12px)直接 override `tagPadding[size]`,\n // 達成 GitHub PeoplePicker fixed 12px inset(對齊 cell context 同 13px from cell.left 含 1px border)。\n // - form + 有 tag → `!px-[var(--field-px)]`(12px 固定 inset)+ tagAreaPaddingLeftPx undefined → field.padL=12 ✓\n // - table-cell + 有 tag → naked variant `!px-[var(--table-cell-px)]` 已是 12px,不 inject ✓\n // - isEmpty → 不 inject,走 Combobox 預設文字 inset(`tagPadding[size]` 公式自然 vertical center)\n className={cn(className, !isEmpty && surface === 'form' && '!px-[var(--field-px)]')}\n aria-label={ariaLabel}\n // 2026-05-15 Bug 1 fix(Claude+Codex Step 5 比稿 consensus,user verbatim「就 A」):per-length 動態\n // wrapper class — length=1 降階單人視覺需要 width constraint chain(`flex-1 min-w-0 overflow-hidden`),\n // length>=2 stack 視覺保留 overlap(`-ml-0.5 first:ml-0 relative inline-flex group/avatar`)。對齊\n // spec.md §C row 1(length=1 = avatar+人名+ellipsis)+ §D row 1(length>=2 = stack overlap)。\n // 真根因:Combobox `OverflowTagList` 把所有 tagRenderer 結果包 `shrink-0`,加 `inline-flex` 後\n // wrapper 變 intrinsic content-width → PersonDisplay `w-full` resolves to intrinsic → truncate 無效。\n // 修法:length=1 wrapper 改 `flex-1 min-w-0 overflow-hidden` 提供 width constraint 給 PersonDisplay。\n // SSOT helper `getPeoplePickerTagWrapperClass(count)` 集中,future 改 wrapper 行為改一處。\n tagWrapperClassName={getPeoplePickerTagWrapperClass(selectedNames.length)}\n // 2026-05-16 真 root cause fix:overflow chip wrapper 套同 `-ml-0.5` 讓 chip 物理上\n // 跟 avatar 同 slot(等寬同 step,non-overlapping 多 24px 區塊不再 saw)。對齊 user\n // 「avatars 和 +N 都是同尺寸圓形,空間最多容固定數量圓形」物理模型 directive +\n // MUI AvatarGroup / Primer AvatarStack 共識(`AvatarGroup.js` L54-59 same negative margin)。\n overflowWrapperClassName=\"-ml-0.5 first:ml-0 relative inline-flex\"\n tagAreaGapPx={0}\n tagAreaPaddingLeftPx={undefined}\n // 2026-05-12 Round 7 fix(user 抓 image 2「+N tag 應該圓形不是矩形」+ 對齊 GitHub picker idiom):\n // Combobox default `overflowShape='tag'`(矩形 chip,文字 Combobox 慣例);PeoplePicker stack\n // mode pass `'circle'`(圓形 avatar-shape,跟 avatar 一樣大)。對齊 MultiPersonDisplay readonly path\n // 既有 OverflowIndicator default 'circle' SSOT。\n overflowShape=\"circle\"\n // 2026-05-15 Bug 3 fix:formula-based visible count override(避免 Combobox DOM measurement +\n // 60px fallback 不 deterministic)。SSOT in `./avatar-stack-overflow.ts`,display + edit 共用。\n visibleCountOverride={stackVisibleCount}\n // 2026-05-14 I4 fix(per codex+Layer A 共識):hidden items 在 `+N` overflow popover 顯\n // Tag with avatar(對齊 display MultiPersonDisplay popover SSOT,user 抓 display vs edit\n // overflow 視覺不一致)。\n renderHiddenTag={(item) => {\n const p = resolvePerson(findPerson(people, item.value))\n return (\n <Tag\n key={item.value}\n color=\"neutral\"\n size=\"sm\"\n avatar={\n <Avatar\n src={p.avatarUrl}\n alt={p.name}\n size={16}\n hoverCard={buildPersonProfileCard(p)}\n />\n }\n onRemove={() => {\n onChange?.(selectedNames.filter(n => n !== item.value).map(n => findPerson(people, n)))\n }}\n >\n {p.name}\n </Tag>\n )\n }}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // any-allow: rest 含 `onChange: FormEventHandler` 跟 Combobox onChange signature 衝突 — DOM runtime spread 安全(per codex P2 forward)\n {...(rest as any)}\n tagRenderer={(item, onRemove) => {\n const p = resolvePerson(findPerson(people, item.value))\n // 2026-05-12 Q2 fix(user 拍板「multi 只選 1 人時 trigger = avatar + name,跟 single mode 同」):\n // selectedNames.length === 1 → PersonDisplay(avatar + name)代替 PersonAvatarTag(avatar only)。\n // SSOT 對齊 PeoplePicker single mode line 201 selectedItemRenderer。多選 1 人時視覺等同單選,\n // 只在 length > 1 才走 stack(各 avatar 純 chip)。多選 + inline 搜尋場景拿掉 name 改 cursor\n // 走 `searchIn='trigger'` opt-in(2026-05-12 規則 3 ship,已轉傳 Combobox;default 'menu' 走 panel-top search)。\n if (selectedNames.length === 1) {\n return <PersonDisplay key={item.value} value={p} size={size} />\n }\n return (\n <PersonAvatarTag\n key={item.value}\n person={p}\n size={size}\n onRemove={onRemove}\n />\n )\n }}\n />\n )\n})\nPeoplePicker.displayName = 'PeoplePicker'\n\n// Story auto-compile metadata\nexport const peoplePickerMeta = {\n component: 'PeoplePicker',\n family: 4,\n variants: {},\n sizes: {},\n // 'active' 移除 — trigger 走 Field chrome、menu 走 MenuItem,皆無自有按壓視覺(2026-07-07 詞彙統一 DS-wide 按壓訊號盤點:檔內 0 active: utility / 0 *-active token)。\n states: ['default', 'hover', 'focus-visible', 'disabled'],\n tokens: {\n bg: [],\n fg: ['text-fg-disabled', 'text-fg-muted'],\n ring: [],\n },\n} as const\n\nexport { PeoplePicker }\n// 2026-07-10 C14 export 缺口修(R2 同類:定義存在但無 export 面,consumer 想守 PersonValue 鏈\n// import 不到 → 被逼手刻)。person-display 表面隨 PeoplePicker subpath + root barrel 一併公開。\nexport {\n PersonDisplay,\n MultiPersonDisplay,\n PersonAvatarTag,\n buildPersonProfileCard,\n resolvePerson,\n type PersonValue,\n type PersonData,\n} from './person-display'\n"],"names":["SelectPublic","ComboboxPublic","PeoplePicker","handleMultiChange"],"mappings":"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"}
1
+ {"version":3,"file":"people-picker.js","sources":["../../../src/components/PeoplePicker/people-picker.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// @placeholder-vocabulary-allow: 2026-07-04 Q4 完成 field-controls.spec.md 共享 contract b — emptyPlaceholder forward 已移除,emptyText 直達 Combobox → SelectMenu emptyText(search-empty 真住所);placeholder 為 trigger empty SSOT。\n// @cell-metric-escape-allow: comment describes RETIRED `tagAreaPaddingLeftPx={8}` magic — current code is surface-guarded (`surface === 'form'` only injects `!px-[var(--field-px)]`; table-cell context untouched, lets naked `!px-[var(--table-cell-px)]` SSOT take over). Hook regex grep'd the comment word, not the live code path. Per (a) fix 2026-05-13 user-approved Path a.\nimport * as React from 'react'\nimport { ChevronDown } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, nakedCellRowModeAlign } from '@/design-system/components/Field/field-wrapper'\nimport { useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'\nimport { ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { useFieldSurface, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant } from '@/design-system/components/Field/field-context'\nimport { Avatar } from '@/design-system/components/Avatar/avatar'\nimport { Tag } from '@/design-system/components/Tag/tag'\nimport { Select as SelectPublic } from '@/design-system/components/Select/select'\nimport { Combobox as ComboboxPublic } from '@/design-system/components/Combobox/combobox'\nimport { PersonDisplay, MultiPersonDisplay, PersonAvatarTag, buildPersonProfileCard, resolvePerson, type PersonValue } from './person-display'\nimport {\n getAvatarStackVisibleCount,\n AVATAR_STACK_AVATAR_PX,\n AVATAR_STACK_OVERFLOW_CHIP_PX,\n} from './avatar-stack-overflow'\nimport type { WithFieldVariantInternal } from '@/design-system/components/Field/field-types'\n\n// ── @internal naked variant forward 通道(2026-07-14 API 策展 E)──────────────────────────\n// naked 已從公開 FieldVariant 拆出(field-types.ts FieldVariantInternal)。PeoplePicker 是\n// Select / Combobox 的 wrapper:cell-registry 傳入的 naked 需原樣 forward 給 primitive\n// (M30 wrapper forward 全 primitive surface)。型別層 widen,純型別、零 runtime。\nconst Select = SelectPublic as WithFieldVariantInternal<typeof SelectPublic>\nconst Combobox = ComboboxPublic as WithFieldVariantInternal<typeof ComboboxPublic>\n// Pure helpers extracted to sibling for file-size budget(2026-05-18,P1 ≤ 500 lines)。\n// 不消費 component closure 的純 constant / 純 mapping function 全部搬走,主檔保留 SSOT-bearing\n// render logic(消費 Combobox / Select / state 等 closure 的部分)。\n// SSOT primitive re-export(backward-compat 對外 import 路徑保持 `./people-picker`)。\nimport {\n PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS,\n getPeoplePickerTagWrapperClass,\n personToSelectOption,\n findPerson,\n} from './people-picker-helpers'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\nexport { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass }\n\n// ── PeoplePicker ────────────────────────────────────────────────────────────\n// **2026-05-07 v15.6 SSOT 重構 v2**:\n//\n// - **single mode** wraps `<Select searchable selectedItemRenderer>`\n// - **multi mode** 兩種 displayMode(consumer 自選),**皆 wrap `<Combobox>`**(同 SSOT,\n// 差別在 tagRenderer 視覺):\n// - **'stack'**(default,baseline 既有視覺)— Avatar 疊合 + `+N` overflow indicator,\n// 不可 wrap。tagRenderer 渲染 avatar stack(visible count 走 shared `avatar-stack-overflow`\n// primitive deterministic formula,2026-05-15 Bug 3 fix;view 路徑 `<MultiPersonDisplay>` 同 primitive)。\n// 對齊 Notion / Linear / Atlassian / Slack 多人 quick-glance idiom。\n// - **'pill'**(opt-in)— 每人 Tag pill,可 wrap。Wrap `<Combobox tagRenderer>`,\n// tagRenderer 用 Tag 元件 `avatar` prop SSOT(不塞 children)。\n// `pillShowAvatar` 控 pill 內是否顯 avatar prefix(default true,false → 純文字 pill)。\n// 對齊 GitHub Reviewers / Combobox tag-input idiom。\n\n// **codex P2 fix(2026-05-07 v15.10)**:`extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>`\n// 讓 consumer 可傳 `id` / `data-testid` / `onBlur` / `onFocus` / `aria-*` 等 HTML root props,\n// component 內部 `...rest` forward 到 trigger 容器(對齊 DS 既有 Combobox / Select 慣例)。\n// `onChange` 衝突走 Omit(本 component 用 PersonValue[] custom signature)。\n// 2026-07-17 Dim 26 修:`defaultValue` 一併 Omit — 本元件 controlled-only(spec「Controlled-only\n// rationale」),React.HTMLAttributes 內建的 `defaultValue` 若不 Omit 會讓 consumer 傳入假\n// uncontrolled API,runtime 經 `...rest` 靜默轉送 trigger div 後無效。Omit 本身即 type-level\n// regression(consumer 傳 defaultValue 直接 TS 編譯錯)。DS 先例 steps.tsx:166 同款 Omit。\nexport interface PeoplePickerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange' | 'defaultValue'> {\n /** Field mode(edit / view / readonly / disabled),默認 inherit Field context 或 'edit' */\n mode?: FieldMode\n /** Field chrome variant(對齊 Select / Combobox)*/\n variant?: FieldVariant\n /** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮(value 寬 + slot 寬 + gap + 內 padding);\n * chrome 與互動不變。SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */\n width?: FieldWidth\n size?: 'sm' | 'md' | 'lg'\n /** 當前已選的人(單選 PersonValue,多選 PersonValue[])*/\n value?: PersonValue | PersonValue[] | null\n /** 值變更 callback(永遠 emit array — single mode 取 [0] 即 single value)*/\n onChange?: (value: PersonValue[]) => void\n /** 可選人員清單(edit mode 下拉顯示)*/\n people?: PersonValue[]\n /** 2026-05-12 Stream C Issue 4 fix(codex Q3 Cluster C):trigger empty placeholder。\n * Default '請選擇人員'。**禁** 將 `emptyText`(search-empty)當 trigger placeholder 傳。 */\n placeholder?: string\n /** 搜尋框 placeholder — **僅 multi 模式 panel-top search(`searchIn='menu'`,default)生效**。\n * single mode wrap `<Select searchable>` 走 inline-trigger 搜尋,提示取自 `placeholder`\n * (Select 無 searchPlaceholder prop);multi `searchIn='trigger'` inline 搜尋同理走\n * placeholder 規則(spec「Trigger display SSOT canonical table」)。 */\n searchPlaceholder?: string\n /** 搜尋無結果訊息(filtered menu empty)。**僅**用於 SelectMenu `emptyText`(菜單空狀態,\n * 2026-07-04 Q4 接線完成),不轉 trigger placeholder(2026-05-12 Issue 4 semantic fix)。 */\n emptyText?: string\n className?: string\n disabled?: boolean\n /** Initial open state(uncontrolled)*/\n defaultOpen?: boolean\n /** open state 變更 callback */\n onOpenChange?: (open: boolean) => void\n /**\n * Multi mode 顯示樣式(default 'stack')。Single mode 此 prop 忽略。\n * - 'stack' — Avatar 疊合 + `+N`(空間省、不可 wrap;default)\n * - 'pill' — 每人 Tag pill(可 wrap)\n */\n multiDisplay?: 'stack' | 'pill'\n /**\n * `multiDisplay='pill'` 模式下是否顯示 avatar prefix(default true)。\n * 設 false → 純文字 pill,進一步節省空間。對齊 Tag 元件 `avatar` prop SSOT。\n */\n pillShowAvatar?: boolean\n /** Pill 模式下是否允許 wrap(default true)— 對齊 Combobox `wrap` prop */\n pillWrap?: boolean\n /**\n * 搜尋型態(2026-05-12 規則 3 ship,3-mode SSOT 對齊 A1-A5 spec):\n * - `'menu'`(default,backward-compat)— 浮層內搜尋(panel-top search)\n * - `'trigger'`(multi 模式 opt-in)— inline 搜尋(浮層開時 name 拿掉,avatar 後接 input cursor,\n * 類 Combobox inline-trigger idiom)\n * Single mode 永遠 inline-trigger(wrap Select searchable 直接走 inline),此 prop multi 才有意義。\n */\n searchIn?: 'menu' | 'trigger'\n /**\n * View 態是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)\n * — DataTable cell view↔edit 像素級對齊用。預設 false(裸 PersonDisplay,backward compat)。\n * 設 true 時 view 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,\n * 與 edit (Select / Combobox wrapped) 同 DOM 結構,消除 Layer-B padding mismatch。\n */\n showDisplayEndIcon?: boolean\n /** a11y label */\n 'aria-label'?: string\n}\n\nconst PeoplePicker = React.forwardRef<HTMLDivElement, PeoplePickerProps>(function PeoplePicker({\n mode: modeProp,\n variant: variantProp,\n width,\n size: sizeProp,\n value,\n onChange,\n people = [],\n placeholder = '請選擇人員', // i18n-allow: DS default(2026-05-12 Stream C Issue 4)\n searchPlaceholder = '搜尋人員…', // i18n-allow: DS default\n emptyText = '沒有符合的人員', // i18n-allow: DS default — only for SelectMenu noResultsText\n className,\n disabled: disabledProp,\n defaultOpen = false,\n onOpenChange,\n multiDisplay = 'stack',\n pillShowAvatar = true,\n pillWrap = true,\n searchIn = 'menu',\n showDisplayEndIcon = false,\n 'aria-label': ariaLabel,\n ...rest\n}, ref) {\n const surface = useFieldSurface()\n const emptyDisplay = useFieldEmptyDisplay()\n const size = useResolvedFieldSize(sizeProp) // B 組 cascade fix\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-06-08 SSOT:mode/disabled/variant 統一經 helper;修 <Field disabled> 漏 cascade(原只讀 fieldCtx.mode)\n const resolvedMode: FieldMode = useResolvedFieldMode({ mode: modeProp, disabled })\n const resolvedVariant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const isMulti = Array.isArray(value)\n const isEmpty = !value || (isMulti && value.length === 0)\n\n // 2026-07-05 D3 P0 修:以下派生 + 4 hooks 原宣告在 view/readonly/single/pill 四個 early return\n // 之後 — 同一 mounted instance 的 resolvedMode 於 edit↔view/disabled 切換(<Field mode>/<Field\n // disabled> cascade 正是 runtime 翻轉機制)時 hook 數 7→11 變動 → React #310 crash(與 Combobox\n // beta.76 / LinkInput 2026-07-04 同家族)。全部 hoist 到任何 early return 之前(對齊 select.tsx\n // 「所有 hooks 必在 early return 前 call」canonical);effect 加 mode/stack guard,邏輯不變。\n const selectedNames: string[] = !value\n ? []\n : Array.isArray(value)\n ? value.map(v => resolvePerson(v).name)\n : [resolvePerson(value).name]\n\n // SSOT visible count compute via formula primitive + ResizeObserver(multi stack mode 專用)\n const stackContainerRef = React.useRef<HTMLDivElement | null>(null)\n const [stackVisibleCount, setStackVisibleCount] = React.useState<number | undefined>(undefined)\n React.useLayoutEffect(() => {\n if (resolvedMode !== 'edit' || !isMulti || multiDisplay !== 'stack' || selectedNames.length <= 1) {\n setStackVisibleCount(undefined); return\n }\n const root = stackContainerRef.current\n if (!root) return\n // 2026-05-15 ROOT CAUSE FIX(user 抓「之前說的問題都還是存在」):\n // stackContainerRef 透過 mergedStackRef 接 Combobox forwarded ref → root **就是** [role=combobox]\n // div 自己。原 `root.querySelector('[role=combobox]')` 不找 self 永遠 null → trigger=null →\n // tagArea=null → available=0 → setStackVisibleCount(0) → 整 stack 全 overflow → fallback 到\n // Combobox DOM-based useOverflowCount(非 deterministic 那個算法)。修:用 root 自己當 trigger,\n // 從 root 內找 tagArea(flex-1 min-w-0 div)。\n const calc = () => {\n const trigger = root.matches('[role=\"combobox\"]') ? root : root.querySelector<HTMLElement>('[role=\"combobox\"]')\n const tagArea = trigger?.querySelector<HTMLElement>('div[class*=\"flex-1\"][class*=\"min-w-0\"]')\n const available = tagArea?.clientWidth ?? trigger?.clientWidth ?? 0\n const visible = getAvatarStackVisibleCount({\n availablePx: available,\n total: selectedNames.length,\n avatarPx: AVATAR_STACK_AVATAR_PX[size],\n overflowChipPx: AVATAR_STACK_OVERFLOW_CHIP_PX[size],\n })\n setStackVisibleCount(visible)\n }\n calc()\n const ro = new ResizeObserver(calc)\n ro.observe(root)\n return () => ro.disconnect()\n }, [resolvedMode, isMulti, multiDisplay, selectedNames.length, size])\n // Merge ref:forward to parent + capture for ResizeObserver\n const mergedStackRef = React.useCallback((el: HTMLDivElement | null) => {\n stackContainerRef.current = el\n if (typeof ref === 'function') ref(el)\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = el\n }, [ref])\n\n // ── mode='view' ────────────────────────────────────────────────────────\n // Default(showDisplayEndIcon=false):裸 PersonDisplay / MultiPersonDisplay — backward compat。\n // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,\n // 與 edit (Select / Combobox wrapped) 同 DOM 結構消除 cell view↔edit 像素偏移。\n if (resolvedMode === 'view') {\n if (!showDisplayEndIcon) {\n // 2026-07-17 Dim 9 修:裸顯示分支原直接 return PersonDisplay/MultiPersonDisplay/span,\n // 遺失 ref / className / DOM-safe rest props(違 spec「forwardRef + 單一 root」root props 契約,\n // 與 readonly/disabled 分支不對稱)。補穩定 forwarding root:`w-full min-w-0` 保留\n // PersonDisplay 既有 w-full truncate 寬度約束鏈(單人 fill + 多人 stack 左靠不變),\n // 對齊 switch.tsx:209 view 分支轉發先例。\n return (\n <div ref={ref} className={cn('w-full min-w-0', className)} aria-label={ariaLabel} {...rest}>\n {isEmpty\n ? <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n : isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured />\n : <PersonDisplay value={value as PersonValue} size={size} />}\n </div>\n )\n }\n // 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反 7+ 重複 ternary)\n const iconSize = ICON_SIZE[size as 'sm' | 'md' | 'lg']\n return (\n <div\n // 2026-07-17 Dim 9 修:D-path view root 補 ref / aria-label / {...rest} 轉發(原只套 className,\n // 遺失 root props;對齊 readonly/disabled 分支與 spec root props 契約)。\n ref={ref}\n className={cn(fieldWrapperStyles({ mode: 'view', variant: resolvedVariant, width, size }), className)}\n data-field-mode=\"view\"\n aria-label={ariaLabel}\n {...rest}\n >\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign)}>\n {isEmpty\n ? <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n : isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured />\n : <PersonDisplay value={value as PersonValue} size={size} />}\n </span>\n <ItemSuffix className=\"pointer-events-none\">\n <ChevronDown size={iconSize} className=\"shrink-0 text-fg-muted\" aria-hidden />\n </ItemSuffix>\n </div>\n )\n }\n\n // ── readonly / disabled — Field wrapper chrome,Avatar 視覺保留 ───────────\n if (resolvedMode !== 'edit') {\n return (\n <div\n ref={ref}\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant: resolvedVariant, width, size }), className)}\n data-field-mode={resolvedMode}\n aria-disabled={resolvedMode === 'disabled' ? true : undefined}\n aria-label={ariaLabel}\n {...rest}\n >\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign, resolvedMode === 'disabled' && 'text-fg-disabled')}>\n {/* 2026-07-14 deep-audit 修:disabled 傳入 → 抑制 Avatar ProfileCard hoverCard + avatar dim\n (spec「disabled:灰化整個 field,不可互動」原被 hoverCard falsify);readonly 保留 hoverCard(純展示仍可查閱) */}\n {isEmpty\n ? <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n : isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured disabled={resolvedMode === 'disabled'} />\n : <PersonDisplay value={value as PersonValue} size={size} disabled={resolvedMode === 'disabled'} />}\n </span>\n {/* 2026-06-26 類型身份 indicator:edit 顯示 / readonly 不顯示 / disabled 保留(fg-disabled,對齊原生 <select disabled>);naked cell 依 showDisplayEndIcon */}\n {(resolvedVariant === 'naked' ? showDisplayEndIcon : resolvedMode === 'disabled') && (\n <ItemSuffix className=\"pointer-events-none\">\n <ChevronDown size={ICON_SIZE[size as 'sm' | 'md' | 'lg']} className={cn('shrink-0', resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted')} aria-hidden />\n </ItemSuffix>\n )}\n </div>\n )\n }\n\n // ── edit mode ─────────────────────────────────────────────────────────────\n // (selectedNames 派生已 hoist 至檔上方 hooks 區,見 D3 P0 修註解)\n\n // ── single mode → wraps Select ────────────────────────────────────────────\n if (!isMulti) {\n const handleSingleChange = (name: string) => onChange?.([findPerson(people, name)])\n return (\n <Select\n ref={ref as React.Ref<HTMLDivElement>}\n // 2026-07-14 deep-audit fix:width 補 forward(原漏傳 → single edit path 忽略公開 width prop;\n // multi pill / stack 皆有傳,對齊 M30 wrapper forward 全 primitive surface)\n width={width}\n size={size}\n variant={resolvedVariant}\n options={people.map(personToSelectOption)}\n value={selectedNames[0] ?? null}\n onChange={handleSingleChange}\n searchable\n placeholder={placeholder}\n // 2026-05-12 Issue 4:placeholder = trigger empty。2026-07-04 Q4:emptyText 走 Select →\n // SelectMenu 接線(search-empty 語意,與 trigger-empty 分離)。\n emptyText={emptyText}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n className={className}\n aria-label={ariaLabel}\n selectedItemRenderer={(opt) => <PersonDisplay value={findPerson(people, opt.value)} size={size} />}\n // **codex P2 forward**:Select 原生屬性走 allowlist(`Pick<SelectHTMLAttributes>`,\n // 2026-07-14 API 策展 D,見 select.tsx SelectProps docblock),event handler element\n // 型別跟 PeoplePicker `HTMLAttributes<HTMLDivElement>` 不一致(`onCopy` / `onChange` 等)。\n // Runtime spread 等效 — DOM 收到 attrs 不挑剔(非 allowlist attrs 落 CustomSelect rest,\n // 續 spread 到 trigger div,runtime 行為不變)。\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // any-allow: rest 含 `onChange: FormEventHandler` 跟 Select onChange signature 衝突 — DOM runtime spread 安全(per codex P2 forward)\n {...(rest as any)}\n />\n )\n }\n\n // ── multi 'pill' → wraps Combobox(對齊 GitHub Reviewers / Combobox idiom)────\n if (multiDisplay === 'pill') {\n const handleMultiChange = (next: string[]) => {\n onChange?.(next.map(name => findPerson(people, name)))\n }\n return (\n <Combobox\n width={width}\n ref={ref as React.Ref<HTMLDivElement>}\n size={size}\n variant={resolvedVariant}\n options={people.map(personToSelectOption)}\n value={selectedNames}\n onChange={handleMultiChange}\n searchable\n // 2026-07-14 deep-audit fix:searchIn 補 forward(原漏傳 → pill 模式永遠 Combobox default 'menu',\n // documented multi opt-in `searchIn='trigger'` silently 無效;stack branch 已傳,對齊 M30 forward 全 surface)\n searchIn={searchIn}\n searchPlaceholder={searchPlaceholder}\n // 2026-05-12 Stream C Issue 4(codex Q3):placeholder = trigger empty hint('請選擇人員')\n // — semantic clean separation。2026-07-04 Q4 拍板完成 1-cycle 承諾:emptyPlaceholder forward\n // 移除,emptyText 改傳 Combobox → SelectMenu emptyText(search-empty 真住所,菜單空狀態)。\n placeholder={placeholder}\n emptyText={emptyText}\n wrap={pillWrap}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n className={className}\n aria-label={ariaLabel}\n // codex P2 forward(see Select branch comment for type-cast rationale)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // any-allow: rest 含 `onChange: FormEventHandler` 跟 Combobox onChange signature 衝突 — DOM runtime spread 安全(per codex P2 forward)\n {...(rest as any)}\n // **Tag SSOT canonical**:用 `avatar` prop(不塞 children),Tag 內部統一\n // wrap 進 16×16 圓形 mask container(per Tag tsx line 175)。\n tagRenderer={(item, onRemove) => {\n const p = resolvePerson(findPerson(people, item.value))\n return (\n <Tag\n key={item.value}\n size={size}\n color=\"neutral\"\n // 2026-05-18 7B' fix(per user 拍板「執行」+ Codex Round 3 共識,paired with Combobox L286):\n // 拿掉 `unbounded` 對齊 Tag canonical max-w-40 cap + 內建 ellipsis。PeoplePicker pill 走\n // Combobox tagRenderer slot,SSOT = Tag primitive 視覺(per codex Round 3 verdict)。\n // 人名 99% < 25 chars 不觸發 cap;極端長名(複數姓 + middle name)觸發 ellipsis 是合理 UX。\n avatar={pillShowAvatar\n ? <Avatar src={p.avatarUrl} alt={p.name} size={16} hoverCard={buildPersonProfileCard(p)} />\n : undefined}\n onRemove={onRemove}\n >\n {p.name}\n </Tag>\n )\n }}\n />\n )\n }\n\n // ── multi 'stack' (default) → wraps Combobox 跟 pill mode 同 SSOT,差別在 tagRenderer 視覺。\n //\n // **2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus)**:visible count 走 shared\n // `avatar-stack-overflow` primitive deterministic formula(取代 Combobox DOM offsetWidth-based\n // useOverflowCount + 60px fallback 不 deterministic),pass override 給 Combobox bypass internal\n // measurement。`MultiPersonDisplay`(view path)同 primitive,view + edit 結果一致。\n // 對齊 user verbatim SSOT「同 cell width 同 overflow 判斷」+ codex Q3 consensus shared primitive。\n const handleMultiChange = (next: string[]) => {\n onChange?.(next.map(name => findPerson(people, name)))\n }\n // ── edit mode ─────────────────────────────────────────────────────────────\n // (selectedNames 派生已 hoist 至檔上方 hooks 區,見 D3 P0 修註解)\n\n return (\n <Combobox\n width={width}\n ref={mergedStackRef}\n size={size}\n variant={resolvedVariant}\n options={people.map(personToSelectOption)}\n value={selectedNames}\n onChange={handleMultiChange}\n searchable\n searchIn={searchIn}\n searchPlaceholder={searchPlaceholder}\n // 2026-05-12 Stream C Issue 4(codex Q3):placeholder = trigger empty('請選擇人員');emptyText = search-empty(僅 backward-compat forward 1 cycle)\n placeholder={placeholder}\n emptyText={emptyText}\n wrap={false}\n defaultOpen={defaultOpen}\n onOpenChange={onOpenChange}\n // 2026-05-13 (a) fix(user 拍 Path a + Layer A density-drift root-cause):\n // 撤掉 `tagAreaPaddingLeftPx={8}` magic — Combobox `tagPadding[size]` 是 density-dependent\n // calc 公式(`(field-height - icon-size) / 2`),只在 md size + default density 才 = 4px;\n // 其他 size/density 漂 6px / 8px → 4+8=12 spec 公式不成立。\n // (a) fix:form context + 有 tag → 改 inject `!px-[var(--field-px)]`(固定 12px)直接 override `tagPadding[size]`,\n // 達成 GitHub PeoplePicker fixed 12px inset(對齊 cell context 同 13px from cell.left 含 1px border)。\n // - form + 有 tag → `!px-[var(--field-px)]`(12px 固定 inset)+ tagAreaPaddingLeftPx undefined → field.padL=12 ✓\n // - table-cell + 有 tag → naked variant `!px-[var(--table-cell-px)]` 已是 12px,不 inject ✓\n // - isEmpty → 不 inject,走 Combobox 預設文字 inset(`tagPadding[size]` 公式自然 vertical center)\n className={cn(className, !isEmpty && surface === 'form' && '!px-[var(--field-px)]')}\n aria-label={ariaLabel}\n // 2026-05-15 Bug 1 fix(Claude+Codex Step 5 比稿 consensus,user verbatim「就 A」):per-length 動態\n // wrapper class — length=1 降階單人視覺需要 width constraint chain(`flex-1 min-w-0 overflow-hidden`),\n // length>=2 stack 視覺保留 overlap(`-ml-0.5 first:ml-0 relative inline-flex group/avatar`)。對齊\n // spec.md §C row 1(length=1 = avatar+人名+ellipsis)+ §D row 1(length>=2 = stack overlap)。\n // 真根因:Combobox `OverflowTagList` 把所有 tagRenderer 結果包 `shrink-0`,加 `inline-flex` 後\n // wrapper 變 intrinsic content-width → PersonDisplay `w-full` resolves to intrinsic → truncate 無效。\n // 修法:length=1 wrapper 改 `flex-1 min-w-0 overflow-hidden` 提供 width constraint 給 PersonDisplay。\n // SSOT helper `getPeoplePickerTagWrapperClass(count)` 集中,future 改 wrapper 行為改一處。\n tagWrapperClassName={getPeoplePickerTagWrapperClass(selectedNames.length)}\n // 2026-05-16 真 root cause fix:overflow chip wrapper 套同 `-ml-0.5` 讓 chip 物理上\n // 跟 avatar 同 slot(等寬同 step,non-overlapping 多 24px 區塊不再 saw)。對齊 user\n // 「avatars 和 +N 都是同尺寸圓形,空間最多容固定數量圓形」物理模型 directive +\n // MUI AvatarGroup / Primer AvatarStack 共識(`AvatarGroup.js` L54-59 same negative margin)。\n overflowWrapperClassName=\"-ml-0.5 first:ml-0 relative inline-flex\"\n tagAreaGapPx={0}\n tagAreaPaddingLeftPx={undefined}\n // 2026-05-12 Round 7 fix(user 抓 image 2「+N tag 應該圓形不是矩形」+ 對齊 GitHub picker idiom):\n // Combobox default `overflowShape='tag'`(矩形 chip,文字 Combobox 慣例);PeoplePicker stack\n // mode pass `'circle'`(圓形 avatar-shape,跟 avatar 一樣大)。對齊 MultiPersonDisplay readonly path\n // 既有 OverflowIndicator default 'circle' SSOT。\n overflowShape=\"circle\"\n // 2026-05-15 Bug 3 fix:formula-based visible count override(避免 Combobox DOM measurement +\n // 60px fallback 不 deterministic)。SSOT in `./avatar-stack-overflow.ts`,view + edit 共用。\n visibleCountOverride={stackVisibleCount}\n // 2026-05-14 I4 fix(per codex+Layer A 共識):hidden items 在 `+N` overflow popover 顯\n // Tag with avatar(對齊 view path MultiPersonDisplay popover SSOT,user 抓 display vs edit\n // overflow 視覺不一致)。\n renderHiddenTag={(item) => {\n const p = resolvePerson(findPerson(people, item.value))\n return (\n <Tag\n key={item.value}\n color=\"neutral\"\n size=\"sm\"\n avatar={\n <Avatar\n src={p.avatarUrl}\n alt={p.name}\n size={16}\n hoverCard={buildPersonProfileCard(p)}\n />\n }\n onRemove={() => {\n onChange?.(selectedNames.filter(n => n !== item.value).map(n => findPerson(people, n)))\n }}\n >\n {p.name}\n </Tag>\n )\n }}\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n // any-allow: rest 含 `onChange: FormEventHandler` 跟 Combobox onChange signature 衝突 — DOM runtime spread 安全(per codex P2 forward)\n {...(rest as any)}\n tagRenderer={(item, onRemove) => {\n const p = resolvePerson(findPerson(people, item.value))\n // 2026-05-12 Q2 fix(user 拍板「multi 只選 1 人時 trigger = avatar + name,跟 single mode 同」):\n // selectedNames.length === 1 → PersonDisplay(avatar + name)代替 PersonAvatarTag(avatar only)。\n // SSOT 對齊 PeoplePicker single mode line 201 selectedItemRenderer。多選 1 人時視覺等同單選,\n // 只在 length > 1 才走 stack(各 avatar 純 chip)。多選 + inline 搜尋場景拿掉 name 改 cursor\n // 走 `searchIn='trigger'` opt-in(2026-05-12 規則 3 ship,已轉傳 Combobox;default 'menu' 走 panel-top search)。\n if (selectedNames.length === 1) {\n return <PersonDisplay key={item.value} value={p} size={size} />\n }\n return (\n <PersonAvatarTag\n key={item.value}\n person={p}\n size={size}\n onRemove={onRemove}\n />\n )\n }}\n />\n )\n})\nPeoplePicker.displayName = 'PeoplePicker'\n\n// Story auto-compile metadata\nexport const peoplePickerMeta = {\n component: 'PeoplePicker',\n family: 4,\n variants: {},\n sizes: {},\n // 'active' 移除 — trigger 走 Field chrome、menu 走 MenuItem,皆無自有按壓視覺(2026-07-07 詞彙統一 DS-wide 按壓訊號盤點:檔內 0 active: utility / 0 *-active token)。\n states: ['default', 'hover', 'focus-visible', 'disabled'],\n tokens: {\n bg: [],\n fg: ['text-fg-disabled', 'text-fg-muted'],\n ring: [],\n },\n} as const\n\nexport { PeoplePicker }\n// 2026-07-10 C14 export 缺口修(R2 同類:定義存在但無 export 面,consumer 想守 PersonValue 鏈\n// import 不到 → 被逼手刻)。person-display 表面隨 PeoplePicker subpath + root barrel 一併公開。\nexport {\n PersonDisplay,\n MultiPersonDisplay,\n PersonAvatarTag,\n buildPersonProfileCard,\n resolvePerson,\n type PersonValue,\n type PersonData,\n} from './person-display'\n"],"names":["SelectPublic","ComboboxPublic","PeoplePicker","handleMultiChange"],"mappings":"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"}
@@ -48,7 +48,7 @@ declare function MultiPersonDisplay({ value, size, max, measured, onRemove, disa
48
48
  max?: number;
49
49
  /**
50
50
  * 2026-05-15 codex Round 5 C+ SSOT fix:`measured=true` 啟動 container-width 量測(取代 hardcode `max ?? 3`)
51
- * → display + edit stack 同 algorithm(同 cell width → 同 overflow 判斷),不再 display 用固定 3 vs edit
51
+ * → view + edit stack 同 algorithm(同 cell width → 同 overflow 判斷),不再 view 用固定 3 vs edit
52
52
  * 用 useOverflowCount。對齊 field-controls.spec.md:286 「4-mode 共享 renderer」contract + user round 3
53
53
  * verbatim「同空間兩判斷點」SSOT directive。Default false 保 backward compat(non-cell context 仍 max ?? 3)。
54
54
  */
@@ -1 +1 @@
1
- {"version":3,"file":"person-display.js","sources":["../../../src/components/PeoplePicker/person-display.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 { X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { useFieldEmptyDisplay } from '@/design-system/components/Field/field-context'\nimport { Tag } from '@/design-system/components/Tag/tag'\nimport { OverflowIndicator } from '@/design-system/components/OverflowIndicator/overflow-indicator'\nimport { Avatar } from '@/design-system/components/Avatar/avatar'\nimport { ProfileCard, ProfileCardDefaultActions } from '@/design-system/components/ProfileCard/profile-card'\nimport { useTableIsScrolling } from '@/design-system/components/Field/field-context'\nimport { ItemPrefix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport {\n getAvatarStackVisibleCount,\n AVATAR_STACK_AVATAR_PX,\n AVATAR_STACK_OVERFLOW_CHIP_PX,\n} from './avatar-stack-overflow'\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n// PersonData 承載 ProfileCard 所需的完整資訊。DS 全域 person avatar 的 hoverCard ProfileCard 顯示\n// 同一組 sections(name + subtitle + status + 2 default fields(id + employeeNumber,見下方\n// NAMECARD_DEFAULT_FIELD_KEYS 對齊註解)+ 自訂 fields + actions + View more)— 缺資料顯 placeholder;\n// **例外:status undefined 時整 status block 省略(collapse,= loading transient,見 status jsDoc)**。\n// 對齊 avatar.spec.md「person avatar hover → ProfileCard」DS-wide canonical。\nexport interface PersonData {\n name: string\n avatarUrl?: string\n /** 角色 / 部門 / ID 等 meta 單行(ProfileCard subtitle) */\n description?: string\n /** Presence 狀態(對齊 Avatar presence canonical)。**2026-05-14 v12 update**(per user 拍板):\n * production 每 user 一定有 presence state,**undefined = loading transient(資料還沒讀到)**,\n * 不是「user 沒設定」。ProfileCard 在 undefined 期間隱藏整 status block,**禁** render「Status not set」\n * placeholder 文字。 */\n status?: 'online' | 'away' | 'busy' | 'offline'\n /** Status 訊息(ProfileCard status section)。只在 status defined 時 render,缺則顯 `—` placeholder。\n * Status undefined 整 block skip(無 statusMessage 也跟著 skip)。 */\n statusMessage?: React.ReactNode\n /** **2026-05-07 v15.7 user directive**:ProfileCard default 只 render `id` + `employeeNumber`,\n * 其他 description 一律 opt-in by consumer 透過 `fields` array prop。對齊\n * `NAMECARD_DEFAULT_FIELD_KEYS = ['id', 'employeeNumber']`。 */\n id?: string\n employeeNumber?: string\n /** 自訂額外 fields(在 default fields 之後 append)。Email / Phone / Department / Location\n * / 任何其他 description 一律走這個 prop(opt-in,consumer 自選)。 */\n fields?: { label: string; value: string }[]\n /** 跳至完整 profile 頁的 handler(hover ProfileCard 必含,不傳時 fallback noop placeholder) */\n onViewProfile?: () => void\n /** ProfileCard 預設 Chat 按鈕 handler(2026-07-06 user 拍板加接線;未傳 dev-warn,見 ProfileCardDefaultActions) */\n onChat?: () => void\n /** ProfileCard 預設 Audio call 按鈕 handler(ChevronDown 下拉行為留 v2) */\n onCall?: () => void\n}\n\nexport type PersonValue = string | PersonData\n\nfunction resolvePerson(value: PersonValue): PersonData {\n return typeof value === 'string' ? { name: value } : value\n}\n\n// buildPersonProfileCard — DS 全域 person avatar hoverCard 的 canonical ProfileCard JSX 建構器。\n// SSOT for「avatar hover ProfileCard 一致視覺」— 任何 person avatar consumer 都走這個 helper,\n// 不可繞道直接 build ProfileCard。\n//\n// **2026-05-07 v15.7 user directive**:default field values 只 `id` + `employeeNumber`,\n// 對齊 NAMECARD_DEFAULT_FIELD_KEYS。其他 description(email/phone/department/location/etc)\n// consumer 想顯式透過 `person.fields` opt-in 傳入。\nfunction buildPersonProfileCard(person: PersonData): React.ReactNode {\n return (\n <ProfileCard\n name={person.name}\n subtitle={person.description}\n avatar={{ src: person.avatarUrl, alt: person.name }}\n status={person.status}\n statusMessage={person.statusMessage}\n defaultFieldValues={{\n id: person.id,\n employeeNumber: person.employeeNumber,\n }}\n fields={person.fields}\n actions={<ProfileCardDefaultActions onChat={person.onChat} onCall={person.onCall} />}\n // onViewMore hover context 必含(avatar.spec.md canonical)。consumer 傳\n // `onViewProfile` 則用真 handler,否則 noop placeholder(UI 仍渲染 View more\n // footer,避免 preview 變死路)。\n onViewMore={person.onViewProfile ?? (() => {})}\n />\n )\n}\n\n// ── Avatar Size ─────────────────────────────────────────────────────────────\n// 與 Tag 高度對齊:sm=20px, md/lg=24px(對齊 item-anatomy AVATAR_SIZE.inline)\n\nconst AVATAR_PX: Record<'sm' | 'md' | 'lg', number> = { sm: 20, md: 24, lg: 24 }\n\n// ── PersonAvatar ────────────────────────────────────────────────────────────\n// Consume DS `Avatar` primitive(2026-04-22 refactor,M1 SSOT consumption)+ 預設 ProfileCard\n// hoverCard(avatar.spec.md DS-wide「person avatar hover → ProfileCard」canonical)。\n//\n// 之前用 local `<img>` / `<User icon />` hand-craft 繞過 DS Avatar,違反 M1。本次 refactor:\n// - 所有 person avatar 經過 DS Avatar primitive(size 對應 uiSize family,fallback / icon / badge 集中管理)\n// - 人員資訊 → ProfileCard(subtitle = description,actions = ProfileCardDefaultActions)\n\n// 2026-05-13 (a) perf fix(per codex Layer C HoverCard subtree dominant):\n// useMemo `buildPersonProfileCard` per-person stable ref。原 every render call → new JSX ref →\n// Avatar.memo bails → HoverCard subtree 重建。Stable ref → memo skip → big win on scroll。\n//\n// (c) push-up scroll-defer:當 DataTable virtualizer.isScrolling=true,**完全不 build ProfileCard**\n// (Avatar 收 undefined → 跳 HoverCard wrapper)。原 (c) v1 在 Avatar 層 skip wrapper 但 ProfileCard\n// JSX subtree 仍在此處 build → 浪費 React reconciliation work。push 到此處才真省。\nfunction PersonAvatar({\n person,\n size = 'md',\n className = '',\n style,\n disabled = false,\n}: {\n person: PersonData\n size?: 'sm' | 'md' | 'lg'\n className?: string\n style?: React.CSSProperties\n /** disabled field context(2026-07-14 deep-audit 修):抑制 ProfileCard hoverCard(Avatar 收\n * undefined → 無 HoverCard wrapper / 無 tabIndex,真不可互動)+ avatar 自身 dim(host-controlled\n * opacity — avatar.spec.md「Avatar 在 disabled 元件內 host-controlled opacity」canonical;\n * PeoplePicker disabled 分支無 fieldCtx,Avatar self-dim 搆不到,host 補)。\n * 對齊 people-picker.spec.md「disabled:灰化整個 field,不可互動」。 */\n disabled?: boolean\n}) {\n const isTableScrolling = useTableIsScrolling()\n const nameCard = React.useMemo(\n () => (isTableScrolling || disabled ? undefined : buildPersonProfileCard(person)),\n [person, isTableScrolling, disabled]\n )\n return (\n <Avatar\n src={person.avatarUrl}\n alt={person.name}\n size={AVATAR_PX[size]}\n className={cn(className, disabled && 'opacity-disabled')}\n style={style}\n hoverCard={nameCard}\n />\n )\n}\n\n// ── Single Person Display ───────────────────────────────────────────────────\n\n// 2026-05-14 item-anatomy SSOT fix(per codex+Layer A 共識 path (a) + user 拍板「全部做完」):\n// outer 改 items-start + Avatar 外包 ItemPrefix primitive consumption。單行視覺 = items-center 等效;\n// 多行(autoRowHeight cell)避免 avatar+name center 整 row 不對齊 first-line text top。M1 消費既有\n// 對齊 TreeView / MenuItem / SelectionItem 共用 ItemPrefix wrap chevron/icon/avatar canonical。\nfunction PersonDisplay({ value, size = 'md', disabled = false }: { value?: PersonValue | null; size?: 'sm' | 'md' | 'lg'; /** 見 PersonAvatar.disabled jsDoc(抑制 hoverCard + dim) */ disabled?: boolean }) {\nconst emptyDisplay = useFieldEmptyDisplay()\n if (!value) return <span className=\"text-foreground\">{emptyDisplay}</span>\n\n const person = resolvePerson(value)\n\n // 2026-05-14 I1 fix(per codex addendum verdict):outer `inline-flex` → `flex w-full`\n // 完成 truncate 寬度約束鏈。原 inline-flex content-width parent constrain 不到 name span\n // → cell overflow-hidden 硬裁 → ellipsis dots 不可見。改 flex(block-level full width)\n // + inner name span `flex-1 min-w-0 truncate` 真實 truncate-with-ellipsis 顯示。\n // 對齊 GitHub Primer ActionList / Slack users_select / Atlassian UserPicker truncation canonical。\n return (\n <span className=\"flex items-start gap-2 min-w-0 w-full\">\n <ItemPrefix><PersonAvatar person={person} size={size} disabled={disabled} /></ItemPrefix>\n <span className=\"truncate flex-1 min-w-0\">{person.name}</span>\n </span>\n )\n}\nPersonDisplay.displayName = 'PersonDisplay'\n\n// ── Multi Person Display ────────────────────────────────────────────────────\n// 多人堆疊:avatar 重疊(-2px),不顯示人名。\n// 第一個 avatar z-index 最高(在最上面),依此類推。\n// 溢出時顯示 +N 指示器,hover 出 tooltip 列出溢出的人(avatar + 人名)。\n\nfunction MultiPersonDisplay({\n value,\n size = 'md',\n max,\n measured = false,\n onRemove,\n disabled = false,\n}: {\n value?: PersonValue[] | null\n size?: 'sm' | 'md' | 'lg'\n /** 最多顯示幾個 avatar(不含 +N),預設 3。`measured=true` 時忽略此 prop(改 container width 算)*/\n max?: number\n /**\n * 2026-05-15 codex Round 5 C+ SSOT fix:`measured=true` 啟動 container-width 量測(取代 hardcode `max ?? 3`)\n * → display + edit stack 同 algorithm(同 cell width → 同 overflow 判斷),不再 display 用固定 3 vs edit\n * 用 useOverflowCount。對齊 field-controls.spec.md:286 「4-mode 共享 renderer」contract + user round 3\n * verbatim「同空間兩判斷點」SSOT directive。Default false 保 backward compat(non-cell context 仍 max ?? 3)。\n */\n measured?: boolean\n /** 傳入時啟用 dismiss(edit mode),callback 接收被移除的 person */\n onRemove?: (person: PersonValue) => void\n /** 見 PersonAvatar.disabled jsDoc(抑制全 stack ProfileCard hoverCard + avatar dim) */\n disabled?: boolean\n}) {\n const emptyDisplay = useFieldEmptyDisplay()\n // 2026-07-05 D3 P1 修(React #310 家族):3 hooks 原在 empty early return 之後 — value 非空↔空\n // 切換時 hook 數 0↔3 變動必 crash(現靠 consumer 三元切換 element type 偶然避開)。hoist 到 return 前。\n // 2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus):消費 shared `avatar-stack-overflow`\n // primitive。原 inline canvas-based formula 是 dual-implementation 違反 user SSOT「同 cell width 同\n // overflow 判斷」(edit path 用 Combobox useOverflowCount DOM offsetWidth / display path 用 inline\n // canvas)。**抽 primitive 統一**:display + edit 共用 `getAvatarStackVisibleCount` formula。\n // SSOT in `./avatar-stack-overflow.ts`,M14 mechanical guard 防 future drift。\n const containerRef = React.useRef<HTMLSpanElement>(null)\n const [measuredCount, setMeasuredCount] = React.useState<number | null>(null)\n React.useLayoutEffect(() => {\n if (!measured || !value || value.length === 0) return\n const el = containerRef.current\n if (!el) return\n const calc = () => {\n const visible = getAvatarStackVisibleCount({\n availablePx: el.clientWidth,\n total: value.length,\n avatarPx: AVATAR_STACK_AVATAR_PX[size],\n overflowChipPx: AVATAR_STACK_OVERFLOW_CHIP_PX[size],\n })\n setMeasuredCount(visible)\n }\n calc()\n const ro = new ResizeObserver(calc)\n ro.observe(el)\n return () => ro.disconnect()\n }, [measured, size, value])\n\n if (!value || value.length === 0) return <span className=\"text-foreground\">{emptyDisplay}</span>\n\n const resolvedMax = measured && measuredCount !== null ? measuredCount : (max ?? 3)\n const people = value.map(resolvePerson)\n const visible = people.slice(0, resolvedMax)\n const hidden = people.slice(resolvedMax)\n const overflow = hidden.length\n\n // 單人回退到 PersonDisplay(顯示名字)\n if (people.length === 1) {\n return <PersonDisplay value={value[0]} size={size} disabled={disabled} />\n }\n\n // 2026-05-14 item-anatomy SSOT fix(per codex+Layer A 共識):outer items-start + avatar stack\n // 鎖 first-line baseline(整 stack 是 prefix slot,h-[1lh] 對齊 first line)。\n return (\n <span ref={containerRef} className=\"inline-flex items-start min-w-0\">\n <ItemPrefix className=\"!justify-start\"><span className=\"inline-flex items-center min-w-0\">\n {visible.map((person, i) => {\n // **2026-05-07 v15.11 Bug D 升級 SSOT**:visible avatar 也支援 inline dismiss\n // (對齊 user directive「avatar = tag」)。Dismiss overlay 走 `AvatarDismissOverlay`\n // 共用 SSOT(下方 export),Combobox tagRenderer / 此處 / 任何 future avatar consumer\n // 都用同一視覺 — 紅圈 X 對齊 avatar 右上,hover/focus-visible 才顯。\n const handleDismiss = onRemove ? () => onRemove(value![i]) : undefined\n return (\n <span key={person.name + i} className={`relative inline-flex group/avatar ${i > 0 ? '-ml-0.5' : ''}`} style={{ zIndex: visible.length - i }}>\n <PersonAvatar\n person={person}\n size={size}\n className=\"ring-2 ring-[var(--surface)]\"\n disabled={disabled}\n />\n {handleDismiss && <AvatarDismissOverlay onRemove={handleDismiss} label={person.name} />}\n </span>\n )\n })}\n {overflow > 0 && (\n <OverflowIndicator\n count={overflow}\n size={size}\n className=\"ring-2 ring-[var(--surface)] -ml-0.5\"\n >\n {hidden.map((person, i) => (\n <Tag\n key={person.name + i}\n color=\"neutral\"\n size=\"sm\"\n // Tag.avatar 是 ReactNode(非 AvatarData object)——傳 <Avatar> 元素。\n // Tag 內部用 `w-4 h-4 rounded-full` 容器 slot,Avatar 填滿 object-cover。\n // **hoverCard 必帶**(avatar.spec.md DS-wide canonical:所有 person avatar 必 hover → ProfileCard)。\n // 跟 PersonAvatar 共用 `buildPersonProfileCard` helper 確保顯示資訊一致。\n avatar={\n <Avatar\n src={person.avatarUrl}\n alt={person.name}\n size={16}\n // disabled field:同 PersonAvatar — 抑制 ProfileCard hoverCard(不可互動)\n hoverCard={disabled ? undefined : buildPersonProfileCard(person)}\n />\n }\n onRemove={onRemove ? () => onRemove(value![resolvedMax + i]) : undefined}\n >\n {person.name}\n </Tag>\n ))}\n </OverflowIndicator>\n )}\n </span></ItemPrefix>\n </span>\n )\n}\nMultiPersonDisplay.displayName = 'MultiPersonDisplay'\n\n// ── AvatarDismissOverlay ────────────────────────────────────────────────────\n// SSOT for「person avatar overlay dismiss」(2026-05-07 v15.12,user spec confirmed)。\n//\n// **Visual canonical**(對齊 DS new token `--surface-strong`):\n// - **12×12 圓**(固定,不隨 field size 變)\n// - **bg `--surface-strong`**(neutral-6),hover → `--surface-strong-hover`\n// (light=neutral-5 / dark=neutral-7,跨 mode 對稱)\n// - **X icon size=12 strokeWidth=3**(icon 跟底色一樣大,對齊 checkbox checkmark\n// sm/md stroke 規格;2026-06-12 同步 checkbox 2026-05-18 簡化 3.5→3,SSOT →\n// .claude/references/ui-dev-rules.md「小尺寸 icon stroke 補償」)\n// - **text-on-emphasis**(白 X,確保飽和色底對比)\n// - **位置 `absolute -top-px -right-1`**(top -1px / right -4px,右緣凸出 avatar 外 4px —\n// v15.15 user-confirmed asymmetric canonical,rationale 見下方 className 內註解)\n//\n// **a11y**(codex P1 fix):`opacity-0` 而非 `display:none` — element 在 DOM/tab-order,\n// keyboard tab 可達,觸控 focus-within 也顯。Hover / focus-within / focus-visible\n// 三條件之一觸發 `opacity-100`。\n//\n// **Why centralize**:Combobox tagRenderer (PeoplePicker stack mode) + MultiPersonDisplay\n// dismiss 共用 SSOT,改 1 處全 sync(M17 propagation)。\nfunction AvatarDismissOverlay({ onRemove, label }: { onRemove: () => void; label: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onRemove() }}\n aria-label={`移除 ${label}`}\n className={[\n // **Position(2026-05-07 v15.15 user-confirmed)**:asymmetric `-top-px -right-1`\n // (top -1px / right -4px)— field padding-y(4px sm/md)緊 → top 只 -1px 安全;\n // padding-x 12px 寬鬆 → right 凸 4px 達 badge canonical visual。對齊 ClickUp\n // 世界級 idiom(asymmetric offset by avatar/field size constraint)。\n 'absolute -top-px -right-1 z-10',\n 'inline-flex items-center justify-center',\n // **12×12 + 2px white ring**(SSOT match stacked avatar,Slack/Material/iOS\n // notification badge 2px ring canonical)。改用 `[box-shadow:...]` 而非 `ring-2`\n // 避免跟下方 `focus-visible:ring-2` 在 tailwind-merge 衝突(同 ring family\n // override 互殺)。Box-shadow inset 0 不影響 layout,也不被 focus-visible ring\n // 蓋掉(focus 那邊另一條 outline ring 不同 layer)。\n 'w-3 h-3 rounded-full [box-shadow:0_0_0_2px_var(--surface)]',\n // bg-surface-strong = neutral-6-opaque / hover = neutral-7-opaque(both modes,\n // step-7 dark 公式自動 lighter → engaged 跨 mode 對稱)\n 'bg-surface-strong text-on-emphasis hover:bg-surface-strong-hover',\n // a11y(codex P1 fix):opacity 而非 display:none — element 在 DOM/tab-order,\n // keyboard 可達。Hover / focus-within / focus-visible 三條件之一觸發。\n 'opacity-0 group-hover/avatar:opacity-100 group-focus-within/avatar:opacity-100 focus-visible:opacity-100',\n 'transition-opacity duration-150',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n ].join(' ')}\n >\n <X size={12} strokeWidth={3} aria-hidden />\n </button>\n )\n}\n\n// ── PersonAvatarTag(Combobox tagRenderer SSOT for stack mode)─────────────\n// PeoplePicker `multiDisplay='stack'` 模式 wraps Combobox,tagRenderer 不能用 Tag pill\n// (那是 pill mode),改 render 此元件 — Avatar overlap 視覺 + AvatarDismissOverlay。\n// 對齊 user directive「avatar = tag 概念,差別只在視覺,SSOT 一致」(2026-05-07 v15.13)。\n//\n// **架構**(v15.13 重構):本元件**不自包** `group/avatar` / `-ml-0.5` overlap wrapper,\n// 因 Combobox `tagRenderer` 結果會被內部 `<div shrink-0>` 包成 measurement wrapper\n// (useOverflowCount 必要)。把 overlap + group 拉到 Combobox 的 `tagWrapperClassName`\n// 上,sibling-level overlap + group selector 才能正確 chain → AvatarDismissOverlay 的\n// `group-hover/avatar:opacity-100` 才會通。\nfunction PersonAvatarTag({\n person, size = 'md', onRemove,\n}: {\n person: PersonData\n size?: 'sm' | 'md' | 'lg'\n onRemove?: () => void\n}) {\n return (\n <>\n <PersonAvatar person={person} size={size} className=\"ring-2 ring-[var(--surface)]\" />\n {onRemove && <AvatarDismissOverlay onRemove={onRemove} label={person.name} />}\n </>\n )\n}\nPersonAvatarTag.displayName = 'PersonAvatarTag'\n\nexport { PersonDisplay, MultiPersonDisplay, PersonAvatarTag, buildPersonProfileCard, resolvePerson }\n"],"names":["visible"],"mappings":"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"}
1
+ {"version":3,"file":"person-display.js","sources":["../../../src/components/PeoplePicker/person-display.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 { X } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { useFieldEmptyDisplay } from '@/design-system/components/Field/field-context'\nimport { Tag } from '@/design-system/components/Tag/tag'\nimport { OverflowIndicator } from '@/design-system/components/OverflowIndicator/overflow-indicator'\nimport { Avatar } from '@/design-system/components/Avatar/avatar'\nimport { ProfileCard, ProfileCardDefaultActions } from '@/design-system/components/ProfileCard/profile-card'\nimport { useTableIsScrolling } from '@/design-system/components/Field/field-context'\nimport { ItemPrefix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport {\n getAvatarStackVisibleCount,\n AVATAR_STACK_AVATAR_PX,\n AVATAR_STACK_OVERFLOW_CHIP_PX,\n} from './avatar-stack-overflow'\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n// PersonData 承載 ProfileCard 所需的完整資訊。DS 全域 person avatar 的 hoverCard ProfileCard 顯示\n// 同一組 sections(name + subtitle + status + 2 default fields(id + employeeNumber,見下方\n// NAMECARD_DEFAULT_FIELD_KEYS 對齊註解)+ 自訂 fields + actions + View more)— 缺資料顯 placeholder;\n// **例外:status undefined 時整 status block 省略(collapse,= loading transient,見 status jsDoc)**。\n// 對齊 avatar.spec.md「person avatar hover → ProfileCard」DS-wide canonical。\nexport interface PersonData {\n name: string\n avatarUrl?: string\n /** 角色 / 部門 / ID 等 meta 單行(ProfileCard subtitle) */\n description?: string\n /** Presence 狀態(對齊 Avatar presence canonical)。**2026-05-14 v12 update**(per user 拍板):\n * production 每 user 一定有 presence state,**undefined = loading transient(資料還沒讀到)**,\n * 不是「user 沒設定」。ProfileCard 在 undefined 期間隱藏整 status block,**禁** render「Status not set」\n * placeholder 文字。 */\n status?: 'online' | 'away' | 'busy' | 'offline'\n /** Status 訊息(ProfileCard status section)。只在 status defined 時 render,缺則顯 `—` placeholder。\n * Status undefined 整 block skip(無 statusMessage 也跟著 skip)。 */\n statusMessage?: React.ReactNode\n /** **2026-05-07 v15.7 user directive**:ProfileCard default 只 render `id` + `employeeNumber`,\n * 其他 description 一律 opt-in by consumer 透過 `fields` array prop。對齊\n * `NAMECARD_DEFAULT_FIELD_KEYS = ['id', 'employeeNumber']`。 */\n id?: string\n employeeNumber?: string\n /** 自訂額外 fields(在 default fields 之後 append)。Email / Phone / Department / Location\n * / 任何其他 description 一律走這個 prop(opt-in,consumer 自選)。 */\n fields?: { label: string; value: string }[]\n /** 跳至完整 profile 頁的 handler(hover ProfileCard 必含,不傳時 fallback noop placeholder) */\n onViewProfile?: () => void\n /** ProfileCard 預設 Chat 按鈕 handler(2026-07-06 user 拍板加接線;未傳 dev-warn,見 ProfileCardDefaultActions) */\n onChat?: () => void\n /** ProfileCard 預設 Audio call 按鈕 handler(ChevronDown 下拉行為留 v2) */\n onCall?: () => void\n}\n\nexport type PersonValue = string | PersonData\n\nfunction resolvePerson(value: PersonValue): PersonData {\n return typeof value === 'string' ? { name: value } : value\n}\n\n// buildPersonProfileCard — DS 全域 person avatar hoverCard 的 canonical ProfileCard JSX 建構器。\n// SSOT for「avatar hover ProfileCard 一致視覺」— 任何 person avatar consumer 都走這個 helper,\n// 不可繞道直接 build ProfileCard。\n//\n// **2026-05-07 v15.7 user directive**:default field values 只 `id` + `employeeNumber`,\n// 對齊 NAMECARD_DEFAULT_FIELD_KEYS。其他 description(email/phone/department/location/etc)\n// consumer 想顯式透過 `person.fields` opt-in 傳入。\nfunction buildPersonProfileCard(person: PersonData): React.ReactNode {\n return (\n <ProfileCard\n name={person.name}\n subtitle={person.description}\n avatar={{ src: person.avatarUrl, alt: person.name }}\n status={person.status}\n statusMessage={person.statusMessage}\n defaultFieldValues={{\n id: person.id,\n employeeNumber: person.employeeNumber,\n }}\n fields={person.fields}\n actions={<ProfileCardDefaultActions onChat={person.onChat} onCall={person.onCall} />}\n // onViewMore hover context 必含(avatar.spec.md canonical)。consumer 傳\n // `onViewProfile` 則用真 handler,否則 noop placeholder(UI 仍渲染 View more\n // footer,避免 preview 變死路)。\n onViewMore={person.onViewProfile ?? (() => {})}\n />\n )\n}\n\n// ── Avatar Size ─────────────────────────────────────────────────────────────\n// 與 Tag 高度對齊:sm=20px, md/lg=24px(對齊 item-anatomy AVATAR_SIZE.inline)\n\nconst AVATAR_PX: Record<'sm' | 'md' | 'lg', number> = { sm: 20, md: 24, lg: 24 }\n\n// ── PersonAvatar ────────────────────────────────────────────────────────────\n// Consume DS `Avatar` primitive(2026-04-22 refactor,M1 SSOT consumption)+ 預設 ProfileCard\n// hoverCard(avatar.spec.md DS-wide「person avatar hover → ProfileCard」canonical)。\n//\n// 之前用 local `<img>` / `<User icon />` hand-craft 繞過 DS Avatar,違反 M1。本次 refactor:\n// - 所有 person avatar 經過 DS Avatar primitive(size 對應 uiSize family,fallback / icon / badge 集中管理)\n// - 人員資訊 → ProfileCard(subtitle = description,actions = ProfileCardDefaultActions)\n\n// 2026-05-13 (a) perf fix(per codex Layer C HoverCard subtree dominant):\n// useMemo `buildPersonProfileCard` per-person stable ref。原 every render call → new JSX ref →\n// Avatar.memo bails → HoverCard subtree 重建。Stable ref → memo skip → big win on scroll。\n//\n// (c) push-up scroll-defer:當 DataTable virtualizer.isScrolling=true,**完全不 build ProfileCard**\n// (Avatar 收 undefined → 跳 HoverCard wrapper)。原 (c) v1 在 Avatar 層 skip wrapper 但 ProfileCard\n// JSX subtree 仍在此處 build → 浪費 React reconciliation work。push 到此處才真省。\nfunction PersonAvatar({\n person,\n size = 'md',\n className = '',\n style,\n disabled = false,\n}: {\n person: PersonData\n size?: 'sm' | 'md' | 'lg'\n className?: string\n style?: React.CSSProperties\n /** disabled field context(2026-07-14 deep-audit 修):抑制 ProfileCard hoverCard(Avatar 收\n * undefined → 無 HoverCard wrapper / 無 tabIndex,真不可互動)+ avatar 自身 dim(host-controlled\n * opacity — avatar.spec.md「Avatar 在 disabled 元件內 host-controlled opacity」canonical;\n * PeoplePicker disabled 分支無 fieldCtx,Avatar self-dim 搆不到,host 補)。\n * 對齊 people-picker.spec.md「disabled:灰化整個 field,不可互動」。 */\n disabled?: boolean\n}) {\n const isTableScrolling = useTableIsScrolling()\n const nameCard = React.useMemo(\n () => (isTableScrolling || disabled ? undefined : buildPersonProfileCard(person)),\n [person, isTableScrolling, disabled]\n )\n return (\n <Avatar\n src={person.avatarUrl}\n alt={person.name}\n size={AVATAR_PX[size]}\n className={cn(className, disabled && 'opacity-disabled')}\n style={style}\n hoverCard={nameCard}\n />\n )\n}\n\n// ── Single Person Display ───────────────────────────────────────────────────\n\n// 2026-05-14 item-anatomy SSOT fix(per codex+Layer A 共識 path (a) + user 拍板「全部做完」):\n// outer 改 items-start + Avatar 外包 ItemPrefix primitive consumption。單行視覺 = items-center 等效;\n// 多行(autoRowHeight cell)避免 avatar+name center 整 row 不對齊 first-line text top。M1 消費既有\n// 對齊 TreeView / MenuItem / SelectionItem 共用 ItemPrefix wrap chevron/icon/avatar canonical。\nfunction PersonDisplay({ value, size = 'md', disabled = false }: { value?: PersonValue | null; size?: 'sm' | 'md' | 'lg'; /** 見 PersonAvatar.disabled jsDoc(抑制 hoverCard + dim) */ disabled?: boolean }) {\nconst emptyDisplay = useFieldEmptyDisplay()\n if (!value) return <span className=\"text-foreground\">{emptyDisplay}</span>\n\n const person = resolvePerson(value)\n\n // 2026-05-14 I1 fix(per codex addendum verdict):outer `inline-flex` → `flex w-full`\n // 完成 truncate 寬度約束鏈。原 inline-flex content-width parent constrain 不到 name span\n // → cell overflow-hidden 硬裁 → ellipsis dots 不可見。改 flex(block-level full width)\n // + inner name span `flex-1 min-w-0 truncate` 真實 truncate-with-ellipsis 顯示。\n // 對齊 GitHub Primer ActionList / Slack users_select / Atlassian UserPicker truncation canonical。\n return (\n <span className=\"flex items-start gap-2 min-w-0 w-full\">\n <ItemPrefix><PersonAvatar person={person} size={size} disabled={disabled} /></ItemPrefix>\n <span className=\"truncate flex-1 min-w-0\">{person.name}</span>\n </span>\n )\n}\nPersonDisplay.displayName = 'PersonDisplay'\n\n// ── Multi Person Display ────────────────────────────────────────────────────\n// 多人堆疊:avatar 重疊(-2px),不顯示人名。\n// 第一個 avatar z-index 最高(在最上面),依此類推。\n// 溢出時顯示 +N 指示器,hover 出 tooltip 列出溢出的人(avatar + 人名)。\n\nfunction MultiPersonDisplay({\n value,\n size = 'md',\n max,\n measured = false,\n onRemove,\n disabled = false,\n}: {\n value?: PersonValue[] | null\n size?: 'sm' | 'md' | 'lg'\n /** 最多顯示幾個 avatar(不含 +N),預設 3。`measured=true` 時忽略此 prop(改 container width 算)*/\n max?: number\n /**\n * 2026-05-15 codex Round 5 C+ SSOT fix:`measured=true` 啟動 container-width 量測(取代 hardcode `max ?? 3`)\n * → view + edit stack 同 algorithm(同 cell width → 同 overflow 判斷),不再 view 用固定 3 vs edit\n * 用 useOverflowCount。對齊 field-controls.spec.md:286 「4-mode 共享 renderer」contract + user round 3\n * verbatim「同空間兩判斷點」SSOT directive。Default false 保 backward compat(non-cell context 仍 max ?? 3)。\n */\n measured?: boolean\n /** 傳入時啟用 dismiss(edit mode),callback 接收被移除的 person */\n onRemove?: (person: PersonValue) => void\n /** 見 PersonAvatar.disabled jsDoc(抑制全 stack ProfileCard hoverCard + avatar dim) */\n disabled?: boolean\n}) {\n const emptyDisplay = useFieldEmptyDisplay()\n // 2026-07-05 D3 P1 修(React #310 家族):3 hooks 原在 empty early return 之後 — value 非空↔空\n // 切換時 hook 數 0↔3 變動必 crash(現靠 consumer 三元切換 element type 偶然避開)。hoist 到 return 前。\n // 2026-05-15 Bug 3 fix(Claude+Codex Step 5 比稿 consensus):消費 shared `avatar-stack-overflow`\n // primitive。原 inline canvas-based formula 是 dual-implementation 違反 user SSOT「同 cell width 同\n // overflow 判斷」(edit path 用 Combobox useOverflowCount DOM offsetWidth / view path 用 inline\n // canvas)。**抽 primitive 統一**:view + edit 共用 `getAvatarStackVisibleCount` formula。\n // SSOT in `./avatar-stack-overflow.ts`,M14 mechanical guard 防 future drift。\n const containerRef = React.useRef<HTMLSpanElement>(null)\n const [measuredCount, setMeasuredCount] = React.useState<number | null>(null)\n React.useLayoutEffect(() => {\n if (!measured || !value || value.length === 0) return\n const el = containerRef.current\n if (!el) return\n const calc = () => {\n const visible = getAvatarStackVisibleCount({\n availablePx: el.clientWidth,\n total: value.length,\n avatarPx: AVATAR_STACK_AVATAR_PX[size],\n overflowChipPx: AVATAR_STACK_OVERFLOW_CHIP_PX[size],\n })\n setMeasuredCount(visible)\n }\n calc()\n const ro = new ResizeObserver(calc)\n ro.observe(el)\n return () => ro.disconnect()\n }, [measured, size, value])\n\n if (!value || value.length === 0) return <span className=\"text-foreground\">{emptyDisplay}</span>\n\n const resolvedMax = measured && measuredCount !== null ? measuredCount : (max ?? 3)\n const people = value.map(resolvePerson)\n const visible = people.slice(0, resolvedMax)\n const hidden = people.slice(resolvedMax)\n const overflow = hidden.length\n\n // 單人回退到 PersonDisplay(顯示名字)\n if (people.length === 1) {\n return <PersonDisplay value={value[0]} size={size} disabled={disabled} />\n }\n\n // 2026-05-14 item-anatomy SSOT fix(per codex+Layer A 共識):outer items-start + avatar stack\n // 鎖 first-line baseline(整 stack 是 prefix slot,h-[1lh] 對齊 first line)。\n return (\n <span ref={containerRef} className=\"inline-flex items-start min-w-0\">\n <ItemPrefix className=\"!justify-start\"><span className=\"inline-flex items-center min-w-0\">\n {visible.map((person, i) => {\n // **2026-05-07 v15.11 Bug D 升級 SSOT**:visible avatar 也支援 inline dismiss\n // (對齊 user directive「avatar = tag」)。Dismiss overlay 走 `AvatarDismissOverlay`\n // 共用 SSOT(下方 export),Combobox tagRenderer / 此處 / 任何 future avatar consumer\n // 都用同一視覺 — 紅圈 X 對齊 avatar 右上,hover/focus-visible 才顯。\n const handleDismiss = onRemove ? () => onRemove(value![i]) : undefined\n return (\n <span key={person.name + i} className={`relative inline-flex group/avatar ${i > 0 ? '-ml-0.5' : ''}`} style={{ zIndex: visible.length - i }}>\n <PersonAvatar\n person={person}\n size={size}\n className=\"ring-2 ring-[var(--surface)]\"\n disabled={disabled}\n />\n {handleDismiss && <AvatarDismissOverlay onRemove={handleDismiss} label={person.name} />}\n </span>\n )\n })}\n {overflow > 0 && (\n <OverflowIndicator\n count={overflow}\n size={size}\n className=\"ring-2 ring-[var(--surface)] -ml-0.5\"\n >\n {hidden.map((person, i) => (\n <Tag\n key={person.name + i}\n color=\"neutral\"\n size=\"sm\"\n // Tag.avatar 是 ReactNode(非 AvatarData object)——傳 <Avatar> 元素。\n // Tag 內部用 `w-4 h-4 rounded-full` 容器 slot,Avatar 填滿 object-cover。\n // **hoverCard 必帶**(avatar.spec.md DS-wide canonical:所有 person avatar 必 hover → ProfileCard)。\n // 跟 PersonAvatar 共用 `buildPersonProfileCard` helper 確保顯示資訊一致。\n avatar={\n <Avatar\n src={person.avatarUrl}\n alt={person.name}\n size={16}\n // disabled field:同 PersonAvatar — 抑制 ProfileCard hoverCard(不可互動)\n hoverCard={disabled ? undefined : buildPersonProfileCard(person)}\n />\n }\n onRemove={onRemove ? () => onRemove(value![resolvedMax + i]) : undefined}\n >\n {person.name}\n </Tag>\n ))}\n </OverflowIndicator>\n )}\n </span></ItemPrefix>\n </span>\n )\n}\nMultiPersonDisplay.displayName = 'MultiPersonDisplay'\n\n// ── AvatarDismissOverlay ────────────────────────────────────────────────────\n// SSOT for「person avatar overlay dismiss」(2026-05-07 v15.12,user spec confirmed)。\n//\n// **Visual canonical**(對齊 DS new token `--surface-strong`):\n// - **12×12 圓**(固定,不隨 field size 變)\n// - **bg `--surface-strong`**(neutral-6),hover → `--surface-strong-hover`\n// (light=neutral-5 / dark=neutral-7,跨 mode 對稱)\n// - **X icon size=12 strokeWidth=3**(icon 跟底色一樣大,對齊 checkbox checkmark\n// sm/md stroke 規格;2026-06-12 同步 checkbox 2026-05-18 簡化 3.5→3,SSOT →\n// .claude/references/ui-dev-rules.md「小尺寸 icon stroke 補償」)\n// - **text-on-emphasis**(白 X,確保飽和色底對比)\n// - **位置 `absolute -top-px -right-1`**(top -1px / right -4px,右緣凸出 avatar 外 4px —\n// v15.15 user-confirmed asymmetric canonical,rationale 見下方 className 內註解)\n//\n// **a11y**(codex P1 fix):`opacity-0` 而非 `display:none` — element 在 DOM/tab-order,\n// keyboard tab 可達,觸控 focus-within 也顯。Hover / focus-within / focus-visible\n// 三條件之一觸發 `opacity-100`。\n//\n// **Why centralize**:Combobox tagRenderer (PeoplePicker stack mode) + MultiPersonDisplay\n// dismiss 共用 SSOT,改 1 處全 sync(M17 propagation)。\nfunction AvatarDismissOverlay({ onRemove, label }: { onRemove: () => void; label: string }) {\n return (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); onRemove() }}\n aria-label={`移除 ${label}`}\n className={[\n // **Position(2026-05-07 v15.15 user-confirmed)**:asymmetric `-top-px -right-1`\n // (top -1px / right -4px)— field padding-y(4px sm/md)緊 → top 只 -1px 安全;\n // padding-x 12px 寬鬆 → right 凸 4px 達 badge canonical visual。對齊 ClickUp\n // 世界級 idiom(asymmetric offset by avatar/field size constraint)。\n 'absolute -top-px -right-1 z-10',\n 'inline-flex items-center justify-center',\n // **12×12 + 2px white ring**(SSOT match stacked avatar,Slack/Material/iOS\n // notification badge 2px ring canonical)。改用 `[box-shadow:...]` 而非 `ring-2`\n // 避免跟下方 `focus-visible:ring-2` 在 tailwind-merge 衝突(同 ring family\n // override 互殺)。Box-shadow inset 0 不影響 layout,也不被 focus-visible ring\n // 蓋掉(focus 那邊另一條 outline ring 不同 layer)。\n 'w-3 h-3 rounded-full [box-shadow:0_0_0_2px_var(--surface)]',\n // bg-surface-strong = neutral-6-opaque / hover = neutral-7-opaque(both modes,\n // step-7 dark 公式自動 lighter → engaged 跨 mode 對稱)\n 'bg-surface-strong text-on-emphasis hover:bg-surface-strong-hover',\n // a11y(codex P1 fix):opacity 而非 display:none — element 在 DOM/tab-order,\n // keyboard 可達。Hover / focus-within / focus-visible 三條件之一觸發。\n 'opacity-0 group-hover/avatar:opacity-100 group-focus-within/avatar:opacity-100 focus-visible:opacity-100',\n 'transition-opacity duration-150',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',\n ].join(' ')}\n >\n <X size={12} strokeWidth={3} aria-hidden />\n </button>\n )\n}\n\n// ── PersonAvatarTag(Combobox tagRenderer SSOT for stack mode)─────────────\n// PeoplePicker `multiDisplay='stack'` 模式 wraps Combobox,tagRenderer 不能用 Tag pill\n// (那是 pill mode),改 render 此元件 — Avatar overlap 視覺 + AvatarDismissOverlay。\n// 對齊 user directive「avatar = tag 概念,差別只在視覺,SSOT 一致」(2026-05-07 v15.13)。\n//\n// **架構**(v15.13 重構):本元件**不自包** `group/avatar` / `-ml-0.5` overlap wrapper,\n// 因 Combobox `tagRenderer` 結果會被內部 `<div shrink-0>` 包成 measurement wrapper\n// (useOverflowCount 必要)。把 overlap + group 拉到 Combobox 的 `tagWrapperClassName`\n// 上,sibling-level overlap + group selector 才能正確 chain → AvatarDismissOverlay 的\n// `group-hover/avatar:opacity-100` 才會通。\nfunction PersonAvatarTag({\n person, size = 'md', onRemove,\n}: {\n person: PersonData\n size?: 'sm' | 'md' | 'lg'\n onRemove?: () => void\n}) {\n return (\n <>\n <PersonAvatar person={person} size={size} className=\"ring-2 ring-[var(--surface)]\" />\n {onRemove && <AvatarDismissOverlay onRemove={onRemove} label={person.name} />}\n </>\n )\n}\nPersonAvatarTag.displayName = 'PersonAvatarTag'\n\nexport { PersonDisplay, MultiPersonDisplay, PersonAvatarTag, buildPersonProfileCard, resolvePerson }\n"],"names":["visible"],"mappings":"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"}
@@ -16,7 +16,7 @@ import { type AvatarData } from '../../components/Avatar/avatar';
16
16
  * 跨 consumer(avatar.principles / profile-card.stories / future product code)應該用
17
17
  * 同一組預設,避免每個範例各自發明 action 組合,讓 reader 誤以為 action 會隨情境自動變。
18
18
  *
19
- * ── 使用方式(hover context 必含 onViewMore,見 profile-card.spec.md 「View more」節)──
19
+ * ── 使用方式(hover context 必含 onViewMore — canonical owner 見 avatar.spec.md「onViewMore 為 hover context 必含」段;顯示條件見 profile-card.spec.md「View More」節)──
20
20
  * <ProfileCard name="..." actions={<ProfileCardDefaultActions />} onViewMore={...} />
21
21
  *
22
22
  * ── 何時要換成自訂 action ──
@@ -1 +1 @@
1
- {"version":3,"file":"profile-card.js","sources":["../../../src/components/ProfileCard/profile-card.tsx"],"sourcesContent":["/**\n * Public 元件(2026-07-04 Q8 拍板升 public,原 @internal 標記移除)。\n * 理由:avatar.spec.md「hover 必出 ProfileCard」DS-wide canonical 要求 consumer 直接\n * import ProfileCard + ProfileCardDefaultActions 組 HoverCard — 按 ui-development.md\n * 唯一判準(DS 想讓 consumer 直接用 = public)internal 標記是 governance bug;\n * 世界級對照:Atlassian ProfileCard 同為 public standalone。\n */\n// @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 { MessageCircle, Phone, ChevronDown } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Avatar, type AvatarData } from '@/design-system/components/Avatar/avatar'\nimport { Button } from '@/design-system/components/Button/button'\nimport { DescriptionList, DescriptionItem } from '@/design-system/components/DescriptionList/description-list'\nimport { ScrollArea } from '@/design-system/components/ScrollArea/scroll-area'\nimport { ItemContent } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n/**\n * ProfileCardDefaultActions — canonical 預設 action 組合\n *\n * ── 為什麼需要 export ──\n * ProfileCard 的 action 列在世界級 chat/contact app 是「關係型快速動作」的 canonical\n * (Slack / iMessage / LinkedIn / Figma 皆如此):**Chat / Message + Audio call**。\n * 跨 consumer(avatar.principles / profile-card.stories / future product code)應該用\n * 同一組預設,避免每個範例各自發明 action 組合,讓 reader 誤以為 action 會隨情境自動變。\n *\n * ── 使用方式(hover context 必含 onViewMore,見 profile-card.spec.md 「View more」節)──\n * <ProfileCard name=\"...\" actions={<ProfileCardDefaultActions />} onViewMore={...} />\n *\n * ── 何時要換成自訂 action ──\n * - Single-action 情境(只要「傳訊息」)→ consumer 傳 `<Button>傳訊息</Button>`\n * - 特定情境的 action(管理員「撤銷邀請」/ HR「離職管理」)→ consumer 自訂\n * - 非人員關係動作(「訂購此商品」)→ 根本不應該用 ProfileCard\n *\n * Chat + Audio call 是 **default**,不是 **only**——consumer 可覆寫,但需有明確理由。\n */\nexport const ProfileCardDefaultActions = ({\n onChat,\n onCall,\n}: {\n /** Chat 按鈕 handler(2026-07-06 user 拍板:預設鈕必可接線,未傳 = dev-warn;PersonData.onChat 自動 forward) */\n onChat?: () => void\n /** Audio call 按鈕 handler(ChevronDown 下拉行為留 v2,先接主 callback) */\n onCall?: () => void\n}) => {\n // Dev-mode warning(對齊本檔 defaultFieldValues dev-warn 先例):預設 actions 沒接 handler\n // = 按鈕點了永遠沒反應(2026-07-06 D4 finding);production 必傳 callback 或自組 actions。\n if (process.env.NODE_ENV !== 'production' && !onChat && !onCall) {\n // eslint-disable-next-line no-console\n console.warn(\n '[DS ProfileCard] ProfileCardDefaultActions 未接 onChat/onCall——按鈕點擊無反應。請傳入 callback(PersonData.onChat/onCall 會自動 forward)或自組 actions。'\n )\n }\n return (\n <>\n <Button variant=\"tertiary\" size=\"sm\" startIcon={MessageCircle} onClick={onChat}>Chat</Button>\n <Button variant=\"tertiary\" size=\"sm\" startIcon={Phone} endIcon={ChevronDown} onClick={onCall}>Audio call</Button>\n </>\n )\n}\n\n/**\n * ProfileCard — 人員 HoverCard 的內容元件\n *\n * ── Status 對齊 Avatar presence canonical(2026-04-20) ──\n * status type = `online | away | busy | offline`,跟 Avatar 的 presence prop 對齊\n * (世界級 Slack / Teams / Discord term);dot 色走 `--status-*` semantic token\n * (獨立於 success/error/warning,避免語義衝突)。\n *\n * ── Avatar 對齊 ──\n * 跟 FileItem rich 統一:右側 text column 用 justify-center + minHeight=avatar。\n * 短文字置中於 avatar,長文字(多行名字)自然撐高。\n *\n * ── Info fields ──\n * Status message / ID / Employee number 等唯讀屬性全部用 DescriptionList 家族\n * 承載(不手刻 dt/dd),canonical 由 DS primitive own。\n */\n\nconst AVATAR_SIZE = 64\n\ntype StatusType = 'online' | 'away' | 'busy' | 'offline'\n\n// Presence semantic tokens(見 color/semantic.css)——跟 Avatar status dot 共用\nconst STATUS_DOT_COLOR: Record<StatusType, string> = {\n online: 'var(--status-online)',\n away: 'var(--status-away)',\n busy: 'var(--status-busy)',\n offline: 'var(--status-offline)',\n}\n\nconst STATUS_LABEL: Record<StatusType, string> = {\n online: 'Online',\n away: 'Away',\n busy: 'Busy',\n offline: 'Offline',\n}\n\n/**\n * ProfileCard SSOT — 預設 field keys(現行 v15.7:default 只 `id` + `employeeNumber`;\n * v11 always-render 為歷史脈絡,已退役 — 見下方 2026-05-07 註解 + render 處 v12 註解)\n *\n * ── 為什麼 SSOT ──\n * User explicit rule:「所有 namecard 預設顯示的資訊都是要一樣完整的」。前 v10 props\n * 全 optional + body conditional render → consumer 漏傳 fields 視覺缺 section,每個範例\n * 各自不一致(同 person 在 DataTable / PeoplePicker / avatar.principles 看起來不同)。\n *\n * v11 canonical(歷史):ProfileCard 當時 always renders 4 default sections — 缺 data → 顯\n * `EMPTY_PLACEHOLDER`(\"-\")。現行:default fields 縮為 2(v15.7)+ status 條件 render(v12),\n * 「視覺結構 SSOT 在此元件,不依賴 consumer」原則不變。\n *\n * ── 對齊 world-class ──\n * Slack profile card / Linear member card / Notion person card / GitHub user card / Figma user card\n * 都是 fixed schema(role / email / location / department / department / pronouns 等),\n * 不會因為某 user 沒填 phone 整個 phone field 不見 — 缺 = 顯 `Not set` 或留白。\n *\n * ── 為什麼 placeholder 不 hide ──\n * Hide → consumer 不知道少傳 → 視覺漂移;Placeholder → 永遠看到「該欄該有」+ dev-warn 提示\n * consumer 補資料,自動防漂移(M19 ensure-canonical 對齊)。\n */\n// **2026-05-07 v15.7 user directive**:default render 只 `id` + `employeeNumber` 兩個。\n// Email / Phone / Department / Location 等其他 description 一律 opt-in by consumer 透過\n// `fields` array prop。對齊 user 明確「應該確保所有都只有這兩個,因為我並沒有要求你要選其他的」。\nexport const NAMECARD_DEFAULT_FIELD_KEYS = ['id', 'employeeNumber'] as const\ntype ProfileCardDefaultFieldKey = typeof NAMECARD_DEFAULT_FIELD_KEYS[number]\n\nconst DEFAULT_FIELD_LABEL: Record<ProfileCardDefaultFieldKey, string> = {\n id: 'ID',\n employeeNumber: 'Employee number',\n}\n\nconst FIELD_PLACEHOLDER = '-'\n\nexport interface ProfileCardProps extends React.HTMLAttributes<HTMLDivElement> {\n name: string\n avatar?: AvatarData\n subtitle?: string\n status?: StatusType\n statusMessage?: React.ReactNode\n actions?: React.ReactNode\n /**\n * Consumer 傳的 field 資料(partial)。預設 keys 走 `NAMECARD_DEFAULT_FIELD_KEYS` —\n * 只有 id / employeeNumber 兩個 default field 永遠 render(缺資料顯 `-`);email / phone /\n * department / location 等其他欄位一律 opt-in by consumer 透過本 prop 傳入。Consumer 想新增\n * 自訂 field 直接傳入(在 default 之後 append),想 override default key value 也直接傳。\n */\n fields?: { label: string; value: React.ReactNode }[]\n /**\n * Default field 的真實值。Object key = NAMECARD_DEFAULT_FIELD_KEYS 之一。\n * 缺 key → render placeholder。Dev mode 會 console.warn 提醒消費者補資料。\n */\n defaultFieldValues?: Partial<Record<ProfileCardDefaultFieldKey, React.ReactNode>>\n onViewMore?: () => void\n viewMoreLabel?: string\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst ProfileCard = React.forwardRef<HTMLDivElement, ProfileCardProps>(\n (\n {\n name,\n avatar,\n subtitle,\n status,\n statusMessage,\n actions,\n fields,\n defaultFieldValues,\n onViewMore,\n viewMoreLabel = 'View more',\n className,\n ...props\n },\n ref,\n ) => {\n // v12 canonical:default fields 永遠 render(缺資料顯 placeholder),consumer 自訂\n // fields 在 default 之後 append。Status section 為條件 render(status undefined →\n // 整 block 隱藏,見下方 render 處)— v11「永遠 render + placeholder」已退役。\n //\n // **Dedup canonical(2026-05-07 v15.8 fix Bug E)**:consumer 的 `fields` array 若含\n // label 撞 default(eg. 「ID」「Employee number」),consumer 值 win — defaults 那一行\n // 跳過(否則 same label 連 render 兩次,如 default placeholder `-` + consumer 真值)。\n // 這是遷移期 forgiving 行為:DEV warn 提示應改用 `defaultFieldValues`,但 production\n // 不破壞既有 consumer。對齊 React `key` 唯一性 + Linear / Slack profile card 一 label\n // 一 row idiom。\n const allFields = React.useMemo(() => {\n const consumerLabels = new Set((fields ?? []).map((f) => f.label))\n const defaults = NAMECARD_DEFAULT_FIELD_KEYS\n .map((key) => ({\n label: DEFAULT_FIELD_LABEL[key],\n value: defaultFieldValues?.[key] ?? FIELD_PLACEHOLDER,\n }))\n .filter((d) => !consumerLabels.has(d.label))\n return fields && fields.length > 0 ? [...defaults, ...fields] : defaults\n }, [defaultFieldValues, fields])\n\n // Dev warn:consumer 透過 `fields` 傳 default key label(legacy pattern)→ 應改 `defaultFieldValues`\n if (process.env.NODE_ENV !== 'production' && fields) {\n const legacyEntry = fields.find((f) =>\n Object.values(DEFAULT_FIELD_LABEL).includes(f.label as string),\n )\n if (legacyEntry) {\n // eslint-disable-next-line no-console\n console.warn(\n `[ProfileCard] \"${name}\":legacy pattern — fields[].label=\"${legacyEntry.label}\" ` +\n `is a default field. Migrate to defaultFieldValues={{ id, employeeNumber }} prop ` +\n `to align with NAMECARD_DEFAULT_FIELD_KEYS canonical.`,\n )\n }\n }\n\n // Dev mode warn:consumer 沒傳 default field 任何 key → 提示補完(避免漂移成 placeholder-only)\n if (process.env.NODE_ENV !== 'production' && !defaultFieldValues) {\n // eslint-disable-next-line no-console\n console.warn(\n `[ProfileCard] \"${name}\":no defaultFieldValues passed — sections will render placeholders. ` +\n `Pass at least { id, employeeNumber } via defaultFieldValues prop. ` +\n `For other description items (email/phone/department/location etc),use \\`fields\\` prop array.`,\n )\n }\n\n // Layout canonical(2026-04-23):Header + Actions 固定上,Body(status + fields)可捲動,\n // View more 固定下。**ProfileCard 自己約束高度**,不依賴 consumer HoverCardContent 設 flex:\n // - `max-h-[var(--radix-hover-card-content-available-height,...)]`:HoverCard / Popover\n // context 自動繼承 Radix viewport-aware 變數;standalone 落到 100vh fallback\n // - 內部 `flex flex-col + overflow-hidden`:Header(shrink-0)+ Body(flex-1 min-h-0 ScrollArea)\n // + Footer(shrink-0)三層 chrome\n // 世界級對照:Slack / Linear / GitHub / Notion hover-profile popover 皆此 chrome pattern。\n return (\n <div\n ref={ref}\n className={cn(\n 'w-[320px] flex flex-col overflow-hidden',\n 'max-h-[var(--radix-hover-card-content-available-height,var(--radix-popover-content-available-height,100vh))]',\n className,\n )}\n {...props}\n >\n {/* ── HEADER(固定): profile + actions ── */}\n <div className=\"shrink-0 flex flex-col\">\n <div className=\"flex items-start gap-3 px-4 py-3\">\n <Avatar\n src={avatar?.src}\n alt={avatar?.alt ?? name}\n color={avatar?.color}\n size={AVATAR_SIZE}\n status={status}\n className=\"shrink-0\"\n />\n {/* ProfileCard typography:label body-lg(16/1.5) + desc body(14/1.5) = reading mode + size=\"lg\"。\n labelClassName escape hatch 加 font-medium(card context 語意)+ labelTruncate=false 允許 wrap。 */}\n <ItemContent\n label={name}\n description={subtitle}\n mode=\"reading\"\n size=\"lg\"\n labelTruncate={false}\n labelClassName=\"text-body-lg font-medium text-foreground\"\n className=\"justify-center\"\n style={{ minHeight: AVATAR_SIZE }}\n />\n </div>\n\n {/* Action buttons — 均分空間 + 填滿格子(canonical):多個 action 等寬瓜分容器,\n 單一 action 也撐滿容器。`grid grid-flow-col auto-cols-fr` + `[&>*]:w-full`。\n 世界級對照:iOS contact card / macOS contact / LinkedIn profile card 的 action row。 */}\n {actions && (\n <div className=\"grid grid-flow-col auto-cols-fr gap-2 px-4 pb-3 [&>*]:w-full\">\n {actions}\n </div>\n )}\n </div>\n\n {/* ── BODY(可捲動,v12 status-conditional 2026-05-14):status + fields ──\n **v12 rule**(per user 拍板「不應該顯示『狀態沒有被設定』,production 每 user 一定有\n presence state,undefined 頂多是 loading transient 還沒讀到」):status undefined →\n 隱藏整 status badge + status message block(loading 期間 skip),禁 render「Status not\n set」這種 placeholder(語義錯,user presence 不會「沒設定」)。**ProfileCard-specific 不外推\n 至 DS 其他元件**(FileItem / DescriptionList / DataTable cell 各自 placeholder 邏輯\n unrelated)。Fields section 仍 always-render(info schema 性質)。 */}\n <ScrollArea className=\"flex-1 min-h-0 border-t border-divider\">\n {/* Status section:`status` defined 才 render(v12 conditional canonical) */}\n {status && (\n <div className=\"px-4 py-3 flex flex-col gap-3\">\n <div className=\"flex items-center gap-2 px-3 py-2 bg-muted rounded-md\">\n <span\n className=\"w-2.5 h-2.5 rounded-full shrink-0\"\n style={{ backgroundColor: STATUS_DOT_COLOR[status] }}\n />\n <span className=\"text-body\">{STATUS_LABEL[status]}</span>\n </div>\n {/* Status message — 只在 status defined 才 render(語意配對:status badge + status\n message 是一組;沒 status 就沒 status message)。缺 statusMessage 顯 placeholder。 */}\n <DescriptionList>\n <DescriptionItem label=\"Status message\">\n {statusMessage ?? <span className=\"text-foreground\">{FIELD_PLACEHOLDER}</span>}\n </DescriptionItem>\n </DescriptionList>\n </div>\n )}\n\n {/* Fields section:status defined 才有 border-t separator;無 status section 時去除 border-t(因 ScrollArea 起點已有上方 border-t,不重疊) */}\n <div className={cn('px-4 py-3', status && 'border-t border-divider')}>\n <DescriptionList cols={2}>\n {allFields.map((f) => (\n <DescriptionItem key={f.label} label={f.label}>\n {f.value === FIELD_PLACEHOLDER\n ? <span className=\"text-foreground\">{FIELD_PLACEHOLDER}</span>\n : f.value}\n </DescriptionItem>\n ))}\n </DescriptionList>\n </div>\n </ScrollArea>\n\n {/* ── FOOTER(固定): View more,py-3 canonical(12px,比一般 link 按鈕多呼吸) ── */}\n {onViewMore && (\n <div className=\"shrink-0 border-t border-divider px-4 py-3\">\n <Button variant=\"link\" size=\"sm\" onClick={onViewMore} className=\"w-full\">{viewMoreLabel}</Button>\n </div>\n )}\n </div>\n )\n },\n)\nProfileCard.displayName = 'ProfileCard'\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 nameCardMeta = {\n component: 'ProfileCard',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: [], // 唯讀 person-info template,無自身互動 state(hover/active/focus/disabled 屬子 Button/Avatar)\n tokens: {\n bg: ['bg-muted'],\n fg: ['text-foreground'],\n ring: [],\n },\n} as const\n\nexport { ProfileCard }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"profile-card.js","sources":["../../../src/components/ProfileCard/profile-card.tsx"],"sourcesContent":["/**\n * Public 元件(2026-07-04 Q8 拍板升 public,原 @internal 標記移除)。\n * 理由:avatar.spec.md「hover 必出 ProfileCard」DS-wide canonical 要求 consumer 直接\n * import ProfileCard + ProfileCardDefaultActions 組 HoverCard — 按 ui-development.md\n * 唯一判準(DS 想讓 consumer 直接用 = public)internal 標記是 governance bug;\n * 世界級對照:Atlassian ProfileCard 同為 public standalone。\n */\n// @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 { MessageCircle, Phone, ChevronDown } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Avatar, type AvatarData } from '@/design-system/components/Avatar/avatar'\nimport { Button } from '@/design-system/components/Button/button'\nimport { DescriptionList, DescriptionItem } from '@/design-system/components/DescriptionList/description-list'\nimport { ScrollArea } from '@/design-system/components/ScrollArea/scroll-area'\nimport { ItemContent } from '@/design-system/patterns/element-anatomy/item-anatomy'\n\n/**\n * ProfileCardDefaultActions — canonical 預設 action 組合\n *\n * ── 為什麼需要 export ──\n * ProfileCard 的 action 列在世界級 chat/contact app 是「關係型快速動作」的 canonical\n * (Slack / iMessage / LinkedIn / Figma 皆如此):**Chat / Message + Audio call**。\n * 跨 consumer(avatar.principles / profile-card.stories / future product code)應該用\n * 同一組預設,避免每個範例各自發明 action 組合,讓 reader 誤以為 action 會隨情境自動變。\n *\n * ── 使用方式(hover context 必含 onViewMore — canonical owner 見 avatar.spec.md「onViewMore 為 hover context 必含」段;顯示條件見 profile-card.spec.md「View More」節)──\n * <ProfileCard name=\"...\" actions={<ProfileCardDefaultActions />} onViewMore={...} />\n *\n * ── 何時要換成自訂 action ──\n * - Single-action 情境(只要「傳訊息」)→ consumer 傳 `<Button>傳訊息</Button>`\n * - 特定情境的 action(管理員「撤銷邀請」/ HR「離職管理」)→ consumer 自訂\n * - 非人員關係動作(「訂購此商品」)→ 根本不應該用 ProfileCard\n *\n * Chat + Audio call 是 **default**,不是 **only**——consumer 可覆寫,但需有明確理由。\n */\nexport const ProfileCardDefaultActions = ({\n onChat,\n onCall,\n}: {\n /** Chat 按鈕 handler(2026-07-06 user 拍板:預設鈕必可接線,未傳 = dev-warn;PersonData.onChat 自動 forward) */\n onChat?: () => void\n /** Audio call 按鈕 handler(ChevronDown 下拉行為留 v2,先接主 callback) */\n onCall?: () => void\n}) => {\n // Dev-mode warning(對齊本檔 defaultFieldValues dev-warn 先例):預設 actions 沒接 handler\n // = 按鈕點了永遠沒反應(2026-07-06 D4 finding);production 必傳 callback 或自組 actions。\n if (process.env.NODE_ENV !== 'production' && !onChat && !onCall) {\n // eslint-disable-next-line no-console\n console.warn(\n '[DS ProfileCard] ProfileCardDefaultActions 未接 onChat/onCall——按鈕點擊無反應。請傳入 callback(PersonData.onChat/onCall 會自動 forward)或自組 actions。'\n )\n }\n return (\n <>\n <Button variant=\"tertiary\" size=\"sm\" startIcon={MessageCircle} onClick={onChat}>Chat</Button>\n <Button variant=\"tertiary\" size=\"sm\" startIcon={Phone} endIcon={ChevronDown} onClick={onCall}>Audio call</Button>\n </>\n )\n}\n\n/**\n * ProfileCard — 人員 HoverCard 的內容元件\n *\n * ── Status 對齊 Avatar presence canonical(2026-04-20) ──\n * status type = `online | away | busy | offline`,跟 Avatar 的 presence prop 對齊\n * (世界級 Slack / Teams / Discord term);dot 色走 `--status-*` semantic token\n * (獨立於 success/error/warning,避免語義衝突)。\n *\n * ── Avatar 對齊 ──\n * 跟 FileItem rich 統一:右側 text column 用 justify-center + minHeight=avatar。\n * 短文字置中於 avatar,長文字(多行名字)自然撐高。\n *\n * ── Info fields ──\n * Status message / ID / Employee number 等唯讀屬性全部用 DescriptionList 家族\n * 承載(不手刻 dt/dd),canonical 由 DS primitive own。\n */\n\nconst AVATAR_SIZE = 64\n\ntype StatusType = 'online' | 'away' | 'busy' | 'offline'\n\n// Presence semantic tokens(見 color/semantic.css)——跟 Avatar status dot 共用\nconst STATUS_DOT_COLOR: Record<StatusType, string> = {\n online: 'var(--status-online)',\n away: 'var(--status-away)',\n busy: 'var(--status-busy)',\n offline: 'var(--status-offline)',\n}\n\nconst STATUS_LABEL: Record<StatusType, string> = {\n online: 'Online',\n away: 'Away',\n busy: 'Busy',\n offline: 'Offline',\n}\n\n/**\n * ProfileCard SSOT — 預設 field keys(現行 v15.7:default 只 `id` + `employeeNumber`;\n * v11 always-render 為歷史脈絡,已退役 — 見下方 2026-05-07 註解 + render 處 v12 註解)\n *\n * ── 為什麼 SSOT ──\n * User explicit rule:「所有 namecard 預設顯示的資訊都是要一樣完整的」。前 v10 props\n * 全 optional + body conditional render → consumer 漏傳 fields 視覺缺 section,每個範例\n * 各自不一致(同 person 在 DataTable / PeoplePicker / avatar.principles 看起來不同)。\n *\n * v11 canonical(歷史):ProfileCard 當時 always renders 4 default sections — 缺 data → 顯\n * `EMPTY_PLACEHOLDER`(\"-\")。現行:default fields 縮為 2(v15.7)+ status 條件 render(v12),\n * 「視覺結構 SSOT 在此元件,不依賴 consumer」原則不變。\n *\n * ── 對齊 world-class ──\n * Slack profile card / Linear member card / Notion person card / GitHub user card / Figma user card\n * 都是 fixed schema(role / email / location / department / department / pronouns 等),\n * 不會因為某 user 沒填 phone 整個 phone field 不見 — 缺 = 顯 `Not set` 或留白。\n *\n * ── 為什麼 placeholder 不 hide ──\n * Hide → consumer 不知道少傳 → 視覺漂移;Placeholder → 永遠看到「該欄該有」+ dev-warn 提示\n * consumer 補資料,自動防漂移(M19 ensure-canonical 對齊)。\n */\n// **2026-05-07 v15.7 user directive**:default render 只 `id` + `employeeNumber` 兩個。\n// Email / Phone / Department / Location 等其他 description 一律 opt-in by consumer 透過\n// `fields` array prop。對齊 user 明確「應該確保所有都只有這兩個,因為我並沒有要求你要選其他的」。\nexport const NAMECARD_DEFAULT_FIELD_KEYS = ['id', 'employeeNumber'] as const\ntype ProfileCardDefaultFieldKey = typeof NAMECARD_DEFAULT_FIELD_KEYS[number]\n\nconst DEFAULT_FIELD_LABEL: Record<ProfileCardDefaultFieldKey, string> = {\n id: 'ID',\n employeeNumber: 'Employee number',\n}\n\nconst FIELD_PLACEHOLDER = '-'\n\nexport interface ProfileCardProps extends React.HTMLAttributes<HTMLDivElement> {\n name: string\n avatar?: AvatarData\n subtitle?: string\n status?: StatusType\n statusMessage?: React.ReactNode\n actions?: React.ReactNode\n /**\n * Consumer 傳的 field 資料(partial)。預設 keys 走 `NAMECARD_DEFAULT_FIELD_KEYS` —\n * 只有 id / employeeNumber 兩個 default field 永遠 render(缺資料顯 `-`);email / phone /\n * department / location 等其他欄位一律 opt-in by consumer 透過本 prop 傳入。Consumer 想新增\n * 自訂 field 直接傳入(在 default 之後 append),想 override default key value 也直接傳。\n */\n fields?: { label: string; value: React.ReactNode }[]\n /**\n * Default field 的真實值。Object key = NAMECARD_DEFAULT_FIELD_KEYS 之一。\n * 缺 key → render placeholder。Dev mode 會 console.warn 提醒消費者補資料。\n */\n defaultFieldValues?: Partial<Record<ProfileCardDefaultFieldKey, React.ReactNode>>\n onViewMore?: () => void\n viewMoreLabel?: string\n}\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst ProfileCard = React.forwardRef<HTMLDivElement, ProfileCardProps>(\n (\n {\n name,\n avatar,\n subtitle,\n status,\n statusMessage,\n actions,\n fields,\n defaultFieldValues,\n onViewMore,\n viewMoreLabel = 'View more',\n className,\n ...props\n },\n ref,\n ) => {\n // v12 canonical:default fields 永遠 render(缺資料顯 placeholder),consumer 自訂\n // fields 在 default 之後 append。Status section 為條件 render(status undefined →\n // 整 block 隱藏,見下方 render 處)— v11「永遠 render + placeholder」已退役。\n //\n // **Dedup canonical(2026-05-07 v15.8 fix Bug E)**:consumer 的 `fields` array 若含\n // label 撞 default(eg. 「ID」「Employee number」),consumer 值 win — defaults 那一行\n // 跳過(否則 same label 連 render 兩次,如 default placeholder `-` + consumer 真值)。\n // 這是遷移期 forgiving 行為:DEV warn 提示應改用 `defaultFieldValues`,但 production\n // 不破壞既有 consumer。對齊 React `key` 唯一性 + Linear / Slack profile card 一 label\n // 一 row idiom。\n const allFields = React.useMemo(() => {\n const consumerLabels = new Set((fields ?? []).map((f) => f.label))\n const defaults = NAMECARD_DEFAULT_FIELD_KEYS\n .map((key) => ({\n label: DEFAULT_FIELD_LABEL[key],\n value: defaultFieldValues?.[key] ?? FIELD_PLACEHOLDER,\n }))\n .filter((d) => !consumerLabels.has(d.label))\n return fields && fields.length > 0 ? [...defaults, ...fields] : defaults\n }, [defaultFieldValues, fields])\n\n // Dev warn:consumer 透過 `fields` 傳 default key label(legacy pattern)→ 應改 `defaultFieldValues`\n if (process.env.NODE_ENV !== 'production' && fields) {\n const legacyEntry = fields.find((f) =>\n Object.values(DEFAULT_FIELD_LABEL).includes(f.label as string),\n )\n if (legacyEntry) {\n // eslint-disable-next-line no-console\n console.warn(\n `[ProfileCard] \"${name}\":legacy pattern — fields[].label=\"${legacyEntry.label}\" ` +\n `is a default field. Migrate to defaultFieldValues={{ id, employeeNumber }} prop ` +\n `to align with NAMECARD_DEFAULT_FIELD_KEYS canonical.`,\n )\n }\n }\n\n // Dev mode warn:consumer 沒傳 default field 任何 key → 提示補完(避免漂移成 placeholder-only)\n if (process.env.NODE_ENV !== 'production' && !defaultFieldValues) {\n // eslint-disable-next-line no-console\n console.warn(\n `[ProfileCard] \"${name}\":no defaultFieldValues passed — sections will render placeholders. ` +\n `Pass at least { id, employeeNumber } via defaultFieldValues prop. ` +\n `For other description items (email/phone/department/location etc),use \\`fields\\` prop array.`,\n )\n }\n\n // Layout canonical(2026-04-23):Header + Actions 固定上,Body(status + fields)可捲動,\n // View more 固定下。**ProfileCard 自己約束高度**,不依賴 consumer HoverCardContent 設 flex:\n // - `max-h-[var(--radix-hover-card-content-available-height,...)]`:HoverCard / Popover\n // context 自動繼承 Radix viewport-aware 變數;standalone 落到 100vh fallback\n // - 內部 `flex flex-col + overflow-hidden`:Header(shrink-0)+ Body(flex-1 min-h-0 ScrollArea)\n // + Footer(shrink-0)三層 chrome\n // 世界級對照:Slack / Linear / GitHub / Notion hover-profile popover 皆此 chrome pattern。\n return (\n <div\n ref={ref}\n className={cn(\n 'w-[320px] flex flex-col overflow-hidden',\n 'max-h-[var(--radix-hover-card-content-available-height,var(--radix-popover-content-available-height,100vh))]',\n className,\n )}\n {...props}\n >\n {/* ── HEADER(固定): profile + actions ── */}\n <div className=\"shrink-0 flex flex-col\">\n <div className=\"flex items-start gap-3 px-4 py-3\">\n <Avatar\n src={avatar?.src}\n alt={avatar?.alt ?? name}\n color={avatar?.color}\n size={AVATAR_SIZE}\n status={status}\n className=\"shrink-0\"\n />\n {/* ProfileCard typography:label body-lg(16/1.5) + desc body(14/1.5) = reading mode + size=\"lg\"。\n labelClassName escape hatch 加 font-medium(card context 語意)+ labelTruncate=false 允許 wrap。 */}\n <ItemContent\n label={name}\n description={subtitle}\n mode=\"reading\"\n size=\"lg\"\n labelTruncate={false}\n labelClassName=\"text-body-lg font-medium text-foreground\"\n className=\"justify-center\"\n style={{ minHeight: AVATAR_SIZE }}\n />\n </div>\n\n {/* Action buttons — 均分空間 + 填滿格子(canonical):多個 action 等寬瓜分容器,\n 單一 action 也撐滿容器。`grid grid-flow-col auto-cols-fr` + `[&>*]:w-full`。\n 世界級對照:iOS contact card / macOS contact / LinkedIn profile card 的 action row。 */}\n {actions && (\n <div className=\"grid grid-flow-col auto-cols-fr gap-2 px-4 pb-3 [&>*]:w-full\">\n {actions}\n </div>\n )}\n </div>\n\n {/* ── BODY(可捲動,v12 status-conditional 2026-05-14):status + fields ──\n **v12 rule**(per user 拍板「不應該顯示『狀態沒有被設定』,production 每 user 一定有\n presence state,undefined 頂多是 loading transient 還沒讀到」):status undefined →\n 隱藏整 status badge + status message block(loading 期間 skip),禁 render「Status not\n set」這種 placeholder(語義錯,user presence 不會「沒設定」)。**ProfileCard-specific 不外推\n 至 DS 其他元件**(FileItem / DescriptionList / DataTable cell 各自 placeholder 邏輯\n unrelated)。Fields section 仍 always-render(info schema 性質)。 */}\n <ScrollArea className=\"flex-1 min-h-0 border-t border-divider\">\n {/* Status section:`status` defined 才 render(v12 conditional canonical) */}\n {status && (\n <div className=\"px-4 py-3 flex flex-col gap-3\">\n <div className=\"flex items-center gap-2 px-3 py-2 bg-muted rounded-md\">\n <span\n className=\"w-2.5 h-2.5 rounded-full shrink-0\"\n style={{ backgroundColor: STATUS_DOT_COLOR[status] }}\n />\n <span className=\"text-body\">{STATUS_LABEL[status]}</span>\n </div>\n {/* Status message — 只在 status defined 才 render(語意配對:status badge + status\n message 是一組;沒 status 就沒 status message)。缺 statusMessage 顯 placeholder。 */}\n <DescriptionList>\n <DescriptionItem label=\"Status message\">\n {statusMessage ?? <span className=\"text-foreground\">{FIELD_PLACEHOLDER}</span>}\n </DescriptionItem>\n </DescriptionList>\n </div>\n )}\n\n {/* Fields section:status defined 才有 border-t separator;無 status section 時去除 border-t(因 ScrollArea 起點已有上方 border-t,不重疊) */}\n <div className={cn('px-4 py-3', status && 'border-t border-divider')}>\n <DescriptionList cols={2}>\n {allFields.map((f) => (\n <DescriptionItem key={f.label} label={f.label}>\n {f.value === FIELD_PLACEHOLDER\n ? <span className=\"text-foreground\">{FIELD_PLACEHOLDER}</span>\n : f.value}\n </DescriptionItem>\n ))}\n </DescriptionList>\n </div>\n </ScrollArea>\n\n {/* ── FOOTER(固定): View more,py-3 canonical(12px,比一般 link 按鈕多呼吸) ── */}\n {onViewMore && (\n <div className=\"shrink-0 border-t border-divider px-4 py-3\">\n <Button variant=\"link\" size=\"sm\" onClick={onViewMore} className=\"w-full\">{viewMoreLabel}</Button>\n </div>\n )}\n </div>\n )\n },\n)\nProfileCard.displayName = 'ProfileCard'\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 nameCardMeta = {\n component: 'ProfileCard',\n family: null, // non-family composite / overlay / layout\n variants: {\n\n },\n sizes: {\n\n },\n states: [], // 唯讀 person-info template,無自身互動 state(hover/active/focus/disabled 屬子 Button/Avatar)\n tokens: {\n bg: ['bg-muted'],\n fg: ['text-foreground'],\n ring: [],\n },\n} as const\n\nexport { ProfileCard }\n"],"names":[],"mappings":";;;;;;;;;AAoCO,MAAM,4BAA4B,CAAC;AAAA,EACxC;AAAA,EACA;AACF,MAKM;AAGJ,MAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,UAAU,CAAC,QAAQ;AAE/D,YAAQ;AAAA,MACN;AAAA,IAAA;AAAA,EAEJ;AACA,SACE,qBAAA,UAAA,EACE,UAAA;AAAA,IAAA,oBAAC,QAAA,EAAO,SAAQ,YAAW,MAAK,MAAK,WAAW,eAAe,SAAS,QAAQ,UAAA,OAAA,CAAI;AAAA,IACpF,oBAAC,QAAA,EAAO,SAAQ,YAAW,MAAK,MAAK,WAAW,OAAO,SAAS,aAAa,SAAS,QAAQ,UAAA,aAAA,CAAU;AAAA,EAAA,GAC1G;AAEJ;AAmBA,MAAM,cAAc;AAKpB,MAAM,mBAA+C;AAAA,EACnD,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AACX;AAEA,MAAM,eAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AACX;AA2BO,MAAM,8BAA8B,CAAC,MAAM,gBAAgB;AAGlE,MAAM,sBAAkE;AAAA,EACtE,IAAI;AAAA,EACJ,gBAAgB;AAClB;AAEA,MAAM,oBAAoB;AA0B1B,MAAM,cAAc,MAAM;AAAA,EACxB,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB;AAAA,IAChB;AAAA,IACA,GAAG;AAAA,EAAA,GAEL,QACG;AAWH,UAAM,YAAY,MAAM,QAAQ,MAAM;AACpC,YAAM,iBAAiB,IAAI,KAAK,UAAU,CAAA,GAAI,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AACjE,YAAM,WAAW,4BACd,IAAI,CAAC,SAAS;AAAA,QACb,OAAO,oBAAoB,GAAG;AAAA,QAC9B,QAAO,yDAAqB,SAAQ;AAAA,MAAA,EACpC,EACD,OAAO,CAAC,MAAM,CAAC,eAAe,IAAI,EAAE,KAAK,CAAC;AAC7C,aAAO,UAAU,OAAO,SAAS,IAAI,CAAC,GAAG,UAAU,GAAG,MAAM,IAAI;AAAA,IAClE,GAAG,CAAC,oBAAoB,MAAM,CAAC;AAG/B,QAAI,QAAQ,IAAI,aAAa,gBAAgB,QAAQ;AACnD,YAAM,cAAc,OAAO;AAAA,QAAK,CAAC,MAC/B,OAAO,OAAO,mBAAmB,EAAE,SAAS,EAAE,KAAe;AAAA,MAAA;AAE/D,UAAI,aAAa;AAEf,gBAAQ;AAAA,UACN,kBAAkB,IAAI,sCAAsC,YAAY,KAAK;AAAA,QAAA;AAAA,MAIjF;AAAA,IACF;AAGA,QAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,oBAAoB;AAEhE,cAAQ;AAAA,QACN,kBAAkB,IAAI;AAAA,MAAA;AAAA,IAI1B;AASA,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,QAED,GAAG;AAAA,QAGJ,UAAA;AAAA,UAAA,qBAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,YAAA,qBAAC,OAAA,EAAI,WAAU,oCACb,UAAA;AAAA,cAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,KAAK,iCAAQ;AAAA,kBACb,MAAK,iCAAQ,QAAO;AAAA,kBACpB,OAAO,iCAAQ;AAAA,kBACf,MAAM;AAAA,kBACN;AAAA,kBACA,WAAU;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIZ;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,OAAO;AAAA,kBACP,aAAa;AAAA,kBACb,MAAK;AAAA,kBACL,MAAK;AAAA,kBACL,eAAe;AAAA,kBACf,gBAAe;AAAA,kBACf,WAAU;AAAA,kBACV,OAAO,EAAE,WAAW,YAAA;AAAA,gBAAY;AAAA,cAAA;AAAA,YAClC,GACF;AAAA,YAKC,WACC,oBAAC,OAAA,EAAI,WAAU,gEACZ,UAAA,QAAA,CACH;AAAA,UAAA,GAEJ;AAAA,UASA,qBAAC,YAAA,EAAW,WAAU,0CAEnB,UAAA;AAAA,YAAA,UACC,qBAAC,OAAA,EAAI,WAAU,iCACb,UAAA;AAAA,cAAA,qBAAC,OAAA,EAAI,WAAU,yDACb,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO,EAAE,iBAAiB,iBAAiB,MAAM,EAAA;AAAA,kBAAE;AAAA,gBAAA;AAAA,oCAEpD,QAAA,EAAK,WAAU,aAAa,UAAA,aAAa,MAAM,EAAA,CAAE;AAAA,cAAA,GACpD;AAAA,cAGA,oBAAC,iBAAA,EACC,UAAA,oBAAC,iBAAA,EAAgB,OAAM,kBACpB,UAAA,iBAAiB,oBAAC,QAAA,EAAK,WAAU,mBAAmB,UAAA,kBAAA,CAAkB,GACzE,EAAA,CACF;AAAA,YAAA,GACF;AAAA,gCAID,OAAA,EAAI,WAAW,GAAG,aAAa,UAAU,yBAAyB,GACjE,UAAA,oBAAC,iBAAA,EAAgB,MAAM,GACpB,UAAA,UAAU,IAAI,CAAC,MACd,oBAAC,iBAAA,EAA8B,OAAO,EAAE,OACrC,UAAA,EAAE,UAAU,oBACT,oBAAC,UAAK,WAAU,mBAAmB,UAAA,mBAAkB,IACrD,EAAE,MAAA,GAHc,EAAE,KAIxB,CACD,GACH,EAAA,CACF;AAAA,UAAA,GACF;AAAA,UAGC,cACC,oBAAC,OAAA,EAAI,WAAU,8CACb,8BAAC,QAAA,EAAO,SAAQ,QAAO,MAAK,MAAK,SAAS,YAAY,WAAU,UAAU,yBAAc,EAAA,CAC1F;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AACA,YAAY,cAAc;AAInB,MAAM,eAAe;AAAA,EAC1B,WAAW;AAAA,EACX,QAAQ;AAAA;AAAA,EACR,UAAU,CAAA;AAAA,EAGV,OAAO,CAAA;AAAA,EAGP,QAAQ,CAAA;AAAA;AAAA,EACR,QAAQ;AAAA,IACN,IAAI,CAAC,UAAU;AAAA,IACf,IAAI,CAAC,iBAAiB;AAAA,IACtB,MAAM,CAAA;AAAA,EAAC;AAEX;"}
@@ -4,11 +4,11 @@ import { type VariantProps } from "class-variance-authority";
4
4
  import type { FieldMode, FieldVariant } from "../../components/Field/field-types";
5
5
  import type { LucideIcon } from "lucide-react";
6
6
  import type { AvatarData } from "../../components/Avatar/avatar";
7
- export interface RadioGroupProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root> {
7
+ export interface RadioGroupProps extends Omit<React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>, 'asChild'> {
8
8
  /**
9
9
  * Field mode(2026-05-05 Phase B3 align):
10
10
  * edit — 一般可互動 RadioGroup(預設)
11
- * display — **純展示**:不渲染 Radix Root / 任何 radio 視覺;RadioGroup 本體 walk
11
+ * view — **純展示**:不渲染 Radix Root / 任何 radio 視覺;RadioGroup 本體 walk
12
12
  * children,僅 control.value === group.value 那筆把 label 渲染為純文字 span。
13
13
  * 對齊 Carbon read-only / DataTable single-select cell read mode。
14
14
  * readonly — standalone:ReadonlyContext 傳 items 鎖互動保留視覺;Field 內:灰框 + 選中項 label(不渲染 radio 群組)
@@ -26,7 +26,7 @@ declare const radioItemVariants: (props?: ({
26
26
  size?: "sm" | "md" | "lg" | null | undefined;
27
27
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
28
28
  type RadioItemPrimitiveProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>;
29
- export interface RadioGroupItemProps extends RadioItemPrimitiveProps, VariantProps<typeof radioItemVariants> {
29
+ export interface RadioGroupItemProps extends Omit<RadioItemPrimitiveProps, 'asChild' | 'children'>, VariantProps<typeof radioItemVariants> {
30
30
  /**
31
31
  * Inline label。提供時 RadioGroupItem 自動透過 SelectionItem 包裝,
32
32
  * 套用 codified 樣式(text-body / text-foreground / disabled 色)。
@@ -1 +1 @@
1
- {"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../../src/components/RadioGroup/radio-group.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,mBAAmB,MAAM,6BAA6B,CAAA;AAElE,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAG3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAA;AAa1E,MAAM,WAAW,eACf,SAAQ,KAAK,CAAC,wBAAwB,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC;IACvE;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAkCD,QAAA,MAAM,UAAU,wFAsGd,CAAA;AAWF,QAAA,MAAM,iBAAiB;;8EA2BtB,CAAA;AAOD,KAAK,uBAAuB,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;AAE9F,MAAM,WAAW,mBACf,SAAQ,uBAAuB,EAC7B,YAAY,CAAC,OAAO,iBAAiB,CAAC;IACxC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,qHAAqH;IACrH,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAID,QAAA,MAAM,cAAc,+FA6FnB,CAAA;AAKD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBjB,CAAA;AAEV,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA"}
1
+ {"version":3,"file":"radio-group.d.ts","sourceRoot":"","sources":["../../../src/components/RadioGroup/radio-group.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,mBAAmB,MAAM,6BAA6B,CAAA;AAElE,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAGjE,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAG3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0CAA0C,CAAA;AAa1E,MAAM,WAAW,eAIf,SAAQ,IAAI,CAAC,KAAK,CAAC,wBAAwB,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IACxF;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAkCD,QAAA,MAAM,UAAU,wFAsGd,CAAA;AAWF,QAAA,MAAM,iBAAiB;;8EA2BtB,CAAA;AAOD,KAAK,uBAAuB,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;AAE9F,MAAM,WAAW,mBAGf,SAAQ,IAAI,CAAC,uBAAuB,EAAE,SAAS,GAAG,UAAU,CAAC,EAC3D,YAAY,CAAC,OAAO,iBAAiB,CAAC;IACxC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,qHAAqH;IACrH,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAID,QAAA,MAAM,cAAc,+FA6FnB,CAAA;AAKD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBjB,CAAA;AAEV,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA"}
@@ -45,7 +45,7 @@ const RadioGroup = React.forwardRef(({ className, mode, variant: _chrome, value,
45
45
  children: _children,
46
46
  ...restDomProps
47
47
  } = props;
48
- if (resolvedMode === "display") {
48
+ if (resolvedMode === "view") {
49
49
  const selectedValue = value ?? defaultValue;
50
50
  if (!selectedValue) {
51
51
  return /* @__PURE__ */ jsx("div", { ...restDomProps, ref, role: "group", className: cn("grid", className), children: /* @__PURE__ */ jsx("span", { className: fieldEmptyColorClass(resolvedMode), children: emptyDisplay }) });