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

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 (604) hide show
  1. package/CLAUDE.md +8 -8
  2. package/README.md +3 -2
  3. package/dist/components/Alert/alert.js.map +1 -1
  4. package/dist/components/AppShell/_demo-helpers.d.ts.map +1 -1
  5. package/dist/components/AppShell/app-shell.d.ts +1 -1
  6. package/dist/components/AppShell/app-shell.d.ts.map +1 -1
  7. package/dist/components/AppShell/app-shell.js +22 -2
  8. package/dist/components/AppShell/app-shell.js.map +1 -1
  9. package/dist/components/Avatar/avatar.d.ts.map +1 -1
  10. package/dist/components/Avatar/avatar.js +4 -4
  11. package/dist/components/Avatar/avatar.js.map +1 -1
  12. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  13. package/dist/components/Breadcrumb/breadcrumb.js +1 -1
  14. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  15. package/dist/components/Button/button.d.ts +2 -2
  16. package/dist/components/Button/button.d.ts.map +1 -1
  17. package/dist/components/Button/button.js +12 -3
  18. package/dist/components/Button/button.js.map +1 -1
  19. package/dist/components/Calendar/calendar.d.ts +13 -5
  20. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  21. package/dist/components/Calendar/calendar.js +7 -1
  22. package/dist/components/Calendar/calendar.js.map +1 -1
  23. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  24. package/dist/components/Carousel/carousel.js +8 -3
  25. package/dist/components/Carousel/carousel.js.map +1 -1
  26. package/dist/components/Chart/chart.d.ts.map +1 -1
  27. package/dist/components/Chart/chart.js +1 -0
  28. package/dist/components/Chart/chart.js.map +1 -1
  29. package/dist/components/Checkbox/checkbox.d.ts +1 -1
  30. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  31. package/dist/components/Checkbox/checkbox.js +8 -4
  32. package/dist/components/Checkbox/checkbox.js.map +1 -1
  33. package/dist/components/Chip/chip.d.ts +1 -1
  34. package/dist/components/Chip/chip.d.ts.map +1 -1
  35. package/dist/components/Chip/chip.js.map +1 -1
  36. package/dist/components/Coachmark/coachmark.d.ts +10 -3
  37. package/dist/components/Coachmark/coachmark.d.ts.map +1 -1
  38. package/dist/components/Coachmark/coachmark.js.map +1 -1
  39. package/dist/components/Combobox/combobox.d.ts +5 -1
  40. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  41. package/dist/components/Combobox/combobox.js +30 -13
  42. package/dist/components/Combobox/combobox.js.map +1 -1
  43. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  44. package/dist/components/DataTable/cell-registry.js +53 -62
  45. package/dist/components/DataTable/cell-registry.js.map +1 -1
  46. package/dist/components/DataTable/column-types.d.ts +10 -4
  47. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  48. package/dist/components/DataTable/column-types.js.map +1 -1
  49. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts +1 -1
  50. package/dist/components/DataTable/data-table-column-visibility-panel.js +183 -0
  51. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -0
  52. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  53. package/dist/components/DataTable/data-table-filter-panel.js +607 -0
  54. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -0
  55. package/dist/components/DataTable/data-table-interaction-layer.d.ts +11 -15
  56. package/dist/components/DataTable/data-table-interaction-layer.d.ts.map +1 -1
  57. package/dist/components/DataTable/data-table-interaction-layer.js +1 -3
  58. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  59. package/dist/components/DataTable/data-table-sort-manager.js +140 -0
  60. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -0
  61. package/dist/components/DataTable/data-table.d.ts +5 -6
  62. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  63. package/dist/components/DataTable/data-table.js +36 -15
  64. package/dist/components/DataTable/data-table.js.map +1 -1
  65. package/dist/components/DataTable/filter-operators.js +140 -0
  66. package/dist/components/DataTable/filter-operators.js.map +1 -0
  67. package/dist/components/DataTable/filter-tree.js +312 -0
  68. package/dist/components/DataTable/filter-tree.js.map +1 -0
  69. package/dist/components/DataTable/index.d.ts +3 -0
  70. package/dist/components/DataTable/index.d.ts.map +1 -1
  71. package/dist/components/DataTable/index.js +12 -1
  72. package/dist/components/DataTable/index.js.map +1 -1
  73. package/dist/components/DataTable/lib/column-meta.js +25 -0
  74. package/dist/components/DataTable/lib/column-meta.js.map +1 -0
  75. package/dist/components/DateGrid/date-grid.d.ts.map +1 -1
  76. package/dist/components/DateGrid/date-grid.js +3 -1
  77. package/dist/components/DateGrid/date-grid.js.map +1 -1
  78. package/dist/components/DatePicker/date-picker.d.ts +7 -1
  79. package/dist/components/DatePicker/date-picker.d.ts.map +1 -1
  80. package/dist/components/DatePicker/date-picker.js +105 -74
  81. package/dist/components/DatePicker/date-picker.js.map +1 -1
  82. package/dist/components/Dialog/dialog.d.ts +20 -3
  83. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  84. package/dist/components/Dialog/dialog.js +38 -20
  85. package/dist/components/Dialog/dialog.js.map +1 -1
  86. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  87. package/dist/components/DropdownMenu/dropdown-menu.js +3 -1
  88. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  89. package/dist/components/Field/field-context.d.ts +45 -5
  90. package/dist/components/Field/field-context.d.ts.map +1 -1
  91. package/dist/components/Field/field-context.js +19 -0
  92. package/dist/components/Field/field-context.js.map +1 -1
  93. package/dist/components/Field/field-edit-keys.d.ts +21 -0
  94. package/dist/components/Field/field-edit-keys.d.ts.map +1 -0
  95. package/dist/components/Field/field-edit-keys.js +19 -0
  96. package/dist/components/Field/field-edit-keys.js.map +1 -0
  97. package/dist/components/Field/field-types.d.ts +20 -1
  98. package/dist/components/Field/field-types.d.ts.map +1 -1
  99. package/dist/components/Field/field-types.js.map +1 -1
  100. package/dist/components/Field/field-wrapper.d.ts +3 -2
  101. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  102. package/dist/components/Field/field-wrapper.js +38 -39
  103. package/dist/components/Field/field-wrapper.js.map +1 -1
  104. package/dist/components/Field/field.d.ts +2 -1
  105. package/dist/components/Field/field.d.ts.map +1 -1
  106. package/dist/components/Field/field.js.map +1 -1
  107. package/dist/components/FieldControlGroup/field-control-group.d.ts +1 -1
  108. package/dist/components/FieldControlGroup/field-control-group.js.map +1 -1
  109. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  110. package/dist/components/FileItem/file-item.js +1 -1
  111. package/dist/components/FileItem/file-item.js.map +1 -1
  112. package/dist/components/FileUpload/file-upload.d.ts +1 -1
  113. package/dist/components/FileUpload/file-upload.js.map +1 -1
  114. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  115. package/dist/components/FileViewer/file-viewer.js +7 -2
  116. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  117. package/dist/components/FileViewer/image-renderer.d.ts.map +1 -1
  118. package/dist/components/FileViewer/image-renderer.js +22 -1
  119. package/dist/components/FileViewer/image-renderer.js.map +1 -1
  120. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  121. package/dist/components/HoverCard/hover-card.js +5 -3
  122. package/dist/components/HoverCard/hover-card.js.map +1 -1
  123. package/dist/components/InlineEdit/index.d.ts +2 -0
  124. package/dist/components/InlineEdit/index.d.ts.map +1 -0
  125. package/dist/components/InlineEdit/index.js +5 -0
  126. package/dist/components/InlineEdit/index.js.map +1 -0
  127. package/dist/components/InlineEdit/inline-edit.d.ts +59 -0
  128. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -0
  129. package/dist/components/InlineEdit/inline-edit.js +164 -0
  130. package/dist/components/InlineEdit/inline-edit.js.map +1 -0
  131. package/dist/components/Input/input.d.ts +6 -11
  132. package/dist/components/Input/input.d.ts.map +1 -1
  133. package/dist/components/Input/input.js +43 -13
  134. package/dist/components/Input/input.js.map +1 -1
  135. package/dist/components/LinkInput/link-input.d.ts +2 -2
  136. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  137. package/dist/components/LinkInput/link-input.js +6 -5
  138. package/dist/components/LinkInput/link-input.js.map +1 -1
  139. package/dist/components/Menu/menu-item.d.ts +14 -2
  140. package/dist/components/Menu/menu-item.d.ts.map +1 -1
  141. package/dist/components/Menu/menu-item.js +25 -3
  142. package/dist/components/Menu/menu-item.js.map +1 -1
  143. package/dist/components/NumberInput/number-input.d.ts +3 -3
  144. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  145. package/dist/components/NumberInput/number-input.js +6 -5
  146. package/dist/components/NumberInput/number-input.js.map +1 -1
  147. package/dist/components/OverflowIndicator/overflow-indicator.d.ts.map +1 -1
  148. package/dist/components/OverflowIndicator/overflow-indicator.js +2 -6
  149. package/dist/components/OverflowIndicator/overflow-indicator.js.map +1 -1
  150. package/dist/components/Pagination/pagination.js +1 -1
  151. package/dist/components/Pagination/pagination.js.map +1 -1
  152. package/dist/components/PeoplePicker/index.js +7 -1
  153. package/dist/components/PeoplePicker/index.js.map +1 -1
  154. package/dist/components/PeoplePicker/people-picker.d.ts +9 -2
  155. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  156. package/dist/components/PeoplePicker/people-picker.js +23 -10
  157. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  158. package/dist/components/PeoplePicker/person-display.d.ts +6 -3
  159. package/dist/components/PeoplePicker/person-display.d.ts.map +1 -1
  160. package/dist/components/PeoplePicker/person-display.js +19 -14
  161. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  162. package/dist/components/Popover/popover.d.ts.map +1 -1
  163. package/dist/components/Popover/popover.js +3 -1
  164. package/dist/components/Popover/popover.js.map +1 -1
  165. package/dist/components/ProfileCard/profile-card.d.ts +2 -2
  166. package/dist/components/ProfileCard/profile-card.js +3 -3
  167. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  168. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  169. package/dist/components/RadioGroup/radio-group.js +15 -9
  170. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  171. package/dist/components/ScrollArea/scroll-area.d.ts +11 -1
  172. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  173. package/dist/components/ScrollArea/scroll-area.js +6 -3
  174. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  175. package/dist/components/Select/select.d.ts +46 -5
  176. package/dist/components/Select/select.d.ts.map +1 -1
  177. package/dist/components/Select/select.js +109 -28
  178. package/dist/components/Select/select.js.map +1 -1
  179. package/dist/components/SelectMenu/select-menu.d.ts +3 -1
  180. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  181. package/dist/components/SelectMenu/select-menu.js +8 -1
  182. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  183. package/dist/components/SelectionControl/boolean-value.d.ts +11 -0
  184. package/dist/components/SelectionControl/boolean-value.d.ts.map +1 -0
  185. package/dist/components/SelectionControl/boolean-value.js +23 -0
  186. package/dist/components/SelectionControl/boolean-value.js.map +1 -0
  187. package/dist/components/SelectionControl/index.d.ts +1 -0
  188. package/dist/components/SelectionControl/index.d.ts.map +1 -1
  189. package/dist/components/SelectionControl/index.js +2 -0
  190. package/dist/components/SelectionControl/index.js.map +1 -1
  191. package/dist/components/Sheet/index.js +2 -1
  192. package/dist/components/Sheet/sheet.d.ts +7 -1
  193. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  194. package/dist/components/Sheet/sheet.js +5 -2
  195. package/dist/components/Sheet/sheet.js.map +1 -1
  196. package/dist/components/Sidebar/sidebar.d.ts +9 -4
  197. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  198. package/dist/components/Sidebar/sidebar.js +8 -10
  199. package/dist/components/Sidebar/sidebar.js.map +1 -1
  200. package/dist/components/Slider/slider.d.ts.map +1 -1
  201. package/dist/components/Slider/slider.js.map +1 -1
  202. package/dist/components/Switch/switch.d.ts +6 -6
  203. package/dist/components/Switch/switch.d.ts.map +1 -1
  204. package/dist/components/Switch/switch.js +3 -2
  205. package/dist/components/Switch/switch.js.map +1 -1
  206. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  207. package/dist/components/Tabs/tabs.js +15 -1
  208. package/dist/components/Tabs/tabs.js.map +1 -1
  209. package/dist/components/Textarea/textarea.d.ts +2 -2
  210. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  211. package/dist/components/Textarea/textarea.js +50 -42
  212. package/dist/components/Textarea/textarea.js.map +1 -1
  213. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  214. package/dist/components/TimePicker/time-columns.js +42 -38
  215. package/dist/components/TimePicker/time-columns.js.map +1 -1
  216. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  217. package/dist/components/TimePicker/time-picker.js +8 -6
  218. package/dist/components/TimePicker/time-picker.js.map +1 -1
  219. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  220. package/dist/components/Tooltip/tooltip.js +7 -5
  221. package/dist/components/Tooltip/tooltip.js.map +1 -1
  222. package/dist/components/TreeView/tree-view.d.ts +56 -1
  223. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  224. package/dist/components/TreeView/tree-view.js +211 -12
  225. package/dist/components/TreeView/tree-view.js.map +1 -1
  226. package/dist/index.d.ts +115 -58
  227. package/dist/index.d.ts.map +1 -1
  228. package/dist/index.js +93 -108
  229. package/dist/index.js.map +1 -1
  230. package/dist/patterns/element-anatomy/item-anatomy.d.ts +7 -6
  231. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  232. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  233. package/dist/tokens/categorical-color.js +15 -0
  234. package/dist/tokens/categorical-color.js.map +1 -1
  235. package/dist/tokens/motion/motion.d.ts +7 -6
  236. package/dist/tokens/motion/motion.d.ts.map +1 -1
  237. package/dist/tokens/motion/motion.js +6 -6
  238. package/dist/tokens/motion/motion.js.map +1 -1
  239. package/dist/tokens/motion/overlay-motion.d.ts +19 -0
  240. package/dist/tokens/motion/overlay-motion.d.ts.map +1 -0
  241. package/dist/tokens/motion/overlay-motion.js +9 -0
  242. package/dist/tokens/motion/overlay-motion.js.map +1 -0
  243. package/dist/tokens/uiSize/icon-size.js +5 -0
  244. package/dist/tokens/uiSize/icon-size.js.map +1 -0
  245. package/ds-canonical/fork/governance.lock +31 -19
  246. package/ds-canonical/fork/hooks/_log-fire.sh +46 -0
  247. package/ds-canonical/fork/hooks/block_prototype_imports.py +15 -4
  248. package/ds-canonical/fork/hooks/check_consumer_app_invariants.sh +145 -13
  249. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +2 -1
  250. package/ds-canonical/fork/hooks/check_dynamic_tailwind_class.sh +47 -0
  251. package/ds-canonical/fork/hooks/check_escape_marker_abuse.sh +27 -0
  252. package/ds-canonical/fork/hooks/check_field_family_invariants.sh +61 -1
  253. package/ds-canonical/fork/hooks/check_layout_space_magic_numbers.sh +28 -4
  254. package/ds-canonical/fork/hooks/check_opacity_token_usage.sh +28 -0
  255. package/ds-canonical/fork/hooks/check_story_determinism.sh +2 -0
  256. package/ds-canonical/fork/hooks/check_story_invariants.sh +119 -0
  257. package/ds-canonical/fork/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  258. package/ds-canonical/fork/manifest.json +15 -0
  259. package/ds-canonical/fork/preamble.md +20 -18
  260. package/ds-canonical/fork/skills/bug-fix-rhythm/SKILL.md +3 -3
  261. package/ds-canonical/fork/skills/code-quality-audit/SKILL.md +3 -3
  262. package/ds-canonical/fork/skills/delivery-handoff/SKILL.md +1 -1
  263. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +3 -3
  264. package/ds-canonical/fork/skills/propose-options/SKILL.md +3 -3
  265. package/ds-canonical/fork/skills/prototype/SKILL.md +1 -1
  266. package/ds-canonical/fork/skills/scan-similar-bugs/SKILL.md +2 -2
  267. package/ds-canonical/fork/skills/visual-audit/SKILL.md +2 -2
  268. package/ds-canonical/hooks/README.md +1 -1
  269. package/ds-canonical/hooks/block_prototype_imports.py +15 -4
  270. package/ds-canonical/hooks/check_audit_post_report_validator.sh +65 -7
  271. package/ds-canonical/hooks/check_codex_brief_invariants.sh +28 -1
  272. package/ds-canonical/hooks/check_consumer_app_invariants.sh +145 -13
  273. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +2 -1
  274. package/ds-canonical/hooks/check_dynamic_tailwind_class.sh +47 -0
  275. package/ds-canonical/hooks/check_escape_marker_abuse.sh +27 -0
  276. package/ds-canonical/hooks/check_field_family_invariants.sh +61 -1
  277. package/ds-canonical/hooks/check_layout_space_magic_numbers.sh +28 -4
  278. package/ds-canonical/hooks/check_naming_and_abstraction.sh +1 -1
  279. package/ds-canonical/hooks/check_opacity_token_usage.sh +28 -0
  280. package/ds-canonical/hooks/check_pixel_quantified_audit.sh +3 -2
  281. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +6 -1
  282. package/ds-canonical/hooks/check_ssot_header_declaration.sh +3 -1
  283. package/ds-canonical/hooks/check_story_determinism.sh +2 -0
  284. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +8 -7
  285. package/ds-canonical/hooks/check_tabs_content_chrome_body_double_gap.sh +29 -0
  286. package/ds-canonical/hooks/lib/_story_compile_drift.sh +1 -1
  287. package/ds-canonical/hooks/lib/_token_hygiene.sh +10 -1
  288. package/ds-canonical/hooks/stop_self_audit.sh +31 -0
  289. package/ds-canonical/hooks/tests/test_block_prototype_imports.sh +24 -0
  290. package/ds-canonical/hooks/tests/test_check_audit_post_report_validator.sh +44 -0
  291. package/ds-canonical/hooks/tests/test_check_codex_brief_invariants.sh +43 -2
  292. package/ds-canonical/hooks/tests/test_check_consumer_ds_primitive_misuse.sh +112 -0
  293. package/ds-canonical/hooks/tests/test_check_consumer_story_baseline.sh +9 -2
  294. package/ds-canonical/hooks/tests/test_check_dynamic_tailwind_class.sh +76 -0
  295. package/ds-canonical/hooks/tests/test_check_escape_marker_abuse.sh +24 -0
  296. package/ds-canonical/hooks/tests/test_check_field_family_invariants.sh +27 -2
  297. package/ds-canonical/hooks/tests/test_check_opacity_token_usage.sh +39 -0
  298. package/ds-canonical/hooks/tests/test_check_tabs_content_chrome_body_double_gap.sh +76 -0
  299. package/ds-canonical/references/audit-coverage-vs-24-checklist.md +1 -1
  300. package/ds-canonical/references/build-ui-canonicals.md +2 -1
  301. package/ds-canonical/references/failure-class-registry.json +145 -0
  302. package/ds-canonical/references/governance-audit-coverage.md +33 -0
  303. package/ds-canonical/references/item-anatomy-recipe.md +2 -2
  304. package/ds-canonical/references/scenario-definition.md +6 -9
  305. package/ds-canonical/references/ssot-consultation.md +2 -2
  306. package/ds-canonical/references/ssot-index.md +5 -4
  307. package/ds-canonical/references/story-baseline-registry.json +8 -2
  308. package/ds-canonical/references/structural-token-retention.md +6 -9
  309. package/ds-canonical/rules/meta-patterns.md +8 -8
  310. package/ds-canonical/rules/self-verify.md +4 -3
  311. package/ds-canonical/rules/story-rules.md +2 -2
  312. package/ds-canonical/rules/ui-development.md +2 -2
  313. package/ds-canonical/skills/bug-fix-rhythm/SKILL.md +3 -3
  314. package/ds-canonical/skills/code-quality-audit/SKILL.md +3 -3
  315. package/ds-canonical/skills/codex-collab/SKILL.md +9 -7
  316. package/ds-canonical/skills/codex-collab/references/brief-template.md +1 -1
  317. package/ds-canonical/skills/codify-principle/SKILL.md +2 -2
  318. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  319. package/ds-canonical/skills/component-quality-gate/references/checklist.md +2 -2
  320. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +51 -58
  321. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-a-workflow.md +29 -0
  322. package/ds-canonical/skills/deep-audit-cross-codex/references/phase-b-codex-brief.md +29 -10
  323. package/ds-canonical/skills/deep-audit-cross-codex/references/triage-rubric.md +21 -0
  324. package/ds-canonical/skills/delivery-handoff/SKILL.md +1 -1
  325. package/ds-canonical/skills/design-system-audit/SKILL.md +26 -25
  326. package/ds-canonical/skills/design-system-audit/references/audit-prompts.md +13 -1
  327. package/ds-canonical/skills/design-system-audit/references/rule-placement.md +1 -1
  328. package/ds-canonical/skills/governance-health/SKILL.md +1 -1
  329. package/ds-canonical/skills/knowledge-prune/SKILL.md +3 -0
  330. package/ds-canonical/skills/knowledge-prune/references/prune-dimensions-d5-d10.md +1 -0
  331. package/ds-canonical/skills/new-component/SKILL.md +5 -5
  332. package/ds-canonical/skills/new-component/references/new-component-checklist.md +1 -1
  333. package/ds-canonical/skills/product-ui-audit/SKILL.md +3 -3
  334. package/ds-canonical/skills/propose-options/SKILL.md +3 -3
  335. package/ds-canonical/skills/prototype/SKILL.md +1 -1
  336. package/ds-canonical/skills/scan-similar-bugs/SKILL.md +2 -2
  337. package/ds-canonical/skills/story-auto-compile-migrate/SKILL.md +3 -3
  338. package/ds-canonical/skills/story-writing/SKILL.md +3 -3
  339. package/ds-canonical/skills/visual-audit/SKILL.md +2 -2
  340. package/ds-story-manifest.json +29 -20
  341. package/llms-full.txt +22 -1
  342. package/llms.txt +5 -4
  343. package/package.json +7 -3
  344. package/src/components/Accordion/accordion.principles.stories.tsx +1 -1
  345. package/src/components/Accordion/accordion.stories.tsx +16 -1
  346. package/src/components/Alert/alert.principles.stories.tsx +1 -1
  347. package/src/components/Alert/alert.spec.md +8 -10
  348. package/src/components/Alert/alert.stories.tsx +28 -28
  349. package/src/components/Alert/alert.tsx +1 -1
  350. package/src/components/AppShell/_demo-helpers.tsx +6 -3
  351. package/src/components/AppShell/app-shell.spec.md +4 -4
  352. package/src/components/AppShell/app-shell.tsx +28 -2
  353. package/src/components/AspectRatio/aspect-ratio.spec.md +1 -1
  354. package/src/components/AspectRatio/aspect-ratio.stories.tsx +7 -89
  355. package/src/components/Avatar/avatar.anatomy.stories.tsx +7 -3
  356. package/src/components/Avatar/avatar.principles.stories.tsx +19 -15
  357. package/src/components/Avatar/avatar.spec.md +2 -2
  358. package/src/components/Avatar/avatar.stories.tsx +8 -6
  359. package/src/components/Avatar/avatar.tsx +13 -5
  360. package/src/components/Badge/badge.principles.stories.tsx +1 -1
  361. package/src/components/Badge/badge.spec.md +2 -0
  362. package/src/components/Badge/badge.stories.tsx +4 -2
  363. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +6 -4
  364. package/src/components/Breadcrumb/breadcrumb.stories.tsx +6 -5
  365. package/src/components/Breadcrumb/breadcrumb.tsx +3 -2
  366. package/src/components/BulkActionBar/bulk-action-bar.spec.md +4 -2
  367. package/src/components/Button/button.principles.stories.tsx +1 -1
  368. package/src/components/Button/button.spec.md +2 -2
  369. package/src/components/Button/button.tsx +18 -3
  370. package/src/components/Calendar/calendar.anatomy.stories.tsx +12 -10
  371. package/src/components/Calendar/calendar.principles.stories.tsx +14 -6
  372. package/src/components/Calendar/calendar.spec.md +5 -4
  373. package/src/components/Calendar/calendar.stories.tsx +7 -4
  374. package/src/components/Calendar/calendar.tsx +26 -7
  375. package/src/components/Carousel/carousel.anatomy.stories.tsx +5 -4
  376. package/src/components/Carousel/carousel.spec.md +2 -2
  377. package/src/components/Carousel/carousel.tsx +11 -3
  378. package/src/components/Chart/chart.anatomy.stories.tsx +7 -4
  379. package/src/components/Chart/chart.principles.stories.tsx +1 -1
  380. package/src/components/Chart/chart.stories.tsx +2 -8
  381. package/src/components/Chart/chart.tsx +3 -0
  382. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +28 -49
  383. package/src/components/Checkbox/checkbox.principles.stories.tsx +1 -1
  384. package/src/components/Checkbox/checkbox.spec.md +11 -26
  385. package/src/components/Checkbox/checkbox.stories.tsx +11 -8
  386. package/src/components/Checkbox/checkbox.tsx +18 -13
  387. package/src/components/Chip/chip.anatomy.stories.tsx +44 -24
  388. package/src/components/Chip/chip.principles.stories.tsx +1 -1
  389. package/src/components/Chip/chip.spec.md +5 -4
  390. package/src/components/Chip/chip.tsx +5 -1
  391. package/src/components/CircularProgress/circular-progress.principles.stories.tsx +7 -4
  392. package/src/components/CircularProgress/circular-progress.spec.md +3 -3
  393. package/src/components/CircularProgress/circular-progress.stories.tsx +2 -2
  394. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +2 -2
  395. package/src/components/Coachmark/coachmark.principles.stories.tsx +2 -1
  396. package/src/components/Coachmark/coachmark.spec.md +5 -5
  397. package/src/components/Coachmark/coachmark.stories.tsx +3 -1
  398. package/src/components/Coachmark/coachmark.tsx +10 -3
  399. package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -2
  400. package/src/components/Combobox/combobox.tsx +53 -19
  401. package/src/components/Command/command.anatomy.stories.tsx +2 -2
  402. package/src/components/Command/command.principles.stories.tsx +1 -1
  403. package/src/components/Command/command.stories.tsx +42 -10
  404. package/src/components/DataTable/cell-registry.tsx +86 -63
  405. package/src/components/DataTable/column-types.ts +10 -1
  406. package/src/components/DataTable/data-table-column-visibility-panel.tsx +1 -1
  407. package/src/components/DataTable/data-table-filter-panel.tsx +4 -1
  408. package/src/components/DataTable/data-table-interaction-layer.tsx +15 -19
  409. package/src/components/DataTable/data-table.anatomy.stories.tsx +15 -13
  410. package/src/components/DataTable/data-table.principles.stories.tsx +9 -9
  411. package/src/components/DataTable/data-table.spec.md +32 -12
  412. package/src/components/DataTable/data-table.stories.tsx +16 -17
  413. package/src/components/DataTable/data-table.tsx +103 -60
  414. package/src/components/DataTable/index.ts +3 -0
  415. package/src/components/DateGrid/date-grid.anatomy.stories.tsx +4 -4
  416. package/src/components/DateGrid/date-grid.principles.stories.tsx +1 -1
  417. package/src/components/DateGrid/date-grid.spec.md +1 -1
  418. package/src/components/DateGrid/date-grid.tsx +3 -1
  419. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +8 -8
  420. package/src/components/DatePicker/date-picker.principles.stories.tsx +3 -3
  421. package/src/components/DatePicker/date-picker.spec.md +3 -3
  422. package/src/components/DatePicker/date-picker.stories.tsx +4 -5
  423. package/src/components/DatePicker/date-picker.tsx +99 -45
  424. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +12 -10
  425. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  426. package/src/components/DescriptionList/description-list.spec.md +3 -3
  427. package/src/components/DescriptionList/description-list.stories.tsx +7 -6
  428. package/src/components/Dialog/dialog.anatomy.stories.tsx +1 -0
  429. package/src/components/Dialog/dialog.spec.md +9 -0
  430. package/src/components/Dialog/dialog.stories.tsx +66 -5
  431. package/src/components/Dialog/dialog.tsx +60 -25
  432. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +1 -1
  433. package/src/components/DropdownMenu/dropdown-menu.principles.stories.tsx +8 -6
  434. package/src/components/DropdownMenu/dropdown-menu.spec.md +5 -5
  435. package/src/components/DropdownMenu/dropdown-menu.tsx +18 -9
  436. package/src/components/Empty/empty.anatomy.stories.tsx +1 -1
  437. package/src/components/Empty/empty.spec.md +2 -2
  438. package/src/components/Field/field-context.ts +69 -5
  439. package/src/components/Field/field-controls.spec.md +62 -8
  440. package/src/components/Field/field-edit-keys.ts +66 -0
  441. package/src/components/Field/field-types.ts +58 -9
  442. package/src/components/Field/field-wrapper.tsx +50 -42
  443. package/src/components/Field/field.anatomy.stories.tsx +9 -6
  444. package/src/components/Field/field.spec.md +1 -1
  445. package/src/components/Field/field.stories.tsx +1 -1
  446. package/src/components/Field/field.tsx +2 -1
  447. package/src/components/Field/form-validation.spec.md +3 -3
  448. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +6 -6
  449. package/src/components/FieldControlGroup/field-control-group.spec.md +9 -4
  450. package/src/components/FieldControlGroup/field-control-group.tsx +1 -1
  451. package/src/components/FileItem/file-item.anatomy.stories.tsx +1 -1
  452. package/src/components/FileItem/file-item.spec.md +5 -8
  453. package/src/components/FileItem/file-item.stories.tsx +36 -25
  454. package/src/components/FileItem/file-item.tsx +8 -6
  455. package/src/components/FileUpload/file-upload.anatomy.stories.tsx +6 -6
  456. package/src/components/FileUpload/file-upload.principles.stories.tsx +5 -5
  457. package/src/components/FileUpload/file-upload.spec.md +1 -1
  458. package/src/components/FileUpload/file-upload.tsx +1 -1
  459. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +4 -3
  460. package/src/components/FileViewer/file-viewer.principles.stories.tsx +3 -3
  461. package/src/components/FileViewer/file-viewer.spec.md +30 -12
  462. package/src/components/FileViewer/file-viewer.stories.tsx +1 -2
  463. package/src/components/FileViewer/file-viewer.tsx +12 -4
  464. package/src/components/FileViewer/image-renderer.tsx +35 -7
  465. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -2
  466. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -3
  467. package/src/components/HoverCard/hover-card.spec.md +5 -5
  468. package/src/components/HoverCard/hover-card.stories.tsx +16 -16
  469. package/src/components/HoverCard/hover-card.tsx +5 -3
  470. package/src/components/InlineEdit/index.ts +5 -0
  471. package/src/components/InlineEdit/inline-edit.spec.md +149 -0
  472. package/src/components/InlineEdit/inline-edit.stories.tsx +246 -0
  473. package/src/components/InlineEdit/inline-edit.tsx +287 -0
  474. package/src/components/Input/input.anatomy.stories.tsx +8 -7
  475. package/src/components/Input/input.principles.stories.tsx +2 -12
  476. package/src/components/Input/input.spec.md +13 -18
  477. package/src/components/Input/input.tsx +69 -22
  478. package/src/components/LinkInput/link-input.anatomy.stories.tsx +1 -1
  479. package/src/components/LinkInput/link-input.principles.stories.tsx +2 -2
  480. package/src/components/LinkInput/link-input.tsx +11 -10
  481. package/src/components/Menu/menu-item.anatomy.stories.tsx +3 -3
  482. package/src/components/Menu/menu-item.principles.stories.tsx +1 -1
  483. package/src/components/Menu/menu-item.spec.md +22 -15
  484. package/src/components/Menu/menu-item.stories.tsx +39 -11
  485. package/src/components/Menu/menu-item.tsx +38 -4
  486. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  487. package/src/components/Notice/notice.spec.md +16 -3
  488. package/src/components/NumberInput/number-input.anatomy.stories.tsx +3 -3
  489. package/src/components/NumberInput/number-input.principles.stories.tsx +1 -1
  490. package/src/components/NumberInput/number-input.spec.md +4 -4
  491. package/src/components/NumberInput/number-input.tsx +19 -12
  492. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +10 -8
  493. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +3 -3
  494. package/src/components/OverflowIndicator/overflow-indicator.spec.md +4 -2
  495. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +71 -63
  496. package/src/components/OverflowIndicator/overflow-indicator.tsx +9 -8
  497. package/src/components/Pagination/pagination.spec.md +1 -1
  498. package/src/components/Pagination/pagination.stories.tsx +2 -6
  499. package/src/components/Pagination/pagination.tsx +1 -1
  500. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +4 -4
  501. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +2 -2
  502. package/src/components/PeoplePicker/people-picker.spec.md +6 -6
  503. package/src/components/PeoplePicker/people-picker.tsx +56 -16
  504. package/src/components/PeoplePicker/person-display.tsx +32 -16
  505. package/src/components/Popover/popover.anatomy.stories.tsx +2 -2
  506. package/src/components/Popover/popover.tsx +3 -1
  507. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +12 -23
  508. package/src/components/ProfileCard/profile-card.spec.md +3 -3
  509. package/src/components/ProfileCard/profile-card.tsx +6 -6
  510. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +3 -1
  511. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +1 -1
  512. package/src/components/ProgressBar/progress-bar.stories.tsx +50 -42
  513. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +10 -28
  514. package/src/components/RadioGroup/radio-group.stories.tsx +29 -32
  515. package/src/components/RadioGroup/radio-group.tsx +41 -15
  516. package/src/components/Rating/rating.spec.md +11 -3
  517. package/src/components/ScrollArea/scroll-area.anatomy.stories.tsx +1 -1
  518. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  519. package/src/components/ScrollArea/scroll-area.spec.md +7 -3
  520. package/src/components/ScrollArea/scroll-area.stories.tsx +1 -1
  521. package/src/components/ScrollArea/scroll-area.tsx +17 -4
  522. package/src/components/Select/select.anatomy.stories.tsx +3 -3
  523. package/src/components/Select/select.spec.md +27 -17
  524. package/src/components/Select/select.stories.tsx +33 -0
  525. package/src/components/Select/select.tsx +190 -36
  526. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +4 -4
  527. package/src/components/SelectMenu/select-menu.spec.md +15 -7
  528. package/src/components/SelectMenu/select-menu.tsx +16 -3
  529. package/src/components/SelectionControl/boolean-value.tsx +39 -0
  530. package/src/components/SelectionControl/index.ts +1 -0
  531. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +2 -2
  532. package/src/components/SelectionControl/selection-item.principles.stories.tsx +2 -2
  533. package/src/components/SelectionControl/selection-item.spec.md +3 -3
  534. package/src/components/SelectionControl/selection-item.stories.tsx +3 -3
  535. package/src/components/Separator/separator.spec.md +2 -2
  536. package/src/components/Separator/separator.stories.tsx +6 -27
  537. package/src/components/Sheet/sheet.anatomy.stories.tsx +1 -1
  538. package/src/components/Sheet/sheet.principles.stories.tsx +1 -1
  539. package/src/components/Sheet/sheet.spec.md +2 -2
  540. package/src/components/Sheet/sheet.tsx +9 -5
  541. package/src/components/Sidebar/sidebar.anatomy.stories.tsx +16 -12
  542. package/src/components/Sidebar/sidebar.principles.stories.tsx +10 -8
  543. package/src/components/Sidebar/sidebar.spec.md +13 -15
  544. package/src/components/Sidebar/sidebar.stories.tsx +8 -7
  545. package/src/components/Sidebar/sidebar.tsx +37 -25
  546. package/src/components/Skeleton/skeleton.stories.tsx +4 -11
  547. package/src/components/Slider/slider.anatomy.stories.tsx +3 -3
  548. package/src/components/Slider/slider.principles.stories.tsx +2 -2
  549. package/src/components/Slider/slider.spec.md +5 -5
  550. package/src/components/Slider/slider.tsx +3 -1
  551. package/src/components/Steps/steps.anatomy.stories.tsx +4 -4
  552. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  553. package/src/components/Steps/steps.spec.md +1 -1
  554. package/src/components/Switch/switch.anatomy.stories.tsx +7 -7
  555. package/src/components/Switch/switch.principles.stories.tsx +4 -4
  556. package/src/components/Switch/switch.spec.md +8 -8
  557. package/src/components/Switch/switch.stories.tsx +9 -24
  558. package/src/components/Switch/switch.tsx +17 -13
  559. package/src/components/Tabs/tabs.anatomy.stories.tsx +10 -7
  560. package/src/components/Tabs/tabs.spec.md +1 -1
  561. package/src/components/Tabs/tabs.tsx +21 -1
  562. package/src/components/Textarea/textarea.anatomy.stories.tsx +1 -1
  563. package/src/components/Textarea/textarea.principles.stories.tsx +1 -1
  564. package/src/components/Textarea/textarea.spec.md +4 -4
  565. package/src/components/Textarea/textarea.tsx +72 -46
  566. package/src/components/TimePicker/time-columns.tsx +6 -2
  567. package/src/components/TimePicker/time-picker.principles.stories.tsx +1 -1
  568. package/src/components/TimePicker/time-picker.spec.md +3 -3
  569. package/src/components/TimePicker/time-picker.tsx +16 -10
  570. package/src/components/Toast/toast.stories.tsx +7 -4
  571. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +4 -4
  572. package/src/components/Tooltip/tooltip.principles.stories.tsx +3 -3
  573. package/src/components/Tooltip/tooltip.spec.md +1 -1
  574. package/src/components/Tooltip/tooltip.stories.tsx +4 -39
  575. package/src/components/Tooltip/tooltip.tsx +8 -6
  576. package/src/components/TreeView/tree-view.anatomy.stories.tsx +6 -3
  577. package/src/components/TreeView/tree-view.spec.md +42 -11
  578. package/src/components/TreeView/tree-view.stories.tsx +1 -0
  579. package/src/components/TreeView/tree-view.tsx +322 -17
  580. package/src/index.ts +584 -60
  581. package/src/patterns/action-bar/action-bar.spec.md +9 -0
  582. package/src/patterns/action-bar/action-bar.stories.tsx +6 -3
  583. package/src/patterns/element-anatomy/inline-action.spec.md +2 -0
  584. package/src/patterns/element-anatomy/item-anatomy.spec.md +14 -5
  585. package/src/patterns/element-anatomy/item-anatomy.stories.tsx +6 -4
  586. package/src/patterns/element-anatomy/item-anatomy.tsx +7 -6
  587. package/src/patterns/header-canonical/header-canonical.spec.md +5 -4
  588. package/src/patterns/overlay-surface/overlay-surface.spec.md +22 -1
  589. package/src/styles/tokens.css +3 -0
  590. package/src/tokens/README.md +1 -1
  591. package/src/tokens/color/color.spec.md +3 -3
  592. package/src/tokens/color/color.stories.tsx +3 -3
  593. package/src/tokens/density/density.stories.tsx +16 -3
  594. package/src/tokens/layoutSpace/layoutSpace.spec.md +3 -1
  595. package/src/tokens/motion/motion.css +33 -21
  596. package/src/tokens/motion/motion.spec.md +32 -15
  597. package/src/tokens/motion/motion.stories.tsx +58 -5
  598. package/src/tokens/motion/motion.ts +7 -6
  599. package/src/tokens/motion/overlay-motion.ts +26 -0
  600. package/src/tokens/orphan-tokens.spec.md +4 -4
  601. package/src/tokens/token-system.spec.md +1 -0
  602. package/src/tokens/uiSize/uiSize.spec.md +1 -1
  603. package/src/tokens/uiSize/uiSize.stories.tsx +4 -2
  604. package/src/tokens/utility-registry.json +160 -23
@@ -1 +1 @@
1
- {"version":3,"file":"pagination.js","sources":["../../../src/components/Pagination/pagination.tsx"],"sourcesContent":["// ────────────────────────────── 消費的 SSOT ──────────────────────────────\n// - Button:../Button/button.tsx —— 全部按鈕純 variant 組裝零視覺客製(2026-07-06 user 抓出):\n// 上下頁 = text iconOnly / 未選數字 = text / 當前頁 = secondary(rest primary 描邊染字不染底、\n// hover 升 hover 階、active 深一階 —— 與 semantic.css「選中」canonical + 拍板 #8 完全同拼寫);\n// 選中「語意」由 aria-current=\"page\" 承載(非 pressed —— pressed 是可取消 toggle,當前頁不可取消)\n// - Select(size=\"sm\"):../Select/select.tsx —— 完整形態的「N 筆/頁」選單\n// - Ellipsis icon:MoreHorizontal(.claude/rules/ui-development.md「Icon canonical」)\n// - DOM 骨架:shadcn Pagination(nav > ul > li + aria-current=\"page\");\n// controlled 事件驅動 + total/pageSize 資料模型對齊 Ant Pagination(2026-07-06 user 拍板:\n// Pagination 本體 = 完整功能 SSOT —— showTotal / 每頁筆數皆本元件 own,Table 轉發 config 消費)\n// 設計規則:./pagination.spec.md\nimport * as React from 'react'\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/design-system/components/Button/button'\nimport { Select } from '@/design-system/components/Select/select'\nimport { useControllable } from '@/design-system/hooks/use-controllable'\n\n// MUI usePagination 預設同款(boundaryCount/siblingCount = 1/1)。內部常數不開 props(M21\n// 最小 API);未來若開放,命名必沿用 MUI siblingCount / boundaryCount。\n// 最大格位 = 首尾各 1 + 當前頁左右各 1 + 當前頁 + 2 顆 ellipsis = 7,超過即摺疊。\nconst BOUNDARY_COUNT = 1\nconst SIBLING_COUNT = 1\n\ntype PaginationSlot = number | 'ellipsis-start' | 'ellipsis-end'\n\n// 摺疊演算法照 MUI usePagination(1/1 配置);兩顆 ellipsis 用 distinct 穩定 key\n// (Breadcrumb Math.random key remount 前車之鑑,breadcrumb.tsx:208-210)。\nfunction getPaginationRange(page: number, totalPages: number): PaginationSlot[] {\n const range = (start: number, end: number) =>\n Array.from({ length: end - start + 1 }, (_, i) => start + i)\n\n // 全部放得下(≤ 7 頁)→ 不摺疊\n if (totalPages <= BOUNDARY_COUNT * 2 + SIBLING_COUNT * 2 + 3) return range(1, totalPages)\n\n const startPages = range(1, BOUNDARY_COUNT)\n const endPages = range(totalPages - BOUNDARY_COUNT + 1, totalPages)\n const siblingsStart = Math.max(\n Math.min(page - SIBLING_COUNT, totalPages - BOUNDARY_COUNT - SIBLING_COUNT * 2 - 1),\n BOUNDARY_COUNT + 2,\n )\n const siblingsEnd = Math.min(\n Math.max(page + SIBLING_COUNT, BOUNDARY_COUNT + SIBLING_COUNT * 2 + 2),\n totalPages - BOUNDARY_COUNT - 1,\n )\n\n return [\n ...startPages,\n ...(siblingsStart > BOUNDARY_COUNT + 2\n ? (['ellipsis-start'] as const)\n : [BOUNDARY_COUNT + 1]),\n ...range(siblingsStart, siblingsEnd),\n ...(siblingsEnd < totalPages - BOUNDARY_COUNT - 1\n ? (['ellipsis-end'] as const)\n : [totalPages - BOUNDARY_COUNT]),\n ...endPages,\n ]\n}\n\nexport interface PaginationProps extends React.ComponentPropsWithoutRef<'nav'> {\n /** 資料總筆數(Ant `total` 同款資料模型;<= 0 不渲染)。總頁數 = ceil(total / pageSize) 內部推導。 */\n total: number\n /** 每頁筆數(controlled;搭配 onPageSizeChange)。不傳 = uncontrolled(defaultPageSize 起始)。 */\n pageSize?: number\n /** uncontrolled 每頁筆數初始值(預設 20)。 */\n defaultPageSize?: number\n /** 當前頁(1-based,controlled)。不傳 = uncontrolled(defaultPage 起始)。越界防禦性 clamp。 */\n page?: number\n /** uncontrolled 初始頁(1-based,預設 1)。 */\n defaultPage?: number\n /** 換頁 callback(1-based)。URL 同步在此接 router,不把按鈕換 <a>。每頁筆數變更時自動回第 1 頁並 fire。 */\n onPageChange?: (page: number) => void\n /** 每頁筆數變更 callback。 */\n onPageSizeChange?: (pageSize: number) => void\n /** 完整形態:左側顯示「第 x–y 筆,共 N 筆」range 資訊(Ant showTotal / MUI / Carbon 同款,opt-in)。 */\n showTotal?: boolean\n /** 完整形態:頁碼右側渲染「N 筆/頁」選單(消費 Select sm;Ant showSizeChanger 同款,opt-in)。 */\n pageSizeOptions?: number[]\n /** 上一頁按鈕 aria-label(iconOnly 必有名)。 */\n prevAriaLabel?: string\n /** 下一頁按鈕 aria-label。 */\n nextAriaLabel?: string\n}\n\n/**\n * Pagination —— 大量資料切頁後的位置導覽(數字頁碼派,2026-07-05 user 拍板)。\n *\n * 本元件是分頁的**完整功能 SSOT**(2026-07-06 user 拍板):頁碼 + 總筆數資訊(showTotal)\n * + 每頁筆數選單(pageSizeOptions)全部 own 在此;完整形態 layout =「資訊左、操作右」\n * (Ant 源碼結構同款:total 文字最左、size changer 最右)。DataTable 等 consumer 轉發\n * config 消費本元件,不自拼分頁列。與虛擬滾動互斥。詳 ./pagination.spec.md。\n */\nconst Pagination = React.forwardRef<HTMLElement, PaginationProps>(\n (\n {\n total,\n pageSize: pageSizeProp,\n defaultPageSize = 20,\n page: pageProp,\n defaultPage = 1,\n onPageChange,\n onPageSizeChange,\n showTotal = false,\n pageSizeOptions,\n prevAriaLabel = '上一頁', // i18n-allow: DS default; consumer override via prop(precedent calendar.tsx)\n nextAriaLabel = '下一頁', // i18n-allow: DS default; consumer override via prop\n className,\n ...props\n },\n ref,\n ) => {\n // Hooks 必在 early return 之前(React #310 canonical,select.tsx:503 同慣例)\n const [pageSize, setPageSize] = useControllable<number>({\n value: pageSizeProp,\n defaultValue: defaultPageSize,\n onChange: onPageSizeChange,\n })\n const [page, setPage] = useControllable<number>({\n value: pageProp,\n defaultValue: defaultPage,\n onChange: onPageChange,\n })\n\n // 無資料 → 不渲染(空狀態由 Empty / 列表層表達,詳 spec 邊界案例)\n if (total <= 0) return null\n\n // pageSize <= 0 防禦 clamp(consumer contract violation)——防 totalPages 變 Infinity/NaN\n // 渲染垃圾格位(spec 邊界案例表有對應 row)\n const safePageSize = Math.max(1, Math.floor(pageSize))\n const totalPages = Math.max(1, Math.ceil(total / safePageSize))\n const current = Math.min(Math.max(page, 1), totalPages)\n const slots = getPaginationRange(current, totalPages)\n const hasSizeChanger = !!pageSizeOptions && pageSizeOptions.length > 0\n const hasExtras = showTotal || hasSizeChanger\n const rangeStart = (current - 1) * safePageSize + 1\n const rangeEnd = Math.min(current * safePageSize, total)\n // 當前 pageSize 不在 options 內時補進清單頭(否則 Select trigger 顯示裸值失去「N 筆/頁」文案)\n const sizeOptions = hasSizeChanger\n ? (pageSizeOptions!.includes(safePageSize) ? pageSizeOptions! : [safePageSize, ...pageSizeOptions!])\n : []\n\n const pageList = (\n <ul className=\"flex items-center gap-1\">\n <li>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronLeft}\n aria-label={prevAriaLabel}\n disabled={current <= 1}\n onClick={() => setPage(current - 1)}\n />\n </li>\n {slots.map((slot) =>\n typeof slot === 'number' ? (\n <li key={slot}>\n {/* 當前頁 = <Button variant=\"secondary\"> 一比一零客製(2026-07-06 user 抓出可純組裝):\n secondary 的 rest(primary 描邊+染字+不染底)/ hover(升 hover 階)/ active(深一階)\n 與 semantic.css「選中」canonical + 拍板 #8 完全同拼寫,且無 neutral 灰底 hover —\n 消費既有 variant 取代手寫平行拼寫(M17/M23 SSOT)。選中「語意」由 aria-current=\"page\"\n 承載,Button 僅為視覺 host;未選 = text variant。className 只剩等寬幾何\n (蓋掉 size sm 的 min-w-14/px-3,方形 item 對齊 Ant;兩 variant 同 border 寬零位移)。 */}\n <Button\n variant={slot === current ? 'secondary' : 'text'}\n size=\"sm\"\n aria-current={slot === current ? 'page' : undefined}\n className=\"min-w-[var(--field-height-sm)] px-1 justify-center tabular-nums\"\n onClick={() => setPage(slot)}\n >\n {slot}\n </Button>\n </li>\n ) : (\n // Ellipsis 純指示不可點(Ant / MUI / shadcn 同);寬度對齊數字鈕保持節奏\n <li\n key={slot}\n aria-hidden\n className=\"flex min-w-[var(--field-height-sm)] items-center justify-center\"\n >\n <MoreHorizontal size={16} className=\"text-fg-muted\" />\n </li>\n ),\n )}\n <li>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronRight}\n aria-label={nextAriaLabel}\n disabled={current >= totalPages}\n onClick={() => setPage(current + 1)}\n />\n </li>\n </ul>\n )\n\n return (\n <nav\n ref={ref}\n aria-label=\"Pagination\"\n className={cn(\n 'flex items-center',\n // 完整形態 =「資訊左、操作右」(Ant 源碼結構:total 文字最左 li、size changer 最右 li)\n hasExtras && 'w-full justify-between gap-[var(--layout-space-tight)]',\n className,\n )}\n {...props}\n >\n {hasExtras && (\n // i18n-allow: DS default(range 格式 = Ant/MUI/Carbon 共識);showTotal=false 時渲染\n // 空 span 佔 justify-between 左位,不含 stray 文字節點\n <span className=\"text-body text-fg-secondary\">\n {showTotal ? `第 ${rangeStart}–${rangeEnd} 筆,共 ${total} 筆` : null}\n </span>\n )}\n <div className=\"flex items-center gap-[var(--layout-space-tight)]\">\n {pageList}\n {hasSizeChanger && (\n <Select\n size=\"sm\"\n aria-label=\"每頁筆數\" // i18n-allow: DS default\n className=\"w-28\"\n value={String(safePageSize)}\n onChange={(v) => {\n const next = Number(v)\n // 同值重選 / 非法值不動作——防「重選 20 筆/頁」誤把頁碼重置回第 1 頁\n if (!Number.isFinite(next) || next <= 0 || next === safePageSize) return\n setPageSize(next)\n // 換每頁筆數回第 1 頁——MUI TablePagination / TanStack autoResetPageIndex 派;\n // Ant 為 preserve-position(clamp)派,本 DS 採 reset-to-1(spec「完整形態」段有註記)\n setPage(1)\n }}\n options={sizeOptions.map((n) => ({ value: String(n), label: `${n} 筆/頁` }))} // i18n-allow: DS default(Ant「20 / page」內嵌同款)\n />\n )}\n </div>\n </nav>\n )\n },\n)\nPagination.displayName = 'Pagination'\n\nexport const paginationMeta = {\n component: 'Pagination',\n family: null, // non-family composite(nav 橫排 control row;按鈕消費 Family 3 Button Pill)\n variants: {},\n // 單一尺寸(按鈕固定 Button sm;無 size 軸)—— 頁碼列是 chrome 級導覽不隨 Field 密度縮放,\n // spec「SizeMatrix N/A rationale」段有完整理由\n sizes: {},\n // 'selected' = 當前頁(語意由 aria-current=\"page\" 承載;2026-07-07 meta 詞彙統一:持續選中一律 'selected')\n states: ['default', 'hover', 'active', 'selected', 'focus-visible', 'disabled'],\n tokens: {\n // bg:未選/上下頁(Button text)hover 灰底 + active 深一階;當前頁(secondary)bg-surface\n bg: ['bg-surface', 'bg-neutral-hover', 'bg-neutral-active'],\n fg: ['text-foreground', 'text-primary', 'text-primary-hover', 'text-primary-active', 'text-fg-muted', 'text-fg-secondary', 'text-fg-disabled'],\n border: ['border-primary', 'border-primary-hover', 'border-primary-active'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Pagination }\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pagination.js","sources":["../../../src/components/Pagination/pagination.tsx"],"sourcesContent":["// ────────────────────────────── 消費的 SSOT ──────────────────────────────\n// - Button:../Button/button.tsx —— 全部按鈕純 variant 組裝零視覺客製(2026-07-06 user 抓出):\n// 上下頁 = text iconOnly / 未選數字 = text / 當前頁 = secondary(rest primary 描邊染字不染底、\n// hover 升 hover 階、active 深一階 —— 與 semantic.css「選中」canonical + 拍板 #8 完全同拼寫);\n// 選中「語意」由 aria-current=\"page\" 承載(非 pressed —— pressed 是可取消 toggle,當前頁不可取消)\n// - Select(size=\"sm\"):../Select/select.tsx —— 完整形態的「N 筆/頁」選單\n// - Ellipsis icon:MoreHorizontal(.claude/rules/ui-development.md「Icon canonical」)\n// - DOM 骨架:shadcn Pagination(nav > ul > li + aria-current=\"page\");\n// controlled 事件驅動 + total/pageSize 資料模型對齊 Ant Pagination(2026-07-06 user 拍板:\n// Pagination 本體 = 完整功能 SSOT —— showTotal / 每頁筆數皆本元件 own,Table 轉發 config 消費)\n// 設計規則:./pagination.spec.md\nimport * as React from 'react'\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/design-system/components/Button/button'\nimport { Select } from '@/design-system/components/Select/select'\nimport { useControllable } from '@/design-system/hooks/use-controllable'\n\n// MUI usePagination 預設同款(boundaryCount/siblingCount = 1/1)。內部常數不開 props(M21\n// 最小 API);未來若開放,命名必沿用 MUI siblingCount / boundaryCount。\n// 最大格位 = 首尾各 1 + 當前頁左右各 1 + 當前頁 + 2 顆 ellipsis = 7,超過即摺疊。\nconst BOUNDARY_COUNT = 1\nconst SIBLING_COUNT = 1\n\ntype PaginationSlot = number | 'ellipsis-start' | 'ellipsis-end'\n\n// 摺疊演算法照 MUI usePagination(1/1 配置);兩顆 ellipsis 用 distinct 穩定 key\n// (Breadcrumb Math.random key remount 前車之鑑,breadcrumb.tsx:208-210)。\nfunction getPaginationRange(page: number, totalPages: number): PaginationSlot[] {\n const range = (start: number, end: number) =>\n Array.from({ length: end - start + 1 }, (_, i) => start + i)\n\n // 全部放得下(≤ 7 頁)→ 不摺疊\n if (totalPages <= BOUNDARY_COUNT * 2 + SIBLING_COUNT * 2 + 3) return range(1, totalPages)\n\n const startPages = range(1, BOUNDARY_COUNT)\n const endPages = range(totalPages - BOUNDARY_COUNT + 1, totalPages)\n const siblingsStart = Math.max(\n Math.min(page - SIBLING_COUNT, totalPages - BOUNDARY_COUNT - SIBLING_COUNT * 2 - 1),\n BOUNDARY_COUNT + 2,\n )\n const siblingsEnd = Math.min(\n Math.max(page + SIBLING_COUNT, BOUNDARY_COUNT + SIBLING_COUNT * 2 + 2),\n totalPages - BOUNDARY_COUNT - 1,\n )\n\n return [\n ...startPages,\n ...(siblingsStart > BOUNDARY_COUNT + 2\n ? (['ellipsis-start'] as const)\n : [BOUNDARY_COUNT + 1]),\n ...range(siblingsStart, siblingsEnd),\n ...(siblingsEnd < totalPages - BOUNDARY_COUNT - 1\n ? (['ellipsis-end'] as const)\n : [totalPages - BOUNDARY_COUNT]),\n ...endPages,\n ]\n}\n\nexport interface PaginationProps extends React.ComponentPropsWithoutRef<'nav'> {\n /** 資料總筆數(Ant `total` 同款資料模型;<= 0 不渲染)。總頁數 = ceil(total / pageSize) 內部推導。 */\n total: number\n /** 每頁筆數(controlled;搭配 onPageSizeChange)。不傳 = uncontrolled(defaultPageSize 起始)。 */\n pageSize?: number\n /** uncontrolled 每頁筆數初始值(預設 20)。 */\n defaultPageSize?: number\n /** 當前頁(1-based,controlled)。不傳 = uncontrolled(defaultPage 起始)。越界防禦性 clamp。 */\n page?: number\n /** uncontrolled 初始頁(1-based,預設 1)。 */\n defaultPage?: number\n /** 換頁 callback(1-based)。URL 同步在此接 router,不把按鈕換 <a>。每頁筆數變更時自動回第 1 頁並 fire。 */\n onPageChange?: (page: number) => void\n /** 每頁筆數變更 callback。 */\n onPageSizeChange?: (pageSize: number) => void\n /** 完整形態:左側顯示「第 x–y 筆,共 N 筆」range 資訊(Ant showTotal / MUI / Carbon 同款,opt-in)。 */\n showTotal?: boolean\n /** 完整形態:頁碼右側渲染「N 筆/頁」選單(消費 Select sm;Ant showSizeChanger 同款,opt-in)。 */\n pageSizeOptions?: number[]\n /** 上一頁按鈕 aria-label(iconOnly 必有名)。 */\n prevAriaLabel?: string\n /** 下一頁按鈕 aria-label。 */\n nextAriaLabel?: string\n}\n\n/**\n * Pagination —— 大量資料切頁後的位置導覽(數字頁碼派,2026-07-05 user 拍板)。\n *\n * 本元件是分頁的**完整功能 SSOT**(2026-07-06 user 拍板):頁碼 + 總筆數資訊(showTotal)\n * + 每頁筆數選單(pageSizeOptions)全部 own 在此;完整形態 layout =「資訊左、操作右」\n * (Ant 源碼結構同款:total 文字最左、size changer 最右)。DataTable 等 consumer 轉發\n * config 消費本元件,不自拼分頁列。與虛擬滾動互斥。詳 ./pagination.spec.md。\n */\nconst Pagination = React.forwardRef<HTMLElement, PaginationProps>(\n (\n {\n total,\n pageSize: pageSizeProp,\n defaultPageSize = 20,\n page: pageProp,\n defaultPage = 1,\n onPageChange,\n onPageSizeChange,\n showTotal = false,\n pageSizeOptions,\n prevAriaLabel = '上一頁', // i18n-allow: DS default; consumer override via prop(precedent calendar.tsx)\n nextAriaLabel = '下一頁', // i18n-allow: DS default; consumer override via prop\n className,\n ...props\n },\n ref,\n ) => {\n // Hooks 必在 early return 之前(React #310 canonical,select.tsx:503 同慣例)\n const [pageSize, setPageSize] = useControllable<number>({\n value: pageSizeProp,\n defaultValue: defaultPageSize,\n onChange: onPageSizeChange,\n })\n const [page, setPage] = useControllable<number>({\n value: pageProp,\n defaultValue: defaultPage,\n onChange: onPageChange,\n })\n\n // 無資料 → 不渲染(空狀態由 Empty / 列表層表達,詳 spec 邊界案例)\n if (total <= 0) return null\n\n // pageSize <= 0 防禦 clamp(consumer contract violation)——防 totalPages 變 Infinity/NaN\n // 渲染垃圾格位(spec 邊界案例表有對應 row)\n const safePageSize = Math.max(1, Math.floor(pageSize))\n const totalPages = Math.max(1, Math.ceil(total / safePageSize))\n const current = Math.min(Math.max(page, 1), totalPages)\n const slots = getPaginationRange(current, totalPages)\n const hasSizeChanger = !!pageSizeOptions && pageSizeOptions.length > 0\n const hasExtras = showTotal || hasSizeChanger\n const rangeStart = (current - 1) * safePageSize + 1\n const rangeEnd = Math.min(current * safePageSize, total)\n // 當前 pageSize 不在 options 內時補進清單頭(否則 Select trigger 顯示裸值失去「N 筆/頁」文案)\n const sizeOptions = hasSizeChanger\n ? (pageSizeOptions!.includes(safePageSize) ? pageSizeOptions! : [safePageSize, ...pageSizeOptions!])\n : []\n\n const pageList = (\n <ul className=\"flex items-center gap-1\">\n <li>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronLeft}\n aria-label={prevAriaLabel}\n disabled={current <= 1}\n onClick={() => setPage(current - 1)}\n />\n </li>\n {slots.map((slot) =>\n typeof slot === 'number' ? (\n <li key={slot}>\n {/* 當前頁 = <Button variant=\"secondary\"> 一比一零客製(2026-07-06 user 抓出可純組裝):\n secondary 的 rest(primary 描邊+染字+不染底)/ hover(升 hover 階)/ active(深一階)\n 與 semantic.css「選中」canonical + 拍板 #8 完全同拼寫,且無 neutral 灰底 hover —\n 消費既有 variant 取代手寫平行拼寫(M17/M23 SSOT)。選中「語意」由 aria-current=\"page\"\n 承載,Button 僅為視覺 host;未選 = text variant。className 只剩等寬幾何\n (蓋掉 size sm 的 min-w-14/px-3,方形 item 對齊 Ant;兩 variant 同 border 寬零位移)。 */}\n <Button\n variant={slot === current ? 'secondary' : 'text'}\n size=\"sm\"\n aria-current={slot === current ? 'page' : undefined}\n className=\"min-w-[var(--field-height-sm)] px-1 justify-center tabular-nums\"\n onClick={() => setPage(slot)}\n >\n {slot}\n </Button>\n </li>\n ) : (\n // Ellipsis 純指示不可點(MUI / shadcn 同;Ant 為可點 jump-5 派,見 spec);寬度對齊數字鈕保持節奏\n <li\n key={slot}\n aria-hidden\n className=\"flex min-w-[var(--field-height-sm)] items-center justify-center\"\n >\n <MoreHorizontal size={16} className=\"text-fg-muted\" />\n </li>\n ),\n )}\n <li>\n <Button\n variant=\"text\"\n size=\"sm\"\n iconOnly\n startIcon={ChevronRight}\n aria-label={nextAriaLabel}\n disabled={current >= totalPages}\n onClick={() => setPage(current + 1)}\n />\n </li>\n </ul>\n )\n\n return (\n <nav\n ref={ref}\n aria-label=\"Pagination\"\n className={cn(\n 'flex items-center',\n // 完整形態 =「資訊左、操作右」(Ant 源碼結構:total 文字最左 li、size changer 最右 li)\n hasExtras && 'w-full justify-between gap-[var(--layout-space-tight)]',\n className,\n )}\n {...props}\n >\n {hasExtras && (\n // i18n-allow: DS default(range 格式 = Ant/MUI/Carbon 共識);showTotal=false 時渲染\n // 空 span 佔 justify-between 左位,不含 stray 文字節點\n <span className=\"text-body text-fg-secondary\">\n {showTotal ? `第 ${rangeStart}–${rangeEnd} 筆,共 ${total} 筆` : null}\n </span>\n )}\n <div className=\"flex items-center gap-[var(--layout-space-tight)]\">\n {pageList}\n {hasSizeChanger && (\n <Select\n size=\"sm\"\n aria-label=\"每頁筆數\" // i18n-allow: DS default\n className=\"w-28\"\n value={String(safePageSize)}\n onChange={(v) => {\n const next = Number(v)\n // 同值重選 / 非法值不動作——防「重選 20 筆/頁」誤把頁碼重置回第 1 頁\n if (!Number.isFinite(next) || next <= 0 || next === safePageSize) return\n setPageSize(next)\n // 換每頁筆數回第 1 頁——MUI TablePagination / TanStack autoResetPageIndex 派;\n // Ant 為 preserve-position(clamp)派,本 DS 採 reset-to-1(spec「完整形態」段有註記)\n setPage(1)\n }}\n options={sizeOptions.map((n) => ({ value: String(n), label: `${n} 筆/頁` }))} // i18n-allow: DS default(Ant「20 / page」內嵌同款)\n />\n )}\n </div>\n </nav>\n )\n },\n)\nPagination.displayName = 'Pagination'\n\nexport const paginationMeta = {\n component: 'Pagination',\n family: null, // non-family composite(nav 橫排 control row;按鈕消費 Family 3 Button Pill)\n variants: {},\n // 單一尺寸(按鈕固定 Button sm;無 size 軸)—— 頁碼列是 chrome 級導覽不隨 Field 密度縮放,\n // spec「SizeMatrix N/A rationale」段有完整理由\n sizes: {},\n // 'selected' = 當前頁(語意由 aria-current=\"page\" 承載;2026-07-07 meta 詞彙統一:持續選中一律 'selected')\n states: ['default', 'hover', 'active', 'selected', 'focus-visible', 'disabled'],\n tokens: {\n // bg:未選/上下頁(Button text)hover 灰底 + active 深一階;當前頁(secondary)bg-surface\n bg: ['bg-surface', 'bg-neutral-hover', 'bg-neutral-active'],\n fg: ['text-foreground', 'text-primary', 'text-primary-hover', 'text-primary-active', 'text-fg-muted', 'text-fg-secondary', 'text-fg-disabled'],\n border: ['border-primary', 'border-primary-hover', 'border-primary-active'],\n ring: ['ring-ring'],\n },\n} as const\n\nexport { Pagination }\n"],"names":[],"mappings":"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"}
@@ -1,9 +1,15 @@
1
1
  import { PeoplePicker, peoplePickerMeta } from "./people-picker.js";
2
+ import { MultiPersonDisplay, PersonAvatarTag, PersonDisplay, buildPersonProfileCard, resolvePerson } from "./person-display.js";
2
3
  import { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass } from "./people-picker-helpers.js";
3
4
  export {
5
+ MultiPersonDisplay,
4
6
  PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS,
5
7
  PeoplePicker,
8
+ PersonAvatarTag,
9
+ PersonDisplay,
10
+ buildPersonProfileCard,
6
11
  getPeoplePickerTagWrapperClass,
7
- peoplePickerMeta
12
+ peoplePickerMeta,
13
+ resolvePerson
8
14
  };
9
15
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import type { FieldMode, FieldVariant } from '../../components/Field/field-types';
2
+ import type { FieldMode, FieldVariant, FieldWidth } from '../../components/Field/field-types';
3
3
  import { type PersonValue } from './person-display';
4
4
  import { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass } from './people-picker-helpers';
5
5
  export { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS, getPeoplePickerTagWrapperClass };
@@ -8,6 +8,9 @@ export interface PeoplePickerProps extends Omit<React.HTMLAttributes<HTMLDivElem
8
8
  mode?: FieldMode;
9
9
  /** Field chrome variant(對齊 Select / Combobox)*/
10
10
  variant?: FieldVariant;
11
+ /** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮(value 寬 + slot 寬 + gap + 內 padding);
12
+ * chrome 與互動不變。SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */
13
+ width?: FieldWidth;
11
14
  size?: 'sm' | 'md' | 'lg';
12
15
  /** 當前已選的人(單選 PersonValue,多選 PersonValue[])*/
13
16
  value?: PersonValue | PersonValue[] | null;
@@ -18,7 +21,10 @@ export interface PeoplePickerProps extends Omit<React.HTMLAttributes<HTMLDivElem
18
21
  /** 2026-05-12 Stream C Issue 4 fix(codex Q3 Cluster C):trigger empty placeholder。
19
22
  * Default '請選擇人員'。**禁** 將 `emptyText`(search-empty)當 trigger placeholder 傳。 */
20
23
  placeholder?: string;
21
- /** 搜尋框 placeholder */
24
+ /** 搜尋框 placeholder — **僅 multi 模式 panel-top search(`searchIn='menu'`,default)生效**。
25
+ * single mode wrap `<Select searchable>` 走 inline-trigger 搜尋,提示取自 `placeholder`
26
+ * (Select 無 searchPlaceholder prop);multi `searchIn='trigger'` inline 搜尋同理走
27
+ * placeholder 規則(spec「Trigger display SSOT canonical table」)。 */
22
28
  searchPlaceholder?: string;
23
29
  /** 搜尋無結果訊息(filtered menu empty)。**僅**用於 SelectMenu `emptyText`(菜單空狀態,
24
30
  * 2026-07-04 Q4 接線完成),不轉 trigger placeholder(2026-05-12 Issue 4 semantic fix)。 */
@@ -74,4 +80,5 @@ export declare const peoplePickerMeta: {
74
80
  };
75
81
  };
76
82
  export { PeoplePicker };
83
+ export { PersonDisplay, MultiPersonDisplay, PersonAvatarTag, buildPersonProfileCard, resolvePerson, type PersonValue, type PersonData, } from './person-display';
77
84
  //# sourceMappingURL=people-picker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"people-picker.d.ts","sourceRoot":"","sources":["../../../src/components/PeoplePicker/people-picker.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,8CAA8C,CAAA;AAQ3F,OAAO,EAA6F,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAU9I,OAAO,EACL,mCAAmC,EACnC,8BAA8B,EAG/B,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,mCAAmC,EAAE,8BAA8B,EAAE,CAAA;AAqB9E,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC/F,yFAAyF;IACzF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,GAAG,IAAI,CAAA;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,IAAI,CAAA;IACzC,4BAA4B;IAC5B,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;IACtB;oFACgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sBAAsB;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;uFACmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sCAAsC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC/B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,iBAAiB;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,QAAA,MAAM,YAAY,0FAyVhB,CAAA;AAIF,eAAO,MAAM,gBAAgB;;;;;;;;;;;CAYnB,CAAA;AAEV,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"people-picker.d.ts","sourceRoot":"","sources":["../../../src/components/PeoplePicker/people-picker.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAwB,UAAU,EAAE,MAAM,8CAA8C,CAAA;AAS7H,OAAO,EAA6F,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAkB9I,OAAO,EACL,mCAAmC,EACnC,8BAA8B,EAG/B,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,mCAAmC,EAAE,8BAA8B,EAAE,CAAA;AAqB9E,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IAC/F,yFAAyF;IACzF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,gDAAgD;IAChD,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB;8EAC0E;IAC1E,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,EAAE,GAAG,IAAI,CAAA;IAC1C,oEAAoE;IACpE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,IAAI,CAAA;IACzC,4BAA4B;IAC5B,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;IACtB;oFACgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;sEAGkE;IAClE,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;uFACmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sCAAsC;IACtC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC/B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,iBAAiB;IACjB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,QAAA,MAAM,YAAY,0FAuWhB,CAAA;AAIF,eAAO,MAAM,gBAAgB;;;;;;;;;;;CAYnB,CAAA;AAEV,OAAO,EAAE,YAAY,EAAE,CAAA;AAGvB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAA"}
@@ -2,20 +2,23 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { ChevronDown } from "lucide-react";
4
4
  import { cn } from "../../lib/utils.js";
5
- import { EMPTY_DISPLAY, nakedCellRowModeAlign, fieldWrapperStyles } from "../Field/field-wrapper.js";
5
+ import { nakedCellRowModeAlign, fieldWrapperStyles } from "../Field/field-wrapper.js";
6
+ import { useFieldSurface, useFieldEmptyDisplay, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, fieldEmptyColorClass } from "../Field/field-context.js";
6
7
  import { ICON_SIZE, ItemSuffix } from "../../patterns/element-anatomy/item-anatomy.js";
7
- import { useFieldSurface, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant } from "../Field/field-context.js";
8
8
  import { Avatar } from "../Avatar/avatar.js";
9
9
  import { Tag } from "../Tag/tag.js";
10
- import { Select } from "../Select/select.js";
11
- import { Combobox } from "../Combobox/combobox.js";
10
+ import { Select as Select$1 } from "../Select/select.js";
11
+ import { Combobox as Combobox$1 } from "../Combobox/combobox.js";
12
12
  import { resolvePerson, MultiPersonDisplay, PersonDisplay, buildPersonProfileCard, PersonAvatarTag } from "./person-display.js";
13
13
  import { getAvatarStackVisibleCount, AVATAR_STACK_AVATAR_PX, AVATAR_STACK_OVERFLOW_CHIP_PX } from "./avatar-stack-overflow.js";
14
14
  import { findPerson, personToSelectOption, getPeoplePickerTagWrapperClass } from "./people-picker-helpers.js";
15
15
  import { PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS } from "./people-picker-helpers.js";
16
+ const Select = Select$1;
17
+ const Combobox = Combobox$1;
16
18
  const PeoplePicker = React.forwardRef(function PeoplePicker2({
17
19
  mode: modeProp,
18
20
  variant: variantProp,
21
+ width,
19
22
  size: sizeProp,
20
23
  value,
21
24
  onChange,
@@ -39,6 +42,7 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
39
42
  ...rest
40
43
  }, ref) {
41
44
  const surface = useFieldSurface();
45
+ const emptyDisplay = useFieldEmptyDisplay();
42
46
  const size = useResolvedFieldSize(sizeProp);
43
47
  const disabled = useResolvedFieldDisabled(disabledProp);
44
48
  const resolvedMode = useResolvedFieldMode({ mode: modeProp, disabled });
@@ -79,17 +83,17 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
79
83
  }, [ref]);
80
84
  if (resolvedMode === "display") {
81
85
  if (!showDisplayEndIcon) {
82
- if (isEmpty) return /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY });
86
+ if (isEmpty) return /* @__PURE__ */ jsx("span", { className: fieldEmptyColorClass(resolvedMode), children: emptyDisplay });
83
87
  return isMulti ? /* @__PURE__ */ jsx(MultiPersonDisplay, { value, size, measured: true }) : /* @__PURE__ */ jsx(PersonDisplay, { value, size });
84
88
  }
85
89
  const iconSize = ICON_SIZE[size];
86
90
  return /* @__PURE__ */ jsxs(
87
91
  "div",
88
92
  {
89
- className: cn(fieldWrapperStyles({ mode: "display", variant: resolvedVariant, size }), className),
93
+ className: cn(fieldWrapperStyles({ mode: "display", variant: resolvedVariant, width, size }), className),
90
94
  "data-field-mode": "display",
91
95
  children: [
92
- /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 inline-flex items-center", nakedCellRowModeAlign), children: isEmpty ? /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY }) : isMulti ? /* @__PURE__ */ jsx(MultiPersonDisplay, { value, size, measured: true }) : /* @__PURE__ */ jsx(PersonDisplay, { value, size }) }),
96
+ /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 inline-flex items-center", nakedCellRowModeAlign), children: isEmpty ? /* @__PURE__ */ jsx("span", { className: fieldEmptyColorClass(resolvedMode), children: emptyDisplay }) : isMulti ? /* @__PURE__ */ jsx(MultiPersonDisplay, { value, size, measured: true }) : /* @__PURE__ */ jsx(PersonDisplay, { value, size }) }),
93
97
  /* @__PURE__ */ jsx(ItemSuffix, { className: "pointer-events-none", children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize, className: "shrink-0 text-fg-muted", "aria-hidden": true }) })
94
98
  ]
95
99
  }
@@ -100,13 +104,13 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
100
104
  "div",
101
105
  {
102
106
  ref,
103
- className: cn(fieldWrapperStyles({ mode: resolvedMode, variant: resolvedVariant, size }), className),
107
+ className: cn(fieldWrapperStyles({ mode: resolvedMode, variant: resolvedVariant, width, size }), className),
104
108
  "data-field-mode": resolvedMode,
105
109
  "aria-disabled": resolvedMode === "disabled" ? true : void 0,
106
110
  "aria-label": ariaLabel,
107
111
  ...rest,
108
112
  children: [
109
- /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 inline-flex items-center", nakedCellRowModeAlign, resolvedMode === "disabled" && "text-fg-disabled"), children: isEmpty ? /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY }) : isMulti ? /* @__PURE__ */ jsx(MultiPersonDisplay, { value, size, measured: true }) : /* @__PURE__ */ jsx(PersonDisplay, { value, size }) }),
113
+ /* @__PURE__ */ jsx("span", { className: cn("flex-1 min-w-0 inline-flex items-center", nakedCellRowModeAlign, resolvedMode === "disabled" && "text-fg-disabled"), children: isEmpty ? /* @__PURE__ */ jsx("span", { className: fieldEmptyColorClass(resolvedMode), children: emptyDisplay }) : isMulti ? /* @__PURE__ */ jsx(MultiPersonDisplay, { value, size, measured: true, disabled: resolvedMode === "disabled" }) : /* @__PURE__ */ jsx(PersonDisplay, { value, size, disabled: resolvedMode === "disabled" }) }),
110
114
  (resolvedVariant === "naked" ? showDisplayEndIcon : resolvedMode === "disabled") && /* @__PURE__ */ jsx(ItemSuffix, { className: "pointer-events-none", children: /* @__PURE__ */ jsx(ChevronDown, { size: ICON_SIZE[size], className: cn("shrink-0", resolvedMode === "disabled" ? "text-fg-disabled" : "text-fg-muted"), "aria-hidden": true }) })
111
115
  ]
112
116
  }
@@ -118,6 +122,7 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
118
122
  Select,
119
123
  {
120
124
  ref,
125
+ width,
121
126
  size,
122
127
  variant: resolvedVariant,
123
128
  options: people.map(personToSelectOption),
@@ -142,6 +147,7 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
142
147
  return /* @__PURE__ */ jsx(
143
148
  Combobox,
144
149
  {
150
+ width,
145
151
  ref,
146
152
  size,
147
153
  variant: resolvedVariant,
@@ -149,6 +155,7 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
149
155
  value: selectedNames,
150
156
  onChange: handleMultiChange2,
151
157
  searchable: true,
158
+ searchIn,
152
159
  searchPlaceholder,
153
160
  placeholder,
154
161
  emptyText,
@@ -181,6 +188,7 @@ const PeoplePicker = React.forwardRef(function PeoplePicker2({
181
188
  return /* @__PURE__ */ jsx(
182
189
  Combobox,
183
190
  {
191
+ width,
184
192
  ref: mergedStackRef,
185
193
  size,
186
194
  variant: resolvedVariant,
@@ -261,9 +269,14 @@ const peoplePickerMeta = {
261
269
  }
262
270
  };
263
271
  export {
272
+ MultiPersonDisplay,
264
273
  PEOPLE_PICKER_LENGTH1_WRAPPER_CLASS,
265
274
  PeoplePicker,
275
+ PersonAvatarTag,
276
+ PersonDisplay,
277
+ buildPersonProfileCard,
266
278
  getPeoplePickerTagWrapperClass,
267
- peoplePickerMeta
279
+ peoplePickerMeta,
280
+ resolvePerson
268
281
  };
269
282
  //# sourceMappingURL=people-picker.js.map
@@ -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 } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, EMPTY_DISPLAY, nakedCellRowModeAlign } from '@/design-system/components/Field/field-wrapper'\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 } from '@/design-system/components/Select/select'\nimport { Combobox } 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'\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 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 */\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 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 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: FieldVariant = 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=\"text-fg-muted\">{EMPTY_DISPLAY}</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, 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=\"text-fg-muted\">{EMPTY_DISPLAY}</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, 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 {isEmpty\n ? <span className=\"text-fg-muted\">{EMPTY_DISPLAY}</span>\n : isMulti\n ? <MultiPersonDisplay value={value as PersonValue[]} size={size} measured />\n : <PersonDisplay value={value as PersonValue} size={size} />}\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 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 extends `SelectHTMLAttributes<HTMLSelectElement>`,\n // event handler element 型別跟 PeoplePicker `HTMLAttributes<HTMLDivElement>` 不一致\n // (`onCopy` / `onChange` 等)。Runtime spread 等效 — DOM 收到 attrs 不挑剔。\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 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 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 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"],"names":["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;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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"}
@@ -33,14 +33,15 @@ export interface PersonData {
33
33
  export type PersonValue = string | PersonData;
34
34
  declare function resolvePerson(value: PersonValue): PersonData;
35
35
  declare function buildPersonProfileCard(person: PersonData): React.ReactNode;
36
- declare function PersonDisplay({ value, size }: {
36
+ declare function PersonDisplay({ value, size, disabled }: {
37
37
  value?: PersonValue | null;
38
- size?: 'sm' | 'md' | 'lg';
38
+ size?: 'sm' | 'md' | 'lg'; /** 見 PersonAvatar.disabled jsDoc(抑制 hoverCard + dim) */
39
+ disabled?: boolean;
39
40
  }): import("react/jsx-runtime").JSX.Element;
40
41
  declare namespace PersonDisplay {
41
42
  var displayName: string;
42
43
  }
43
- declare function MultiPersonDisplay({ value, size, max, measured, onRemove, }: {
44
+ declare function MultiPersonDisplay({ value, size, max, measured, onRemove, disabled, }: {
44
45
  value?: PersonValue[] | null;
45
46
  size?: 'sm' | 'md' | 'lg';
46
47
  /** 最多顯示幾個 avatar(不含 +N),預設 3。`measured=true` 時忽略此 prop(改 container width 算)*/
@@ -54,6 +55,8 @@ declare function MultiPersonDisplay({ value, size, max, measured, onRemove, }: {
54
55
  measured?: boolean;
55
56
  /** 傳入時啟用 dismiss(edit mode),callback 接收被移除的 person */
56
57
  onRemove?: (person: PersonValue) => void;
58
+ /** 見 PersonAvatar.disabled jsDoc(抑制全 stack ProfileCard hoverCard + avatar dim) */
59
+ disabled?: boolean;
57
60
  }): import("react/jsx-runtime").JSX.Element;
58
61
  declare namespace MultiPersonDisplay {
59
62
  var displayName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"person-display.d.ts","sourceRoot":"","sources":["../../../src/components/PeoplePicker/person-display.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAqB9B,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;0BAGsB;IACtB,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/C;mEAC+D;IAC/D,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B;;oEAEgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;6DACyD;IACzD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC3C,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,oGAAoG;IACpG,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,CAAA;AAE7C,iBAAS,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CAErD;AASD,iBAAS,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC,SAAS,CAoBnE;AAwDD,iBAAS,aAAa,CAAC,EAAE,KAAK,EAAE,IAAW,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;CAAE,2CAgBvG;kBAhBQ,aAAa;;;AAwBtB,iBAAS,kBAAkB,CAAC,EAC1B,KAAK,EACL,IAAW,EACX,GAAG,EACH,QAAgB,EAChB,QAAQ,GACT,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAC5B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;CACzC,2CAiGA;kBArHQ,kBAAkB;;;AAwL3B,iBAAS,eAAe,CAAC,EACvB,MAAM,EAAE,IAAW,EAAE,QAAQ,GAC9B,EAAE;IACD,MAAM,EAAE,UAAU,CAAA;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,2CAOA;kBAbQ,eAAe;;;AAgBxB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,sBAAsB,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"person-display.d.ts","sourceRoot":"","sources":["../../../src/components/PeoplePicker/person-display.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAuB9B,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;0BAGsB;IACtB,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IAC/C;mEAC+D;IAC/D,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC/B;;oEAEgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;6DACyD;IACzD,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC3C,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,oGAAoG;IACpG,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,CAAA;AAE7C,iBAAS,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CAErD;AASD,iBAAS,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC,SAAS,CAoBnE;AA+DD,iBAAS,aAAa,CAAC,EAAE,KAAK,EAAE,IAAW,EAAE,QAAgB,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,wDAAwD;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,2CAiBtM;kBAjBQ,aAAa;;;AAyBtB,iBAAS,kBAAkB,CAAC,EAC1B,KAAK,EACL,IAAW,EACX,GAAG,EACH,QAAgB,EAChB,QAAQ,EACR,QAAgB,GACjB,EAAE;IACD,KAAK,CAAC,EAAE,WAAW,EAAE,GAAG,IAAI,CAAA;IAC5B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;IACxC,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,2CAoGA;kBA3HQ,kBAAkB;;;AA8L3B,iBAAS,eAAe,CAAC,EACvB,MAAM,EAAE,IAAW,EAAE,QAAQ,GAC9B,EAAE;IACD,MAAM,EAAE,UAAU,CAAA;IAClB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB,2CAOA;kBAbQ,eAAe;;;AAgBxB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,sBAAsB,EAAE,aAAa,EAAE,CAAA"}
@@ -1,12 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { X } from "lucide-react";
4
- import { EMPTY_DISPLAY } from "../Field/field-wrapper.js";
4
+ import { cn } from "../../lib/utils.js";
5
+ import { useFieldEmptyDisplay, useTableIsScrolling } from "../Field/field-context.js";
5
6
  import { Tag } from "../Tag/tag.js";
6
7
  import { OverflowIndicator } from "../OverflowIndicator/overflow-indicator.js";
7
8
  import { Avatar } from "../Avatar/avatar.js";
8
9
  import { ProfileCard, ProfileCardDefaultActions } from "../ProfileCard/profile-card.js";
9
- import { useTableIsScrolling } from "../Field/field-context.js";
10
10
  import { ItemPrefix } from "../../patterns/element-anatomy/item-anatomy.js";
11
11
  import { getAvatarStackVisibleCount, AVATAR_STACK_AVATAR_PX, AVATAR_STACK_OVERFLOW_CHIP_PX } from "./avatar-stack-overflow.js";
12
12
  function resolvePerson(value) {
@@ -37,12 +37,13 @@ function PersonAvatar({
37
37
  person,
38
38
  size = "md",
39
39
  className = "",
40
- style
40
+ style,
41
+ disabled = false
41
42
  }) {
42
43
  const isTableScrolling = useTableIsScrolling();
43
44
  const nameCard = React.useMemo(
44
- () => isTableScrolling ? void 0 : buildPersonProfileCard(person),
45
- [person, isTableScrolling]
45
+ () => isTableScrolling || disabled ? void 0 : buildPersonProfileCard(person),
46
+ [person, isTableScrolling, disabled]
46
47
  );
47
48
  return /* @__PURE__ */ jsx(
48
49
  Avatar,
@@ -50,17 +51,18 @@ function PersonAvatar({
50
51
  src: person.avatarUrl,
51
52
  alt: person.name,
52
53
  size: AVATAR_PX[size],
53
- className,
54
+ className: cn(className, disabled && "opacity-disabled"),
54
55
  style,
55
56
  hoverCard: nameCard
56
57
  }
57
58
  );
58
59
  }
59
- function PersonDisplay({ value, size = "md" }) {
60
- if (!value) return /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY });
60
+ function PersonDisplay({ value, size = "md", disabled = false }) {
61
+ const emptyDisplay = useFieldEmptyDisplay();
62
+ if (!value) return /* @__PURE__ */ jsx("span", { className: "text-foreground", children: emptyDisplay });
61
63
  const person = resolvePerson(value);
62
64
  return /* @__PURE__ */ jsxs("span", { className: "flex items-start gap-2 min-w-0 w-full", children: [
63
- /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(PersonAvatar, { person, size }) }),
65
+ /* @__PURE__ */ jsx(ItemPrefix, { children: /* @__PURE__ */ jsx(PersonAvatar, { person, size, disabled }) }),
64
66
  /* @__PURE__ */ jsx("span", { className: "truncate flex-1 min-w-0", children: person.name })
65
67
  ] });
66
68
  }
@@ -70,8 +72,10 @@ function MultiPersonDisplay({
70
72
  size = "md",
71
73
  max,
72
74
  measured = false,
73
- onRemove
75
+ onRemove,
76
+ disabled = false
74
77
  }) {
78
+ const emptyDisplay = useFieldEmptyDisplay();
75
79
  const containerRef = React.useRef(null);
76
80
  const [measuredCount, setMeasuredCount] = React.useState(null);
77
81
  React.useLayoutEffect(() => {
@@ -92,14 +96,14 @@ function MultiPersonDisplay({
92
96
  ro.observe(el);
93
97
  return () => ro.disconnect();
94
98
  }, [measured, size, value]);
95
- if (!value || value.length === 0) return /* @__PURE__ */ jsx("span", { className: "text-fg-muted", children: EMPTY_DISPLAY });
99
+ if (!value || value.length === 0) return /* @__PURE__ */ jsx("span", { className: "text-foreground", children: emptyDisplay });
96
100
  const resolvedMax = measured && measuredCount !== null ? measuredCount : max ?? 3;
97
101
  const people = value.map(resolvePerson);
98
102
  const visible = people.slice(0, resolvedMax);
99
103
  const hidden = people.slice(resolvedMax);
100
104
  const overflow = hidden.length;
101
105
  if (people.length === 1) {
102
- return /* @__PURE__ */ jsx(PersonDisplay, { value: value[0], size });
106
+ return /* @__PURE__ */ jsx(PersonDisplay, { value: value[0], size, disabled });
103
107
  }
104
108
  return /* @__PURE__ */ jsx("span", { ref: containerRef, className: "inline-flex items-start min-w-0", children: /* @__PURE__ */ jsx(ItemPrefix, { className: "!justify-start", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center min-w-0", children: [
105
109
  visible.map((person, i) => {
@@ -110,7 +114,8 @@ function MultiPersonDisplay({
110
114
  {
111
115
  person,
112
116
  size,
113
- className: "ring-2 ring-[var(--surface)]"
117
+ className: "ring-2 ring-[var(--surface)]",
118
+ disabled
114
119
  }
115
120
  ),
116
121
  handleDismiss && /* @__PURE__ */ jsx(AvatarDismissOverlay, { onRemove: handleDismiss, label: person.name })
@@ -133,7 +138,7 @@ function MultiPersonDisplay({
133
138
  src: person.avatarUrl,
134
139
  alt: person.name,
135
140
  size: 16,
136
- hoverCard: buildPersonProfileCard(person)
141
+ hoverCard: disabled ? void 0 : buildPersonProfileCard(person)
137
142
  }
138
143
  ),
139
144
  onRemove: onRemove ? () => onRemove(value[resolvedMax + i]) : void 0,