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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/AGENTS.md +210 -0
  2. package/CLAUDE.md +17 -191
  3. package/cli-init.mjs +30 -2
  4. package/dist/components/Accordion/accordion.d.ts +2 -2
  5. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  6. package/dist/components/Accordion/accordion.js.map +1 -1
  7. package/dist/components/Avatar/avatar.js +1 -1
  8. package/dist/components/Avatar/avatar.js.map +1 -1
  9. package/dist/components/BulkActionBar/bulk-action-bar.d.ts +1 -1
  10. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  11. package/dist/components/BulkActionBar/bulk-action-bar.js +3 -3
  12. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  13. package/dist/components/Button/button-group.d.ts +2 -2
  14. package/dist/components/Button/button-group.d.ts.map +1 -1
  15. package/dist/components/Button/button-group.js +2 -2
  16. package/dist/components/Button/button-group.js.map +1 -1
  17. package/dist/components/Button/button.d.ts +2 -1
  18. package/dist/components/Button/button.d.ts.map +1 -1
  19. package/dist/components/Button/button.js +1 -1
  20. package/dist/components/Button/button.js.map +1 -1
  21. package/dist/components/Carousel/carousel.d.ts +14 -8
  22. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  23. package/dist/components/Carousel/carousel.js +64 -37
  24. package/dist/components/Carousel/carousel.js.map +1 -1
  25. package/dist/components/Checkbox/checkbox-group.d.ts.map +1 -1
  26. package/dist/components/Checkbox/checkbox-group.js +21 -14
  27. package/dist/components/Checkbox/checkbox-group.js.map +1 -1
  28. package/dist/components/Checkbox/checkbox.d.ts +2 -2
  29. package/dist/components/Checkbox/checkbox.d.ts.map +1 -1
  30. package/dist/components/Checkbox/checkbox.js +49 -10
  31. package/dist/components/Checkbox/checkbox.js.map +1 -1
  32. package/dist/components/Combobox/combobox.d.ts +15 -6
  33. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  34. package/dist/components/Combobox/combobox.js +13 -7
  35. package/dist/components/Combobox/combobox.js.map +1 -1
  36. package/dist/components/Command/command.d.ts.map +1 -1
  37. package/dist/components/Command/command.js +11 -2
  38. package/dist/components/Command/command.js.map +1 -1
  39. package/dist/components/DataTable/cell-registry.d.ts +5 -5
  40. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  41. package/dist/components/DataTable/cell-registry.js +41 -38
  42. package/dist/components/DataTable/cell-registry.js.map +1 -1
  43. package/dist/components/DataTable/column-types.d.ts +1 -17
  44. package/dist/components/DataTable/column-types.d.ts.map +1 -1
  45. package/dist/components/DataTable/column-types.js.map +1 -1
  46. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table-column-visibility-panel.js +71 -64
  48. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  49. package/dist/components/DataTable/data-table-filter-panel.d.ts +0 -2
  50. package/dist/components/DataTable/data-table-filter-panel.d.ts.map +1 -1
  51. package/dist/components/DataTable/data-table-filter-panel.js +3 -4
  52. package/dist/components/DataTable/data-table-filter-panel.js.map +1 -1
  53. package/dist/components/DataTable/data-table-interaction-layer.d.ts +2 -2
  54. package/dist/components/DataTable/data-table-interaction-layer.js.map +1 -1
  55. package/dist/components/DataTable/data-table-sort-manager.js +2 -2
  56. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  57. package/dist/components/DataTable/data-table.d.ts +1 -1
  58. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  59. package/dist/components/DataTable/data-table.js +44 -32
  60. package/dist/components/DataTable/data-table.js.map +1 -1
  61. package/dist/components/DatePicker/date-picker.d.ts +3 -3
  62. package/dist/components/DatePicker/date-picker.js +4 -4
  63. package/dist/components/DatePicker/date-picker.js.map +1 -1
  64. package/dist/components/DescriptionList/description-list.d.ts +3 -3
  65. package/dist/components/DescriptionList/description-list.d.ts.map +1 -1
  66. package/dist/components/DescriptionList/description-list.js +6 -6
  67. package/dist/components/DescriptionList/description-list.js.map +1 -1
  68. package/dist/components/Dialog/dialog.d.ts +2 -2
  69. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  70. package/dist/components/Dialog/dialog.js.map +1 -1
  71. package/dist/components/DropdownMenu/dropdown-menu.d.ts +8 -3
  72. package/dist/components/DropdownMenu/dropdown-menu.d.ts.map +1 -1
  73. package/dist/components/DropdownMenu/dropdown-menu.js +7 -7
  74. package/dist/components/DropdownMenu/dropdown-menu.js.map +1 -1
  75. package/dist/components/Field/field-context.d.ts +16 -10
  76. package/dist/components/Field/field-context.d.ts.map +1 -1
  77. package/dist/components/Field/field-context.js.map +1 -1
  78. package/dist/components/Field/field-types.d.ts +2 -2
  79. package/dist/components/Field/field-types.d.ts.map +1 -1
  80. package/dist/components/Field/field-types.js.map +1 -1
  81. package/dist/components/Field/field-wrapper.d.ts +20 -4
  82. package/dist/components/Field/field-wrapper.d.ts.map +1 -1
  83. package/dist/components/Field/field-wrapper.js +30 -31
  84. package/dist/components/Field/field-wrapper.js.map +1 -1
  85. package/dist/components/Field/field.d.ts +1 -1
  86. package/dist/components/Field/field.d.ts.map +1 -1
  87. package/dist/components/Field/field.js +25 -3
  88. package/dist/components/Field/field.js.map +1 -1
  89. package/dist/components/Field/use-form-validation.d.ts +1 -1
  90. package/dist/components/Field/use-form-validation.js.map +1 -1
  91. package/dist/components/FileItem/file-item.d.ts.map +1 -1
  92. package/dist/components/FileItem/file-item.js +2 -5
  93. package/dist/components/FileItem/file-item.js.map +1 -1
  94. package/dist/components/FileUpload/file-upload.d.ts.map +1 -1
  95. package/dist/components/FileUpload/file-upload.js +5 -1
  96. package/dist/components/FileUpload/file-upload.js.map +1 -1
  97. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  98. package/dist/components/FileViewer/file-viewer.js +2 -1
  99. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  100. package/dist/components/HoverCard/hover-card.d.ts +2 -2
  101. package/dist/components/HoverCard/hover-card.d.ts.map +1 -1
  102. package/dist/components/HoverCard/hover-card.js +4 -2
  103. package/dist/components/HoverCard/hover-card.js.map +1 -1
  104. package/dist/components/InlineEdit/inline-edit.d.ts +23 -16
  105. package/dist/components/InlineEdit/inline-edit.d.ts.map +1 -1
  106. package/dist/components/InlineEdit/inline-edit.js +104 -62
  107. package/dist/components/InlineEdit/inline-edit.js.map +1 -1
  108. package/dist/components/Input/input.d.ts +1 -1
  109. package/dist/components/Input/input.d.ts.map +1 -1
  110. package/dist/components/Input/input.js +6 -6
  111. package/dist/components/Input/input.js.map +1 -1
  112. package/dist/components/LinkInput/link-input.d.ts +5 -5
  113. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  114. package/dist/components/LinkInput/link-input.js +3 -3
  115. package/dist/components/LinkInput/link-input.js.map +1 -1
  116. package/dist/components/Notice/notice.d.ts +17 -1
  117. package/dist/components/Notice/notice.d.ts.map +1 -1
  118. package/dist/components/Notice/notice.js +7 -1
  119. package/dist/components/Notice/notice.js.map +1 -1
  120. package/dist/components/NumberInput/number-input.d.ts +1 -1
  121. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  122. package/dist/components/NumberInput/number-input.js +12 -1
  123. package/dist/components/NumberInput/number-input.js.map +1 -1
  124. package/dist/components/PeoplePicker/avatar-stack-overflow.d.ts +1 -1
  125. package/dist/components/PeoplePicker/avatar-stack-overflow.js.map +1 -1
  126. package/dist/components/PeoplePicker/people-picker.d.ts +5 -5
  127. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  128. package/dist/components/PeoplePicker/people-picker.js +7 -5
  129. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  130. package/dist/components/PeoplePicker/person-display.d.ts +1 -1
  131. package/dist/components/PeoplePicker/person-display.js.map +1 -1
  132. package/dist/components/ProfileCard/profile-card.d.ts +1 -1
  133. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  134. package/dist/components/RadioGroup/radio-group.d.ts +3 -3
  135. package/dist/components/RadioGroup/radio-group.d.ts.map +1 -1
  136. package/dist/components/RadioGroup/radio-group.js +1 -1
  137. package/dist/components/RadioGroup/radio-group.js.map +1 -1
  138. package/dist/components/Rating/rating.d.ts.map +1 -1
  139. package/dist/components/Rating/rating.js +4 -0
  140. package/dist/components/Rating/rating.js.map +1 -1
  141. package/dist/components/ScrollArea/scroll-area.d.ts +3 -2
  142. package/dist/components/ScrollArea/scroll-area.d.ts.map +1 -1
  143. package/dist/components/ScrollArea/scroll-area.js.map +1 -1
  144. package/dist/components/SegmentedControl/segmented-control.d.ts +4 -3
  145. package/dist/components/SegmentedControl/segmented-control.d.ts.map +1 -1
  146. package/dist/components/SegmentedControl/segmented-control.js.map +1 -1
  147. package/dist/components/Select/select.d.ts +16 -6
  148. package/dist/components/Select/select.d.ts.map +1 -1
  149. package/dist/components/Select/select.js +17 -5
  150. package/dist/components/Select/select.js.map +1 -1
  151. package/dist/components/SelectMenu/select-menu.d.ts +17 -1
  152. package/dist/components/SelectMenu/select-menu.d.ts.map +1 -1
  153. package/dist/components/SelectMenu/select-menu.js +17 -3
  154. package/dist/components/SelectMenu/select-menu.js.map +1 -1
  155. package/dist/components/SelectionControl/boolean-value.d.ts +1 -1
  156. package/dist/components/SelectionControl/boolean-value.js.map +1 -1
  157. package/dist/components/Sheet/sheet.d.ts +2 -2
  158. package/dist/components/Sheet/sheet.d.ts.map +1 -1
  159. package/dist/components/Sheet/sheet.js.map +1 -1
  160. package/dist/components/Sidebar/sidebar.d.ts +1 -1
  161. package/dist/components/Sidebar/sidebar.js +2 -2
  162. package/dist/components/Sidebar/sidebar.js.map +1 -1
  163. package/dist/components/Slider/slider.d.ts.map +1 -1
  164. package/dist/components/Slider/slider.js +6 -3
  165. package/dist/components/Slider/slider.js.map +1 -1
  166. package/dist/components/Steps/steps.d.ts +6 -4
  167. package/dist/components/Steps/steps.d.ts.map +1 -1
  168. package/dist/components/Steps/steps.js +19 -5
  169. package/dist/components/Steps/steps.js.map +1 -1
  170. package/dist/components/Switch/switch.d.ts +4 -4
  171. package/dist/components/Switch/switch.d.ts.map +1 -1
  172. package/dist/components/Switch/switch.js +3 -1
  173. package/dist/components/Switch/switch.js.map +1 -1
  174. package/dist/components/Tabs/tabs.d.ts +1 -1
  175. package/dist/components/Tabs/tabs.d.ts.map +1 -1
  176. package/dist/components/Tabs/tabs.js +73 -23
  177. package/dist/components/Tabs/tabs.js.map +1 -1
  178. package/dist/components/Tag/tag.d.ts +3 -1
  179. package/dist/components/Tag/tag.d.ts.map +1 -1
  180. package/dist/components/Tag/tag.js +2 -2
  181. package/dist/components/Tag/tag.js.map +1 -1
  182. package/dist/components/Textarea/textarea.d.ts +4 -4
  183. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  184. package/dist/components/Textarea/textarea.js +15 -15
  185. package/dist/components/Textarea/textarea.js.map +1 -1
  186. package/dist/components/TimePicker/time-picker.d.ts +4 -4
  187. package/dist/components/TimePicker/time-picker.d.ts.map +1 -1
  188. package/dist/components/TimePicker/time-picker.js +8 -5
  189. package/dist/components/TimePicker/time-picker.js.map +1 -1
  190. package/dist/components/Tooltip/tooltip.d.ts.map +1 -1
  191. package/dist/components/Tooltip/tooltip.js +27 -23
  192. package/dist/components/Tooltip/tooltip.js.map +1 -1
  193. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  194. package/dist/components/TreeView/tree-view.js +16 -0
  195. package/dist/components/TreeView/tree-view.js.map +1 -1
  196. package/dist/index.d.ts +7 -7
  197. package/dist/index.d.ts.map +1 -1
  198. package/dist/index.js +6 -13
  199. package/dist/index.js.map +1 -1
  200. package/dist/lib/drag-visual.d.ts +2 -2
  201. package/dist/lib/drag-visual.js.map +1 -1
  202. package/dist/lib/utils.d.ts +1 -0
  203. package/dist/lib/utils.d.ts.map +1 -1
  204. package/dist/lib/utils.js +21 -1
  205. package/dist/lib/utils.js.map +1 -1
  206. package/dist/patterns/element-anatomy/item-anatomy.d.ts +2 -0
  207. package/dist/patterns/element-anatomy/item-anatomy.d.ts.map +1 -1
  208. package/dist/patterns/element-anatomy/item-anatomy.js +2 -2
  209. package/dist/patterns/element-anatomy/item-anatomy.js.map +1 -1
  210. package/dist/tokens/categorical-color.d.ts +3 -3
  211. package/dist/tokens/categorical-color.d.ts.map +1 -1
  212. package/dist/tokens/categorical-color.js +2 -2
  213. package/dist/tokens/categorical-color.js.map +1 -1
  214. package/ds-canonical/fork/AGENTS.md +213 -0
  215. package/ds-canonical/fork/codex/agents/skills/independent-review/SKILL.md +33 -0
  216. package/ds-canonical/fork/codex/hooks.json +16 -0
  217. package/ds-canonical/fork/governance.lock +22 -7
  218. package/ds-canonical/fork/hooks/check_ds_anchor_preflight.sh +22 -1
  219. package/ds-canonical/fork/hooks/inject_deploy_url_after_push.sh +14 -2
  220. package/ds-canonical/fork/manifest.json +10 -1
  221. package/ds-canonical/fork/preamble.md +3 -2
  222. package/ds-canonical/fork/skills/product-ui-audit/SKILL.md +7 -7
  223. package/ds-canonical/fork/skills/ux-audit/SKILL.md +1 -1
  224. package/ds-canonical/fork/skills/visual-audit/SKILL.md +0 -1
  225. package/ds-canonical/hooks/check_codex_brief_invariants.sh +9 -3
  226. package/ds-canonical/hooks/check_ds_anchor_preflight.sh +22 -1
  227. package/ds-canonical/hooks/check_overlay_open_focus_escape_probe.sh +11 -2
  228. package/ds-canonical/hooks/check_plugin_fork_health.sh +17 -1
  229. package/ds-canonical/hooks/check_post_main_ssot_propagate.sh +21 -4
  230. package/ds-canonical/hooks/inject_deploy_url_after_push.sh +14 -2
  231. package/ds-canonical/hooks/session_start_governance_check.sh +10 -2
  232. package/ds-canonical/references/certified-surfaces.md +20 -0
  233. package/ds-canonical/references/preflight-gate-baseline.json +5 -0
  234. package/ds-canonical/references/principle-dim-map.json +20 -2
  235. package/ds-canonical/references/props-naming.md +2 -1
  236. package/ds-canonical/references/ssot-index.md +2 -2
  237. package/ds-canonical/references/story-baseline-registry.json +2 -2
  238. package/ds-canonical/rules/story-rules.md +1 -1
  239. package/ds-canonical/rules/ui-development.md +2 -1
  240. package/ds-canonical/skills/codex-collab/SKILL.md +7 -7
  241. package/ds-canonical/skills/codex-collab/references/brief-template.md +5 -1
  242. package/ds-canonical/skills/component-quality-gate/SKILL.md +1 -1
  243. package/ds-canonical/skills/deep-audit-cross-codex/SKILL.md +5 -5
  244. package/ds-canonical/skills/design-system-audit/SKILL.md +5 -5
  245. package/ds-canonical/skills/product-ui-audit/SKILL.md +7 -7
  246. package/ds-canonical/skills/ux-audit/SKILL.md +1 -1
  247. package/ds-canonical/skills/visual-audit/SKILL.md +0 -1
  248. package/ds-story-manifest.json +21 -21
  249. package/llms-full.txt +3 -3
  250. package/llms.txt +1 -1
  251. package/package.json +2 -1
  252. package/src/components/Accordion/accordion.anatomy.stories.tsx +11 -11
  253. package/src/components/Accordion/accordion.principles.stories.tsx +21 -6
  254. package/src/components/Accordion/accordion.spec.md +10 -1
  255. package/src/components/Accordion/accordion.stories.tsx +10 -5
  256. package/src/components/Accordion/accordion.tsx +7 -2
  257. package/src/components/Alert/alert.principles.stories.tsx +2 -8
  258. package/src/components/AppShell/app-shell.anatomy.stories.tsx +19 -13
  259. package/src/components/AppShell/app-shell.principles.stories.tsx +21 -21
  260. package/src/components/AppShell/app-shell.spec.md +4 -0
  261. package/src/components/AppShell/app-shell.stories.tsx +4 -5
  262. package/src/components/Avatar/avatar.tsx +1 -1
  263. package/src/components/Badge/badge.spec.md +2 -2
  264. package/src/components/Breadcrumb/breadcrumb.anatomy.stories.tsx +7 -3
  265. package/src/components/Breadcrumb/breadcrumb.principles.stories.tsx +4 -1
  266. package/src/components/Breadcrumb/breadcrumb.stories.tsx +1 -1
  267. package/src/components/BulkActionBar/bulk-action-bar.anatomy.stories.tsx +6 -6
  268. package/src/components/BulkActionBar/bulk-action-bar.principles.stories.tsx +18 -6
  269. package/src/components/BulkActionBar/bulk-action-bar.spec.md +15 -5
  270. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +8 -24
  271. package/src/components/BulkActionBar/bulk-action-bar.tsx +4 -4
  272. package/src/components/Button/button-group.tsx +4 -4
  273. package/src/components/Button/button.anatomy.stories.tsx +26 -7
  274. package/src/components/Button/button.principles.stories.tsx +1 -1
  275. package/src/components/Button/button.spec.md +2 -2
  276. package/src/components/Button/button.stories.tsx +22 -28
  277. package/src/components/Button/button.tsx +2 -1
  278. package/src/components/Calendar/calendar.anatomy.stories.tsx +1 -1
  279. package/src/components/Calendar/calendar.spec.md +1 -1
  280. package/src/components/Carousel/carousel.spec.md +17 -1
  281. package/src/components/Carousel/carousel.tsx +93 -42
  282. package/src/components/Checkbox/checkbox-group.tsx +26 -15
  283. package/src/components/Checkbox/checkbox.anatomy.stories.tsx +3 -3
  284. package/src/components/Checkbox/checkbox.spec.md +12 -3
  285. package/src/components/Checkbox/checkbox.stories.tsx +4 -4
  286. package/src/components/Checkbox/checkbox.tsx +79 -19
  287. package/src/components/Coachmark/coachmark.anatomy.stories.tsx +5 -5
  288. package/src/components/Coachmark/coachmark.principles.stories.tsx +1 -1
  289. package/src/components/Combobox/combobox.anatomy.stories.tsx +11 -4
  290. package/src/components/Combobox/combobox.principles.stories.tsx +10 -11
  291. package/src/components/Combobox/combobox.spec.md +6 -2
  292. package/src/components/Combobox/combobox.stories.tsx +9 -36
  293. package/src/components/Combobox/combobox.tsx +42 -27
  294. package/src/components/Command/command.spec.md +3 -3
  295. package/src/components/Command/command.tsx +9 -2
  296. package/src/components/DataTable/cell-registry.tsx +75 -76
  297. package/src/components/DataTable/column-types.ts +4 -17
  298. package/src/components/DataTable/data-table-column-visibility-panel.tsx +20 -7
  299. package/src/components/DataTable/data-table-filter-panel.tsx +6 -6
  300. package/src/components/DataTable/data-table-interaction-layer.tsx +3 -3
  301. package/src/components/DataTable/data-table-sort-manager.tsx +2 -2
  302. package/src/components/DataTable/data-table.anatomy.stories.tsx +25 -24
  303. package/src/components/DataTable/data-table.css +2 -3
  304. package/src/components/DataTable/data-table.principles.stories.tsx +17 -11
  305. package/src/components/DataTable/data-table.spec.md +7 -7
  306. package/src/components/DataTable/data-table.stories.tsx +39 -29
  307. package/src/components/DataTable/data-table.tsx +90 -67
  308. package/src/components/DataTable/filter-operators.spec.md +2 -0
  309. package/src/components/DateGrid/date-grid.spec.md +1 -1
  310. package/src/components/DatePicker/date-picker.anatomy.stories.tsx +9 -9
  311. package/src/components/DatePicker/date-picker.principles.stories.tsx +4 -4
  312. package/src/components/DatePicker/date-picker.spec.md +9 -9
  313. package/src/components/DatePicker/date-picker.stories.tsx +9 -9
  314. package/src/components/DatePicker/date-picker.tsx +13 -13
  315. package/src/components/DescriptionList/description-list.anatomy.stories.tsx +5 -5
  316. package/src/components/DescriptionList/description-list.principles.stories.tsx +2 -2
  317. package/src/components/DescriptionList/description-list.spec.md +12 -12
  318. package/src/components/DescriptionList/description-list.stories.tsx +3 -3
  319. package/src/components/DescriptionList/description-list.tsx +10 -10
  320. package/src/components/Dialog/dialog.tsx +4 -1
  321. package/src/components/DropdownMenu/dropdown-menu.tsx +27 -14
  322. package/src/components/Field/field-context.ts +17 -11
  323. package/src/components/Field/field-controls.spec.md +44 -37
  324. package/src/components/Field/field-types.ts +14 -12
  325. package/src/components/Field/field-wrapper.tsx +59 -43
  326. package/src/components/Field/field.anatomy.stories.tsx +6 -6
  327. package/src/components/Field/field.principles.stories.tsx +5 -28
  328. package/src/components/Field/field.spec.md +4 -4
  329. package/src/components/Field/field.stories.tsx +103 -72
  330. package/src/components/Field/field.tsx +36 -4
  331. package/src/components/Field/form-validation.spec.md +2 -0
  332. package/src/components/Field/use-form-validation.ts +1 -1
  333. package/src/components/FieldControlGroup/field-control-group.principles.stories.tsx +3 -3
  334. package/src/components/FieldControlGroup/field-control-group.spec.md +3 -3
  335. package/src/components/FileItem/file-item.tsx +10 -8
  336. package/src/components/FileUpload/file-upload.principles.stories.tsx +7 -7
  337. package/src/components/FileUpload/file-upload.spec.md +3 -2
  338. package/src/components/FileUpload/file-upload.tsx +5 -1
  339. package/src/components/FileViewer/file-viewer.anatomy.stories.tsx +1 -1
  340. package/src/components/FileViewer/file-viewer.principles.stories.tsx +1 -1
  341. package/src/components/FileViewer/file-viewer.spec.md +1 -1
  342. package/src/components/FileViewer/file-viewer.stories.tsx +1 -1
  343. package/src/components/FileViewer/file-viewer.tsx +3 -2
  344. package/src/components/HoverCard/hover-card.anatomy.stories.tsx +6 -4
  345. package/src/components/HoverCard/hover-card.principles.stories.tsx +6 -1
  346. package/src/components/HoverCard/hover-card.spec.md +2 -2
  347. package/src/components/HoverCard/hover-card.tsx +4 -2
  348. package/src/components/InlineEdit/inline-edit.anatomy.stories.tsx +184 -0
  349. package/src/components/InlineEdit/inline-edit.principles.stories.tsx +142 -0
  350. package/src/components/InlineEdit/inline-edit.spec.md +71 -46
  351. package/src/components/InlineEdit/inline-edit.stories.tsx +20 -19
  352. package/src/components/InlineEdit/inline-edit.tsx +211 -125
  353. package/src/components/Input/input.anatomy.stories.tsx +15 -15
  354. package/src/components/Input/input.principles.stories.tsx +3 -3
  355. package/src/components/Input/input.spec.md +4 -4
  356. package/src/components/Input/input.stories.tsx +3 -3
  357. package/src/components/Input/input.tsx +13 -13
  358. package/src/components/LinkInput/link-input.anatomy.stories.tsx +2 -2
  359. package/src/components/LinkInput/link-input.principles.stories.tsx +1 -1
  360. package/src/components/LinkInput/link-input.spec.md +6 -2
  361. package/src/components/LinkInput/link-input.stories.tsx +8 -8
  362. package/src/components/LinkInput/link-input.tsx +21 -19
  363. package/src/components/Notice/notice.principles.stories.tsx +1 -1
  364. package/src/components/Notice/notice.tsx +8 -2
  365. package/src/components/NumberInput/number-input.anatomy.stories.tsx +6 -6
  366. package/src/components/NumberInput/number-input.principles.stories.tsx +4 -4
  367. package/src/components/NumberInput/number-input.spec.md +6 -6
  368. package/src/components/NumberInput/number-input.stories.tsx +4 -4
  369. package/src/components/NumberInput/number-input.tsx +17 -5
  370. package/src/components/OverflowIndicator/overflow-indicator.anatomy.stories.tsx +8 -4
  371. package/src/components/OverflowIndicator/overflow-indicator.principles.stories.tsx +6 -7
  372. package/src/components/OverflowIndicator/overflow-indicator.spec.md +1 -1
  373. package/src/components/OverflowIndicator/overflow-indicator.stories.tsx +6 -30
  374. package/src/components/PeoplePicker/avatar-stack-overflow.ts +1 -1
  375. package/src/components/PeoplePicker/people-picker.anatomy.stories.tsx +13 -10
  376. package/src/components/PeoplePicker/people-picker.principles.stories.tsx +5 -1
  377. package/src/components/PeoplePicker/people-picker.stories.tsx +5 -5
  378. package/src/components/PeoplePicker/people-picker.tsx +39 -20
  379. package/src/components/PeoplePicker/person-display.tsx +3 -3
  380. package/src/components/Popover/popover.anatomy.stories.tsx +10 -7
  381. package/src/components/Popover/popover.principles.stories.tsx +49 -28
  382. package/src/components/Popover/popover.spec.md +4 -2
  383. package/src/components/ProfileCard/profile-card.anatomy.stories.tsx +1 -1
  384. package/src/components/ProfileCard/profile-card.tsx +1 -1
  385. package/src/components/ProgressBar/progress-bar.anatomy.stories.tsx +14 -13
  386. package/src/components/ProgressBar/progress-bar.principles.stories.tsx +8 -23
  387. package/src/components/ProgressBar/progress-bar.stories.tsx +8 -2
  388. package/src/components/README.md +1 -0
  389. package/src/components/RadioGroup/radio-group.anatomy.stories.tsx +8 -3
  390. package/src/components/RadioGroup/radio-group.stories.tsx +3 -3
  391. package/src/components/RadioGroup/radio-group.tsx +19 -14
  392. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  393. package/src/components/Rating/rating.principles.stories.tsx +3 -3
  394. package/src/components/Rating/rating.spec.md +2 -2
  395. package/src/components/Rating/rating.stories.tsx +4 -18
  396. package/src/components/Rating/rating.tsx +5 -1
  397. package/src/components/ScrollArea/scroll-area.principles.stories.tsx +1 -1
  398. package/src/components/ScrollArea/scroll-area.spec.md +1 -1
  399. package/src/components/ScrollArea/scroll-area.tsx +5 -2
  400. package/src/components/SegmentedControl/segmented-control.principles.stories.tsx +4 -1
  401. package/src/components/SegmentedControl/segmented-control.spec.md +5 -10
  402. package/src/components/SegmentedControl/segmented-control.tsx +6 -3
  403. package/src/components/Select/select.anatomy.stories.tsx +13 -7
  404. package/src/components/Select/select.principles.stories.tsx +3 -3
  405. package/src/components/Select/select.spec.md +9 -1
  406. package/src/components/Select/select.stories.tsx +41 -27
  407. package/src/components/Select/select.tsx +44 -26
  408. package/src/components/SelectMenu/select-menu.anatomy.stories.tsx +44 -26
  409. package/src/components/SelectMenu/select-menu.principles.stories.tsx +0 -1
  410. package/src/components/SelectMenu/select-menu.stories.tsx +7 -19
  411. package/src/components/SelectMenu/select-menu.tsx +38 -5
  412. package/src/components/SelectionControl/boolean-value.tsx +2 -2
  413. package/src/components/SelectionControl/selection-item.anatomy.stories.tsx +1 -1
  414. package/src/components/SelectionControl/selection-item.principles.stories.tsx +4 -4
  415. package/src/components/Separator/separator.principles.stories.tsx +1 -1
  416. package/src/components/Sheet/sheet.principles.stories.tsx +5 -3
  417. package/src/components/Sheet/sheet.tsx +4 -1
  418. package/src/components/Sidebar/sidebar.tsx +1 -1
  419. package/src/components/Slider/slider.anatomy.stories.tsx +5 -4
  420. package/src/components/Slider/slider.principles.stories.tsx +6 -6
  421. package/src/components/Slider/slider.spec.md +13 -1
  422. package/src/components/Slider/slider.stories.tsx +44 -32
  423. package/src/components/Slider/slider.tsx +13 -4
  424. package/src/components/Steps/steps.anatomy.stories.tsx +7 -7
  425. package/src/components/Steps/steps.principles.stories.tsx +1 -1
  426. package/src/components/Steps/steps.spec.md +4 -2
  427. package/src/components/Steps/steps.stories.tsx +4 -56
  428. package/src/components/Steps/steps.tsx +31 -7
  429. package/src/components/Switch/switch.anatomy.stories.tsx +3 -3
  430. package/src/components/Switch/switch.principles.stories.tsx +1 -1
  431. package/src/components/Switch/switch.spec.md +4 -4
  432. package/src/components/Switch/switch.stories.tsx +3 -3
  433. package/src/components/Switch/switch.tsx +16 -10
  434. package/src/components/Tabs/tabs.anatomy.stories.tsx +6 -0
  435. package/src/components/Tabs/tabs.principles.stories.tsx +10 -2
  436. package/src/components/Tabs/tabs.spec.md +5 -2
  437. package/src/components/Tabs/tabs.stories.tsx +36 -44
  438. package/src/components/Tabs/tabs.tsx +101 -36
  439. package/src/components/Tag/tag.anatomy.stories.tsx +2 -2
  440. package/src/components/Tag/tag.principles.stories.tsx +4 -4
  441. package/src/components/Tag/tag.spec.md +3 -1
  442. package/src/components/Tag/tag.tsx +5 -3
  443. package/src/components/Textarea/textarea.anatomy.stories.tsx +6 -6
  444. package/src/components/Textarea/textarea.spec.md +5 -5
  445. package/src/components/Textarea/textarea.tsx +24 -24
  446. package/src/components/TimePicker/time-picker.anatomy.stories.tsx +12 -11
  447. package/src/components/TimePicker/time-picker.principles.stories.tsx +37 -44
  448. package/src/components/TimePicker/time-picker.spec.md +6 -5
  449. package/src/components/TimePicker/time-picker.stories.tsx +3 -3
  450. package/src/components/TimePicker/time-picker.tsx +24 -14
  451. package/src/components/Toast/toast.principles.stories.tsx +1 -1
  452. package/src/components/Toast/toast.stories.tsx +1 -1
  453. package/src/components/Tooltip/tooltip.anatomy.stories.tsx +15 -6
  454. package/src/components/Tooltip/tooltip.principles.stories.tsx +4 -4
  455. package/src/components/Tooltip/tooltip.spec.md +9 -3
  456. package/src/components/Tooltip/tooltip.stories.tsx +1 -1
  457. package/src/components/Tooltip/tooltip.tsx +12 -2
  458. package/src/components/TreeView/tree-view.anatomy.stories.tsx +16 -14
  459. package/src/components/TreeView/tree-view.principles.stories.tsx +44 -11
  460. package/src/components/TreeView/tree-view.spec.md +8 -6
  461. package/src/components/TreeView/tree-view.stories.tsx +9 -43
  462. package/src/components/TreeView/tree-view.tsx +36 -0
  463. package/src/index.ts +13 -10
  464. package/src/lib/drag-visual.ts +2 -2
  465. package/src/lib/utils.ts +19 -0
  466. package/src/patterns/element-anatomy/inline-action.spec.md +1 -1
  467. package/src/patterns/element-anatomy/item-anatomy.tsx +4 -2
  468. package/src/patterns/header-canonical/header-canonical.spec.md +9 -0
  469. package/src/patterns/header-canonical/header-canonical.stories.tsx +31 -5
  470. package/src/tokens/categorical-color.ts +5 -5
  471. package/src/tokens/color/color.spec.md +4 -4
  472. package/src/tokens/color/primitives.css +9 -2
  473. package/src/tokens/opacity/opacity.spec.md +1 -1
  474. package/src/tokens/orphan-tokens.spec.md +1 -1
  475. package/src/tokens/typography/typography.spec.md +2 -0
  476. package/src/tokens/uiSize/uiSize.css +5 -0
  477. package/src/tokens/uiSize/uiSize.spec.md +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","sources":["../../../src/components/Select/select.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — Select 含 3 子元件(NativeSelect/CustomSelect/ReadonlyDisplay)+ helpers + 4-mode renderer + Field SSOT consumption,split-into-files 會破壞 file-local helper closure\n// @renderer-symmetry-allow: 2026-07-08 WM 戰役 A 案回歸修正 — ReadonlyDisplay 現已消費 selectedItemRenderer(display bare-span / D-path / readonly / disabled 四分支),對齊 field-controls.spec.md 共享 contract (a)「display/readonly/disabled/edit 4 mode 共享同一 renderer」。前 note「display→edit unify deferred」已兌現(值內容層);chrome 結構 unify(D-path)仍為 opt-in showDisplayEndIcon。\nimport * as React from 'react'\nimport { X, ChevronDown } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, bareInputStyles, nakedCellRowModeAlign, fieldDisplayTextClass } from '@/design-system/components/Field/field-wrapper'\nimport { Tag } from '@/design-system/components/Tag/tag'\nimport { ItemInlineAction, ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid, useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'\nimport { SelectMenu, forwardKeyToListbox, useActiveDescendant, type SelectMenuOption } from '@/design-system/components/SelectMenu/select-menu'\nimport { useIsTouchDevice } from '@/design-system/hooks/use-is-touch-device'\nimport { useControllable } from '@/design-system/hooks/use-controllable'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n// ── Tag padding per size ────────────────────────────────────────────────────\nconst tagPadding: Record<string, string> = {\n sm: 'px-[calc((var(--field-height-sm)_-_1.25rem)_/_2)]',\n md: 'px-[calc((var(--field-height-md)_-_1.5rem)_/_2)]',\n lg: 'px-[calc((var(--field-height-lg)_-_1.5rem)_/_2)]',\n}\n\n// ── Display ─────────────────────────────────────────────────────────────────\n\n/**\n * Select 用的 option schema(2026-05-10 Issue 4 + post-prune unify):**explicit extends\n * SelectMenuOption(primitive SSOT)** — 任何 SelectMenuOption 加 field 都自動繼承,不會 drift。\n *\n * Why `extends SelectMenuOption`(per user 「全盤檢查避免下次又改壞或是偏移」要求):\n * - **schema SSOT 機械強制**:TypeScript inheritance 跟著 primitive 走,wrapper consumer 永遠\n * 拿得到 primitive 所有 surface field\n * - **Hook lint**(M30 `check_wrapper_primitive_schema_drift.sh`):grep `interface .*Option`\n * 未 `extends` SelectMenuOption / 同名重複 declare 直接 BLOCK\n *\n * Wrapper-only field(`tagVariant`)— Select 獨有 `display='tag'` 用,SelectMenu primitive 不該知道\n * 此 wrapper-only concern,所以 wrapper 層 extend 加上,不污染 primitive。\n *\n * 對齊 Polaris ChoiceList / Material Autocomplete / Carbon Dropdown 的 wrapper-vs-primitive\n * schema-extension idiom。\n */\nexport interface SelectOption extends SelectMenuOption {\n /** Tag 模式的顏色。只在 display='tag' 時生效,對應 Tag 的 variant。Wrapper-only。 */\n tagVariant?: string\n}\n\n/** 分組設定 — 對齊 SelectMenuGroupConfig SSOT */\nexport interface SelectGroupConfig {\n key: string\n label: string\n}\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n/**\n * 原生 `<select>` 屬性 allowlist(2026-07-14 API 策展 D,user 拍板「全部收窄」)。\n *\n * 舊契約 `extends Omit<SelectHTMLAttributes, ...>` 型別承諾**全部**原生 select 屬性,但桌機\n * 自訂 combobox(div trigger + hidden input mirror)只有部分真生效 — 其餘 silent no-op /\n * 被元件內部覆寫,「型別承諾 ≠ 實作出口」= footgun。改 `Pick<>` 顯式 allowlist,**只承諾\n * 兩路徑(desktop CustomSelect / mobile NativeSelect)皆有實作出口的屬性**,盤點以 code 為準:\n *\n * - `id` — 桌機 trigger div / mobile `<select>`,皆 `idProp ?? fieldCtx?.id`\n * - `name` / `form` / `required` — 桌機經 hidden input mirror(D2 2026-07-13,見 hiddenInputEl\n * docblock)/ mobile 原生 `<select>` spread\n * - `disabled` — 兩路徑 `useResolvedFieldDisabled` cascade → mode 分流\n * - `className` / `style` — 兩路徑 field wrapper\n * - `onFocus` / `onBlur` — 桌機 rest spread 到 focusable trigger(tabIndex=0)/ mobile spread\n * - `onKeyDown` — 桌機 consumer handler 先跑再走元件導覽(dim-9)/ mobile 原生\n * - `aria-label` / `aria-describedby` / `aria-errormessage` — 兩路徑顯式接線(fieldCtx fallback)\n * - `autoFocus` / `autoComplete` — **mobile-only**:NativeSelect 原生 `<select>` 生效;桌機\n * custom combobox 無原生對應 = documented no-op(桌機 autofill 由 hidden input mirror 的\n * option-match onChange guard 承擔)\n * - `data-*` — 兩路徑 spread passthrough(dim-9 契約;index signature 顯式承諾,見下)\n *\n * 被砍者(原 extends 承諾但從未生效 / 被元件覆寫,不再進型別):`multiple` / `children` /\n * `tabIndex`(桌機恆 0)/ `aria-labelledby`(桌機由 fieldCtx.labelId / aria-label 管理,\n * consumer 值會被覆寫)/ 其餘 generic HTMLAttributes(title / dir / onClick 等)。\n * 需要時先接線(兩路徑等效)再入表,**不回 extends 全開**。\n *\n * 世界級對照:自訂 combobox 皆走 curated 原生屬性子集,無人 extends 全部 SelectHTMLAttributes —\n * Radix Select.Root 顯式列舉 name/disabled/required/form/autoComplete\n * (radix-ui.com/primitives/docs/components/select#root)/ Headless UI Listbox name/form/disabled\n * (headlessui.com/react/listbox#using-with-html-forms)/ React Aria Select name/autoComplete/\n * isDisabled/isRequired(react-spectrum.adobe.com/react-aria/Select.html)。\n */\nexport interface SelectProps\n extends Pick<\n React.SelectHTMLAttributes<HTMLSelectElement>,\n // ── 兩路徑皆真生效 ──\n | 'id' | 'className' | 'style'\n | 'name' | 'form' | 'required' | 'disabled'\n | 'onFocus' | 'onBlur' | 'onKeyDown'\n | 'aria-label' | 'aria-describedby' | 'aria-errormessage'\n // ── mobile-only(NativeSelect 原生 <select> 生效;桌機 custom combobox documented no-op)──\n | 'autoFocus' | 'autoComplete'\n > {\n /** `data-*` passthrough(桌機 trigger div rest spread / mobile `<select>` spread;dim-9 契約)。 */\n [dataAttribute: `data-${string}`]: unknown\n mode?: FieldMode\n /** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */\n variant?: FieldVariant\n /** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮:value 寬 + slot 元素寬 + gap +\n * field 內 padding;chrome 與互動不變。場景 = detail pane inline metadata。\n * SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */\n width?: FieldWidth\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n options: SelectOption[]\n /** 分組顯示(對齊 SelectMenu groups SSOT)。option.group 對應 groups[].key */\n groups?: SelectGroupConfig[]\n /** Controlled value(consumer 自管 state)。傳 `value` + `onChange` 表示 controlled mode。 */\n value?: string | null\n /** Uncontrolled 初始值(2026-05-21 D3 audit add per user verbatim「決策三照妳建議」+「都給我做到好」)。\n * 不傳 `value` 時 Select 自管 internal state,以 `defaultValue` 為初始值,選變更時 fire `onChange`\n * callback 通知 consumer(但 state 仍歸 Select)。對齊 Radix Select(`defaultValue`)+ shadcn Input\n * (`defaultValue`)+ React `<input>` dual-mode canonical。\n * 互斥規則:同時傳 `value` + `defaultValue` 走 controlled(value 勝),`defaultValue` 僅 first-mount 用。 */\n defaultValue?: string | null\n onChange?: (value: string) => void\n placeholder?: string\n clearable?: boolean\n display?: 'plain' | 'tag'\n startIcon?: LucideIcon\n /** 啟用搜尋(desktop 時 field 變 input,打字即篩選) */\n searchable?: boolean\n /** Loading state(2026-05-15 audit B fix;2026-07-04 Q3 拍板措辭修訂)。\n * Forward 給 SelectMenu primitive SSOT;spinner 只在**無可顯示選項時**佔 empty slot(cmdk CommandEmpty\n * 機制)— 已有 stale options 時保留顯示不清空(對齊 MUI Autocomplete「only if there are no suggestions」)。\n * Trigger 不變(chevron 保留 user 隨時可點開)。*/\n loading?: boolean\n\n /** Menu list 最小列數(空狀態 / 選項少時的視覺一致 reserve)。預設 3 — 選項 < 3 時顯式縮(如 And/Or 兩選項) */\n minRows?: number\n /** Initial open state(uncontrolled)。對齊 Radix Popover defaultOpen canonical;DataTable cell-as-input\n * click → 1 step open menu(Airtable / Notion canonical),consumer pass `defaultOpen` 達成。\n * Note:Native Select(mobile)無 popover 概念,此 prop 僅 Custom path 生效。 */\n defaultOpen?: boolean\n /** open state 變更 callback(對齊 Radix Popover onOpenChange canonical)。\n * DataTable cell-as-input 用:open=false 時 cell 自動 exit edit mode(避免 dismiss 後卡住)。 */\n onOpenChange?: (open: boolean) => void\n /**\n * Display mode 顯 picker intrinsic end icon(2026-05-08 D path Phase 1)。\n * 預設 false:`mode=\"display\"` 純展示 bare span(向後相容)。\n * `variant=\"naked\" && mode=\"display\"` 場景(DataTable cell)opt-in 設 true → wrap 進\n * Field naked-display + 渲 ChevronDown ItemSuffix。**只 display mode 生效**;readonly /\n * disabled / edit 已有 Field wrapper + suffix(不受此 prop 影響)。\n * Authority:`data-table.spec.md:204` + `inline-action.spec.md:157`「Field family endAction(自動繼承)」。\n * @default false\n */\n showDisplayEndIcon?: boolean\n /**\n * 「已選項目」客製 render(2026-05-07 v15.5;2026-07-08 A 案回歸修正擴及 4 mode)。\n *\n * 設了 → 已選值不走純文字 / Tag 預設 path,改用 consumer 提供的 ReactNode(收 selectedOpt)。\n * **display / readonly / disabled / edit 4 mode 共享同一 renderer**(field-controls.spec.md\n * 共享 contract (a),禁 edit-only)— renderer 輸出屬「值內容」(status icon+text 等語意呈現),\n * display 態照常渲染;A 案撤的是 affordance(chevron/outline),非值內容(field.spec.md L6 分層)。\n * Searchable+open 仍走 input(搜尋優先)。Empty value(no selection)仍走 placeholder。\n *\n * 用例:PeoplePicker 用此 slot 把 single 選中的 person render 成 PersonDisplay\n * (avatar + name)而非純文字 label;DataTable status 欄 icon+text。對齊 PeoplePicker = Select wrapper SSOT。\n */\n selectedItemRenderer?: (selectedOpt: SelectOption) => React.ReactNode\n /** 搜尋無結果提示(2026-07-04 Q4 拍板接線 — 原 spec 宣稱可覆寫但 prop 從未轉發)。\n * Forward 給 SelectMenu primitive SSOT(default 在 SelectMenu 層「沒有符合的選項」);\n * 僅 Custom path(searchable dropdown)生效,Native path 無搜尋空狀態。\n * 對齊 MUI noOptionsText / Ant notFoundContent / Polaris emptyState 三家公開覆寫點共識。 */\n emptyText?: string\n}\n\n// ── Icon / size helpers ─────────────────────────────────────────────────────\n// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反)\nconst getIconSize = (size: string) => ICON_SIZE[size as 'sm' | 'md' | 'lg']\n\n// ── Shared sub-components ───────────────────────────────────────────────────\n\n/**\n * Inline clear button for Select trigger.\n * 共用 SSOT — Native + Custom 兩變體統一消費。差別僅 onClick 內是否 stopPropagation\n * (Custom trigger 是 combobox `<div>`,點 clear 不可冒泡到打開 menu;Native `<select>` 自有原生\n * 行為,不需 stopPropagation)。\n *\n * 消費的 SSOT:\n * - patterns/element-anatomy/item-anatomy.spec.md → ItemInlineAction(canonical row inline action)\n */\nfunction SelectClearButton({\n size,\n onClear,\n stopPropagation = false,\n}: {\n size: 'sm' | 'md' | 'lg'\n onClear: () => void\n stopPropagation?: boolean\n}) {\n return (\n <span className=\"relative z-10\">\n <ItemInlineAction\n size={size}\n action={{\n icon: X,\n label: '清除選取', // i18n-allow: DS default inline-action label\n onClick: stopPropagation ? (e) => { e?.stopPropagation(); onClear() } : () => onClear(),\n }}\n />\n </span>\n )\n}\nSelectClearButton.displayName = 'SelectClearButton'\n\n/**\n * Trigger content for CustomSelect — 三種顯示模式分支(searchable+open / text / tag)\n * 抽出降低 `CustomSelect` forwardRef body 長度;邏輯本質是純展示分流,無 hook / ref。\n */\nfunction CustomSelectTriggerContent({\n searchable,\n open,\n isTextDisplay,\n size,\n value,\n selectedLabel,\n selectedOpt,\n SelectedIcon,\n StartIcon,\n iconSize,\n placeholder,\n search,\n setSearch,\n inputRef,\n activeDescendantId,\n ariaLabel,\n labelId,\n selectedItemRenderer,\n}: {\n searchable: boolean\n open: boolean\n isTextDisplay: boolean\n size: 'sm' | 'md' | 'lg'\n value?: string | null\n selectedLabel: string\n selectedOpt?: SelectOption\n SelectedIcon?: LucideIcon\n StartIcon?: LucideIcon\n iconSize: number\n placeholder?: string\n search: string\n setSearch: (v: string) => void\n inputRef: React.RefObject<HTMLInputElement | null>\n activeDescendantId?: string\n ariaLabel?: string\n labelId?: string\n selectedItemRenderer?: (selectedOpt: SelectOption) => React.ReactNode\n}): React.ReactNode {\n // Searchable + open: 顯示搜尋 input\n // 2026-05-15 Bug 2 fix(Claude+Codex Step 5 比稿 consensus,user verbatim「就 A」):\n // 撤掉 native `<input placeholder=selectedLabel>` 不可靠 ellipsis renderer(browser-specific\n // placeholder painting,user 抓「placeholder 直接被截掉沒 ellipsis」)。改 span overlay:\n // - input native placeholder 限「搜尋…」/「請選擇人員」trigger empty hint(無 selectedLabel)\n // - sibling `<span aria-hidden pointer-events-none absolute inset-0 truncate>` 在 search='' 且\n // 有 selectedLabel 時 overlay 顯該人名(memory aid,truncate-with-ellipsis 可控)\n // 對齊 spec.md §B row 4「open + inline-search + 選 1 人 → input cursor + placeholder = 該人名 + ellipsis」。\n // a11y(2026-07-05 backlog 補接):搜尋 input 是 open 時實際聚焦的元素,accessible name 必接在\n // input 本身(原 codex Q2 guard 註解宣稱「來自 field/label/aria-label」,但接線全在外層 trigger\n // div,焦點所在的 input 無 name)— aria-labelledby 接 FieldLabel labelId、consumer aria-label\n // 優先(對齊 trigger div 同款 guard),兩者皆無時 fallback aria-label「搜尋選項」(對齊\n // combobox.tsx searchAriaLabel canonical default);**不**依賴 placeholder 當 label;overlay\n // span aria-hidden + pointer-events-none。APG「combobox role 移到 input 本身」屬中期重構另案。\n if (searchable && open) {\n const triggerEmptyPlaceholder = placeholder || '搜尋…' // i18n-allow: DS fallback\n const showSelectedOverlay = !search && selectedLabel\n return (\n <span className=\"relative flex-1 min-w-0 inline-flex items-center\">\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n <input\n ref={inputRef as React.RefObject<HTMLInputElement>}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n // a11y(2026-07-05 D4):cmdk active item id(useActiveDescendant)→ SR 播報方向鍵導覽中的 option\n aria-activedescendant={activeDescendantId}\n // accessible name:aria-labelledby(Field label)> consumer aria-label > DS default(accname 優先序)\n aria-label={ariaLabel ?? '搜尋選項'} // i18n-allow: DS default(對齊 combobox.tsx searchAriaLabel canonical)\n aria-labelledby={ariaLabel ? undefined : labelId}\n // Native placeholder 限 trigger empty hint(無 selectedLabel 時);若已 selected,留空交給 overlay span\n placeholder={showSelectedOverlay ? '' : triggerEmptyPlaceholder}\n className={cn(bareInputStyles, 'cursor-text')}\n autoFocus\n />\n {showSelectedOverlay && (\n // 2026-05-16 Bug B 真 root cause fix(Claude+Codex M31 Step 5 比稿 consensus,user verbatim\n // 「修了一百次還沒好」+ codex cite W3C CSS Overflow / MDN / Mozilla Bug 972664#c1):\n // 原 `inline-flex items-center truncate` 套同一 span,text 變 anonymous flex item →\n // `text-overflow:ellipsis` 對 anonymous item 不 styleable → ellipsis dots 不可見(text 純 clip)。\n // 對齊 `person-display.tsx:148` 既有 DS canonical:outer flex container + inner truncate 真實 box。\n // DS-wide grep 29 個 truncate 都遵此 pattern,只本處違反 — 修齊。\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 flex items-center text-fg-muted\"\n >\n <span className=\"min-w-0 flex-1 truncate\">{selectedLabel}</span>\n </span>\n )}\n </span>\n )\n }\n // **selectedItemRenderer slot**(2026-05-07 v15.5):consumer 客製 selected display(e.g.\n // PeoplePicker 接 PersonDisplay)。優先於 isTextDisplay / Tag 預設 path,但 empty value\n // 仍走 placeholder。對齊 PeoplePicker = Select wrapper SSOT。\n if (selectedItemRenderer && value && selectedOpt) {\n return (\n <>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n {/* 2026-05-14 item-anatomy SSOT fix(per codex H2 propagation 斷點):加 nakedCellRowModeAlign\n → autoRowHeight cell 內 selected renderer 也對齊 first-line,不再 vertical-center 整 row。 */}\n <span className={cn(\"flex-1 min-w-0 inline-flex items-center\", nakedCellRowModeAlign)}>{selectedItemRenderer(selectedOpt)}</span>\n </>\n )\n }\n // Text display: 純文字 + optional value icon\n if (isTextDisplay) {\n return (\n <>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n {!StartIcon && SelectedIcon && value && <ItemPrefix><SelectedIcon size={iconSize} className=\"pointer-events-none\" aria-hidden /></ItemPrefix>}\n <span className={cn('flex-1 min-w-0 truncate', !value && 'text-fg-muted')}>\n {value ? selectedLabel : (placeholder ?? '選擇…')}\n </span>\n </>\n )\n }\n // Tag display: 用 option 的 tagVariant\n return (\n <>\n {value && selectedOpt?.tagVariant\n ? <Tag size={size} color={selectedOpt.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral'} className=\"shrink-0 pointer-events-none\">{selectedLabel}</Tag>\n : value\n ? <Tag size={size} className=\"shrink-0 pointer-events-none\">{selectedLabel}</Tag>\n : <span className=\"text-fg-muted\">{placeholder ?? '選擇…'}</span>\n }\n <span className=\"flex-1\" />\n </>\n )\n}\nCustomSelectTriggerContent.displayName = 'CustomSelectTriggerContent'\n\n// ── Shared readonly/disabled/display render ─────────────────────────────────\nfunction ReadonlyDisplay({\n mode, variant: variantProp, width, size, options, value, display, startIcon: StartIcon, className, placeholder, showDisplayEndIcon, selectedItemRenderer,\n}: Pick<SelectProps, 'mode' | 'width' | 'size' | 'options' | 'value' | 'display' | 'startIcon' | 'className' | 'placeholder' | 'showDisplayEndIcon' | 'selectedItemRenderer'> & {\n /** @internal 2026-07-14 API 策展 E:內部 render helper 吃 FieldVariantInternal(naked 由 cell-registry 通道傳入)*/\n variant?: FieldVariantInternal\n}) {\n const resolvedMode = mode ?? 'readonly'\n const emptyDisplay = useFieldEmptyDisplay()\n const variant = variantProp ?? 'default'\n const sz = size ?? 'md'\n const iconSize = getIconSize(sz)\n // selectedOpt 提前 hoist(2026-07-08 A 案回歸修正):display / D-path / readonly / disabled\n // 四分支都需要 — renderer 值內容(field-controls.spec.md contract (a) 4-mode 共享)+ tagVariant 查找。\n const selectedOpt = options?.find(o => o.value === value)\n const label = selectedOpt?.label ?? value\n const iconColor = resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted'\n const isTextDisplay = display !== 'tag'\n // K10+K14 fix(2026-05-04):disabled mode placeholder/empty 顯示色 → fg-disabled(neutral-6),非 fg-muted(neutral-7)\n // user canonical:disabled 顯著性優於 muted。同時 plain mode 必須 respect placeholder prop(之前忽略 = bug)\n const emptyColorCls = fieldEmptyColorClass(resolvedMode)\n const emptyText = placeholder ?? emptyDisplay\n\n // mode='display':2 path(2026-05-08 D path Phase 1 Select canary)\n // ❌ 預設(無 showDisplayEndIcon):純內容輸出 bare span/Tag(原行為,backward compat)\n // 對齊原 SelectDisplay sub-component(retired)。readonly / disabled 仍走下方 fieldWrapperStyles。\n // ✅ showDisplayEndIcon=true(DataTable cell opt-in):Field naked-display wrapper +\n // ChevronDown ItemSuffix。SSOT canonical 跟 readonly/edit/disabled mode 同 DOM 結構。\n // Authority: data-table.spec.md:204 + inline-action.spec.md:157「Field family endAction」\n if (resolvedMode === 'display') {\n if (!showDisplayEndIcon) {\n // 2026-05-14 I2 fix(spec contract (e) display typography canonical):bare span 必套\n // `fieldDisplayTextClass(sz)`(sm/md→text-body,lg→text-body-lg)— 對齊跨 Field\n // family display 視覺尺寸統一。\n if (!value) return <span className={cn(fieldDisplayTextClass(sz), emptyColorCls, className)}>{emptyText}</span>\n // 2026-07-08 A 案回歸修正:selectedItemRenderer(值內容:status icon+text 等語意呈現)\n // display 態照常渲染 — 無 chrome 無 chevron,只有值內容本身。分層原則(field.spec.md L6):\n // 本 renderer 歸「值內容」,恆顯;A 案撤的是 affordance(chevron/outline),非值內容。\n // 對齊 field-controls.spec.md 共享 contract (a)「4 mode 共享同一 renderer(禁 edit-only)」。\n if (selectedItemRenderer && selectedOpt) {\n return (\n <span className={cn(fieldDisplayTextClass(sz), 'inline-flex items-center min-w-0', nakedCellRowModeAlign, className)}>\n {selectedItemRenderer(selectedOpt)}\n </span>\n )\n }\n if (isTextDisplay) return <span className={cn(fieldDisplayTextClass(sz), 'truncate', className)}>{label}</span>\n const tVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n return <Tag size={sz} color={tVariant} className={className}>{label}</Tag>\n }\n // D path opt-in: Field naked-display wrapper + ItemSuffix ChevronDown\n const tVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'display', variant, width, size: sz }), value && !isTextDisplay && tagPadding[sz], className)}\n data-field-mode=\"display\"\n >\n {selectedItemRenderer && value && selectedOpt ? (\n // renderer 優先(同 CustomSelectTriggerContent 優先序):值內容歸 renderer,chevron 歸 D-path chrome\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign)}>\n {selectedItemRenderer(selectedOpt)}\n </span>\n ) : isTextDisplay ? (\n <span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && emptyColorCls)}>\n {value ? label : emptyText}\n </span>\n ) : value ? (\n <Tag size={sz} color={tVariant}>{label}</Tag>\n ) : (\n <span className={cn('flex-1 min-w-0', emptyColorCls)}>{emptyText}</span>\n )}\n <ItemSuffix><ChevronDown size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemSuffix>\n </div>\n )\n }\n\n // 2026-06-26 類型身份 indicator 規則:edit 顯示 / readonly 不顯示(純值、不可開下拉,箭頭會誤導) /\n // disabled 保留(fg-disabled,對齊原生 <select disabled> 灰示箭頭 + Accordion M24 precedent)。\n // naked cell 情境依 showDisplayEndIcon = isEditable,維持 2026-05-10 cell canonical「非可編欄不顯」。\n // aria-disabled:styled-disabled(非 native disabled 元素)需明告 AT「inactive」,同時讓 axe 正確\n // 豁免 disabled 文字的 color-contrast(WCAG 1.4.3 inactive UI 例外)。\n const showIndicator = variant === 'naked' ? !!showDisplayEndIcon : resolvedMode === 'disabled'\n const ariaDisabled = resolvedMode === 'disabled' ? true : undefined\n\n // 2026-07-08 A 案回歸修正:readonly / disabled 同樣消費 selectedItemRenderer(值內容 4-mode\n // 共享,field-controls.spec.md contract (a);對照 PeoplePicker readonly/disabled 渲 PersonDisplay\n // 先例)。renderer 優先於 isTextDisplay / Tag 預設 path(同 CustomSelectTriggerContent 優先序);\n // disabled 時 wrapper span 帶 text-fg-disabled 供未自帶色的文字繼承(M24 disabled > muted)。\n if (selectedItemRenderer && value && selectedOpt) {\n return (\n <div className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), className)} data-field-mode={resolvedMode} aria-disabled={ariaDisabled}>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className={cn('pointer-events-none', iconColor)} aria-hidden /></ItemPrefix>}\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign, resolvedMode === 'disabled' && 'text-fg-disabled')}>\n {selectedItemRenderer(selectedOpt)}\n </span>\n {showIndicator && <ItemSuffix className=\"pointer-events-none\"><ChevronDown size={iconSize} className={cn('shrink-0', iconColor)} aria-hidden /></ItemSuffix>}\n </div>\n )\n }\n\n if (isTextDisplay) {\n return (\n <div className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), className)} data-field-mode={resolvedMode} aria-disabled={ariaDisabled}>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className={cn('pointer-events-none', iconColor)} aria-hidden /></ItemPrefix>}\n <span className={cn('flex-1 min-w-0 truncate', resolvedMode === 'disabled' && 'text-fg-disabled')}>\n {value ? label : <span className={emptyColorCls}>{emptyText}</span>}\n </span>\n {showIndicator && <ItemSuffix className=\"pointer-events-none\"><ChevronDown size={iconSize} className={cn('shrink-0', iconColor)} aria-hidden /></ItemSuffix>}\n </div>\n )\n }\n\n const tagVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n\n return (\n <div className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), value && tagPadding[sz], className)} style={{ paddingRight: 'var(--field-px)' }} data-field-mode={resolvedMode} aria-disabled={ariaDisabled}>\n {value ? <Tag size={sz} color={tagVariant}>{label}</Tag> : <span className={emptyColorCls}>{emptyText}</span>}\n {showIndicator && <ItemSuffix className=\"pointer-events-none\"><ChevronDown size={iconSize} className={cn('shrink-0', iconColor)} aria-hidden /></ItemSuffix>}\n </div>\n )\n}\n\n// ── Native Select (mobile) ─────────────────────────────────────────────\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst NativeSelect = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ mode, variant: variantProp, width, error: errorProp = false, size: sizeProp, options, value: valueProp, defaultValue, onChange, placeholder, className, disabled: disabledProp, clearable = false, display = 'plain', startIcon: StartIcon, showDisplayEndIcon, id: idProp, 'aria-describedby': ariaDescribedByProp, 'aria-errormessage': ariaErrorMessageProp,\n // 2026-07-04:Custom-path-only props 顯式 destructure 丟棄(不 spread 到原生 <select> 消 React\n // unknown-prop warning);各 prop docblock 已註「僅 Custom path 生效」語意\n // 2026-07-08 A 案回歸修正:selectedItemRenderer 從丟棄名單移出 — Native path 的\n // ReadonlyDisplay(display/readonly/disabled)同樣消費值內容 renderer(contract (a) 4-mode\n // 共享,值內容不因 pointer type 而異);native <select> edit 路徑仍不消費(原生 option 無法客製 render)。\n searchable: _searchable, groups: _groups, loading: _loading, minRows: _minRows, emptyText: _emptyText, defaultOpen: _defaultOpen, onOpenChange: _onOpenChange, selectedItemRenderer,\n ...props }, ref) => {\n const fieldCtx = useFieldContext()\n const error = useResolvedFieldInvalid(errorProp)\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-05-31 #11:size 從 Field context cascade(對齊 Input/NumberInput + MUI FormControl)\n const size = useResolvedFieldSize(sizeProp)\n // 2026-06-08 SSOT:mode 經 useResolvedFieldMode(prop > 有效 disabled > fieldCtx.mode > 'edit');修 <Field mode=\"display\"> 漏 cascade\n const resolvedMode = useResolvedFieldMode({ mode, disabled })\n const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const iconSize = getIconSize(size)\n // 2026-05-21 D3 audit:Controlled / Uncontrolled dual-mode via 既有 SSOT hook(同 CustomSelect)\n const [value, setValue] = useControllable<string | null>({\n value: valueProp,\n defaultValue: defaultValue ?? null,\n onChange: onChange ? (next) => onChange(next ?? '') : undefined,\n })\n const handleNativeChange = (v: string) => setValue(v)\n const showClear = clearable && value && resolvedMode === 'edit'\n const isTextDisplay = display === 'plain'\n const selectRef = React.useRef<HTMLSelectElement | null>(null)\n const setSelectRef = React.useCallback((el: HTMLSelectElement | null) => {\n selectRef.current = el\n if (typeof ref === 'function') ref(el)\n else if (ref) (ref as React.MutableRefObject<HTMLSelectElement | null>).current = el\n }, [ref])\n\n if (resolvedMode !== 'edit') {\n return <ReadonlyDisplay mode={resolvedMode} variant={variant} width={width} size={size} options={options} value={value} display={display} startIcon={StartIcon} className={className} placeholder={placeholder} showDisplayEndIcon={showDisplayEndIcon} selectedItemRenderer={selectedItemRenderer} />\n }\n\n const selectEl = (\n <select\n ref={setSelectRef}\n id={idProp ?? fieldCtx?.id}\n value={value ?? ''}\n onChange={(e) => handleNativeChange(e.target.value)}\n disabled={disabled}\n aria-invalid={error || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n className={cn(bareInputStyles, 'cursor-pointer appearance-none', !value && 'text-fg-muted', !isTextDisplay && value && 'absolute inset-0 w-full h-full opacity-0 z-0')}\n {...props}\n >\n {placeholder && <option value=\"\" disabled>{placeholder}</option>}\n {/* disabled forward(2026-07-04):對齊桌機 path menuOptions disabled forward — 觸控原生 option 同樣不可選(spec「disabled 選項」邊界案例) */}\n {options.map(opt => <option key={opt.value} value={opt.value} disabled={opt.disabled}>{opt.label}</option>)}\n </select>\n )\n\n const clearEl = showClear ? (\n <SelectClearButton size={size ?? 'md'} onClear={() => handleNativeChange('')} />\n ) : null\n\n const chevronEl = (\n <ItemSuffix className=\"relative z-10 pointer-events-none\">\n <ChevronDown size={iconSize} className=\"text-fg-muted\" aria-hidden />\n </ItemSuffix>\n )\n const selectedOpt = options?.find(o => o.value === value)\n const label = selectedOpt?.label ?? value\n const nativeTagVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n const SelectedOptIcon = selectedOpt?.icon\n\n if (!isTextDisplay) {\n return (\n <div className={cn(fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }), value && tagPadding[size], 'relative',\n className)}\n style={{ paddingRight: 'var(--field-px)' }} data-field-mode=\"edit\" data-error={error ? '' : undefined}>\n {value ? <Tag size={size} color={nativeTagVariant} className=\"shrink-0 relative z-10 pointer-events-none\">{label}</Tag> : <span className=\"text-fg-muted\">{placeholder ?? '選擇...'}</span>}\n {selectEl}\n <span className=\"flex-1\" />\n {clearEl}\n {chevronEl}\n </div>\n )\n }\n\n return (\n <div className={cn(fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }),\n className)}\n data-field-mode=\"edit\" data-error={error ? '' : undefined}>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n {!StartIcon && SelectedOptIcon && value && <ItemPrefix><SelectedOptIcon size={iconSize} className=\"pointer-events-none\" aria-hidden /></ItemPrefix>}\n {selectEl}\n {clearEl}\n {chevronEl}\n </div>\n )\n }\n)\nNativeSelect.displayName = 'NativeSelect'\n\n// ── Custom Select (desktop — consumes SelectMenu) ────────────────────────\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst CustomSelect = React.forwardRef<HTMLDivElement, SelectProps>(\n ({ mode, variant: variantProp, width, error: errorProp = false, size: sizeProp, options, groups, value: valueProp, defaultValue, onChange, placeholder, className, disabled: disabledProp, name, required, form, clearable = false, display = 'plain', startIcon: StartIcon, searchable = false, loading, minRows, emptyText, defaultOpen = false, onOpenChange, selectedItemRenderer, showDisplayEndIcon, id: idProp, 'aria-describedby': ariaDescribedByProp, 'aria-errormessage': ariaErrorMessageProp, 'aria-label': ariaLabel, onKeyDown: onKeyDownProp, style: styleProp,\n // 2026-07-14 API 策展 D:mobile-only props(allowlist 註記)desktop 顯式丟棄 — div trigger 無原生\n // 對應,不 spread 進 DOM(對稱 NativeSelect 丟棄 custom-path-only props 的既有 pattern)\n autoFocus: _autoFocus, autoComplete: _autoComplete, ...rest }, ref) => {\n const fieldCtx = useFieldContext()\n const error = useResolvedFieldInvalid(errorProp)\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-05-31 #11:size 從 Field context cascade(對齊 Input/NumberInput + MUI FormControl)\n const size = useResolvedFieldSize(sizeProp)\n // 2026-06-08 SSOT:mode 經 useResolvedFieldMode(prop > 有效 disabled > fieldCtx.mode > 'edit');修 <Field mode=\"display\"> 漏 cascade\n const resolvedMode = useResolvedFieldMode({ mode, disabled })\n const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const iconSize = getIconSize(size)\n // 2026-05-21 D3 audit:Controlled / Uncontrolled dual-mode via 既有 SSOT hook(M17 對齊,取代自刻 isControlled pattern)。\n // Phase B codex 抓:之前 Custom clear 走 `onChange?.('')` 沒 setInternalValue → uncontrolled clear 失效。useControllable 統一 setter 修。\n // onChange forward coerce null → ''(consumer 簽名 `(value: string) => void`,null 是 internal empty signal)。\n const [value, setValue] = useControllable<string | null>({\n value: valueProp,\n defaultValue: defaultValue ?? null,\n onChange: onChange ? (next) => onChange(next ?? '') : undefined,\n })\n const showClear = clearable && value && resolvedMode === 'edit'\n const isTextDisplay = display === 'plain'\n\n const [open, setOpen] = React.useState(defaultOpen)\n const [search, setSearch] = React.useState('')\n const inputRef = React.useRef<HTMLInputElement>(null)\n // a11y(2026-07-04):listbox 容器 id——trigger aria-controls 指向 SelectMenu PopoverContent\n // (對齊姊妹元件 combobox.tsx:677 既有 canonical;React.useId SSR/CSR 穩定)。\n const listboxId = React.useId()\n // a11y(2026-07-05 D4):追蹤 cmdk active item id → searchable trigger input 綁 aria-activedescendant\n // (機制詳 select-menu.tsx useActiveDescendant docblock;必在 early return 前呼叫 — React #310 hook 順序)。\n const activeOptionId = useActiveDescendant(listboxId, open)\n\n // 關閉時清搜尋\n React.useEffect(() => { if (!open) setSearch('') }, [open])\n\n // **React #310 fix(2026-05-04)**:所有 hooks 必在任何 early return 前 call,\n // 否則 disabled→edit 切換時 hook count 變動 → React 死亡。\n // 原本 useMemo(L280, L291) 在 early return 之後 = latent bug,K13 觸發(filter Op 從 disabled\n // 變 edit 當 user 選欄位)。修法:把所有 useMemo 提到 early return 之前。\n const selectedOpt = options?.find(o => o.value === value)\n // 2026-05-06 v9.1:value 不在 options 也要顯示原值(不沉默丟失)。原 fallback `''` 致\n // SelectCell 開 edit 時若 cell value 不在當前 options(e.g. 上游資料漂移 / options async\n // 後到 / 跨 dataset),trigger 顯示空白 — user 報「value 不見」。對齊 ReadonlyDisplay 同\n // 級 fallback `?? value`。\n const selectedLabel = selectedOpt?.label ?? value ?? ''\n const SelectedIcon = selectedOpt?.icon\n // ── 過濾選項 ──\n const filteredOptions = searchable && search\n ? options.filter(o => o.label.toLowerCase().includes(search.toLowerCase()))\n : options\n // ── 轉換 SelectOption → SelectMenuOption(必在 early return 前) ──\n // Issue 4(2026-05-10):forward avatar / description / disabled SSOT(per SelectMenuOption schema)。\n const menuOptions: SelectMenuOption[] = React.useMemo(\n () => filteredOptions.map(opt => ({\n value: opt.value,\n label: opt.label,\n icon: isTextDisplay ? opt.icon : undefined,\n avatar: opt.avatar,\n description: opt.description,\n disabled: opt.disabled,\n group: opt.group,\n })),\n [filteredOptions, isTextDisplay]\n )\n // ── Tag display 自訂 label 渲染(必在 early return 前) ──\n const renderLabel = React.useMemo(() => {\n if (isTextDisplay) return undefined\n return (menuOpt: SelectMenuOption) => {\n const srcOpt = options.find(o => o.value === menuOpt.value)\n if (srcOpt?.tagVariant) {\n return <Tag size={size} color={srcOpt.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral'}>{menuOpt.label}</Tag>\n }\n return menuOpt.label\n }\n }, [isTextDisplay, options, size])\n\n // **React #310 fix v2(2026-05-04)**:`handleValueChange` useCallback 也必在 early return 前\n // 原本 L306(early return 後)→ disabled→edit 切換時 hook count 仍變 → #310 持續\n // 2026-05-21 D3:`useControllable` 統一 controlled / uncontrolled state + onChange forward,不再手動 if-branch。\n const handleValueChange = React.useCallback(\n (newValue: string | string[]) => {\n setValue(Array.isArray(newValue) ? newValue[0] : newValue)\n },\n [setValue]\n )\n\n // Early return AFTER all hooks(disabled / readonly / display mode 走 ReadonlyDisplay)\n if (resolvedMode !== 'edit') {\n return <ReadonlyDisplay mode={resolvedMode} variant={variant} width={width} size={size} options={options} value={value} display={display} startIcon={StartIcon} className={className} placeholder={placeholder} showDisplayEndIcon={showDisplayEndIcon} selectedItemRenderer={selectedItemRenderer} />\n }\n\n // 2026-05-21 D3 Phase B codex 抓:Custom clear 用 setValue 不直接 onChange,uncontrolled clear 才能真清 internal state。\n const clearEl = showClear ? (\n <SelectClearButton size={size ?? 'md'} onClear={() => setValue('')} stopPropagation />\n ) : null\n\n const chevronEl = (\n <ItemSuffix>\n <ChevronDown size={iconSize} className={cn('text-fg-muted transition-transform', open && 'rotate-180')} aria-hidden />\n </ItemSuffix>\n )\n\n // ── Hidden input form mirror(2026-07-13 D2 拍板 Option A;MUI SelectInput idiom)──\n // 桌機自訂 combobox 無原生 form control,`name` / `required` / `form` 歷史上被靜默丟棄\n // (mobile NativeSelect 卻經 {...props} 生效 = 雙路徑提交語義不對稱 footgun)。\n // 補 visually-hidden `<input>` 鏡像,讓桌機也參與原生表單(裸 <form> submit / FormData):\n // - value **單向鏡射**受控 state(useControllable)= projection,非第二 SSOT(M17);\n // 空值時 value=''(不採 Radix hidden <select> 完整 option tree — 其無空 option 時\n // default 第一項,radix-ui/primitives issue #3521 documented footgun)\n // - 原生 required 僅收顯式 `required` prop(裸表單 opt-in);fieldCtx.required 續走\n // aria-required + useFormValidation(RHF)方法論(form-validation.spec.md 規則 1-9),\n // 不對既有 Field+RHF consumer 注入瀏覽器原生 bubble\n // - onChange 唯一用途 = 瀏覽器 autofill:match 既有非 disabled option 才經 canonical\n // setter 寫回(對齊 MUI SelectInput handleChange 同款 guard),其餘輸入忽略\n // - aria-hidden + tabIndex={-1}:AT 與 Tab 序皆不見(semantics 由 role=combobox trigger\n // own);form-validation 規則 8 focus-first-error 以 DOM name 定位 → 可聚焦 mirror →\n // trigger focus-within 顯示 focus 邊框(桌機 Select 脫離「非 native 控件略過」fallback)\n // 世界級對照:MUI Select 非原生模式 opacity-0 hidden input 攜 name/required\n // (github.com/mui/material-ui .../Select/SelectInput.js;Select.test.js 官方測試涵蓋\n // required 阻止提交 + FormData 值)+ React Spectrum HiddenSelect(github.com/adobe/\n // react-spectrum .../@react-aria/select/src/HiddenSelect.tsx)+ Headless UI Listbox\n // name → hidden input kept in sync(headlessui.com/react/listbox#using-with-html-forms)。\n const hiddenInputEl = (\n <input\n type=\"text\"\n name={name}\n form={form}\n value={value ?? ''}\n onChange={(e) => {\n const matched = options.find((o) => o.value === e.target.value && !o.disabled)\n if (matched) setValue(matched.value)\n }}\n required={required || undefined}\n disabled={disabled}\n aria-hidden=\"true\"\n tabIndex={-1}\n className=\"absolute bottom-0 left-0 w-full opacity-0 pointer-events-none\"\n />\n )\n\n const triggerContent = (\n <CustomSelectTriggerContent\n searchable={searchable}\n open={open}\n isTextDisplay={isTextDisplay}\n size={size}\n value={value}\n selectedLabel={selectedLabel}\n selectedOpt={selectedOpt}\n SelectedIcon={SelectedIcon}\n StartIcon={StartIcon}\n iconSize={iconSize}\n placeholder={placeholder}\n search={search}\n setSearch={setSearch}\n inputRef={inputRef}\n activeDescendantId={activeOptionId}\n ariaLabel={ariaLabel}\n labelId={fieldCtx?.labelId}\n selectedItemRenderer={selectedItemRenderer}\n />\n )\n\n // hooks(filteredOptions / menuOptions / renderLabel / handleValueChange)已全 hoist(React #310 fix v2)\n\n const trigger = (\n <div\n // passthrough(2026-07-14 dim-9 修;同日 API 策展 D 收窄):SelectProps allowlist\n // (Pick<SelectHTMLAttributes>,見 SelectProps docblock)承諾的 data-* / onFocus /\n // onBlur 等 attrs,mobile NativeSelect 經 {...props} spread 到 <select> 生效,desktop\n // 原本完整列舉全丟 → 同一 <Select> API 隨 pointer type 靜默失效(consumer data-testid /\n // onBlur mobile 有、desktop 無)。rest 先 spread —— component 契約 attrs(role / aria-* /\n // id / tabIndex / onKeyDown / className)在後,不可被覆寫;consumer onKeyDown 經\n // onKeyDownProp 在 handler 內先跑(見下)。mobile-only attrs(autoFocus / autoComplete)\n // 已在 destructure 層丟棄不進 rest(div trigger 無原生語意;desktop 表單語意由 hidden\n // input mirror 承擔,見 D2 docblock)。\n {...(rest as unknown as React.HTMLAttributes<HTMLDivElement>)}\n ref={ref}\n id={idProp ?? fieldCtx?.id}\n role=\"combobox\"\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-label={ariaLabel}\n // a11y(2026-07-04):div-based role=combobox 的 <label for> 無效,接 FieldLabel labelId\n // (field-context.ts labelId jsDoc 明文);consumer aria-label 優先(對齊 slider.tsx:166 guard canonical)。\n aria-labelledby={ariaLabel ? undefined : fieldCtx?.labelId}\n aria-invalid={error || undefined}\n // D2(2026-07-13):顯式 required prop 同步進 aria-required(mirror 本身 aria-hidden,\n // AT 看不到其 required;語意由 trigger 播報 — 對齊 mobile 原生 <select required> 行為)\n aria-required={(required || fieldCtx?.required) || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n tabIndex={0}\n className={cn(\n fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }),\n !isTextDisplay && value && !searchable && tagPadding[size],\n // 2026-05-06 v13.3 SSOT retire:per-control `open && 'border-primary'` 移除。Field default\n // state machine `data-[state=open]:border-border-hover`(灰深)處理 open。\n // 2026-07-04 Q1:error border 同樣收進 fieldWrapperStyles error variant(error 勝 focus 色)。\n // D2(2026-07-13):`relative` = hidden input mirror 的 absolute 定位容器\n // (fieldWrapperStyles base 無 relative;對齊 NativeSelect tag 分支同款顯式加法)。\n 'relative cursor-pointer',\n className,\n )}\n style={styleProp || !isTextDisplay ? { ...styleProp, ...(!isTextDisplay ? { paddingRight: 'var(--field-px)' } : undefined) } : undefined}\n data-field-mode=\"edit\"\n data-error={error ? '' : undefined}\n onKeyDown={(e) => {\n // passthrough(dim-9):consumer onKeyDown 先跑 —— 對齊 native path(<select> 上\n // consumer handler 同樣最先收到);component 導覽邏輯照舊在後。\n onKeyDownProp?.(e as unknown as React.KeyboardEvent<HTMLSelectElement>)\n // 2026-07-14 dim-10 修:內層清除按鈕(SelectClearButton → ItemInlineAction <button>)\n // 的 Enter/Space 會 bubble 到本 handler 被 preventDefault 吞掉 → 鍵盤無法清除。\n // 事件源自 descendant button 時不執行 trigger 鍵盤邏輯(保留原生 activation)。\n // 注意:不能一刀切 e.target !== e.currentTarget — searchable inline <input> 的\n // 鍵盤事件仍需下方 forwardKeyToListbox 轉送選單導覽。\n if (e.target !== e.currentTarget && (e.target as HTMLElement).closest?.('button')) return\n // 2026-07-05 D4 P0:open 後 ArrowUp/Down/Enter 轉送 cmdk root(見 select-menu.tsx\n // forwardKeyToListbox docblock — 原「open 後不攔讓方向鍵導覽」在跨 DOM 子樹機制上不成立)\n if (open && forwardKeyToListbox(listboxId, e)) return\n if (e.key === 'Enter' || e.key === ' ') {\n // 2026-06-11 P0 a11y(R2 deep-audit):原 guard `!searchable` 連「關閉時的鍵盤開啟」一起擋\n // → searchable Select / PeoplePicker single 鍵盤打不開(WCAG 2.1.1)。原意只是開啟後\n // 別吃掉搜尋框的 Space/Enter → 正確 guard = !open(關閉才攔;開啟後不干擾 input 輸入)。\n if (!open) { e.preventDefault(); setOpen(true) }\n }\n // APG combobox 展開鍵:ArrowDown 也可開(對齊 combobox.tsx 同 pattern;open 後不攔讓方向鍵導覽選單)\n if (e.key === 'ArrowDown' && !open) { e.preventDefault(); setOpen(true) }\n if (e.key === 'Escape') setOpen(false)\n }}\n >\n {triggerContent}\n {clearEl}\n {chevronEl}\n {hiddenInputEl}\n </div>\n )\n\n return (\n <SelectMenu\n options={menuOptions}\n groups={groups}\n value={value ?? null}\n onValueChange={handleValueChange}\n searchable={false}\n loading={loading}\n emptyText={emptyText}\n size={size}\n minRows={minRows}\n open={open}\n onOpenChange={(o) => { setOpen(o); onOpenChange?.(o) }}\n contentId={listboxId}\n renderLabel={renderLabel}\n onOpenAutoFocus={searchable ? (e) => { e.preventDefault(); inputRef.current?.focus() } : undefined}\n >\n {trigger}\n </SelectMenu>\n )\n }\n)\nCustomSelect.displayName = 'CustomSelect'\n\n// ── Public component(自動偵測 mobile / desktop)──────────────────────────────\n\nconst Select = React.forwardRef<HTMLSelectElement | HTMLDivElement, SelectProps>(\n (props, ref) => {\n const isMobile = useIsTouchDevice()\n\n if (isMobile) {\n return <NativeSelect ref={ref as React.Ref<HTMLSelectElement>} {...props} />\n }\n\n return <CustomSelect ref={ref as React.Ref<HTMLDivElement>} {...props} />\n }\n)\nSelect.displayName = 'Select'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const selectMeta = {\n component: 'Select',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n // 'active' 移除 — trigger 走 Field chrome、menu row 走 MenuItem(其 meta 無 active)(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 { Select }\n"],"names":["tVariant"],"mappings":"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"}
1
+ {"version":3,"file":"select.js","sources":["../../../src/components/Select/select.tsx"],"sourcesContent":["// @benchmark-unverified-blanket: file-level retraction per M22 (d) — claims herein not individually URL-cited; treat as unverified visual/usage rumor unless retrofit per-claim. Hook escape preserved.\n// code-quality-allow: file-size — Select 含 3 子元件(NativeSelect/CustomSelect/ReadonlyDisplay)+ helpers + 4-mode renderer + Field SSOT consumption,split-into-files 會破壞 file-local helper closure\n// @renderer-symmetry-allow: 2026-07-08 WM 戰役 A 案回歸修正 — ReadonlyDisplay 現已消費 selectedItemRenderer(view bare-span / D-path / readonly / disabled 四分支),對齊 field-controls.spec.md 共享 contract (a)「view/readonly/disabled/edit 4 mode 共享同一 renderer」。前 note「display→edit unify deferred」已兌現(值內容層);chrome 結構 unify(D-path)仍為 opt-in showDisplayEndIcon。\nimport * as React from 'react'\nimport { X, ChevronDown } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, bareInputStyles, nakedCellRowModeAlign, fieldDisplayTextClass } from '@/design-system/components/Field/field-wrapper'\nimport { Tag } from '@/design-system/components/Tag/tag'\nimport { ItemInlineAction, ItemPrefix, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid, useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'\nimport { SelectMenu, forwardKeyToListbox, useActiveDescendant, type SelectMenuOption } from '@/design-system/components/SelectMenu/select-menu'\nimport { useIsTouchDevice } from '@/design-system/hooks/use-is-touch-device'\nimport { useControllable } from '@/design-system/hooks/use-controllable'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n// ── Tag padding per size ────────────────────────────────────────────────────\nconst tagPadding: Record<string, string> = {\n sm: 'px-[calc((var(--field-height-sm)_-_1.25rem)_/_2)]',\n md: 'px-[calc((var(--field-height-md)_-_1.5rem)_/_2)]',\n lg: 'px-[calc((var(--field-height-lg)_-_1.5rem)_/_2)]',\n}\n\n// ── Display ─────────────────────────────────────────────────────────────────\n\n/**\n * Select 用的 option schema(2026-05-10 Issue 4 + post-prune unify):**explicit extends\n * SelectMenuOption(primitive SSOT)** — 任何 SelectMenuOption 加 field 都自動繼承,不會 drift。\n *\n * Why `extends SelectMenuOption`(per user 「全盤檢查避免下次又改壞或是偏移」要求):\n * - **schema SSOT 機械強制**:TypeScript inheritance 跟著 primitive 走,wrapper consumer 永遠\n * 拿得到 primitive 所有 surface field\n * - **Hook lint**(M30 `check_wrapper_primitive_schema_drift.sh`):grep `interface .*Option`\n * 未 `extends` SelectMenuOption / 同名重複 declare 直接 BLOCK\n *\n * Wrapper-only field(`tagVariant`)— Select 獨有 `display='tag'` 用,SelectMenu primitive 不該知道\n * 此 wrapper-only concern,所以 wrapper 層 extend 加上,不污染 primitive。\n *\n * 對齊 Polaris ChoiceList / Material Autocomplete / Carbon Dropdown 的 wrapper-vs-primitive\n * schema-extension idiom。\n */\nexport interface SelectOption extends SelectMenuOption {\n /** Tag 模式的顏色。只在 display='tag' 時生效,對應 Tag 的 variant。Wrapper-only。 */\n tagVariant?: string\n}\n\n/** 分組設定 — 對齊 SelectMenuGroupConfig SSOT */\nexport interface SelectGroupConfig {\n key: string\n label: string\n}\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n/**\n * 原生 `<select>` 屬性 allowlist(2026-07-14 API 策展 D,user 拍板「全部收窄」)。\n *\n * 舊契約 `extends Omit<SelectHTMLAttributes, ...>` 型別承諾**全部**原生 select 屬性,但桌機\n * 自訂 combobox(div trigger + hidden input mirror)只有部分真生效 — 其餘 silent no-op /\n * 被元件內部覆寫,「型別承諾 ≠ 實作出口」= footgun。改 `Pick<>` 顯式 allowlist,**只承諾\n * 兩路徑(desktop CustomSelect / mobile NativeSelect)皆有實作出口的屬性**,盤點以 code 為準:\n *\n * - `id` — 桌機 trigger div / mobile `<select>`,皆 `idProp ?? fieldCtx?.id`\n * - `name` / `form` / `required` — 桌機經 hidden input mirror(D2 2026-07-13,見 hiddenInputEl\n * docblock)/ mobile 原生 `<select>` spread\n * - `disabled` — 兩路徑 `useResolvedFieldDisabled` cascade → mode 分流\n * - `className` / `style` — 兩路徑 field wrapper\n * - `onFocus` / `onBlur` — 桌機 rest spread 到 focusable trigger(tabIndex=0)/ mobile spread\n * - `onKeyDown` — 桌機 consumer handler 先跑再走元件導覽(dim-9)/ mobile 原生\n * - `aria-label` / `aria-describedby` / `aria-errormessage` — 兩路徑顯式接線(fieldCtx fallback)\n * - `autoFocus` / `autoComplete` — **mobile-only**:NativeSelect 原生 `<select>` 生效;桌機\n * custom combobox 無原生對應 = documented no-op(桌機 autofill 由 hidden input mirror 的\n * option-match onChange guard 承擔)\n * - `data-*` — 兩路徑 spread passthrough(dim-9 契約;index signature 顯式承諾,見下)\n *\n * 被砍者(原 extends 承諾但從未生效 / 被元件覆寫,不再進型別):`multiple` / `children` /\n * `tabIndex`(桌機恆 0)/ `aria-labelledby`(桌機由 fieldCtx.labelId / aria-label 管理,\n * consumer 值會被覆寫)/ 其餘 generic HTMLAttributes(title / dir / onClick 等)。\n * 需要時先接線(兩路徑等效)再入表,**不回 extends 全開**。\n *\n * 世界級對照:自訂 combobox 皆走 curated 原生屬性子集,無人 extends 全部 SelectHTMLAttributes —\n * Radix Select.Root 顯式列舉 name/disabled/required/form/autoComplete\n * (radix-ui.com/primitives/docs/components/select#root)/ Headless UI Listbox name/form/disabled\n * (headlessui.com/react/listbox#using-with-html-forms)/ React Aria Select name/autoComplete/\n * isDisabled/isRequired(react-spectrum.adobe.com/react-aria/Select.html)。\n */\nexport interface SelectProps\n extends Pick<\n React.SelectHTMLAttributes<HTMLSelectElement>,\n // ── 兩路徑皆真生效 ──\n | 'id' | 'className' | 'style'\n | 'name' | 'form' | 'required' | 'disabled'\n | 'onFocus' | 'onBlur' | 'onKeyDown'\n | 'aria-label' | 'aria-describedby' | 'aria-errormessage'\n // ── mobile-only(NativeSelect 原生 <select> 生效;桌機 custom combobox documented no-op)──\n | 'autoFocus' | 'autoComplete'\n > {\n /** `data-*` passthrough(桌機 trigger div rest spread / mobile `<select>` spread;dim-9 契約)。 */\n [dataAttribute: `data-${string}`]: unknown\n mode?: FieldMode\n /** Field chrome variant. Default = context.variant ?? 'default'. Per-prop override. */\n variant?: FieldVariant\n /** 寬度軸 — `fill` 填滿容器(default)/ `hug` 依內容收縮:value 寬 + slot 元素寬 + gap +\n * field 內 padding;chrome 與互動不變。場景 = detail pane inline metadata。\n * SSOT → field-controls.spec.md「寬度軸(width: fill / hug)」。 */\n width?: FieldWidth\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n options: SelectOption[]\n /** 分組顯示(對齊 SelectMenu groups SSOT)。option.group 對應 groups[].key */\n groups?: SelectGroupConfig[]\n /** Controlled value(consumer 自管 state)。傳 `value` + `onChange` 表示 controlled mode。 */\n value?: string | null\n /** Uncontrolled 初始值(2026-05-21 D3 audit add per user verbatim「決策三照妳建議」+「都給我做到好」)。\n * 不傳 `value` 時 Select 自管 internal state,以 `defaultValue` 為初始值,選變更時 fire `onChange`\n * callback 通知 consumer(但 state 仍歸 Select)。對齊 Radix Select(`defaultValue`)+ shadcn Input\n * (`defaultValue`)+ React `<input>` dual-mode canonical。\n * 互斥規則:同時傳 `value` + `defaultValue` 走 controlled(value 勝),`defaultValue` 僅 first-mount 用。 */\n defaultValue?: string | null\n onChange?: (value: string) => void\n placeholder?: string\n clearable?: boolean\n display?: 'plain' | 'tag'\n startIcon?: LucideIcon\n /** 啟用搜尋(desktop 時 field 變 input,打字即篩選) */\n searchable?: boolean\n /** Loading state(2026-05-15 audit B fix;2026-07-04 Q3 拍板措辭修訂)。\n * Forward 給 SelectMenu primitive SSOT;spinner 只在**無可顯示選項時**佔 empty slot(cmdk CommandEmpty\n * 機制)— 已有 stale options 時保留顯示不清空(對齊 MUI Autocomplete「only if there are no suggestions」)。\n * Trigger 不變(chevron 保留 user 隨時可點開)。*/\n loading?: boolean\n\n /** Menu list 最小列數(空狀態 / 選項少時的視覺一致 reserve)。預設 3 — 選項 < 3 時顯式縮(如 And/Or 兩選項) */\n minRows?: number\n /** Initial open state(uncontrolled)。對齊 Radix Popover defaultOpen canonical;DataTable cell-as-input\n * click → 1 step open menu(Airtable / Notion canonical),consumer pass `defaultOpen` 達成。\n * Note:Native Select(mobile)無 popover 概念,此 prop 僅 Custom path 生效。 */\n defaultOpen?: boolean\n /** open state 變更 callback(對齊 Radix Popover onOpenChange canonical)。\n * DataTable cell-as-input 用:open=false 時 cell 自動 exit edit mode(避免 dismiss 後卡住)。 */\n onOpenChange?: (open: boolean) => void\n /**\n * View mode 顯 picker intrinsic end icon(2026-05-08 D path Phase 1)。\n * 預設 false:`mode=\"view\"` 純展示 bare span(向後相容)。\n * `variant=\"naked\" && mode=\"view\"` 場景(DataTable cell)opt-in 設 true → wrap 進\n * Field naked-view + 渲 ChevronDown ItemSuffix。**只 view mode 生效**;readonly /\n * disabled / edit 已有 Field wrapper + suffix(不受此 prop 影響)。\n * Authority:`data-table.spec.md:204` + `inline-action.spec.md:157`「Field family endAction(自動繼承)」。\n * @default false\n */\n showDisplayEndIcon?: boolean\n /**\n * 「已選項目」客製 render(2026-05-07 v15.5;2026-07-08 A 案回歸修正擴及 4 mode)。\n *\n * 設了 → 已選值不走純文字 / Tag 預設 path,改用 consumer 提供的 ReactNode(收 selectedOpt)。\n * **view / readonly / disabled / edit 4 mode 共享同一 renderer**(field-controls.spec.md\n * 共享 contract (a),禁 edit-only)— renderer 輸出屬「值內容」(status icon+text 等語意呈現),\n * view 態照常渲染;A 案撤的是 affordance(chevron/outline),非值內容(field.spec.md L6 分層)。\n * Searchable+open 仍走 input(搜尋優先)。Empty value(no selection)仍走 placeholder。\n *\n * 用例:PeoplePicker 用此 slot 把 single 選中的 person render 成 PersonDisplay\n * (avatar + name)而非純文字 label;DataTable status 欄 icon+text。對齊 PeoplePicker = Select wrapper SSOT。\n */\n selectedItemRenderer?: (selectedOpt: SelectOption) => React.ReactNode\n /** 搜尋無結果提示(2026-07-04 Q4 拍板接線 — 原 spec 宣稱可覆寫但 prop 從未轉發)。\n * Forward 給 SelectMenu primitive SSOT(default 在 SelectMenu 層「沒有符合的選項」);\n * 僅 Custom path(searchable dropdown)生效,Native path 無搜尋空狀態。\n * 對齊 MUI noOptionsText / Ant notFoundContent / Polaris emptyState 三家公開覆寫點共識。 */\n emptyText?: string\n /**\n * 可建立新選項(creatable,2026-07-18 決策11 user 拍板 forward 到 Select)。**需搭配 `searchable`**\n * ——搜尋非空且無完全同名既有選項時,dropdown 顯 create row(Plus + `createLabel`)。\n * 邏輯/顯示/互動 SSOT 住在 SelectMenu(Select 的 trigger 搜尋以受控 `search` 驅動 SelectMenu creatable\n * 顯隱)。與 Combobox.creatable 同一底層。非 searchable 時無 create 通道(無輸入處)。 */\n creatable?: boolean\n /** 建立新選項 callback(收使用者輸入的搜尋字串)。 */\n onCreate?: (value: string) => void\n /** create row 的 label 格式,預設 '直接使用「{query}」'(forward SelectMenu SSOT)。 */\n createLabel?: (query: string) => string\n}\n\n// ── Icon / size helpers ─────────────────────────────────────────────────────\n// 2026-05-18 改 import ICON_SIZE SSOT(per user『做完』approval,消除 M17 違反)\nconst getIconSize = (size: string) => ICON_SIZE[size as 'sm' | 'md' | 'lg']\n\n// ── Shared sub-components ───────────────────────────────────────────────────\n\n/**\n * Inline clear button for Select trigger.\n * 共用 SSOT — Native + Custom 兩變體統一消費。差別僅 onClick 內是否 stopPropagation\n * (Custom trigger 是 combobox `<div>`,點 clear 不可冒泡到打開 menu;Native `<select>` 自有原生\n * 行為,不需 stopPropagation)。\n *\n * 消費的 SSOT:\n * - patterns/element-anatomy/item-anatomy.spec.md → ItemInlineAction(canonical row inline action)\n */\nfunction SelectClearButton({\n size,\n onClear,\n stopPropagation = false,\n}: {\n size: 'sm' | 'md' | 'lg'\n onClear: () => void\n stopPropagation?: boolean\n}) {\n return (\n <span className=\"relative z-10\">\n <ItemInlineAction\n size={size}\n action={{\n icon: X,\n label: '清除選取', // i18n-allow: DS default inline-action label\n onClick: stopPropagation ? (e) => { e?.stopPropagation(); onClear() } : () => onClear(),\n }}\n />\n </span>\n )\n}\nSelectClearButton.displayName = 'SelectClearButton'\n\n/**\n * Trigger content for CustomSelect — 三種顯示模式分支(searchable+open / text / tag)\n * 抽出降低 `CustomSelect` forwardRef body 長度;邏輯本質是純展示分流,無 hook / ref。\n */\nfunction CustomSelectTriggerContent({\n searchable,\n open,\n isTextDisplay,\n size,\n value,\n selectedLabel,\n selectedOpt,\n SelectedIcon,\n StartIcon,\n iconSize,\n placeholder,\n search,\n setSearch,\n inputRef,\n activeDescendantId,\n ariaLabel,\n labelId,\n selectedItemRenderer,\n}: {\n searchable: boolean\n open: boolean\n isTextDisplay: boolean\n size: 'sm' | 'md' | 'lg'\n value?: string | null\n selectedLabel: string\n selectedOpt?: SelectOption\n SelectedIcon?: LucideIcon\n StartIcon?: LucideIcon\n iconSize: number\n placeholder?: string\n search: string\n setSearch: (v: string) => void\n inputRef: React.RefObject<HTMLInputElement | null>\n activeDescendantId?: string\n ariaLabel?: string\n labelId?: string\n selectedItemRenderer?: (selectedOpt: SelectOption) => React.ReactNode\n}): React.ReactNode {\n // Searchable + open: 顯示搜尋 input\n // 2026-05-15 Bug 2 fix(Claude+Codex Step 5 比稿 consensus,user verbatim「就 A」):\n // 撤掉 native `<input placeholder=selectedLabel>` 不可靠 ellipsis renderer(browser-specific\n // placeholder painting,user 抓「placeholder 直接被截掉沒 ellipsis」)。改 span overlay:\n // - input native placeholder 限「搜尋…」/「請選擇人員」trigger empty hint(無 selectedLabel)\n // - sibling `<span aria-hidden pointer-events-none absolute inset-0 truncate>` 在 search='' 且\n // 有 selectedLabel 時 overlay 顯該人名(memory aid,truncate-with-ellipsis 可控)\n // 對齊 spec.md §B row 4「open + inline-search + 選 1 人 → input cursor + placeholder = 該人名 + ellipsis」。\n // a11y(2026-07-05 backlog 補接):搜尋 input 是 open 時實際聚焦的元素,accessible name 必接在\n // input 本身(原 codex Q2 guard 註解宣稱「來自 field/label/aria-label」,但接線全在外層 trigger\n // div,焦點所在的 input 無 name)— aria-labelledby 接 FieldLabel labelId、consumer aria-label\n // 優先(對齊 trigger div 同款 guard),兩者皆無時 fallback aria-label「搜尋選項」(對齊\n // combobox.tsx searchAriaLabel canonical default);**不**依賴 placeholder 當 label;overlay\n // span aria-hidden + pointer-events-none。APG「combobox role 移到 input 本身」屬中期重構另案。\n if (searchable && open) {\n const triggerEmptyPlaceholder = placeholder || '搜尋…' // i18n-allow: DS fallback\n const showSelectedOverlay = !search && selectedLabel\n return (\n <span className=\"relative flex-1 min-w-0 inline-flex items-center\">\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n <input\n ref={inputRef as React.RefObject<HTMLInputElement>}\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n // a11y(2026-07-05 D4):cmdk active item id(useActiveDescendant)→ SR 播報方向鍵導覽中的 option\n aria-activedescendant={activeDescendantId}\n // accessible name:aria-labelledby(Field label)> consumer aria-label > DS default(accname 優先序)\n aria-label={ariaLabel ?? '搜尋選項'} // i18n-allow: DS default(對齊 combobox.tsx searchAriaLabel canonical)\n aria-labelledby={ariaLabel ? undefined : labelId}\n // Native placeholder 限 trigger empty hint(無 selectedLabel 時);若已 selected,留空交給 overlay span\n placeholder={showSelectedOverlay ? '' : triggerEmptyPlaceholder}\n className={cn(bareInputStyles, 'cursor-text')}\n autoFocus\n />\n {showSelectedOverlay && (\n // 2026-05-16 Bug B 真 root cause fix(Claude+Codex M31 Step 5 比稿 consensus,user verbatim\n // 「修了一百次還沒好」+ codex cite W3C CSS Overflow / MDN / Mozilla Bug 972664#c1):\n // 原 `inline-flex items-center truncate` 套同一 span,text 變 anonymous flex item →\n // `text-overflow:ellipsis` 對 anonymous item 不 styleable → ellipsis dots 不可見(text 純 clip)。\n // 對齊 `person-display.tsx:148` 既有 DS canonical:outer flex container + inner truncate 真實 box。\n // DS-wide grep 29 個 truncate 都遵此 pattern,只本處違反 — 修齊。\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 flex items-center text-fg-muted\"\n >\n <span className=\"min-w-0 flex-1 truncate\">{selectedLabel}</span>\n </span>\n )}\n </span>\n )\n }\n // **selectedItemRenderer slot**(2026-05-07 v15.5):consumer 客製 selected display(e.g.\n // PeoplePicker 接 PersonDisplay)。優先於 isTextDisplay / Tag 預設 path,但 empty value\n // 仍走 placeholder。對齊 PeoplePicker = Select wrapper SSOT。\n if (selectedItemRenderer && value && selectedOpt) {\n return (\n <>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n {/* 2026-05-14 item-anatomy SSOT fix(per codex H2 propagation 斷點):加 nakedCellRowModeAlign\n → autoRowHeight cell 內 selected renderer 也對齊 first-line,不再 vertical-center 整 row。 */}\n <span className={cn(\"flex-1 min-w-0 inline-flex items-center\", nakedCellRowModeAlign)}>{selectedItemRenderer(selectedOpt)}</span>\n </>\n )\n }\n // Text display: 純文字 + optional value icon\n if (isTextDisplay) {\n return (\n <>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n {!StartIcon && SelectedIcon && value && <ItemPrefix><SelectedIcon size={iconSize} className=\"pointer-events-none\" aria-hidden /></ItemPrefix>}\n <span className={cn('flex-1 min-w-0 truncate', !value && 'text-fg-muted')}>\n {value ? selectedLabel : (placeholder ?? '選擇…')}\n </span>\n </>\n )\n }\n // Tag display: 用 option 的 tagVariant\n return (\n <>\n {value && selectedOpt?.tagVariant\n ? <Tag size={size} color={selectedOpt.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral'} className=\"shrink-0 pointer-events-none\">{selectedLabel}</Tag>\n : value\n ? <Tag size={size} className=\"shrink-0 pointer-events-none\">{selectedLabel}</Tag>\n : <span className=\"text-fg-muted\">{placeholder ?? '選擇…'}</span>\n }\n <span className=\"flex-1\" />\n </>\n )\n}\nCustomSelectTriggerContent.displayName = 'CustomSelectTriggerContent'\n\n// ── Shared readonly/disabled/view render ─────────────────────────────────\nfunction ReadonlyDisplay({\n mode, variant: variantProp, width, size, options, value, display, startIcon: StartIcon, className, placeholder, showDisplayEndIcon, selectedItemRenderer,\n}: Pick<SelectProps, 'mode' | 'width' | 'size' | 'options' | 'value' | 'display' | 'startIcon' | 'className' | 'placeholder' | 'showDisplayEndIcon' | 'selectedItemRenderer'> & {\n /** @internal 2026-07-14 API 策展 E:內部 render helper 吃 FieldVariantInternal(naked 由 cell-registry 通道傳入)*/\n variant?: FieldVariantInternal\n}) {\n const resolvedMode = mode ?? 'readonly'\n const emptyDisplay = useFieldEmptyDisplay()\n const variant = variantProp ?? 'default'\n const sz = size ?? 'md'\n const iconSize = getIconSize(sz)\n // selectedOpt 提前 hoist(2026-07-08 A 案回歸修正):view / D-path / readonly / disabled\n // 四分支都需要 — renderer 值內容(field-controls.spec.md contract (a) 4-mode 共享)+ tagVariant 查找。\n const selectedOpt = options?.find(o => o.value === value)\n const label = selectedOpt?.label ?? value\n const iconColor = resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted'\n const isTextDisplay = display !== 'tag'\n // K10+K14 fix(2026-05-04):disabled mode placeholder/empty 顯示色 → fg-disabled(neutral-6),非 fg-muted(neutral-7)\n // user canonical:disabled 顯著性優於 muted。同時 plain mode 必須 respect placeholder prop(之前忽略 = bug)\n const emptyColorCls = fieldEmptyColorClass(resolvedMode)\n const emptyText = placeholder ?? emptyDisplay\n\n // mode='view':2 path(2026-05-08 D path Phase 1 Select canary)\n // ❌ 預設(無 showDisplayEndIcon):純內容輸出 bare span/Tag(原行為,backward compat)\n // 對齊原 SelectDisplay sub-component(retired)。readonly / disabled 仍走下方 fieldWrapperStyles。\n // ✅ showDisplayEndIcon=true(DataTable cell opt-in):Field naked-view wrapper +\n // ChevronDown ItemSuffix。SSOT canonical 跟 readonly/edit/disabled mode 同 DOM 結構。\n // Authority: data-table.spec.md:204 + inline-action.spec.md:157「Field family endAction」\n if (resolvedMode === 'view') {\n if (!showDisplayEndIcon) {\n // 2026-05-14 I2 fix(spec contract (e) view typography canonical):bare span 必套\n // `fieldDisplayTextClass(sz)`(sm/md→text-body,lg→text-body-lg)— 對齊跨 Field\n // family view 視覺尺寸統一。\n if (!value) return <span className={cn(fieldDisplayTextClass(sz), emptyColorCls, className)}>{emptyText}</span>\n // 2026-07-08 A 案回歸修正:selectedItemRenderer(值內容:status icon+text 等語意呈現)\n // view 態照常渲染 — 無 chrome 無 chevron,只有值內容本身。分層原則(field.spec.md L6):\n // 本 renderer 歸「值內容」,恆顯;A 案撤的是 affordance(chevron/outline),非值內容。\n // 對齊 field-controls.spec.md 共享 contract (a)「4 mode 共享同一 renderer(禁 edit-only)」。\n if (selectedItemRenderer && selectedOpt) {\n return (\n <span className={cn(fieldDisplayTextClass(sz), 'inline-flex items-center min-w-0', nakedCellRowModeAlign, className)}>\n {selectedItemRenderer(selectedOpt)}\n </span>\n )\n }\n if (isTextDisplay) return <span className={cn(fieldDisplayTextClass(sz), 'truncate', className)}>{label}</span>\n const tVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n return <Tag size={sz} color={tVariant} className={className}>{label}</Tag>\n }\n // D path opt-in: Field naked-view wrapper + ItemSuffix ChevronDown\n const tVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'view', variant, width, size: sz }), value && !isTextDisplay && tagPadding[sz], className)}\n data-field-mode=\"view\"\n >\n {selectedItemRenderer && value && selectedOpt ? (\n // renderer 優先(同 CustomSelectTriggerContent 優先序):值內容歸 renderer,chevron 歸 D-path chrome\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign)}>\n {selectedItemRenderer(selectedOpt)}\n </span>\n ) : isTextDisplay ? (\n <span className={cn(bareInputStyles, 'flex-1 min-w-0 truncate', !value && emptyColorCls)}>\n {value ? label : emptyText}\n </span>\n ) : value ? (\n <Tag size={sz} color={tVariant}>{label}</Tag>\n ) : (\n <span className={cn('flex-1 min-w-0', emptyColorCls)}>{emptyText}</span>\n )}\n <ItemSuffix><ChevronDown size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemSuffix>\n </div>\n )\n }\n\n // 2026-06-26 類型身份 indicator 規則:edit 顯示 / readonly 不顯示(純值、不可開下拉,箭頭會誤導) /\n // disabled 保留(fg-disabled,對齊原生 <select disabled> 灰示箭頭 + Accordion M24 precedent)。\n // naked cell 情境依 showDisplayEndIcon = isEditable,維持 2026-05-10 cell canonical「非可編欄不顯」。\n // aria-disabled:styled-disabled(非 native disabled 元素)需明告 AT「inactive」,同時讓 axe 正確\n // 豁免 disabled 文字的 color-contrast(WCAG 1.4.3 inactive UI 例外)。\n const showIndicator = variant === 'naked' ? !!showDisplayEndIcon : resolvedMode === 'disabled'\n const ariaDisabled = resolvedMode === 'disabled' ? true : undefined\n\n // 2026-07-08 A 案回歸修正:readonly / disabled 同樣消費 selectedItemRenderer(值內容 4-mode\n // 共享,field-controls.spec.md contract (a);對照 PeoplePicker readonly/disabled 渲 PersonDisplay\n // 先例)。renderer 優先於 isTextDisplay / Tag 預設 path(同 CustomSelectTriggerContent 優先序);\n // disabled 時 wrapper span 帶 text-fg-disabled 供未自帶色的文字繼承(M24 disabled > muted)。\n if (selectedItemRenderer && value && selectedOpt) {\n return (\n <div className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), className)} data-field-mode={resolvedMode} aria-disabled={ariaDisabled}>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className={cn('pointer-events-none', iconColor)} aria-hidden /></ItemPrefix>}\n <span className={cn('flex-1 min-w-0 inline-flex items-center', nakedCellRowModeAlign, resolvedMode === 'disabled' && 'text-fg-disabled')}>\n {selectedItemRenderer(selectedOpt)}\n </span>\n {showIndicator && <ItemSuffix className=\"pointer-events-none\"><ChevronDown size={iconSize} className={cn('shrink-0', iconColor)} aria-hidden /></ItemSuffix>}\n </div>\n )\n }\n\n if (isTextDisplay) {\n return (\n <div className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), className)} data-field-mode={resolvedMode} aria-disabled={ariaDisabled}>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className={cn('pointer-events-none', iconColor)} aria-hidden /></ItemPrefix>}\n <span className={cn('flex-1 min-w-0 truncate', resolvedMode === 'disabled' && 'text-fg-disabled')}>\n {value ? label : <span className={emptyColorCls}>{emptyText}</span>}\n </span>\n {showIndicator && <ItemSuffix className=\"pointer-events-none\"><ChevronDown size={iconSize} className={cn('shrink-0', iconColor)} aria-hidden /></ItemSuffix>}\n </div>\n )\n }\n\n const tagVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n\n return (\n <div className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), value && tagPadding[sz], className)} style={{ paddingRight: 'var(--field-px)' }} data-field-mode={resolvedMode} aria-disabled={ariaDisabled}>\n {value ? <Tag size={sz} color={tagVariant}>{label}</Tag> : <span className={emptyColorCls}>{emptyText}</span>}\n {showIndicator && <ItemSuffix className=\"pointer-events-none\"><ChevronDown size={iconSize} className={cn('shrink-0', iconColor)} aria-hidden /></ItemSuffix>}\n </div>\n )\n}\n\n// ── Native Select (mobile) ─────────────────────────────────────────────\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst NativeSelect = React.forwardRef<HTMLSelectElement, SelectProps>(\n ({ mode, variant: variantProp, width, error: errorProp = false, size: sizeProp, options, value: valueProp, defaultValue, onChange, placeholder, className, disabled: disabledProp, clearable = false, display = 'plain', startIcon: StartIcon, showDisplayEndIcon, id: idProp, 'aria-describedby': ariaDescribedByProp, 'aria-errormessage': ariaErrorMessageProp,\n // 2026-07-04:Custom-path-only props 顯式 destructure 丟棄(不 spread 到原生 <select> 消 React\n // unknown-prop warning);各 prop docblock 已註「僅 Custom path 生效」語意\n // 2026-07-08 A 案回歸修正:selectedItemRenderer 從丟棄名單移出 — Native path 的\n // ReadonlyDisplay(view/readonly/disabled)同樣消費值內容 renderer(contract (a) 4-mode\n // 共享,值內容不因 pointer type 而異);native <select> edit 路徑仍不消費(原生 option 無法客製 render)。\n searchable: _searchable, groups: _groups, loading: _loading, minRows: _minRows, emptyText: _emptyText, creatable: _creatable, onCreate: _onCreate, createLabel: _createLabel, defaultOpen: _defaultOpen, onOpenChange: _onOpenChange, selectedItemRenderer,\n ...props }, ref) => {\n const fieldCtx = useFieldContext()\n const error = useResolvedFieldInvalid(errorProp)\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-05-31 #11:size 從 Field context cascade(對齊 Input/NumberInput + MUI FormControl)\n const size = useResolvedFieldSize(sizeProp)\n // 2026-06-08 SSOT:mode 經 useResolvedFieldMode(prop > 有效 disabled > fieldCtx.mode > 'edit');修 <Field mode=\"view\"> 漏 cascade\n const resolvedMode = useResolvedFieldMode({ mode, disabled })\n const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const iconSize = getIconSize(size)\n // 2026-05-21 D3 audit:Controlled / Uncontrolled dual-mode via 既有 SSOT hook(同 CustomSelect)\n const [value, setValue] = useControllable<string | null>({\n value: valueProp,\n defaultValue: defaultValue ?? null,\n onChange: onChange ? (next) => onChange(next ?? '') : undefined,\n })\n const handleNativeChange = (v: string) => setValue(v)\n const showClear = clearable && value && resolvedMode === 'edit'\n const isTextDisplay = display === 'plain'\n const selectRef = React.useRef<HTMLSelectElement | null>(null)\n const setSelectRef = React.useCallback((el: HTMLSelectElement | null) => {\n selectRef.current = el\n if (typeof ref === 'function') ref(el)\n else if (ref) (ref as React.MutableRefObject<HTMLSelectElement | null>).current = el\n }, [ref])\n\n if (resolvedMode !== 'edit') {\n return <ReadonlyDisplay mode={resolvedMode} variant={variant} width={width} size={size} options={options} value={value} display={display} startIcon={StartIcon} className={className} placeholder={placeholder} showDisplayEndIcon={showDisplayEndIcon} selectedItemRenderer={selectedItemRenderer} />\n }\n\n const selectEl = (\n <select\n ref={setSelectRef}\n id={idProp ?? fieldCtx?.id}\n value={value ?? ''}\n onChange={(e) => handleNativeChange(e.target.value)}\n disabled={disabled}\n aria-invalid={error || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n className={cn(bareInputStyles, 'cursor-pointer appearance-none', !value && 'text-fg-muted', !isTextDisplay && value && 'absolute inset-0 w-full h-full opacity-0 z-0')}\n {...props}\n >\n {placeholder && <option value=\"\" disabled>{placeholder}</option>}\n {/* disabled forward(2026-07-04):對齊桌機 path menuOptions disabled forward — 觸控原生 option 同樣不可選(spec「disabled 選項」邊界案例) */}\n {options.map(opt => <option key={opt.value} value={opt.value} disabled={opt.disabled}>{opt.label}</option>)}\n </select>\n )\n\n const clearEl = showClear ? (\n <SelectClearButton size={size ?? 'md'} onClear={() => handleNativeChange('')} />\n ) : null\n\n const chevronEl = (\n <ItemSuffix className=\"relative z-10 pointer-events-none\">\n <ChevronDown size={iconSize} className=\"text-fg-muted\" aria-hidden />\n </ItemSuffix>\n )\n const selectedOpt = options?.find(o => o.value === value)\n const label = selectedOpt?.label ?? value\n const nativeTagVariant = selectedOpt?.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral' | undefined\n const SelectedOptIcon = selectedOpt?.icon\n\n if (!isTextDisplay) {\n return (\n <div className={cn(fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }), value && tagPadding[size], 'relative',\n className)}\n style={{ paddingRight: 'var(--field-px)' }} data-field-mode=\"edit\" data-error={error ? '' : undefined}>\n {value ? <Tag size={size} color={nativeTagVariant} className=\"shrink-0 relative z-10 pointer-events-none\">{label}</Tag> : <span className=\"text-fg-muted\">{placeholder ?? '選擇...'}</span>}\n {selectEl}\n <span className=\"flex-1\" />\n {clearEl}\n {chevronEl}\n </div>\n )\n }\n\n return (\n <div className={cn(fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }),\n className)}\n data-field-mode=\"edit\" data-error={error ? '' : undefined}>\n {StartIcon && <ItemPrefix><StartIcon size={iconSize} className=\"text-fg-muted pointer-events-none\" aria-hidden /></ItemPrefix>}\n {!StartIcon && SelectedOptIcon && value && <ItemPrefix><SelectedOptIcon size={iconSize} className=\"pointer-events-none\" aria-hidden /></ItemPrefix>}\n {selectEl}\n {clearEl}\n {chevronEl}\n </div>\n )\n }\n)\nNativeSelect.displayName = 'NativeSelect'\n\n// ── Custom Select (desktop — consumes SelectMenu) ────────────────────────\n\n// code-quality-allow: long-function — foundational composite main body — 拆 sub-fn 會複雜化 local state / ref / context binding\nconst CustomSelect = React.forwardRef<HTMLDivElement, SelectProps>(\n ({ mode, variant: variantProp, width, error: errorProp = false, size: sizeProp, options, groups, value: valueProp, defaultValue, onChange, placeholder, className, disabled: disabledProp, name, required, form, clearable = false, display = 'plain', startIcon: StartIcon, searchable = false, loading, minRows, emptyText, creatable = false, onCreate, createLabel, defaultOpen = false, onOpenChange, selectedItemRenderer, showDisplayEndIcon, id: idProp, 'aria-describedby': ariaDescribedByProp, 'aria-errormessage': ariaErrorMessageProp, 'aria-label': ariaLabel, onKeyDown: onKeyDownProp, style: styleProp,\n // 2026-07-14 API 策展 D:mobile-only props(allowlist 註記)desktop 顯式丟棄 — div trigger 無原生\n // 對應,不 spread 進 DOM(對稱 NativeSelect 丟棄 custom-path-only props 的既有 pattern)\n autoFocus: _autoFocus, autoComplete: _autoComplete, ...rest }, ref) => {\n const fieldCtx = useFieldContext()\n const error = useResolvedFieldInvalid(errorProp)\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-05-31 #11:size 從 Field context cascade(對齊 Input/NumberInput + MUI FormControl)\n const size = useResolvedFieldSize(sizeProp)\n // 2026-06-08 SSOT:mode 經 useResolvedFieldMode(prop > 有效 disabled > fieldCtx.mode > 'edit');修 <Field mode=\"view\"> 漏 cascade\n const resolvedMode = useResolvedFieldMode({ mode, disabled })\n const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const iconSize = getIconSize(size)\n // 2026-05-21 D3 audit:Controlled / Uncontrolled dual-mode via 既有 SSOT hook(M17 對齊,取代自刻 isControlled pattern)。\n // Phase B codex 抓:之前 Custom clear 走 `onChange?.('')` 沒 setInternalValue → uncontrolled clear 失效。useControllable 統一 setter 修。\n // onChange forward coerce null → ''(consumer 簽名 `(value: string) => void`,null 是 internal empty signal)。\n const [value, setValue] = useControllable<string | null>({\n value: valueProp,\n defaultValue: defaultValue ?? null,\n onChange: onChange ? (next) => onChange(next ?? '') : undefined,\n })\n const showClear = clearable && value && resolvedMode === 'edit'\n const isTextDisplay = display === 'plain'\n\n const [open, setOpen] = React.useState(defaultOpen)\n const [search, setSearch] = React.useState('')\n const inputRef = React.useRef<HTMLInputElement>(null)\n // a11y(2026-07-04):listbox 容器 id——trigger aria-controls 指向 SelectMenu PopoverContent\n // (對齊姊妹元件 combobox.tsx:677 既有 canonical;React.useId SSR/CSR 穩定)。\n const listboxId = React.useId()\n // a11y(2026-07-05 D4):追蹤 cmdk active item id → searchable trigger input 綁 aria-activedescendant\n // (機制詳 select-menu.tsx useActiveDescendant docblock;必在 early return 前呼叫 — React #310 hook 順序)。\n const activeOptionId = useActiveDescendant(listboxId, open)\n\n // 關閉時清搜尋\n React.useEffect(() => { if (!open) setSearch('') }, [open])\n\n // **React #310 fix(2026-05-04)**:所有 hooks 必在任何 early return 前 call,\n // 否則 disabled→edit 切換時 hook count 變動 → React 死亡。\n // 原本 useMemo(L280, L291) 在 early return 之後 = latent bug,K13 觸發(filter Op 從 disabled\n // 變 edit 當 user 選欄位)。修法:把所有 useMemo 提到 early return 之前。\n const selectedOpt = options?.find(o => o.value === value)\n // 2026-05-06 v9.1:value 不在 options 也要顯示原值(不沉默丟失)。原 fallback `''` 致\n // SelectCell 開 edit 時若 cell value 不在當前 options(e.g. 上游資料漂移 / options async\n // 後到 / 跨 dataset),trigger 顯示空白 — user 報「value 不見」。對齊 ReadonlyDisplay 同\n // 級 fallback `?? value`。\n const selectedLabel = selectedOpt?.label ?? value ?? ''\n const SelectedIcon = selectedOpt?.icon\n // ── 過濾選項 ──\n // 2026-07-18:filter 用 trim 過的 search,對齊 SelectMenu creatable 的 `search.trim()` create-row 判定 —\n // 否則尾隨空白(如 \"Bug \")會讓 filter 漏掉完全同名選項、SelectMenu 卻誤判「無同名」提議重複建立。\n const trimmedSearch = search.trim()\n const filteredOptions = searchable && trimmedSearch\n ? options.filter(o => o.label.toLowerCase().includes(trimmedSearch.toLowerCase()))\n : options\n // ── 轉換 SelectOption → SelectMenuOption(必在 early return 前) ──\n // Issue 4(2026-05-10):forward avatar / description / disabled SSOT(per SelectMenuOption schema)。\n const menuOptions: SelectMenuOption[] = React.useMemo(\n () => filteredOptions.map(opt => ({\n value: opt.value,\n label: opt.label,\n icon: isTextDisplay ? opt.icon : undefined,\n avatar: opt.avatar,\n description: opt.description,\n disabled: opt.disabled,\n group: opt.group,\n })),\n [filteredOptions, isTextDisplay]\n )\n // ── Tag display 自訂 label 渲染(必在 early return 前) ──\n const renderLabel = React.useMemo(() => {\n if (isTextDisplay) return undefined\n return (menuOpt: SelectMenuOption) => {\n const srcOpt = options.find(o => o.value === menuOpt.value)\n if (srcOpt?.tagVariant) {\n return <Tag size={size} color={srcOpt.tagVariant as 'blue' | 'green' | 'red' | 'yellow' | 'neutral'}>{menuOpt.label}</Tag>\n }\n return menuOpt.label\n }\n }, [isTextDisplay, options, size])\n\n // **React #310 fix v2(2026-05-04)**:`handleValueChange` useCallback 也必在 early return 前\n // 原本 L306(early return 後)→ disabled→edit 切換時 hook count 仍變 → #310 持續\n // 2026-05-21 D3:`useControllable` 統一 controlled / uncontrolled state + onChange forward,不再手動 if-branch。\n const handleValueChange = React.useCallback(\n (newValue: string | string[]) => {\n setValue(Array.isArray(newValue) ? newValue[0] : newValue)\n },\n [setValue]\n )\n\n // Early return AFTER all hooks(disabled / readonly / view mode 走 ReadonlyDisplay)\n if (resolvedMode !== 'edit') {\n return <ReadonlyDisplay mode={resolvedMode} variant={variant} width={width} size={size} options={options} value={value} display={display} startIcon={StartIcon} className={className} placeholder={placeholder} showDisplayEndIcon={showDisplayEndIcon} selectedItemRenderer={selectedItemRenderer} />\n }\n\n // 2026-05-21 D3 Phase B codex 抓:Custom clear 用 setValue 不直接 onChange,uncontrolled clear 才能真清 internal state。\n const clearEl = showClear ? (\n <SelectClearButton size={size ?? 'md'} onClear={() => setValue('')} stopPropagation />\n ) : null\n\n const chevronEl = (\n <ItemSuffix>\n <ChevronDown size={iconSize} className={cn('text-fg-muted transition-transform', open && 'rotate-180')} aria-hidden />\n </ItemSuffix>\n )\n\n // ── Hidden input form mirror(2026-07-13 D2 拍板 Option A;MUI SelectInput idiom)──\n // 桌機自訂 combobox 無原生 form control,`name` / `required` / `form` 歷史上被靜默丟棄\n // (mobile NativeSelect 卻經 {...props} 生效 = 雙路徑提交語義不對稱 footgun)。\n // 補 visually-hidden `<input>` 鏡像,讓桌機也參與原生表單(裸 <form> submit / FormData):\n // - value **單向鏡射**受控 state(useControllable)= projection,非第二 SSOT(M17);\n // 空值時 value=''(不採 Radix hidden <select> 完整 option tree — 其無空 option 時\n // default 第一項,radix-ui/primitives issue #3521 documented footgun)\n // - 原生 required 僅收顯式 `required` prop(裸表單 opt-in);fieldCtx.required 續走\n // aria-required + useFormValidation(RHF)方法論(form-validation.spec.md 規則 1-9),\n // 不對既有 Field+RHF consumer 注入瀏覽器原生 bubble\n // - onChange 唯一用途 = 瀏覽器 autofill:match 既有非 disabled option 才經 canonical\n // setter 寫回(對齊 MUI SelectInput handleChange 同款 guard),其餘輸入忽略\n // - aria-hidden + tabIndex={-1}:AT 與 Tab 序皆不見(semantics 由 role=combobox trigger\n // own);form-validation 規則 8 focus-first-error 以 DOM name 定位 → 可聚焦 mirror →\n // trigger focus-within 顯示 focus 邊框(桌機 Select 脫離「非 native 控件略過」fallback)\n // 世界級對照:MUI Select 非原生模式 opacity-0 hidden input 攜 name/required\n // (github.com/mui/material-ui .../Select/SelectInput.js;Select.test.js 官方測試涵蓋\n // required 阻止提交 + FormData 值)+ React Spectrum HiddenSelect(github.com/adobe/\n // react-spectrum .../@react-aria/select/src/HiddenSelect.tsx)+ Headless UI Listbox\n // name → hidden input kept in sync(headlessui.com/react/listbox#using-with-html-forms)。\n const hiddenInputEl = (\n <input\n type=\"text\"\n name={name}\n form={form}\n value={value ?? ''}\n onChange={(e) => {\n const matched = options.find((o) => o.value === e.target.value && !o.disabled)\n if (matched) setValue(matched.value)\n }}\n required={required || undefined}\n disabled={disabled}\n aria-hidden=\"true\"\n tabIndex={-1}\n className=\"absolute bottom-0 left-0 w-full opacity-0 pointer-events-none\"\n />\n )\n\n const triggerContent = (\n <CustomSelectTriggerContent\n searchable={searchable}\n open={open}\n isTextDisplay={isTextDisplay}\n size={size}\n value={value}\n selectedLabel={selectedLabel}\n selectedOpt={selectedOpt}\n SelectedIcon={SelectedIcon}\n StartIcon={StartIcon}\n iconSize={iconSize}\n placeholder={placeholder}\n search={search}\n setSearch={setSearch}\n inputRef={inputRef}\n activeDescendantId={activeOptionId}\n ariaLabel={ariaLabel}\n labelId={fieldCtx?.labelId}\n selectedItemRenderer={selectedItemRenderer}\n />\n )\n\n // hooks(filteredOptions / menuOptions / renderLabel / handleValueChange)已全 hoist(React #310 fix v2)\n\n const trigger = (\n <div\n // passthrough(2026-07-14 dim-9 修;同日 API 策展 D 收窄):SelectProps allowlist\n // (Pick<SelectHTMLAttributes>,見 SelectProps docblock)承諾的 data-* / onFocus /\n // onBlur 等 attrs,mobile NativeSelect 經 {...props} spread 到 <select> 生效,desktop\n // 原本完整列舉全丟 → 同一 <Select> API 隨 pointer type 靜默失效(consumer data-testid /\n // onBlur mobile 有、desktop 無)。rest 先 spread —— component 契約 attrs(role / aria-* /\n // id / tabIndex / onKeyDown / className)在後,不可被覆寫;consumer onKeyDown 經\n // onKeyDownProp 在 handler 內先跑(見下)。mobile-only attrs(autoFocus / autoComplete)\n // 已在 destructure 層丟棄不進 rest(div trigger 無原生語意;desktop 表單語意由 hidden\n // input mirror 承擔,見 D2 docblock)。\n {...(rest as unknown as React.HTMLAttributes<HTMLDivElement>)}\n ref={ref}\n id={idProp ?? fieldCtx?.id}\n role=\"combobox\"\n aria-expanded={open}\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-label={ariaLabel}\n // a11y(2026-07-04):div-based role=combobox 的 <label for> 無效,接 FieldLabel labelId\n // (field-context.ts labelId jsDoc 明文);consumer aria-label 優先(對齊 slider.tsx:166 guard canonical)。\n aria-labelledby={ariaLabel ? undefined : fieldCtx?.labelId}\n aria-invalid={error || undefined}\n // D2(2026-07-13):顯式 required prop 同步進 aria-required(mirror 本身 aria-hidden,\n // AT 看不到其 required;語意由 trigger 播報 — 對齊 mobile 原生 <select required> 行為)\n aria-required={(required || fieldCtx?.required) || undefined}\n aria-describedby={ariaDescribedByProp ?? fieldCtx?.descriptionId}\n aria-errormessage={ariaErrorMessageProp ?? (error ? fieldCtx?.errorId : undefined)}\n tabIndex={0}\n className={cn(\n fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }),\n !isTextDisplay && value && !searchable && tagPadding[size],\n // 2026-05-06 v13.3 SSOT retire:per-control `open && 'border-primary'` 移除。Field default\n // state machine `data-[state=open]:border-border-hover`(灰深)處理 open。\n // 2026-07-04 Q1:error border 同樣收進 fieldWrapperStyles error variant(error 勝 focus 色)。\n // D2(2026-07-13):`relative` = hidden input mirror 的 absolute 定位容器\n // (fieldWrapperStyles base 無 relative;對齊 NativeSelect tag 分支同款顯式加法)。\n 'relative cursor-pointer',\n className,\n )}\n style={styleProp || !isTextDisplay ? { ...styleProp, ...(!isTextDisplay ? { paddingRight: 'var(--field-px)' } : undefined) } : undefined}\n data-field-mode=\"edit\"\n data-error={error ? '' : undefined}\n onKeyDown={(e) => {\n // passthrough(dim-9):consumer onKeyDown 先跑 —— 對齊 native path(<select> 上\n // consumer handler 同樣最先收到);component 導覽邏輯照舊在後。\n onKeyDownProp?.(e as unknown as React.KeyboardEvent<HTMLSelectElement>)\n // 2026-07-14 dim-10 修:內層清除按鈕(SelectClearButton → ItemInlineAction <button>)\n // 的 Enter/Space 會 bubble 到本 handler 被 preventDefault 吞掉 → 鍵盤無法清除。\n // 事件源自 descendant button 時不執行 trigger 鍵盤邏輯(保留原生 activation)。\n // 注意:不能一刀切 e.target !== e.currentTarget — searchable inline <input> 的\n // 鍵盤事件仍需下方 forwardKeyToListbox 轉送選單導覽。\n if (e.target !== e.currentTarget && (e.target as HTMLElement).closest?.('button')) return\n // 2026-07-05 D4 P0:open 後 ArrowUp/Down/Enter 轉送 cmdk root(見 select-menu.tsx\n // forwardKeyToListbox docblock — 原「open 後不攔讓方向鍵導覽」在跨 DOM 子樹機制上不成立)\n if (open && forwardKeyToListbox(listboxId, e)) return\n if (e.key === 'Enter' || e.key === ' ') {\n // 2026-06-11 P0 a11y(R2 deep-audit):原 guard `!searchable` 連「關閉時的鍵盤開啟」一起擋\n // → searchable Select / PeoplePicker single 鍵盤打不開(WCAG 2.1.1)。原意只是開啟後\n // 別吃掉搜尋框的 Space/Enter → 正確 guard = !open(關閉才攔;開啟後不干擾 input 輸入)。\n if (!open) { e.preventDefault(); setOpen(true) }\n }\n // APG combobox 展開鍵:ArrowDown 也可開(對齊 combobox.tsx 同 pattern;open 後不攔讓方向鍵導覽選單)\n if (e.key === 'ArrowDown' && !open) { e.preventDefault(); setOpen(true) }\n if (e.key === 'Escape') setOpen(false)\n }}\n >\n {triggerContent}\n {clearEl}\n {chevronEl}\n {hiddenInputEl}\n </div>\n )\n\n return (\n <SelectMenu\n options={menuOptions}\n groups={groups}\n value={value ?? null}\n onValueChange={handleValueChange}\n searchable={false}\n creatable={creatable}\n onCreate={onCreate}\n createLabel={createLabel}\n search={searchable ? search : undefined}\n onSearchChange={searchable ? setSearch : undefined}\n loading={loading}\n emptyText={emptyText}\n size={size}\n minRows={minRows}\n open={open}\n onOpenChange={(o) => { setOpen(o); onOpenChange?.(o) }}\n contentId={listboxId}\n renderLabel={renderLabel}\n onOpenAutoFocus={searchable ? (e) => { e.preventDefault(); inputRef.current?.focus() } : undefined}\n >\n {trigger}\n </SelectMenu>\n )\n }\n)\nCustomSelect.displayName = 'CustomSelect'\n\n// ── Public component(自動偵測 mobile / desktop)──────────────────────────────\n\nconst Select = React.forwardRef<HTMLSelectElement | HTMLDivElement, SelectProps>(\n (props, ref) => {\n const isMobile = useIsTouchDevice()\n\n if (isMobile) {\n return <NativeSelect ref={ref as React.Ref<HTMLSelectElement>} {...props} />\n }\n\n return <CustomSelect ref={ref as React.Ref<HTMLDivElement>} {...props} />\n }\n)\nSelect.displayName = 'Select'\n\n// Story auto-compile metadata — Phase 1 mechanical migration(2026-04-24)\n// Phase 2 fill needed: purpose descriptions + when rationale + world-class refs\nexport const selectMeta = {\n component: 'Select',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n // 'active' 移除 — trigger 走 Field chrome、menu row 走 MenuItem(其 meta 無 active)(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 { Select }\n"],"names":["tVariant"],"mappings":"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"}
@@ -15,7 +15,7 @@ import type { AvatarData } from '../../components/Avatar/avatar';
15
15
  * ── 架構 ──
16
16
  * Popover(浮動容器)
17
17
  * └── Command(cmdk,搜尋 + 鍵盤導覽)
18
- * ├── CommandInput(搜尋框)
18
+ * ├── CommandPrimitive.Input(搜尋框,raw cmdk + 自建 icon/min-h wrapper,非 DS CommandInput
19
19
  * ├── CommandList(選項列表)
20
20
  * │ └── CommandGroup → MenuItem
21
21
  * └── Footer(多選全選)
@@ -55,6 +55,15 @@ export interface SelectMenuProps {
55
55
  onCreate?: (value: string) => void;
56
56
  /** creatable 的 label 格式,預設 '直接使用「{query}」' */
57
57
  createLabel?: (query: string) => string;
58
+ /**
59
+ * 受控搜尋字串(2026-07-18 決策11:讓 consumer 用**外部搜尋**(如 Select 的 trigger 內嵌 input)
60
+ * 驅動 creatable create-row 顯隱)。傳入 = 受控(SelectMenu 不自管 search、close 不 reset,由
61
+ * parent 負責);不傳 = 內部 uncontrolled(既有行為,零影響)。搭配 `searchable=false` +
62
+ * `creatable` 時,SelectMenu 不畫自己的 input,但 create-row 仍依此 search 顯示。
63
+ */
64
+ search?: string;
65
+ /** 受控搜尋變更通知(選配;SelectMenu 內部無 input 時通常由 parent 單向驅動,不需此) */
66
+ onSearchChange?: (value: string) => void;
58
67
  /** 觸發元件(asChild) */
59
68
  children: React.ReactNode;
60
69
  /** 搜尋框 placeholder */
@@ -94,6 +103,13 @@ export interface SelectMenuProps {
94
103
  * AT 經此容器可定位到內部 cmdk listbox(cmdk List 自帶 auto-generated `role="listbox"` id)。
95
104
  */
96
105
  contentId?: string;
106
+ /**
107
+ * 浮層 accessible name(2026-07-17 Dim 10 a11y 修)。Radix Popover 的 content 為
108
+ * `role="dialog"` 但無自動命名機制 → 無 aria-label 時 dialog 無 accessible name。
109
+ * 預設「選項清單」讓 SR 使用者知道浮層用途;consumer(Combobox / Select / PeoplePicker)
110
+ * 可傳更 contextual 的名(如欄位名)。SSOT 放此一處 → 全 SelectMenu consumer 受益。
111
+ */
112
+ 'aria-label'?: string;
97
113
  className?: string;
98
114
  }
99
115
  declare const SelectMenu: React.ForwardRefExoticComponent<SelectMenuProps & React.RefAttributes<HTMLElement>>;
@@ -1 +1 @@
1
- {"version":3,"file":"select-menu.d.ts","sourceRoot":"","sources":["../../../src/components/SelectMenu/select-menu.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"select-menu.d.ts","sourceRoot":"","sources":["../../../src/components/SelectMenu/select-menu.tsx"],"names":[],"mappings":"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"}
@@ -27,6 +27,8 @@ const SelectMenu = React.forwardRef(function SelectMenu2({
27
27
  creatable = false,
28
28
  onCreate,
29
29
  createLabel = (q) => `直接使用「${q}」`,
30
+ search: controlledSearch,
31
+ onSearchChange,
30
32
  children,
31
33
  searchPlaceholder = "搜尋…",
32
34
  // i18n-allow: DS default; consumer override via searchPlaceholder prop
@@ -45,6 +47,8 @@ const SelectMenu = React.forwardRef(function SelectMenu2({
45
47
  renderLabel,
46
48
  onOpenAutoFocus,
47
49
  contentId,
50
+ "aria-label": ariaLabel = "選項清單",
51
+ // i18n-allow: DS default; consumer override via aria-label prop
48
52
  className
49
53
  }, _ref) {
50
54
  const [open, setOpen] = useControllable({
@@ -52,7 +56,16 @@ const SelectMenu = React.forwardRef(function SelectMenu2({
52
56
  defaultValue: defaultOpen ?? false,
53
57
  onChange: controlledOnOpenChange
54
58
  });
55
- const [search, setSearch] = React.useState("");
59
+ const isSearchControlled = controlledSearch !== void 0;
60
+ const [internalSearch, setInternalSearch] = React.useState("");
61
+ const search = isSearchControlled ? controlledSearch : internalSearch;
62
+ const setSearch = React.useCallback(
63
+ (next) => {
64
+ if (!isSearchControlled) setInternalSearch(next);
65
+ onSearchChange == null ? void 0 : onSearchChange(next);
66
+ },
67
+ [isSearchControlled, onSearchChange]
68
+ );
56
69
  const selectedValues = React.useMemo(() => {
57
70
  if (value == null) return [];
58
71
  return Array.isArray(value) ? value : [value];
@@ -115,8 +128,8 @@ const SelectMenu = React.forwardRef(function SelectMenu2({
115
128
  return grouped;
116
129
  }, [groups, options]);
117
130
  React.useEffect(() => {
118
- if (!open) setSearch("");
119
- }, [open]);
131
+ if (!open && !isSearchControlled) setInternalSearch("");
132
+ }, [open, isSearchControlled]);
120
133
  const handleNonSearchableAutoFocus = React.useCallback((e) => {
121
134
  e.preventDefault();
122
135
  const root = e.currentTarget.querySelector("[cmdk-root]");
@@ -128,6 +141,7 @@ const SelectMenu = React.forwardRef(function SelectMenu2({
128
141
  PopoverContent,
129
142
  {
130
143
  id: contentId,
144
+ "aria-label": ariaLabel,
131
145
  className: cn(
132
146
  "p-0 w-auto rounded-lg border border-border bg-surface-raised overflow-hidden",
133
147
  className