@qijenchen/design-system 0.1.0-beta.146 → 0.1.0-beta.147

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 (257) hide show
  1. package/dist/components/Accordion/accordion.d.ts.map +1 -1
  2. package/dist/components/Accordion/accordion.js +4 -1
  3. package/dist/components/Accordion/accordion.js.map +1 -1
  4. package/dist/components/AccountMenu/account-menu.d.ts.map +1 -1
  5. package/dist/components/AccountMenu/account-menu.js.map +1 -1
  6. package/dist/components/AgentPanel/agent-panel-fab.d.ts +7 -1
  7. package/dist/components/AgentPanel/agent-panel-fab.d.ts.map +1 -1
  8. package/dist/components/AgentPanel/agent-panel-fab.js +13 -9
  9. package/dist/components/AgentPanel/agent-panel-fab.js.map +1 -1
  10. package/dist/components/AgentPanel/agent-panel-logo.d.ts +3 -3
  11. package/dist/components/AgentPanel/agent-panel-logo.js.map +1 -1
  12. package/dist/components/AgentPanel/agent-panel.d.ts.map +1 -1
  13. package/dist/components/AgentPanel/agent-panel.js +6 -1
  14. package/dist/components/AgentPanel/agent-panel.js.map +1 -1
  15. package/dist/components/Breadcrumb/breadcrumb.d.ts +3 -1
  16. package/dist/components/Breadcrumb/breadcrumb.d.ts.map +1 -1
  17. package/dist/components/Breadcrumb/breadcrumb.js.map +1 -1
  18. package/dist/components/BulkActionBar/bulk-action-bar.d.ts.map +1 -1
  19. package/dist/components/BulkActionBar/bulk-action-bar.js +27 -2
  20. package/dist/components/BulkActionBar/bulk-action-bar.js.map +1 -1
  21. package/dist/components/Button/button.d.ts.map +1 -1
  22. package/dist/components/Button/button.js +56 -9
  23. package/dist/components/Button/button.js.map +1 -1
  24. package/dist/components/Calendar/calendar.d.ts +8 -3
  25. package/dist/components/Calendar/calendar.d.ts.map +1 -1
  26. package/dist/components/Calendar/calendar.js +22 -8
  27. package/dist/components/Calendar/calendar.js.map +1 -1
  28. package/dist/components/Carousel/carousel.d.ts.map +1 -1
  29. package/dist/components/Carousel/carousel.js +2 -0
  30. package/dist/components/Carousel/carousel.js.map +1 -1
  31. package/dist/components/Combobox/combobox.d.ts.map +1 -1
  32. package/dist/components/Combobox/combobox.js +10 -4
  33. package/dist/components/Combobox/combobox.js.map +1 -1
  34. package/dist/components/Command/command.d.ts.map +1 -1
  35. package/dist/components/Command/command.js +9 -5
  36. package/dist/components/Command/command.js.map +1 -1
  37. package/dist/components/DataTable/cell-registry.d.ts.map +1 -1
  38. package/dist/components/DataTable/cell-registry.js +2 -1
  39. package/dist/components/DataTable/cell-registry.js.map +1 -1
  40. package/dist/components/DataTable/data-table-column-visibility-panel.d.ts.map +1 -1
  41. package/dist/components/DataTable/data-table-column-visibility-panel.js +24 -24
  42. package/dist/components/DataTable/data-table-column-visibility-panel.js.map +1 -1
  43. package/dist/components/DataTable/data-table-sort-manager.d.ts.map +1 -1
  44. package/dist/components/DataTable/data-table-sort-manager.js +20 -20
  45. package/dist/components/DataTable/data-table-sort-manager.js.map +1 -1
  46. package/dist/components/DataTable/data-table.d.ts.map +1 -1
  47. package/dist/components/DataTable/data-table.js +104 -40
  48. package/dist/components/DataTable/data-table.js.map +1 -1
  49. package/dist/components/Dialog/dialog.d.ts.map +1 -1
  50. package/dist/components/Dialog/dialog.js +55 -43
  51. package/dist/components/Dialog/dialog.js.map +1 -1
  52. package/dist/components/Field/field-context.d.ts +4 -0
  53. package/dist/components/Field/field-context.d.ts.map +1 -1
  54. package/dist/components/Field/field-context.js +1 -2
  55. package/dist/components/Field/field-context.js.map +1 -1
  56. package/dist/components/Field/field-edit-keys.d.ts +8 -0
  57. package/dist/components/Field/field-edit-keys.d.ts.map +1 -1
  58. package/dist/components/Field/field-edit-keys.js +3 -0
  59. package/dist/components/Field/field-edit-keys.js.map +1 -1
  60. package/dist/components/Field/field.d.ts.map +1 -1
  61. package/dist/components/Field/field.js +1 -0
  62. package/dist/components/Field/field.js.map +1 -1
  63. package/dist/components/FileViewer/file-viewer.d.ts.map +1 -1
  64. package/dist/components/FileViewer/file-viewer.js +5 -2
  65. package/dist/components/FileViewer/file-viewer.js.map +1 -1
  66. package/dist/components/LinkInput/link-input.d.ts.map +1 -1
  67. package/dist/components/LinkInput/link-input.js +1 -0
  68. package/dist/components/LinkInput/link-input.js.map +1 -1
  69. package/dist/components/Notice/notice.js +1 -1
  70. package/dist/components/Notice/notice.js.map +1 -1
  71. package/dist/components/NumberInput/number-input.d.ts.map +1 -1
  72. package/dist/components/NumberInput/number-input.js +1 -0
  73. package/dist/components/NumberInput/number-input.js.map +1 -1
  74. package/dist/components/PeoplePicker/people-picker.d.ts.map +1 -1
  75. package/dist/components/PeoplePicker/people-picker.js.map +1 -1
  76. package/dist/components/ProfileCard/profile-card.d.ts.map +1 -1
  77. package/dist/components/ProfileCard/profile-card.js.map +1 -1
  78. package/dist/components/Rating/rating.d.ts.map +1 -1
  79. package/dist/components/Rating/rating.js +6 -3
  80. package/dist/components/Rating/rating.js.map +1 -1
  81. package/dist/components/Select/select.d.ts.map +1 -1
  82. package/dist/components/Select/select.js +13 -7
  83. package/dist/components/Select/select.js.map +1 -1
  84. package/dist/components/SelectionControl/selection-item.d.ts.map +1 -1
  85. package/dist/components/SelectionControl/selection-item.js +1 -0
  86. package/dist/components/SelectionControl/selection-item.js.map +1 -1
  87. package/dist/components/Sidebar/sidebar.d.ts.map +1 -1
  88. package/dist/components/Sidebar/sidebar.js +6 -1
  89. package/dist/components/Sidebar/sidebar.js.map +1 -1
  90. package/dist/components/Steps/steps.d.ts.map +1 -1
  91. package/dist/components/Steps/steps.js +13 -3
  92. package/dist/components/Steps/steps.js.map +1 -1
  93. package/dist/components/Tag/tag.d.ts.map +1 -1
  94. package/dist/components/Tag/tag.js +2 -1
  95. package/dist/components/Tag/tag.js.map +1 -1
  96. package/dist/components/Textarea/textarea.d.ts.map +1 -1
  97. package/dist/components/Textarea/textarea.js +4 -0
  98. package/dist/components/Textarea/textarea.js.map +1 -1
  99. package/dist/components/TimePicker/time-columns.d.ts.map +1 -1
  100. package/dist/components/TimePicker/time-columns.js +3 -3
  101. package/dist/components/TimePicker/time-columns.js.map +1 -1
  102. package/dist/components/TreeView/tree-view.d.ts.map +1 -1
  103. package/dist/components/TreeView/tree-view.js +54 -10
  104. package/dist/components/TreeView/tree-view.js.map +1 -1
  105. package/dist/hooks/use-overflow-items.d.ts.map +1 -1
  106. package/dist/hooks/use-overflow-items.js +2 -0
  107. package/dist/hooks/use-overflow-items.js.map +1 -1
  108. package/dist/hooks/use-truncated.d.ts.map +1 -1
  109. package/dist/hooks/use-truncated.js.map +1 -1
  110. package/dist/index.js +3 -1
  111. package/dist/lib/drag-announcements.d.ts +32 -0
  112. package/dist/lib/drag-announcements.d.ts.map +1 -1
  113. package/dist/lib/drag-announcements.js +39 -1
  114. package/dist/lib/drag-announcements.js.map +1 -1
  115. package/dist/lib/overlay-coexistence.js +1 -1
  116. package/dist/lib/roving-list-keyboard.d.ts +15 -0
  117. package/dist/lib/roving-list-keyboard.d.ts.map +1 -1
  118. package/dist/lib/roving-list-keyboard.js +6 -0
  119. package/dist/lib/roving-list-keyboard.js.map +1 -1
  120. package/dist/lib/utils.js +1 -1
  121. package/dist/lib/utils.js.map +1 -1
  122. package/dist/patterns/horizontal-overflow/horizontal-overflow.d.ts.map +1 -1
  123. package/dist/patterns/horizontal-overflow/horizontal-overflow.js +25 -0
  124. package/dist/patterns/horizontal-overflow/horizontal-overflow.js.map +1 -1
  125. package/dist/patterns/overlay-surface/overlay-surface.js.map +1 -1
  126. package/ds-canonical/fork/codex/agents/skills/performance-audit/SKILL.md +1 -1
  127. package/ds-canonical/fork/consumer/lock.json +11 -11
  128. package/ds-canonical/fork/consumer/managed-files/46f10bc55cdfdf834d0749eebff42ea0bb8576f361b36d2b6ba1851354c50150.blob +47 -9
  129. package/ds-canonical/fork/consumer/managed-files/5af0a46760af338d51fd0f7950675f8e97f7d2f09386b8818fcd7a58e6654e75.blob +71 -1
  130. package/ds-canonical/fork/consumer/managed-files/7eb6cc60abfdabaf6617c336058fad1454ccde08889295767bfd9b7fd153cc6e.blob +45 -6
  131. package/ds-canonical/fork/consumer/managed-files/ab072e7f2eca51f0e18a5e18c4b333260ee5d219a12cc6df5bb2d683f0b2734d.blob +27 -1
  132. package/ds-canonical/fork/governance.lock +9 -9
  133. package/ds-canonical/fork/manifest.json +10 -10
  134. package/ds-canonical/fork/providers/claude/skills/performance-audit/SKILL.md +1 -1
  135. package/ds-canonical/fork/providers/codex/skills/performance-audit/SKILL.md +1 -1
  136. package/ds-canonical/fork/skills/performance-audit/SKILL.md +1 -1
  137. package/ds-canonical/hooks/check_substantive_edit_approval_preflight.sh +29 -8
  138. package/ds-canonical/hooks/tests/test_check_substantive_edit_approval_preflight.sh +16 -6
  139. package/ds-canonical/references/focus-canonical.md +1 -1
  140. package/ds-canonical/references/governance-audit-coverage.md +1 -1
  141. package/ds-canonical/references/hit-area-canonical.md +4 -2
  142. package/ds-canonical/references/keyboard-model-canonical.md +4 -4
  143. package/ds-canonical/rules/meta-patterns.md +1 -1
  144. package/ds-canonical/rules/self-verify.md +4 -4
  145. package/ds-canonical/skills/design-system-audit/references/historical-bugs.md +27 -0
  146. package/ds-canonical/skills/performance-audit/SKILL.md +1 -1
  147. package/ds-story-manifest.json +11 -5
  148. package/llms-full.txt +2 -2
  149. package/llms.txt +2 -2
  150. package/package.json +3 -1
  151. package/src/components/Accordion/accordion.tsx +4 -1
  152. package/src/components/AccountMenu/account-menu.spec.md +1 -2
  153. package/src/components/AccountMenu/account-menu.tsx +0 -1
  154. package/src/components/AgentPanel/agent-decision-card.spec.md +88 -0
  155. package/src/components/AgentPanel/agent-panel-fab.spec.md +151 -0
  156. package/src/components/AgentPanel/agent-panel-fab.tsx +41 -17
  157. package/src/components/AgentPanel/agent-panel-logo.spec.md +87 -0
  158. package/src/components/AgentPanel/agent-panel-logo.tsx +3 -3
  159. package/src/components/AgentPanel/agent-panel.principles.stories.tsx +1 -1
  160. package/src/components/AgentPanel/agent-panel.spec.md +24 -284
  161. package/src/components/AgentPanel/agent-panel.stories.tsx +112 -7
  162. package/src/components/AgentPanel/agent-panel.tsx +9 -4
  163. package/src/components/Breadcrumb/breadcrumb.tsx +3 -1
  164. package/src/components/BulkActionBar/bulk-action-bar.spec.md +1 -0
  165. package/src/components/BulkActionBar/bulk-action-bar.stories.tsx +53 -0
  166. package/src/components/BulkActionBar/bulk-action-bar.tsx +32 -2
  167. package/src/components/Button/button.anatomy.stories.tsx +60 -31
  168. package/src/components/Button/button.spec.md +6 -4
  169. package/src/components/Button/button.tsx +52 -8
  170. package/src/components/Calendar/calendar.anatomy.stories.tsx +10 -7
  171. package/src/components/Calendar/calendar.principles.stories.tsx +8 -3
  172. package/src/components/Calendar/calendar.spec.md +12 -10
  173. package/src/components/Calendar/calendar.stories.tsx +76 -0
  174. package/src/components/Calendar/calendar.tsx +39 -14
  175. package/src/components/Carousel/carousel.spec.md +1 -1
  176. package/src/components/Carousel/carousel.tsx +5 -0
  177. package/src/components/Chip/chip.spec.md +1 -0
  178. package/src/components/Combobox/combobox.anatomy.stories.tsx +2 -1
  179. package/src/components/Combobox/combobox.tsx +19 -5
  180. package/src/components/Command/command.tsx +9 -5
  181. package/src/components/DataTable/cell-registry.tsx +3 -0
  182. package/src/components/DataTable/data-table-column-visibility-panel.tsx +5 -6
  183. package/src/components/DataTable/data-table-known-defects.spec.md +72 -0
  184. package/src/components/DataTable/data-table-scroll-performance.spec.md +295 -0
  185. package/src/components/DataTable/data-table-sort-manager.tsx +5 -6
  186. package/src/components/DataTable/data-table.spec.md +9 -341
  187. package/src/components/DataTable/data-table.stories.tsx +1 -1
  188. package/src/components/DataTable/data-table.tsx +152 -51
  189. package/src/components/DatePicker/date-picker.spec.md +1 -1
  190. package/src/components/Dialog/dialog.spec.md +5 -1
  191. package/src/components/Dialog/dialog.stories.tsx +9 -4
  192. package/src/components/Dialog/dialog.tsx +80 -47
  193. package/src/components/DropdownMenu/dropdown-menu.anatomy.stories.tsx +7 -0
  194. package/src/components/Empty/empty.spec.md +1 -2
  195. package/src/components/Field/field-context.ts +5 -2
  196. package/src/components/Field/field-controls.spec.md +3 -0
  197. package/src/components/Field/field-edit-keys.ts +12 -0
  198. package/src/components/Field/field.spec.md +1 -1
  199. package/src/components/Field/field.tsx +3 -0
  200. package/src/components/FileViewer/file-viewer.tsx +5 -2
  201. package/src/components/LinkInput/link-input.tsx +3 -0
  202. package/src/components/Notice/notice.tsx +1 -1
  203. package/src/components/NumberInput/number-input.tsx +3 -0
  204. package/src/components/Pagination/pagination.spec.md +1 -0
  205. package/src/components/PeoplePicker/people-picker.tsx +0 -3
  206. package/src/components/Popover/popover.spec.md +2 -0
  207. package/src/components/ProfileCard/profile-card.tsx +0 -3
  208. package/src/components/Rating/rating.anatomy.stories.tsx +1 -1
  209. package/src/components/Rating/rating.spec.md +3 -3
  210. package/src/components/Rating/rating.tsx +7 -3
  211. package/src/components/ScrollArea/scroll-area.spec.md +2 -0
  212. package/src/components/Select/select.spec.md +1 -1
  213. package/src/components/Select/select.tsx +11 -4
  214. package/src/components/SelectMenu/select-menu.spec.md +4 -0
  215. package/src/components/SelectionControl/selection-item.tsx +3 -1
  216. package/src/components/Sidebar/sidebar.spec.md +3 -2
  217. package/src/components/Sidebar/sidebar.stories.tsx +79 -0
  218. package/src/components/Sidebar/sidebar.tsx +10 -2
  219. package/src/components/Skeleton/skeleton.spec.md +1 -1
  220. package/src/components/Slider/slider.spec.md +1 -0
  221. package/src/components/Steps/steps-state-visuals.spec.md +157 -0
  222. package/src/components/Steps/steps.spec.md +13 -144
  223. package/src/components/Steps/steps.tsx +29 -5
  224. package/src/components/Tag/tag.spec.md +9 -10
  225. package/src/components/Tag/tag.tsx +2 -2
  226. package/src/components/Textarea/textarea.tsx +4 -0
  227. package/src/components/TimePicker/time-columns.tsx +4 -3
  228. package/src/components/TimePicker/time-picker.spec.md +1 -1
  229. package/src/components/Tooltip/tooltip.spec.md +1 -0
  230. package/src/components/TreeView/tree-view.spec.md +4 -1
  231. package/src/components/TreeView/tree-view.stories.tsx +87 -3
  232. package/src/components/TreeView/tree-view.tsx +88 -12
  233. package/src/hooks/use-overflow-items.ts +4 -0
  234. package/src/hooks/use-truncated.ts +3 -2
  235. package/src/lib/drag-announcements.ts +78 -0
  236. package/src/lib/roving-list-keyboard.ts +20 -0
  237. package/src/lib/utils.ts +1 -1
  238. package/src/patterns/action-bar/action-bar.spec.md +2 -0
  239. package/src/patterns/element-anatomy/inline-action.spec.md +2 -2
  240. package/src/patterns/element-anatomy/item-anatomy.spec.md +5 -3
  241. package/src/patterns/element-anatomy/truncated-text.spec.md +1 -0
  242. package/src/patterns/header-canonical/header-canonical.spec.md +2 -1
  243. package/src/patterns/horizontal-overflow/horizontal-overflow.spec.md +2 -0
  244. package/src/patterns/horizontal-overflow/horizontal-overflow.stories.tsx +36 -0
  245. package/src/patterns/horizontal-overflow/horizontal-overflow.tsx +28 -0
  246. package/src/patterns/overlay-surface/overlay-chrome-sizing.spec.md +180 -0
  247. package/src/patterns/overlay-surface/overlay-surface.spec.md +5 -160
  248. package/src/patterns/overlay-surface/overlay-surface.tsx +1 -1
  249. package/src/patterns/resize-handle/resize-handle.spec.md +2 -2
  250. package/src/tokens/color/color.spec.md +14 -6
  251. package/src/tokens/color/semantic.css +13 -0
  252. package/src/tokens/layoutSpace/layoutSpace.spec.md +2 -0
  253. package/src/tokens/motion/motion.spec.md +5 -0
  254. package/src/tokens/orphan-tokens.spec.md +1 -1
  255. package/src/tokens/uiSize/uiSize.spec.md +1 -1
  256. package/dist/node_modules/aria-hidden/dist/es2015/index.js +0 -147
  257. package/dist/node_modules/aria-hidden/dist/es2015/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"combobox.js","sources":["../../../src/components/Combobox/combobox.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// @renderer-symmetry-allow: ComboboxTagStack(view path)接 consumer tagRenderer 是 Stream C 下 cycle 工作 — 2026-05-12 先 ship Issues 2/3/4 surgical fixes(placeholder vocabulary + cell surface metrics + placeholder truncate),tagRenderer view-path unify deferred per field-controls.spec.md 共享 contract a。當前 multi=1 顯示已透過 PeoplePicker tagRenderer(people-picker.tsx:426-444)PersonDisplay SSOT 對齊;其他 Combobox consumer 走 default `<Tag>` 純文字 backward-compat。\n// code-quality-allow: file-size — Combobox 含 CustomCombobox/useOverflowCount/OverflowTagList/ComboboxTagStack 4 子元件 + 共用 helpers,split-into-files 會破壞 measurement closures + 重複 type definitions。\nimport * as React from 'react'\nimport { useKnownOptions } from '@/design-system/hooks/use-known-options'\nimport { X, ChevronDown } from 'lucide-react'\nimport { CircularProgress } from '@/design-system/components/CircularProgress/circular-progress'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, nakedCellRowModeAlign, fieldDisplayTextClass, fieldTagInsetX, fieldTagInsetY } from '@/design-system/components/Field/field-wrapper'\nimport { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid, useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'\nimport { TAG_HEIGHT_PX, Tag } from '@/design-system/components/Tag/tag'\nimport { ItemInlineAction, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { OverflowIndicator } from '@/design-system/components/OverflowIndicator/overflow-indicator'\nimport { SelectMenu, forwardKeyToListbox, useActiveDescendant, type SelectMenuOption } from '@/design-system/components/SelectMenu/select-menu'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n// ── constants ───────────────────────────────────────────────────────────────\n\nconst GAP = 4\n\n// 非-wrap tag 列 clip SSOT(4-path 共用:OverflowTagList base / readonly / native edit / custom edit):\n// 2026-05-18 F2 以 overflow-hidden 修「窄容器 tags 水平越界蓋 chevron / +N」,但雙軸 hidden 副作用\n// 是垂直同裁 — PeoplePicker stack hover 的 AvatarDismissOverlay(`-top-px` + 2px ring,\n// person-display.tsx v15.15,早於 F2)上緣被切(user 2026-08-05 抓「曾經沒有這問題」= F2 前確實沒有)。\n// 雙贏 = overflow-x-clip:水平維持 clip(F2 bug 不回歸;`clip` 不建 scroll container),垂直 visible\n// (overlay / avatar ring 完整)。**不可**改 overflow-x-hidden:單軸 hidden 令另一軸 visible 計算成\n// auto → 生 scroll container,垂直反而可捲。\nconst tagRowOverflowClass = 'overflow-x-clip'\n\n// Tag 四邊內距的單一來源在 field-wrapper.tsx(`fieldTagInsetX` / `fieldTagInsetY`),Select 共用;理由與公式見該處。\nconst tagPadding = fieldTagInsetX\nconst tagPaddingY = fieldTagInsetY\n\n/**\n * Combobox option schema(2026-05-10 post-Issue-4 audit unify):**explicit extends\n * SelectMenuOption(primitive SSOT)** — 避免重蹈先前 PeoplePicker 改壞的 wrapper schema drift。\n *\n * Why `extends SelectMenuOption`(per user 「全盤檢查避免下次又改壞或是偏移」要求):\n * 原 `interface ComboboxOption { value: string; label: string }` 是 weak schema,跟 Select 的\n * `ComboboxOption`(同名)雙重宣告但欄位不同 → TypeScript 不抓(同名 interface 在不同 file\n * 各 export,consumer import 到哪個版本看 import path)→ schema drift。\n * PeoplePicker multi-mode 走 Combobox 路徑,dropdown menu rows lose avatar / description —\n * user 看到「single mode 有 avatar / multi mode 沒 avatar」inconsistency。\n *\n * Fix(post-Issue-4 follow-up):extend SelectMenuOption → 全 primitive surface 自動繼承。\n * Wrapper-only field 都沒有 → empty body interface(future 加 wrapper-only field 加在此處)。\n * `menuOptions` mapping(below)forward 全 SelectMenuOption surface。\n *\n * 對齊 Polaris ChoiceList / Material Autocomplete / Carbon Dropdown 的 wrapper-vs-primitive\n * schema-extension idiom。Hook `check_wrapper_primitive_schema_drift.sh`(M30 機械強制)。\n */\nexport interface ComboboxOption extends SelectMenuOption {\n // (no wrapper-only fields yet — kept for future扩 + same-name SSOT cross-wrapper)\n}\n\n// ── useOverflowCount (unchanged) ────────────────────────────────────────────\n\nfunction useOverflowCount(\n containerRef: React.RefObject<HTMLDivElement | null>,\n tagEls: React.MutableRefObject<(HTMLDivElement | null)[]>,\n overflowEl: React.RefObject<HTMLDivElement | null>,\n totalCount: number,\n enabled: boolean,\n gap: number = GAP, // (2026-05-07 v15.13)stack avatar 模式傳 0\n visibleCountOverride?: number, // 2026-05-15 Bug 3 fix:override DOM measurement(PeoplePicker stack 走 formula primitive)\n): { visibleCount: number; ready: boolean } {\n const [state, setState] = React.useState({ visibleCount: totalCount, ready: !enabled })\n // 2026-05-18 Round 6 fix(per Codex M31 Round 6 H7 verdict + Step 5 共識):\n // `ofEl.offsetWidth` 在 expanded state(visibleCount === totalCount → overflow=0 →\n // `OverflowIndicator` count≤0 早退 `return null` → ofEl wrapper empty)= 0,fallback 60;\n // 在 collapsed state(+N rendered)= 真實寬(~28-32px)。同 `available` 在兩 state 給\n // 不同 verdict → 臨界值區 `max(B+g+Q, B+g+O) ≤ available < B+g+F` 振盪。Cache last\n // non-zero measurement → measurement state-independent → oscillation 收斂。\n // 初始 60 沿用舊 fallback(無 measure 史 ok-ish over-estimate)。\n const lastOverflowWRef = React.useRef<number>(60)\n\n // 2026-05-16 RACE FIX(user 抓「逐個 click 滿 6」vs「取消全選→再全選」same length 不同 visible):\n //\n // 原 useEffect + 雙 rAF 沒 capture rAF IDs → cleanup 不 cancel pending rAFs。\n // Path B(length=6→0→6):length=0 時 override=undefined 走 internal calc 排 rAF,\n // 然後 length=6 + override=N → deps change → cleanup 跑(disconnect ResizeObserver 但\n // 不 cancel rAF)→ 新 useEffect 跑 override 寫 el.hidden → 舊 rAF 仍 fire → 跑舊\n // internal calc → 覆寫 el.hidden 用 internal measurement(不一致於 override formula)。\n //\n // Fix:\n // 1. useEffect → useLayoutEffect:tighter timing,measurement 在 paint 前 sync\n // 2. Capture rAF IDs,cancel on cleanup\n // 3. scheduleCalc 函式包裝,cancel in-flight rAF 才排新一輪(避免 ResizeObserver\n // re-fire 堆 rAF)\n //\n // 對齊 2026-05-14 I3 fix comment「user 抓『全選 vs 逐個勾 result 不同』」 — 當時 fix\n // 只加 double-rAF 但漏 cancel,本次補完 race close。\n // 2026-05-18 Round 5 fix(per visual test probe):useLayoutEffect 在 nested component 場景\n // 會在 parent ref attach 前 fire(child layout effect 先於 parent ref attach)→ containerRef.current\n // null → early return → calc never runs → setProperty never called → CSS var unset → tag overflow。\n // 改 useEffect:fires AFTER paint,所有 refs 都 attach。double-rAF guard ensures layout done。\n // Trade-off:可能 1-2 frame flicker,但 functional setState guard + paint target measurement 已 cover。\n React.useEffect(() => {\n /**\n * 這次量測可不可信:容器與所有標籤都量到非零寬度才算數。\n *\n * 雙 rAF 的 fallback(2026-05-14 I3)當初是為了「批次渲染場景 tag 還 0-width」——\n * 那個條件在同步這一趟就量得出來,不必無條件再跑一次。實測(2026-09-10,DataTable\n * roadmap 全功能範例、40 步滾輪):每個掛載固定跑兩趟 calc,一次手勢 180 趟、\n * 1080 次幾何讀取,其中第二趟幾乎總是得到相同結果。改成「不可信才補跑」。\n */\n let trustworthy = false\n if (!enabled || totalCount === 0) { setState({ visibleCount: totalCount, ready: true }); return }\n if (visibleCountOverride !== undefined) {\n for (let i = 0; i < tagEls.current.length; i++) {\n const el = tagEls.current[i]\n if (el) el.hidden = i >= visibleCountOverride\n }\n const ofEl = overflowEl.current\n if (ofEl) ofEl.hidden = visibleCountOverride >= totalCount\n setState({ visibleCount: visibleCountOverride, ready: true }); return\n }\n // totalCount=1 fast path:single-tag case 直接 visible 不跑 measurement loop。\n // (歷史:c90d029 曾移除此 bypass,後復原 — 移除會造成 narrow cell 1-selected 跑 unbounded Tag\n // measurement 後 visibleCount=0 → 顯 +1 indicator 而非 single tag,違反 PeoplePicker length===1\n // 走 PersonDisplay SSOT。)\n // 2026-05-16 Round 5 codex edge case fix:explicit unhide DOM nodes(對齊 override branch)。\n // 原 fast-path 只設 React state 不動 `el.hidden`,如 wrappers 之前 hidden 殘留(從 length>1 降到 1)\n // 可能視覺漏顯。Override branch L78-80 同 contract 對齊。\n if (totalCount === 1) {\n for (let i = 0; i < tagEls.current.length; i++) {\n const el = tagEls.current[i]\n if (el) el.hidden = i >= 1\n }\n const ofEl = overflowEl.current\n if (ofEl) ofEl.hidden = true\n trustworthy = true\n setState({ visibleCount: 1, ready: true }); return\n }\n const container = containerRef.current\n if (!container) return\n\n const calc = () => {\n trustworthy = false\n const cs = getComputedStyle(container)\n const available = container.clientWidth - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0)\n // 2026-05-18 Round 5 fix(per user 拍板「那就開始做」+ Codex M31 Round 5 verdict):\n // inject available 成 CSS var,Tag 用 explicit length 而非 cyclic percentage(避 CSS Sizing 3\n // §5.2.1 cyclic percentage 退化問題)。\n container.style.setProperty('--combobox-tag-area-inline-size', `${available}px`)\n for (const el of tagEls.current) if (el) el.hidden = false\n const ofEl = overflowEl.current\n if (ofEl) ofEl.hidden = false\n // 2026-05-18 Round 6 fix:cache last non-zero ofEl width 破 expanded/collapsed state\n // 量測二態(expanded → ofEl 空 offsetWidth=0 / collapsed → real ~28-32px)。沒 cache\n // 之前同 `available` 在兩 state 給不同 verdict → 永動。詳本 hook 頂部 ref 註解。\n const measuredOverflowW = ofEl?.offsetWidth || 0\n if (measuredOverflowW > 0) lastOverflowWRef.current = measuredOverflowW\n const overflowW = lastOverflowWRef.current\n // **#3 fix(2026-05-04)**:width-check 先於 count++,並處理 i=0 邊界(1 tag 自身就太寬 → 全 hidden 顯 +N)\n // 之前 bug:greedy `count++` 永遠至少 = 1,1-tag-too-wide case 視覺呈半個 tag clipped + +N(錯)\n // 修後:1 tag 太寬時 count = 0,全 N tags 走 +N 顯 indicator\n // 2026-05-18 Round 5:量 paint target `[data-tag-root]` 而非 wrapper(per codex Round 5 verdict)。\n // wrapper basis:auto 自由 grow,offsetWidth ≠ Tag actual paint width。\n let used = 0, count = 0\n let anyZero = available <= 0\n for (let i = 0; i < totalCount; i++) {\n const el = tagEls.current[i]\n if (!el) continue\n const tagRoot = el.querySelector('[data-tag-root]') as HTMLElement | null\n const w = tagRoot ? tagRoot.getBoundingClientRect().width : el.offsetWidth\n if (w <= 0) anyZero = true\n const next = used + (count > 0 ? gap : 0) + w\n const remaining = totalCount - count - 1\n // width check FIRST(無 `count > 0` 短路):任何超寬都 break,包含 i=0 case\n if (remaining > 0 && next + gap + overflowW > available) break\n if (remaining === 0 && next > available) break\n used = next; count++\n }\n for (let i = 0; i < tagEls.current.length; i++) { const el = tagEls.current[i]; if (el) el.hidden = i >= count }\n if (ofEl) ofEl.hidden = count >= totalCount\n // 2026-05-18 Round 5 last guard(per Codex Round 5 verdict):safety net 防 measurement drift\n // (sub-pixel / rounding)。verify last visible tag rect.right ≤ container right,超出遞減 count。\n const containerRect = container.getBoundingClientRect()\n while (count > 0) {\n const lastEl = tagEls.current[count - 1]\n const tagRoot = lastEl?.querySelector('[data-tag-root]') as HTMLElement | null\n if (!tagRoot) break\n const tagRect = tagRoot.getBoundingClientRect()\n if (tagRect.right <= containerRect.right + 0.5) break\n count--\n if (lastEl) lastEl.hidden = true\n }\n if (ofEl) ofEl.hidden = count >= totalCount\n // 2026-09-08:標籤列是 `flex-1 min-w-0`,容器夠窄時它會被壓到 clientWidth = 0,\n // 而「+N」本身**在裁切容器內**,於是連它一起被裁掉 —— 使用者看不到「還有幾個」,\n // 那正是空間不足時唯一還帶資訊的元素。(實測 DataTable 篩選面板:標籤區寬度隨容器\n // 180 → 148 → 68 → 0;420px 時「+3」超出裁切祖先 28.4px,完全不可見。)\n // 給容器一個等於「+N」寬度的下限:它是最後才被放棄的東西。\n // 條件用 totalCount 而不是 `!ofEl.hidden`,是為了避免震盪 —— 後者會讓\n // 「設下限 → 空間變夠 → 一個 tag 塞得下 → +N 收起 → 下限撤掉 → 空間又不夠」來回跑。\n container.style.minInlineSize = totalCount > 0 ? `${overflowW}px` : ''\n // 2026-05-18 A' fix functional setState value-equal guard(per Codex Round 3 verdict):\n // effect 內 calc 直跑 + ResizeObserver re-fire 同時跑 → 若每次都 new object setState\n // 觸發 re-render 即使值沒變,可能 cascade。回 prev 不更新 = avoid 抖動。\n trustworthy = !anyZero\n setState(prev => (prev.visibleCount === count && prev.ready) ? prev : { visibleCount: count, ready: true })\n }\n\n // 2026-05-14 I3 fix(per codex M31 verdict + user 抓「全選 vs 逐個勾 result 不同」):\n // double-rAF ensures layout 完成 before measurement(原 single rAF 在 batched render\n // 場景 tag 還 0-width)。Plus observe per-item ResizeObserver — 任何 tag width 變動\n // 都 trigger recalc(deterministic regardless of commit order)。\n //\n // 2026-05-16 Race close:capture rAF IDs + cancel on cleanup(原版 race I3 沒 close\n // 完;user 抓 path A 逐個 click vs path B 取消全選再全選 same length 不同 visible)。\n // 2026-05-18 A' fix(per Codex Round 3 共識,user 拍板「執行」)— effect fire 時 calc() 直跑\n // 完成 `el.hidden` 設定 + functional setState guard(value-equal 不更新 = 避免 ResizeObserver\n // 抖動 cascade rerender)。double-rAF 為 fallback path(ResizeObserver / async update path)。\n // 解 user verbatim「tag 過長 / 過多會先全顯再變 +N 閃動」root cause(per codex Round 3 cite\n // 「render 沒設 hidden + calc imperative 寫 DOM」)。\n // 註:Round 3 原以 useLayoutEffect sync calc(paint 前設 hidden)實作;2026-05-18 Round 5\n // 已改 React.useEffect after-paint(nested 場景 parent ref attach 時序,詳上方 Round 5 註解)。\n calc()\n let rafId1 = 0, rafId2 = 0\n const scheduleCalc = () => {\n if (rafId1) { cancelAnimationFrame(rafId1); rafId1 = 0 }\n if (rafId2) { cancelAnimationFrame(rafId2); rafId2 = 0 }\n rafId1 = requestAnimationFrame(() => {\n rafId1 = 0\n rafId2 = requestAnimationFrame(() => {\n rafId2 = 0\n calc()\n })\n })\n }\n // 同步那趟量到 0 寬(批次渲染 / 尚未版面配置)才補跑雙 rAF;量得準就不再跑第二趟。\n if (!trustworthy) scheduleCalc()\n /**\n * ResizeObserver 在 `observe()` 之後一定會先送一發「初始觀測」,那一發回報的尺寸\n * 就是上面同步 calc 剛量過的同一個版面 —— 拿它再跑一次是純白工。每個 observer\n * 各自吞掉自己的第一發,之後的每一發都是真的尺寸變了,照常重算。\n */\n const skipFirst = (fn: () => void) => { let primed = false; return () => { if (!primed) { primed = true; return } fn() } }\n const containerObs = new ResizeObserver(skipFirst(scheduleCalc))\n containerObs.observe(container)\n const itemObs = new ResizeObserver(skipFirst(scheduleCalc))\n for (const el of tagEls.current) {\n if (el) itemObs.observe(el)\n }\n return () => {\n if (rafId1) cancelAnimationFrame(rafId1)\n if (rafId2) cancelAnimationFrame(rafId2)\n containerObs.disconnect()\n itemObs.disconnect()\n }\n }, [containerRef, totalCount, enabled, gap, visibleCountOverride]) // 2026-05-15 Bug 3 fix:visibleCountOverride 入 deps,override 改 trigger recalc\n\n return state\n}\n\n// ── OverflowTagList (unchanged) ──────────────────────────────────────────────\n\ntype ComboboxOverflowShape = 'circle' | 'tag'\n\n// 2026-05-16 fix:overflow chip wrapper 必能跟 tag wrapper 套同 overlap class\n// (per user 物理模型「avatar 和 +N 都是同尺寸圓形 + 同 step」)。原 chip wrapper\n// 只有 `shrink-0`,在 stack 模式 -ml-0.5 不 apply → chip 不 overlap → 視覺多 22px\n// 額外空間 → length=4→4 / length=5→2+3 saw bug 物理根因。\n// PeoplePicker stack mode pass `'-ml-0.5 first:ml-0 relative inline-flex'` 對齊。\ninterface OverflowTagListProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n items: { value: string; label: string }[]\n size: 'sm' | 'md' | 'lg'\n wrap: boolean\n renderTag: (item: { value: string; label: string }, index: number) => React.ReactNode\n /**\n * 2026-05-14 I4 fix(per codex M31 verdict + user 抓「display overflow 有 avatar / edit 無」):\n * Optional renderer for hidden items in `+N` overflow popover。Default fallback = `<Tag>{label}</Tag>`\n * (純文字 chip,backward-compat)。Consumer pass 此 prop 讓 hidden items 顯示同 avatar 視覺\n * (對齊 view path MultiPersonDisplay overflow popover Tag avatar SSOT)。\n */\n renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode\n onRemove?: (value: string) => void\n trailing?: React.ReactNode\n /** Tag area gap in px(default 4)。Stack mode 傳 0 讓 negative margin 生效 */\n gap?: number\n /**\n * Optional class merged into each tag's outer measurement wrapper `<div className=\"shrink-0\">`.\n * (2026-05-07 v15.13)為 PeoplePicker stack mode 提供 hook point — 讓 stack avatar 走\n * `-ml-0.5 first:ml-0 relative inline-flex group/avatar` 達成 overlap + dismiss group selector,\n * 同時保留 `useOverflowCount` 量測 wrapper(必要,不可移除)。\n *\n * **Caveat(Q2 known tradeoff)**:`-ml-0.5` 負 margin 不改 each wrapper 的 `offsetWidth` →\n * `useOverflowCount` 累加按完整寬計算 → 視覺實際塞得進的 tag 數 > 量測判定能塞的數 →\n * **+N indicator 偏保守**(視覺還有空間但已顯 `+N`)。當前 v1 接受此 tradeoff;若窄 trigger\n * + 多人場景明顯不對,future 可加 `overlapPx` prop 讓量測補償。\n */\n tagWrapperClassName?: string\n /** 2026-05-16 fix:overflow chip 圓形 wrapper 套此 class(stack 模式套 `-ml-0.5` overlap),\n * 讓 chip 跟 avatar 同 step 物理 — 避免「chip 多 24px 額外空間」造成 saw transition。*/\n overflowWrapperClassName?: string\n /**\n * Overflow indicator(+N)形狀(2026-05-12 Round 7 fix,user 抓 PeoplePicker stack +N 該圓形):\n * - `'tag'`(default,backward-compat)— 矩形 chip(對齊 Combobox 文字 tag)\n * - `'circle'`(opt-in for avatar stack consumers)— 圓形 avatar-shape +N(對齊 GitHub picker idiom)\n * PeoplePicker stack mode pass `'circle'`,Combobox 文字 tag 自走 `'tag'`。\n */\n overflowShape?: ComboboxOverflowShape\n /**\n * 2026-05-15 Bug 3 fix:override visible count via formula-based primitive(PeoplePicker stack\n * 用 `avatar-stack-overflow` primitive deterministic formula 計算 visible,bypass DOM offsetWidth\n * measurement)。對齊 user SSOT「同 cell width 同 overflow 判斷」。\n */\n visibleCountOverride?: number\n}\n\nfunction OverflowTagList({ containerRef, items, size, wrap, renderTag, renderHiddenTag, onRemove, trailing, tagWrapperClassName, overflowWrapperClassName, gap = GAP, overflowShape = 'tag', visibleCountOverride }: OverflowTagListProps) {\n const tagEls = React.useRef<(HTMLDivElement | null)[]>([])\n const overflowEl = React.useRef<HTMLDivElement>(null)\n const { visibleCount, ready } = useOverflowCount(containerRef, tagEls, overflowEl, items.length, !wrap, gap, visibleCountOverride)\n tagEls.current.length = items.length\n\n if (wrap) return <>{items.map((item, i) => renderTag(item, i))}{trailing}</>\n\n const overflow = items.length - visibleCount\n const hiddenItems = items.slice(visibleCount)\n\n // 2026-05-18 A' fix(per Codex Round 3 共識,user 拍板「執行」)— 撤掉舊的 `style={{ opacity: ready ? 1 : 0 }}`\n // gate(掛在 `<span className=\"contents\">` 上,但 CSS Display 3 spec 規定 `display:contents` 元素不產生 box,\n // parent opacity 對 children 無效 → gate 從沒生效是 dead code)。Flicker 由 `useOverflowCount` effect 內\n // `calc()` 直跑(現 L190;2026-05-18 Round 5 改 useEffect after-paint + double-rAF guard,詳該 hook 註解)解。\n // `ready` state 保留供未來 instrumentation / debug,不再當 visual gate。\n // 保留 `<span className=\"contents\">` 維持 fragment-like rendering(parent JSX 期望 single child)。\n void ready // intentional: ready 留供 future debug,目前無 consumer\n // **量測 wrapper 必須是 flex 容器,不能是區塊盒**(2026-09-15 user 抓「sm 的 tag 沒垂直置中」,像素實測):\n // 區塊盒的高度由繼承的字型行高決定(欄位 text-body = 21px),sm 的 Tag 只有 20px(h-5),行內的 Tag 對齊\n // 行盒基線、沉到底部 → tag 區 21.8px、tag 上隙 3.9 / 下隙 2.1。md/lg 的 Tag 是 24px ≥ 21,盒子被撐滿才看不出來。\n // flex 容器沒有行盒:高度 = Tag 高度,wrapper `items-center` 直接對 Tag 的盒子置中(sm 3/3、md 3/3、lg 5/5)。\n // Select 的 tag 模式沒有這層 wrapper,一直是正的 —— 這層 wrapper 是 useOverflowCount 量寬用的,寬度量法不變\n //(flex 容器在 flex row 裡 shrink-0 的 max-content 寬 = 內容寬,跟區塊盒相同)。閘:`scripts/tag-field-vertical-inset.mjs`。\n return (\n <span className=\"contents\">\n {items.map((item, i) => (\n // 2026-05-14 I5 fix(per codex M31 verdict + user 抓「avatar stack 堆疊方向不一致」):\n // 加 z-index per-index — 前 item z 高(對齊 MultiPersonDisplay zIndex: visible.length - i\n // canonical + MUI AvatarGroup surplus pattern)。view + edit stack 堆疊方向統一。\n // 2026-09-26:疊放順序改走 CSS 變數,裡面有東西拿到鍵盤焦點時整項升到最上層 —— 焦點框往外畫,不升的話\n // 左半圈會被前一項蓋住(同 avatar.tsx AVATAR_STACK_ITEM_CLASS 的理由;頭像堆疊只在 PeoplePicker 會重疊,一般 Tag 不重疊、升層無副作用)\n <div key={item.value} ref={el => { tagEls.current[i] = el }}\n className={cn('shrink-0 max-w-full flex z-[var(--tag-stack-z)] has-[:focus-visible]:z-[var(--tag-stack-z-focus)]', tagWrapperClassName)}\n style={{ ['--tag-stack-z' as string]: items.length - i, ['--tag-stack-z-focus' as string]: items.length + 1 }}>{renderTag(item, i)}</div>\n ))}\n <div ref={overflowEl}\n className={cn('shrink-0 flex has-[:focus-visible]:z-[var(--tag-stack-z-focus)]', overflowWrapperClassName)}\n style={{ ['--tag-stack-z-focus' as string]: items.length + 1 }}>\n <OverflowIndicator count={overflow} shape={overflowShape} size={size}>\n {hiddenItems.map(item => (\n renderHiddenTag\n ? <React.Fragment key={item.value}>{renderHiddenTag(item)}</React.Fragment>\n : <Tag key={item.value} size=\"sm\" onRemove={onRemove ? () => onRemove(item.value) : undefined}>\n {item.label}\n </Tag>\n ))}\n </OverflowIndicator>\n </div>\n {trailing}\n </span>\n )\n}\n\n// ── Internal tag-stack renderer (consumed by ReadonlyMultiSelect / mode='view') ───\n//\n// Phase B2(2026-05-05):原 ComboboxDisplay sub-component 已 retire,改 inline `<Combobox mode=\"view\">`。\n// 本 helper 只負責 tag-stack 內容渲染(OverflowTagList 消費),不包 Field wrapper。\nfunction ComboboxTagStack({\n value, options, tagSize = 'md', wrap = false, containerRef: externalRef, disabled = false,\n}: {\n value?: string[] | null; options?: ComboboxOption[]; tagSize?: 'sm' | 'md' | 'lg'\n wrap?: boolean; containerRef?: React.RefObject<HTMLDivElement | null>; disabled?: boolean\n}) {\n const emptyDisplay = useFieldEmptyDisplay()\n const ownRef = React.useRef<HTMLDivElement>(null)\n if (!value || value.length === 0) return <span className={fieldEmptyColorClass(disabled ? 'disabled' : 'view')}>{emptyDisplay}</span>\n const items = value.map(v => ({ value: v, label: options?.find(o => o.value === v)?.label ?? v }))\n const disabledClass = disabled ? 'bg-disabled text-fg-disabled' : undefined\n\n const content = (\n <OverflowTagList containerRef={externalRef ?? ownRef} items={items} size={tagSize} wrap={wrap}\n // 2026-05-18 7B' fix(per user 拍板「執行」+ Codex Round 3 共識)— 移除 `unbounded`,Tag 回預設\n // `max-w-40` cap(160px)+ 內建 `[data-tag-text] truncate min-w-0` 自帶 ellipsis。原 unbounded 是\n // 「cell-as-input narrow cell < 160px」設計(`tag.tsx:85-90`),但 generic Combobox tag display\n // 應走 Tag canonical cap-with-ellipsis(per `data-table.spec.md:235`「Tag 文字內部 truncate;\n // multiSelect 動態 +N」+ `data-table.spec.md:467`「Tag 不可被外層 overflow-hidden 裁掉邊框」)。\n // Trade-off:長 tag 觸發 +N 提前(160 + gap + overflowW > available 較 quick)— acceptable per user。\n // Round 2 dynamic slot maxWidth 提案經 user + codex 共識撤回(3 chicken-and-egg fatal,KISS 勝)。\n renderTag={(item) => <Tag size={tagSize} className={cn('shrink-0', disabledClass)}>{item.label}</Tag>} />\n )\n\n if (externalRef) return content\n // 2026-05-05 v9 fix(Bug 4):view path 內 wrapper 必須 `flex-1 min-w-0`,否則在 cell flex\n // parent 下不認領完整可用寬度 → OverflowTagList 量得寬度小於 edit path → 顯 `+N` 多於 edit。\n // edit path tagAreaRef wrapper 已是 `flex-1 min-w-0`(CustomCombobox),\n // view 必對稱才 SSOT。\n // 2026-05-15 F1 Q3 fix(per user round 3 verbatim「單人選取時 Tag 越界蓋 indicator」):\n // `overflow-visible` → `overflow-hidden` 讓 narrow cell width 強制 clip(Tag 內建 truncate\n // 處理 text ellipsis,stack `-ml-0.5` 負 margin 在 wrapper 內不受影響)。對齊\n // `data-table.spec.md:233`「禁硬裁無 ellipsis」+ MUI X / Ant Table column.ellipsis 共識。\n // (2026-05-14 nakedCellRowModeAlign 同保留 — autoRowHeight cell first-line align canonical。)\n return (\n <div ref={ownRef} className={cn('flex-1 min-w-0 flex items-center', nakedCellRowModeAlign, wrap ? 'flex-wrap' : tagRowOverflowClass)} style={{ gap: GAP }}>\n {content}\n </div>\n )\n}\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface ComboboxProps {\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: ComboboxOption[]\n value?: string[]\n onChange?: (value: string[]) => void\n placeholder?: string\n className?: string\n disabled?: boolean\n wrap?: boolean\n clearable?: boolean\n /** 啟用搜尋 */\n searchable?: boolean\n /** 「這個值」在讀取 / 驗證 / 儲存(Field 家族 `loading` SSOT,`field-controls.spec.md`「Loading state」;2026-09-09 user 拍板\n * 收窄語意,與 Input `loading` 同義):觸發點右側、ChevronDown 左邊放列圖示尺寸的 CircularProgress(react-select / Atlassian\n * 的順序:清除 → 轉圈 → 箭頭)+ 觸發點 `aria-busy`;選單照常可開、可選。**不是**選項載入 —— 選項載入用 `optionsLoading`。 */\n loading?: boolean\n /** 選項清單載入中(2026-09-09 user 拍板改名自 `loading`)。Forward 給 SelectMenu SSOT:指示**只在選單內**(沒有可顯示選項時\n * 一列「載入選項中」訊息列 + listbox `aria-busy`),觸發點 / 搜尋列不轉圈;本機過濾已有選項時保留、遠端搜尋抓資料中舊選項\n * 不顯示(`select-menu.spec.md`「Loading」「遠端搜尋」)。 */\n optionsLoading?: boolean\n /** 搜尋框位置:menu(浮層內,預設)或 trigger(inline input) */\n searchIn?: 'menu' | 'trigger'\n /** 遠端搜尋時傳 `false`:不在本機用搜尋字過濾(trigger 模式與浮層模式都不過濾)、伺服器回什麼列什麼;抓資料中(`optionsLoading`)\n * 舊結果不顯示、關鍵字空時顯示 `suggestions`;SSOT select-menu.spec.md「遠端搜尋」。 */\n filterOption?: boolean\n /** 搜尋字改變時回呼(含清空);遠端搜尋搭配 `filterOption={false}` + `optionsLoading`。trigger / menu 兩種搜尋位置都會回呼。 */\n onSearchChange?: (value: string) => void\n /** 遠端搜尋、關鍵字空時顯示的建議清單(部分選項;DS 自動包成「建議」群組,讓使用者知道選項不只這幾筆)。只在 `filterOption={false}`\n * 生效;SSOT `select-menu.spec.md`「Suggestions」。 */\n suggestions?: ComboboxOption[]\n /** 建議群組標題(預設「建議」;forward 給 SelectMenu) */\n suggestionsLabel?: string\n /** 遠端搜尋、關鍵字空、沒有建議也沒在載入時的提示列文案(預設「輸入關鍵字搜尋」;forward 給 SelectMenu) */\n searchHintText?: string\n /** 搜尋框 placeholder(未有選項時顯示)。Default: 「搜尋…」 */\n searchPlaceholder?: string\n /** 搜尋框 ARIA label。Default: 「搜尋選項」 */\n searchAriaLabel?: string\n /** Empty-selection placeholder text。Default: 「選擇…」 */\n emptyPlaceholder?: string\n /** 搜尋無結果提示(2026-07-04 Q4 拍板接線)— forward SelectMenu primitive SSOT(default「沒有符合的選項」) */\n emptyText?: string\n /** 多選 footer 全選按鈕文字 —— 還沒全選時(2026-09-17 補轉發:原本 SelectMenu 有這個 prop 但沒有任何 wrapper 傳下去,\n * 等於 Combobox / PeoplePicker / DataTable 的使用者永遠改不了文案);default「全選」 */\n selectAllLabel?: string\n /** 多選 footer 全選按鈕文字 —— 已全選時,點下去清空;default「取消全選」 */\n deselectAllLabel?: string\n /**\n * 多選:在清單最上面加一列「不限」。**預設關**,由消費端自行開啟(轉發給 `SelectMenu`,\n * 完整語意與「何時該開」見 `../SelectMenu/select-menu.spec.md`)。\n * 只選「不限」時,欄位不渲 Tag,改走**一般已填值**的純文字路徑(與單選欄位同一種樣式)。\n */\n unrestricted?: boolean\n /** 「不限」那一列與欄位上顯示的文字(同一個來源)。預設「不限」。 */\n unrestrictedLabel?: string\n /** 「不限」在 value 陣列裡的保留值。預設 `__unrestricted__`。 */\n unrestrictedValue?: string\n /** 可建立新選項(creatable tag,2026-07-18 user 拍板 forward)—— 搜尋非空且無完全同名既有選項時,\n * dropdown 顯 create row(Plus + `createLabel`);forward 給底層 SelectMenu(邏輯/顯示/互動 SSOT 住在 SelectMenu)。\n * 僅 searchable 桌機路徑生效(需打字);native mobile 路徑不支援。對齊 Ant tags / react-select Creatable。 */\n creatable?: boolean\n /** 建立新選項 callback(forward SelectMenu `onCreate`)。 */\n onCreate?: (value: string) => void\n /** create row 文字格式(forward SelectMenu `createLabel`,預設「直接使用「{query}」」)。 */\n createLabel?: (query: string) => string\n /** a11y:無 Field wrapper 時提供 role='combobox' 的 accessible name(axe aria-input-field-name) */\n 'aria-label'?: string\n /** Initial open state(uncontrolled)— 對齊 Select.defaultOpen / Radix Popover canonical。\n * DataTable cell-as-input 1-step open 用 */\n defaultOpen?: boolean\n /** open state 變更 callback。DataTable cell-as-input 用:open=false → cell exit edit */\n onOpenChange?: (open: boolean) => void\n /**\n * Selected tag pill 客製 render(2026-05-07 v15.5)。\n *\n * 設了 → 每個 selected tag pill 走 consumer 提供的 ReactNode(收 item={value, label}\n * + onRemove,consumer 自己組 onRemove);沒設 → 走預設 `<Tag>` text-only pill。\n *\n * 用例:PeoplePicker(multi)用此 slot 把 selected tag 換成 avatar + name pill,而非\n * 純文字 Tag。對齊 PeoplePicker = Combobox wrapper SSOT。\n */\n tagRenderer?: (item: { value: string; label: string }, onRemove: () => void) => React.ReactNode\n /**\n * 2026-05-14 I4 fix:Optional renderer for hidden items in `+N` overflow popover\n * (對齊 view path MultiPersonDisplay overflow popover 含 avatar SSOT)。PeoplePicker stack\n * pass 此 prop 讓 hidden items 顯 avatar + name(同 view path)。Default fallback\n * `<Tag>{label}</Tag>` 純文字 backward-compat。\n */\n renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode\n /**\n * @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer hook)。\n *\n * Optional class merged into each tag's outer measurement wrapper (2026-05-07 v15.13)。\n * Stack avatar 模式用此 hook point 達成 sibling-level overlap (`-ml-0.5`) + group selector\n * (`group/avatar`)— 既保留 Combobox 必要 measurement wrapper,又讓 dismiss/overlap 視覺生效。\n */\n tagWrapperClassName?: string\n /** @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer hook)。\n * 2026-05-16:overflow chip wrapper 套此 class(對齊 tagWrapperClassName)。Stack 模式\n * pass `-ml-0.5 first:ml-0` 讓 chip 跟 avatar 同 overlap step,物理上 chip = 1 個 slot 不\n * 外加 24px。Default undefined = chip 不 overlap(text-tag mode 等)。*/\n overflowWrapperClassName?: string\n /**\n * Tag area gap in px (2026-05-07 v15.13)。預設 4(pill mode 標準 spacing)。\n * Stack avatar 模式傳 0,讓 `tagWrapperClassName` 的 `-ml-[var(--avatar-stack-overlap)]` negative margin 生效\n * (CSS `gap` 套在 flex container 上會強制 sibling spacing,蓋過 negative margin)。\n * **Q2 known tradeoff**:0 後 useOverflowCount 仍按 wrapper.offsetWidth 累加(不含 overlap\n * 補償)→ +N 偏保守。當前接受;若需精準可 future 加 `overlapPx` 補償邏輯。\n *\n * @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer hook)。\n */\n tagAreaGapPx?: number\n /**\n * tagAreaRef container 左 paddingLeft(px,2026-05-12 加,for PeoplePicker Avatar inset)。\n * Default undefined = no extra padding(Field wrapper `tagPadding[size]` calc 公式自然 inset)。\n * 設值時 tagAreaRef 增 `style.paddingLeft`,**useOverflowCount 的 `available = clientWidth -\n * paddingLeft - paddingRight` 自動 include**(`parseFloat(cs.paddingLeft)` 從 container CSS 抓)\n * → width calc 不漂移,無 side-effect。\n *\n * @internal PeoplePicker stack wrapper 內部協議 — 目前無 active consumer(PeoplePicker 傳 undefined),保留供未來精準 padding;新 consumer 請先評估。\n *\n * **2026-05-13 v2 deprecate path**:原 PeoplePicker pass `{8}` 假設「Combobox tagPadding=4px,4+8=12」\n * 但 `tagPadding[size]` 是 density-dependent calc `(field-height − 2px − tag-height) / 2`(3/3/5;SSOT field-wrapper.tsx fieldTagInsetX,2026-09-15 更正:舊註解寫 icon-size 是錯的),只在 md size +\n * default density 才 = 4px;其他 size/density 漂 6/8px → 4+8=12 公式破。改 PeoplePicker 直接 inject\n * `!px-[var(--field-px)]` className 到 Combobox Field wrapper(per people-picker.spec.md:94 v2),`tagAreaPaddingLeftPx`\n * 走 undefined。Future 仍保留此 prop 給其他 consumer 精準調整 padding,但 PeoplePicker 已不再用。\n */\n tagAreaPaddingLeftPx?: number\n /**\n * Overflow indicator (+N) 形狀(2026-05-12 Round 7,opt-in 給 avatar stack consumer):\n * - `'tag'`(default)— 矩形 chip(Combobox 文字 tag default)\n * - `'circle'`(opt-in)— 圓形 avatar-shape(PeoplePicker stack 用)\n */\n overflowShape?: ComboboxOverflowShape\n /**\n * @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer override)。\n *\n * 2026-05-15 Bug 3 fix:override visible count via formula-based primitive(opt-in;default 走\n * DOM-based `useOverflowCount`)。PeoplePicker stack mode 用 `avatar-stack-overflow` primitive\n * deterministic formula 計算 visible count,forward 給 Combobox bypass DOM offsetWidth\n * measurement,避免 dual-algorithm drift。對齊 user SSOT「同 cell width 同 overflow 判斷」。\n */\n visibleCountOverride?: number\n /**\n * Display 是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)\n * — DataTable cell view↔edit 像素級對齊用。預設 false(裸 tag stack,backward compat)。\n * 設 true 時 view 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,\n * 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。\n */\n showDisplayEndIcon?: boolean\n}\n\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 readonly/disabled/view render ─────────────────────────────────\n\nfunction ReadonlyMultiSelect({\n mode, variant: variantProp, width, size, options, value, wrap, className, showDisplayEndIcon = false,\n unrestricted = false, unrestrictedLabel = '不限', unrestrictedValue = '__unrestricted__', // i18n-allow: DS default(與 SelectMenu 同源)\n}: Pick<ComboboxProps, 'mode' | 'width' | 'size' | 'options' | 'value' | 'wrap' | 'className' | 'showDisplayEndIcon' | 'unrestricted' | 'unrestrictedLabel' | 'unrestrictedValue'> & {\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 = sz === 'lg' ? 20 : 16\n const tagHeight = TAG_HEIGHT_PX[sz]\n const containerRef = React.useRef<HTMLDivElement>(null)\n // 只選了「不限」時不渲 Tag —— 走**一般已填值**那條純文字路徑(2026-09-18 user 拍板)。\n // 互斥保證它只會單獨存在,所以判斷就是「陣列裡只有它」。\n const isUnrestrictedOnly = unrestricted && (value?.length ?? 0) === 1 && value?.[0] === unrestrictedValue\n const hasTags = (value?.length ?? 0) > 0 && !isUnrestrictedOnly\n\n // mode='view'(Phase B2 2026-05-05):純內容輸出 — tag stack 不包 Field wrapper / 不 reserve 高度。\n // 對齊原 ComboboxDisplay sub-component(retired)。\n // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,\n // 與 edit 同結構消除 cell view↔edit 像素偏移(Layer-B padding mismatch)。\n if (resolvedMode === 'view') {\n if (!showDisplayEndIcon) {\n // 2026-05-14 I2 fix(spec contract (e) view typography canonical):empty bare span 套\n // `fieldDisplayTextClass(sz)`(sm/md→text-body,lg→text-body-lg)— 對齊跨 Field family 統一。\n // 「不限」與 placeholder 共用同一顆 span、同一個字級與位置,**唯一差別是不套那層灰**\n // (`Select` 單選欄位就是這樣寫的,select.tsx:352-353;字級 SSOT `field-wrapper.tsx:387`)。\n if (isUnrestrictedOnly) return <span className={cn(fieldDisplayTextClass(sz), className)}>{unrestrictedLabel}</span>\n if (!hasTags) return <span className={cn(fieldDisplayTextClass(sz), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>\n return (\n <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap} />\n )\n }\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'view', variant, width, size: sz }), hasTags && tagPadding[sz],\n // wrap 幾何跟 edit / readonly / disabled 全 mode 一致(2026-09-15 補漏):items-start + 同一個內距公式 + 高度放開,\n // 否則 view 態 wrap 的 tag 會被固定的 h-field-* 裁掉;第一行 y 仍 = 單行 y(field.spec.md:147 中線錨在 field-height/2)。\n hasTags && wrap && cn('items-start', tagPaddingY[sz]), className)}\n style={hasTags ? { paddingRight: 'var(--field-px)', ...(wrap ? { height: 'auto' } : undefined) } : undefined}\n data-field-mode=\"view\"\n >\n {hasTags ? (\n <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap} />\n ) : (\n isUnrestrictedOnly\n ? <span className={cn('flex-1 min-w-0', fieldDisplayTextClass(sz))}>{unrestrictedLabel}</span>\n : <span className={cn('flex-1 min-w-0', fieldEmptyColorClass(resolvedMode))}>{emptyDisplay}</span>\n )}\n {/* wrap 時 chevron 鎖第一行 tag 中線,跟 readonly(:628)/ edit 同一招(field-controls.spec.md:280) */}\n <ItemSuffix className={cn('pointer-events-none', wrap && 'self-start')} style={wrap ? { height: tagHeight } : undefined}>\n <ChevronDown size={iconSize} className=\"shrink-0 text-fg-muted\" aria-hidden />\n </ItemSuffix>\n </div>\n )\n }\n\n return (\n <div ref={containerRef}\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), hasTags && tagPadding[sz],\n // 2026-05-18 #6A Round 1 Step 1/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:451):\n // readonly/disabled path 對齊 L293 view wrapper 已 ship 的 overflow-hidden fix。\n // M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟 view 不對稱。\n // 2026-06-27 對齊 edit path(L598-617):wrap 時 items-start + chevron self-start/tagHeight 鎖第一行;\n // paddingRight: var(--field-px) re-assert 右緣 12px(tagPadding 對稱 calc 會吃掉右緣,跟 edit 一致)。\n wrap ? cn('flex-wrap items-start', tagPaddingY[sz]) : tagRowOverflowClass, className)}\n style={{ gap: GAP, paddingRight: 'var(--field-px)', ...(wrap ? { height: 'auto' } : undefined) }} data-field-mode={resolvedMode}\n aria-disabled={resolvedMode === 'disabled' ? true : undefined}>\n {hasTags ? (\n <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap}\n containerRef={containerRef} disabled={resolvedMode === 'disabled'} />\n ) : (\n isUnrestrictedOnly\n ? <span className={fieldDisplayTextClass(sz)}>{unrestrictedLabel}</span>\n : <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n )}\n {/* 2026-06-26 類型身份 indicator:edit 顯示 / readonly 不顯示(純值、不可開下拉) / disabled 保留(fg-disabled,對齊原生 <select disabled>);naked cell 依 showDisplayEndIcon */}\n {(variant === 'naked' ? !!showDisplayEndIcon : resolvedMode === 'disabled') && (\n <ItemSuffix className={cn('pointer-events-none', wrap && 'self-start')} style={wrap ? { height: tagHeight } : undefined}>\n <ChevronDown size={iconSize} className={cn('shrink-0', resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted')} aria-hidden />\n </ItemSuffix>\n )}\n </div>\n )\n}\n\n// ── Native Combobox (mobile) ────────────────────────────────────────\n\n// 2026-05-16 Bug A root cause fix(Claude+Codex M31 Step 5 比稿 consensus,user verbatim\n// 「圖二/圖三 同 180px 不同 length 不同 visible — 跟 user 一開始抓的問題一模一樣」):\n// 公開 `Combobox.forwardRef` 之前用 `(props, _ref)` 把 ref drop,內部 `CustomCombobox`\n// 從未拿 ref → PeoplePicker `stackContainerRef.current` 永遠 null →\n// `useLayoutEffect` early return → `visibleCountOverride` 永遠 undefined →\n// Combobox 走原 internal `useOverflowCount` 60px chip fallback bug → drift。\n// Fix:internal `__triggerRef` prop(underscore = internal-only)attach root div;\n// 公開 `Combobox.forwardRef` 把 `ref` forward 為 `__triggerRef`。對齊 codex DS-wide iceberg\n// audit:`SelectMenu` / `DateGrid` / `Toast` 的 `_ref` 是 intentional documented(no DOM\n// target);唯本處 actionable drop。\ntype ComboboxInternalProps = ComboboxProps & { __triggerRef?: React.Ref<HTMLDivElement> }\n\nfunction focusAfterTagRemoval(container: HTMLElement | null, owner: HTMLElement | null) {\n const active = document.activeElement\n const buttons = container\n ? Array.from(container.querySelectorAll<HTMLButtonElement>('[data-collection-remove]'))\n .filter((button) => button.getClientRects().length > 0)\n : []\n const index = buttons.indexOf(active as HTMLButtonElement)\n const next = index >= 0 ? buttons[index + 1] ?? buttons[index - 1] : undefined\n const fallback = owner ?? container?.closest<HTMLElement>('[role=\"combobox\"]')\n ;(next ?? fallback)?.focus()\n\n // Some renderers intentionally change anatomy at collection length 1 (PeoplePicker stack:\n // avatar stack → avatar + name). That remounts the button focused above. Re-apply the same\n // next→previous→owner policy after React commits so focus cannot fall back to body.\n const preferredIndex = index >= 0\n ? (buttons[index + 1] ? index : buttons[index - 1] ? index - 1 : -1)\n : -1\n window.requestAnimationFrame(() => {\n const updatedButtons = container\n ? Array.from(container.querySelectorAll<HTMLButtonElement>('[data-collection-remove]'))\n .filter((button) => button.getClientRects().length > 0)\n : []\n const updatedTarget = preferredIndex >= 0 ? updatedButtons[preferredIndex] : undefined\n ;(updatedTarget ?? fallback)?.focus()\n })\n}\n\n// 轉換 ComboboxOption → SelectMenuOption:同一份 mapping 給 options 與 suggestions(2026-09-09 建議清單),不複製第二份。\n// 2026-05-10 post-Issue-4 follow-up:forward 全 SelectMenuOption surface(avatar / description / disabled / icon / group)。\nconst toMenuOption = (opt: ComboboxOption): SelectMenuOption => ({\n value: opt.value,\n label: opt.label,\n icon: opt.icon,\n avatar: opt.avatar,\n description: opt.description,\n disabled: opt.disabled,\n group: opt.group,\n})\n\n// ── Custom Combobox (desktop — consumes SelectMenu) ───────────────────\n\nfunction CustomCombobox({\n mode, variant: variantProp, width, error: errorProp = false, size = 'md', options, value = [], onChange, placeholder,\n className, disabled: disabledProp, wrap = false, clearable = false, searchable = false, loading, optionsLoading, searchIn = 'menu', filterOption = true, onSearchChange,\n suggestions, suggestionsLabel, searchHintText,\n searchPlaceholder = '搜尋…', // i18n-allow: DS default\n searchAriaLabel = '搜尋選項', // i18n-allow: DS default\n emptyPlaceholder = '選擇…', // i18n-allow: DS default\n emptyText,\n selectAllLabel,\n deselectAllLabel,\n unrestricted = false,\n unrestrictedLabel = '不限', // i18n-allow: DS default; consumer override via unrestrictedLabel prop\n unrestrictedValue = '__unrestricted__',\n creatable = false,\n onCreate,\n createLabel,\n defaultOpen = false,\n onOpenChange,\n __triggerRef,\n tagRenderer,\n renderHiddenTag,\n tagWrapperClassName,\n overflowWrapperClassName,\n tagAreaGapPx,\n visibleCountOverride,\n tagAreaPaddingLeftPx,\n overflowShape,\n showDisplayEndIcon = false,\n 'aria-label': ariaLabel,\n}: ComboboxInternalProps) {\n const tagAreaGap = tagAreaGapPx ?? GAP\n const fieldCtx = useFieldContext()\n const error = useResolvedFieldInvalid(errorProp)\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode=\"view\"> 漏 cascade\n const resolvedMode = useResolvedFieldMode({ mode, disabled })\n const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const iconSize = getIconSize(size)\n const showClear = clearable && value.length > 0 && resolvedMode === 'edit'\n const [open, setOpen] = React.useState(defaultOpen)\n const [search, setSearchState] = React.useState('')\n const setSearch = React.useCallback((next: string) => { setSearchState(next); onSearchChange?.(next) }, [onSearchChange])\n // 2026-05-12 Q3 fix:trigger 內 inline 搜尋 input ref,onOpenAutoFocus 時 explicit focus\n // 讓 user 看到 cursor 知道可 inline search(跟 Select inputRef SSOT 同模式)。\n const inputRef = React.useRef<HTMLInputElement>(null)\n // a11y: 為 listbox 容器(SelectMenu 內 PopoverContent)建立穩定 id,讓 trigger 的\n // aria-controls 能指向它(WAI-ARIA combobox pattern 要求)。React.useId 在 SSR/CSR 都穩定。\n const listboxId = React.useId()\n // a11y(2026-07-05 D4):追蹤 cmdk active item id → searchIn='trigger' 搜尋 input 綁 aria-activedescendant\n // (機制詳 select-menu.tsx useActiveDescendant docblock;必在 early return 前呼叫 — React #310 hook 順序)。\n const activeOptionId = useActiveDescendant(listboxId, open)\n\n React.useEffect(() => { if (!open) setSearch('') }, [open])\n\n // React #310 fix(對齊 select.tsx):以下 hooks(useMemo/useRef)必在 conditional early-return 前\n // 無條件呼叫。resolvedMode 在 edit↔非edit 切換時 hook 數量不可變動,否則 Rules of Hooks\n // violation → React #310 「rendered fewer/more hooks」crash(ReadonlyMultiSelect 用不到這些值,\n // 多算無害,對齊 select.tsx hoist pattern)。\n // 已選值的 label:先查 options,再查 suggestions(2026-09-09:從建議群組選的值不在 options 裡),最後查「看過的選項」\n // (hooks/use-known-options.ts;遠端搜尋關閉後結果被清掉、值還在 → 不能退成 id)\n const findKnown = useKnownOptions([options, suggestions], (o) => o.value)\n const items = React.useMemo(\n () => value.map(v => ({ value: v, label: (options.find(o => o.value === v) ?? suggestions?.find(o => o.value === v) ?? findKnown(v))?.label ?? v })),\n [value, options, suggestions, findKnown]\n )\n // 只選了「不限」時,欄位不渲 Tag,改走一般已填值的純文字路徑(2026-09-18 user 拍板)。\n // 互斥保證它只會單獨存在;文字用 `unrestrictedLabel`,與選單那一列**同一個來源**。\n const isUnrestrictedOnly = unrestricted && value.length === 1 && value[0] === unrestrictedValue\n // **「有沒有 Tag」只准有這一個判斷式**(2026-09-18 user 抓到的漂移根因)。\n //\n // 依據逐字在 `../Field/field-controls.spec.md:298`:\n // 「tagPadding 只在有 Tag 時才套用。Placeholder/空值狀態使用 fieldWrapper 的標準\n // `--field-px`(`px-[var(--field-px)]`)padding,確保文字與邊框有足夠間距。」\n // `tagPadding`(= `fieldTagInsetX`,`(欄高 − 2px 邊框 − Tag 高) / 2`)的理由是**讓 Tag 四邊等距**\n //(`../Tag/tag.spec.md`「圓角與間距」+ 本 spec :279,2026-09-15 df463144),跟文字沒有關係——\n // 所以欄位裡**沒有 Tag** 的時候,它本來就不該套。\n //\n // 「只選『不限』」是第三種狀態:值非空、但不渲 Tag。上面那條規則按字面就涵蓋它(沒有 Tag)。\n // 出事的原因是這件事當時有**兩個判斷式**:唯讀路徑的內距看 `hasTags`、可編輯路徑看\n // `value.length > 0`;我新增第三種狀態時只改到渲染那一側 → 可編輯的「不限」字跑到 4px(少 9px)。\n const hasTags = value.length > 0 && !isUnrestrictedOnly\n // 唯讀 / 檢視 / 停用分支只拿得到 options:把已選但不在 options 裡的項補上\n const optionsForDisplay = React.useMemo(() => {\n const missing = value.map(v => (options.some(o => o.value === v) ? undefined : (suggestions?.find(o => o.value === v) ?? findKnown(v)))).filter((o): o is ComboboxOption => !!o)\n return missing.length ? [...options, ...missing] : options\n }, [options, suggestions, value, findKnown])\n const tagAreaRef = React.useRef<HTMLDivElement>(null)\n const tagHeight = TAG_HEIGHT_PX[size]\n\n const handleRemove = (v: string) => {\n focusAfterTagRemoval(tagAreaRef.current, inputRef.current)\n onChange?.(value.filter(x => x !== v))\n }\n\n // searchIn='trigger' 時由 trigger input 過濾,不走 SelectMenu 內建搜尋\n const filteredOptions = React.useMemo(\n () => (searchable && searchIn === 'trigger' && filterOption && search\n ? options.filter(o => o.label.toLowerCase().includes(search.toLowerCase()))\n : options),\n [searchable, searchIn, filterOption, search, options]\n )\n\n // 轉換 ComboboxOption → SelectMenuOption\n // 2026-05-10 post-Issue-4 follow-up:forward 全 SelectMenuOption surface(avatar / description /\n // disabled / icon / group)— 修先前 PeoplePicker multi-mode dropdown 漏 avatar drift bug。\n const menuOptions: SelectMenuOption[] = React.useMemo(\n () => filteredOptions.map(toMenuOption),\n [filteredOptions]\n )\n const menuSuggestions: SelectMenuOption[] | undefined = React.useMemo(\n () => suggestions?.map(toMenuOption),\n [suggestions]\n )\n\n if (resolvedMode !== 'edit') {\n return <ReadonlyMultiSelect mode={resolvedMode} variant={variant} width={width} size={size} options={optionsForDisplay} value={value} wrap={wrap} className={className} showDisplayEndIcon={showDisplayEndIcon} unrestricted={unrestricted} unrestrictedLabel={unrestrictedLabel} unrestrictedValue={unrestrictedValue} />\n }\n\n // 值處理中的轉圈(Field 家族 loading,2026-09-09 user 拍板收窄):觸發點右側、箭頭左邊(react-select / Atlassian 順序:清除 → 轉圈 → 箭頭),\n // 跟 Input 的 endAction 槽同義 —— 與選單開關、選項多寡無關;選項載入的指示在選單內(optionsLoading → SelectMenu)\n const chevronEl = (\n <>\n {loading && <CircularProgress size={iconSize} className=\"shrink-0\" />}\n <ChevronDown size={iconSize} className={cn('shrink-0 text-fg-muted transition-transform motion-reduce:duration-0', open && 'rotate-180')} aria-hidden />\n </>\n )\n\n const trigger = (\n <div\n ref={__triggerRef}\n id={fieldCtx?.id}\n role=\"combobox\" aria-expanded={open} aria-controls={listboxId} tabIndex={0}\n // 2026-09-25 待辦總帳 B11「多選下拉(有全選)行為不變、只改宣告」:宣告的彈出型別 = 焦點實際去哪。\n // 搜尋框在觸發欄位內(searchIn='trigger')→ 焦點留在欄位、清單用 aria-activedescendant = listbox;\n // 其餘(浮層內搜尋框 / 不可打字)焦點進到浮層、Tab 在面板裡繞圈 = dialog。與下方 onOpenAutoFocus 同一個條件。\n // W3C:popup 不是 listbox 時 aria-haspopup 要寫出型別(https://github.com/w3c/aria-practices/blob/3f094fde1c81b25dfa69162563bf28d093f854d4/content/patterns/combobox/combobox-pattern.html#L410-L411),\n // dialog 型「DOM focus moves into the dialog」(同檔 #L395)\n aria-haspopup={searchIn === 'trigger' ? 'listbox' : 'dialog'}\n aria-label={ariaLabel}\n // a11y(2026-07-14 dim-10):div-based role=combobox 的 <label for> 無效,接 FieldLabel labelId\n // (field-context.ts labelId jsDoc);consumer aria-label 優先 — 與 sibling select.tsx:705 同款 guard。\n aria-labelledby={ariaLabel ? undefined : fieldCtx?.labelId}\n aria-invalid={error || undefined}\n // 值處理中(Field 家族 loading):跟 Input wrapper 同樣標 aria-busy(field-controls.spec.md「Loading state」)\n aria-busy={loading || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={fieldCtx?.descriptionId}\n aria-errormessage={error ? fieldCtx?.errorId : undefined}\n // 2026-09-07:本元件是 Field 家族的「單一狀態控制項」——依 focus-canonical 規則二第三列,\n // 滑鼠與鍵盤**共用同一套 focus 樣式**,而 Field 的那一套就是邊框轉 primary\n // (field-wrapper.tsx `focus-within:!border-primary`)。所以這裡要抑制全域外描邊,\n // 跟 DatePicker(:608)/ TimePicker(:378)一致 —— 否則同一顆控件會有兩個焦點指示。\n // **本行不是新增抑制,是補上一直漏掉的那個**:遷移前這顆沒寫 outline-none,\n // 於是全域外描邊一直畫在它上面,是全家族唯一的例外(user 2026-09-07 抓到)。\n // @focus-suppress C — 這一行的元素**就是**那圈欄位外框;承擔者:自己(fieldWrapperStyles 的 focus-within:!border-primary,field-wrapper.tsx:57)\n className={cn(fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }), 'focus-visible:outline-none', hasTags && tagPadding[size], 'relative cursor-pointer',\n wrap && cn('items-start', tagPaddingY[size]),\n // 2026-05-06 v13.3 SSOT retire:per-control `open && 'border-primary'` 移除。Field default\n // 統一處理 — open=灰深(data-state)/ focus=藍;2026-07-04 Q1:error 亦收進 error variant。\n className)}\n style={{ paddingRight: 'var(--field-px)', ...(wrap ? { height: 'auto' } : undefined) }}\n data-field-mode=\"edit\" data-error={error ? '' : undefined}\n // WAI-ARIA APG combobox 鍵盤開啟語意 — 對齊 sibling Select(select.tsx:593-598)。\n // <div role=combobox> 不像 native <button> 自動 synthesize Enter/Space click,故顯式補:\n // Enter/Space → 開(searchable 時不攔,讓 inline search input 自行處理打字);\n // Escape → 關;ArrowDown → 開(APG required combobox 展開鍵,僅在 closed 時攔,\n // open 後不 preventDefault 讓方向鍵自由流向選單導覽)。\n // 純 additive:此 trigger 原無 onKeyDown,不覆寫既有 handler;open 邏輯仍走 setOpen SSOT。\n onKeyDown={(e) => {\n // a11y(2026-07-14 dim-10):Enter/Space 來自 descendant 互動元素(Tag 移除 / clear 按鈕)\n // 時直接放行 —— 否則下方 preventDefault 會取消 native button activation(鍵盤永遠按不動\n // 按鈕)。guard 限 Enter/Space + button 類:search input 的 Enter 仍走 cmdk 選項選取\n // (forwardKeyToListbox),Escape / 方向鍵仍走 combobox 導覽。\n if (\n (e.key === 'Enter' || e.key === ' ') &&\n e.target !== e.currentTarget &&\n (e.target as HTMLElement).closest?.('button, a, [role=\"button\"]')\n ) return\n // 2026-07-05 D4 P0:open 後 ArrowUp/Down/Enter 轉送 cmdk root(select-menu.tsx forwardKeyToListbox)\n if (open && forwardKeyToListbox(listboxId, e)) return\n if (e.key === 'Enter' || e.key === ' ') {\n // 2026-06-11 P0 a11y(R2,同 select.tsx 修):Combobox 恆 searchable → 原 `!searchable`\n // guard 使 Enter/Space 永遠開不了(僅 ArrowDown 可)。正確 guard = !open。\n if (!open) { e.preventDefault(); setOpen(true) }\n }\n if (e.key === 'ArrowDown' && !open) { e.preventDefault(); setOpen(true) }\n if (e.key === 'Escape') setOpen(false)\n }}>\n {/* 2026-05-18 #6A Round 1 Step 2/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:648):\n CustomCombobox edit non-wrap tagArea 對齊 L293 view + L451 readonly + L518 native edit 已 ship 的 overflow-hidden fix。\n 原 overflow-visible 讓 tag 越界蓋 chevron / +N indicator(user 圖三)。M10 propagation 完整 4-path align。 */}\n {/* `isolate`:標籤 wrapper 的疊放順序(`--tag-stack-z`,頭像堆疊用)只在這一列裡比,不跟頁面上其他層比 ——\n 與 avatar.tsx AVATAR_STACK_CLASS(檢視態的堆疊列)同一件事,編輯態這裡就是那一列(2026-09-26 補,M17) */}\n <div ref={tagAreaRef} className={cn('flex-1 min-w-0 flex items-center relative isolate', nakedCellRowModeAlign, wrap ? 'flex-wrap' : tagRowOverflowClass)} style={{ gap: tagAreaGap, paddingLeft: tagAreaPaddingLeftPx }}>\n {/* 有 Tag / 只選「不限」(純文字,同 placeholder 的盒與字級,只是不套灰)/ 空(placeholder)。\n 三選一的第一個條件就是上面那個 `hasTags`,與欄位內距**同一個判斷式**。*/}\n {hasTags ? (\n <OverflowTagList containerRef={tagAreaRef} items={items} size={size} wrap={wrap}\n tagWrapperClassName={tagWrapperClassName}\n overflowWrapperClassName={overflowWrapperClassName}\n gap={tagAreaGap}\n overflowShape={overflowShape}\n visibleCountOverride={visibleCountOverride}\n renderTag={(item) => (\n tagRenderer\n ? tagRenderer(item, () => handleRemove(item.value))\n : <Tag size={size} className=\"shrink-0 relative z-10\"\n onRemove={() => handleRemove(item.value)}>{item.label}</Tag>\n )}\n renderHiddenTag={renderHiddenTag}\n onRemove={handleRemove}\n trailing={searchable && searchIn === 'trigger' ? (\n <input ref={inputRef} value={search} onChange={(e) => setSearch(e.target.value)}\n // 2026-05-15 Drift A fix(per user verbatim SSOT clarification「未選 → placeholder 顯示請選擇之類」):\n // items.length === 0(empty selection)→ 用 `placeholder` trigger empty prop(「請選擇…」),\n // **不**用 `searchPlaceholder`(「搜尋…」);後者僅在 panel-top search input 場景才合理。\n // items.length > 0(已選)→ no placeholder,純 cursor(對齊 Combobox empty cursor SSOT)。\n // SSOT 對齊 select.tsx:185 `placeholder={selectedLabel || placeholder || '搜尋…'}`\n // empty-state fallback to trigger placeholder canonical。\n placeholder={items.length === 0 ? placeholder : ''} onClick={(e) => { e.stopPropagation(); setOpen(true) }}\n aria-label={searchAriaLabel}\n // a11y(2026-07-05 D4):cmdk active item id(useActiveDescendant)→ SR 播報方向鍵導覽中的 option\n aria-activedescendant={activeOptionId}\n // @focus-suppress B — B Field 家族輸入控件;承擔者:裸 input;指示器是 wrapper 邊框\n className=\"flex-1 min-w-[60px] bg-transparent outline-none text-body leading-compact relative z-10\" />\n ) : undefined} />\n ) : isUnrestrictedOnly ? (\n /* 只選「不限」→ 一般已填值的純文字:與下面 placeholder **同一顆 span 的盒**,\n 唯一差別是不套那層灰(對齊單選欄位 select.tsx:352-353)。\n 左緣靠上面 `hasTags` 讓欄位退回 `--field-px`,不是在這裡另外補位移。 */\n <span className={cn('flex-1 min-w-0 truncate', fieldDisplayTextClass(size))}>{unrestrictedLabel}</span>\n ) : (\n /* 2026-05-12 Stream C Issue 3 fix(codex Q3 Cluster C):placeholder span 必 flex-1 min-w-0\n truncate,narrow container 時單行省略(對齊 Combobox text-tag truncate canonical)。\n 原 hardcode wraps in narrow trigger → user 抓「placeholder 文字 wrap multi-line」。 */\n <span className=\"flex-1 min-w-0 truncate text-fg-muted\">{placeholder ?? emptyPlaceholder}</span>\n )}\n </div>\n <ItemSuffix className={cn('relative z-10 pointer-events-none', wrap && 'self-start')}\n style={wrap ? { height: tagHeight } : undefined}>\n {showClear && (\n <span className=\"pointer-events-auto\">\n <ItemInlineAction\n size={size ?? 'md'}\n action={{\n icon: X,\n label: '清除全部', // i18n-allow: DS default inline-action label\n onClick: (e) => { e?.stopPropagation(); onChange?.([]) },\n }}\n />\n </span>\n )}\n {chevronEl}\n </ItemSuffix>\n </div>\n )\n\n return (\n <SelectMenu\n optionsLoading={optionsLoading}\n filterOption={filterOption}\n // 搜尋在觸發點時把搜尋字交給 SelectMenu(受控;對齊 select.tsx):遠端模式要靠它分辨「關鍵字空 → 建議 / 提示」與\n // 「抓資料中 → 清舊清單」,creatable 的建立列也依它顯隱(2026-09-09 之前 trigger 模式沒傳,建立列永遠不出現)。\n search={searchIn === 'trigger' ? search : undefined}\n onSearchChange={searchIn === 'menu' ? onSearchChange : setSearch}\n suggestions={menuSuggestions}\n suggestionsLabel={suggestionsLabel}\n searchHintText={searchHintText}\n emptyText={emptyText}\n selectAllLabel={selectAllLabel}\n deselectAllLabel={deselectAllLabel}\n // 「不限」轉發(2026-09-18):Combobox 是恆多選的消費者,開關與文字都由產品端決定。\n unrestricted={unrestricted}\n unrestrictedLabel={unrestrictedLabel}\n unrestrictedValue={unrestrictedValue}\n options={menuOptions}\n value={value}\n onValueChange={onChange as (value: string | string[]) => void}\n multiple\n creatable={creatable}\n onCreate={onCreate}\n createLabel={createLabel}\n searchable={searchable && searchIn === 'menu'}\n searchPlaceholder={searchPlaceholder}\n searchAriaLabel={searchAriaLabel}\n size={size}\n open={open}\n onOpenChange={(o) => { setOpen(o); onOpenChange?.(o) }}\n // 2026-05-12 Q3 fix(user 抓「inline-searchable 開浮層應出現 cursor」)— 跟 Select line 550\n // 同 SSOT pattern:preventDefault Radix default focus + 顯式 focus inline input → 開時\n // cursor 直接 visible,user 知道可 inline search。\n onOpenAutoFocus={searchIn === 'trigger' ? (e) => { e.preventDefault(); inputRef.current?.focus() } : undefined}\n contentId={listboxId}\n >\n {trigger}\n </SelectMenu>\n )\n}\n\n// ── Public component ────────────────────────────────────────────────────────\n\nconst Combobox = React.forwardRef<HTMLDivElement, ComboboxProps>(\n ({ size: sizeProp, ...props }, ref) => {\n // B 組 cascade fix:public wrapper 一處 resolve size(prop>Field>surface>md)後 forward 給內層,\n // 讓 <Field size> / DataTable cell surface-size 對 Combobox 生效(內層默認 'md' 被此顯式 size 覆蓋)。\n const size = useResolvedFieldSize(sizeProp)\n // 2026-05-16 真 root cause fix:之前用 `_ref` drop ref。修為 forward 給 internal\n // `__triggerRef`,讓 PeoplePicker stack 透過 ref 量 trigger DOM(visibleCountOverride\n // 才生效)。對齊 React forwardRef public-API canonical(MUI Autocomplete / Radix\n // Popover.Trigger 共識)+ codex M31 Step 5 比稿 verdict + DS-wide ref-drop iceberg audit。\n // 2026-09-18 user 拍板:**手機與桌機同一套**,不為裝置分流。\n // 「我完全不想要為了手機客製化元件,我希望就是 SSOT,直接用桌機版的,什麼都完全不動,\n // 就只是讓手機跟桌機同步而已」。\n // 原本觸控會走一個隱藏原生 `<select>` 的 NativeCombobox。移除的理由是**證據**不是偏好:\n // (a) 原生 `<select multiple>` 在任何裝置上都不是下拉(加了 multiple 瀏覽器改渲染成常駐\n // 清單、沒有展開收合),所以那條路徑只能用單選 select「一次加一個」繞,先天做不到多選選單;\n // (b) 它靜默丟棄 20 個 prop(沒有 rest-spread、TypeScript 不報錯、零 warning),\n // 搜尋 / 全選 / 分組 / 遠端搜尋 / 可建立 / 不限 在觸控上全部無效,而 36 個呼叫點正在傳;\n // (c) 它宣稱的 a11y 好處沒有兌現 —— 那顆 `<select>` 的 value 恆為空字串、也沒有 multiple,\n // 輔助科技從被命名的控件上讀不到已選了什麼;\n // (d) 世界級沒有一家為手機換一套多選 UI(Base UI 明文「同一元件 + multiple,觸控只調定位」/\n // Apple HIG pop-up button「iOS 無額外考量」/ Polaris / Atlassian / Radix / react-select\n // 文件對裝置零分支)。\n // 量過:390px 寬下浮層 356px、不溢出、高度放得下;列高 32px 高於 DS 自己的 24px 地板\n // (owner = tokens/uiSize/uiSize.spec.md「元件高度地板」:169)。**刻意不為觸控加大尺寸** ——\n // 那會變成第二套規格,正是這次要消滅的東西。**不拿觸控尺寸建議當依據**:先前這裡寫的\n // 「過 WCAG 2.2 AA(24×24)」已於 2026-09-24 撤回(本 DS 以滑鼠精度為前提,見\n // ds-canonical/references/hit-area-canonical.md「本 DS 不採納觸控尺寸建議」);\n // 同時把 24 門檻的出處從 overlay-surface.spec.md:431 改指真正的 owner(上一行)。\n return <CustomCombobox {...props} size={size} __triggerRef={ref} />\n }\n)\nCombobox.displayName = 'Combobox'\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 comboboxMeta = {\n component: 'Combobox',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n // 'active' 移除 — trigger 走 Field chrome(field-wrapper 無按壓態)、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: ['bg-disabled', 'bg-transparent'],\n fg: ['text-fg-disabled', 'text-fg-muted'],\n ring: [],\n },\n} as const\n\nexport { Combobox }\n"],"names":["_a"],"mappings":"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"}
1
+ {"version":3,"file":"combobox.js","sources":["../../../src/components/Combobox/combobox.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// @renderer-symmetry-allow: ComboboxTagStack(view path)接 consumer tagRenderer 是 Stream C 下 cycle 工作 — 2026-05-12 先 ship Issues 2/3/4 surgical fixes(placeholder vocabulary + cell surface metrics + placeholder truncate),tagRenderer view-path unify deferred per field-controls.spec.md 共享 contract a。當前 multi=1 顯示已透過 PeoplePicker tagRenderer(people-picker.tsx:426-444)PersonDisplay SSOT 對齊;其他 Combobox consumer 走 default `<Tag>` 純文字 backward-compat。\n// code-quality-allow: file-size — Combobox 含 CustomCombobox/useOverflowCount/OverflowTagList/ComboboxTagStack 4 子元件 + 共用 helpers,split-into-files 會破壞 measurement closures + 重複 type definitions。\nimport * as React from 'react'\nimport { useKnownOptions } from '@/design-system/hooks/use-known-options'\nimport { X, ChevronDown } from 'lucide-react'\nimport { CircularProgress } from '@/design-system/components/CircularProgress/circular-progress'\nimport { cn } from '@/lib/utils'\nimport type { FieldMode, FieldVariant, FieldVariantInternal, FieldWidth } from '@/design-system/components/Field/field-types'\nimport { fieldWrapperStyles, nakedCellRowModeAlign, fieldDisplayTextClass, fieldTagInsetX, fieldTagInsetY } from '@/design-system/components/Field/field-wrapper'\nimport { useFieldContext, useResolvedFieldSize, useResolvedFieldDisabled, useResolvedFieldMode, useResolvedFieldVariant, useResolvedFieldInvalid, useFieldEmptyDisplay, fieldEmptyColorClass } from '@/design-system/components/Field/field-context'\nimport { TAG_HEIGHT_PX, Tag } from '@/design-system/components/Tag/tag'\nimport { ItemInlineAction, ItemSuffix } from '@/design-system/patterns/element-anatomy/item-anatomy'\nimport { OverflowIndicator } from '@/design-system/components/OverflowIndicator/overflow-indicator'\nimport { SelectMenu, forwardKeyToListbox, useActiveDescendant, type SelectMenuOption } from '@/design-system/components/SelectMenu/select-menu'\nimport { ICON_SIZE } from '@/design-system/tokens/uiSize/icon-size'\n\n// ── constants ───────────────────────────────────────────────────────────────\n\nconst GAP = 4\n\n// 非-wrap tag 列 clip SSOT(4-path 共用:OverflowTagList base / readonly / native edit / custom edit):\n// 2026-05-18 F2 以 overflow-hidden 修「窄容器 tags 水平越界蓋 chevron / +N」,但雙軸 hidden 副作用\n// 是垂直同裁 — PeoplePicker stack hover 的 AvatarDismissOverlay(`-top-px` + 2px ring,\n// person-display.tsx v15.15,早於 F2)上緣被切(user 2026-08-05 抓「曾經沒有這問題」= F2 前確實沒有)。\n// 雙贏 = overflow-x-clip:水平維持 clip(F2 bug 不回歸;`clip` 不建 scroll container),垂直 visible\n// (overlay / avatar ring 完整)。**不可**改 overflow-x-hidden:單軸 hidden 令另一軸 visible 計算成\n// auto → 生 scroll container,垂直反而可捲。\nconst tagRowOverflowClass = 'overflow-x-clip'\n\n// Tag 四邊內距的單一來源在 field-wrapper.tsx(`fieldTagInsetX` / `fieldTagInsetY`),Select 共用;理由與公式見該處。\nconst tagPadding = fieldTagInsetX\nconst tagPaddingY = fieldTagInsetY\n\n/**\n * Combobox option schema(2026-05-10 post-Issue-4 audit unify):**explicit extends\n * SelectMenuOption(primitive SSOT)** — 避免重蹈先前 PeoplePicker 改壞的 wrapper schema drift。\n *\n * Why `extends SelectMenuOption`(per user 「全盤檢查避免下次又改壞或是偏移」要求):\n * 原 `interface ComboboxOption { value: string; label: string }` 是 weak schema,跟 Select 的\n * `ComboboxOption`(同名)雙重宣告但欄位不同 → TypeScript 不抓(同名 interface 在不同 file\n * 各 export,consumer import 到哪個版本看 import path)→ schema drift。\n * PeoplePicker multi-mode 走 Combobox 路徑,dropdown menu rows lose avatar / description —\n * user 看到「single mode 有 avatar / multi mode 沒 avatar」inconsistency。\n *\n * Fix(post-Issue-4 follow-up):extend SelectMenuOption → 全 primitive surface 自動繼承。\n * Wrapper-only field 都沒有 → empty body interface(future 加 wrapper-only field 加在此處)。\n * `menuOptions` mapping(below)forward 全 SelectMenuOption surface。\n *\n * 對齊 Polaris ChoiceList / Material Autocomplete / Carbon Dropdown 的 wrapper-vs-primitive\n * schema-extension idiom。Hook `check_wrapper_primitive_schema_drift.sh`(M30 機械強制)。\n */\nexport interface ComboboxOption extends SelectMenuOption {\n // (no wrapper-only fields yet — kept for future扩 + same-name SSOT cross-wrapper)\n}\n\n// ── useOverflowCount (unchanged) ────────────────────────────────────────────\n\nfunction useOverflowCount(\n containerRef: React.RefObject<HTMLDivElement | null>,\n tagEls: React.MutableRefObject<(HTMLDivElement | null)[]>,\n overflowEl: React.RefObject<HTMLDivElement | null>,\n totalCount: number,\n enabled: boolean,\n gap: number = GAP, // (2026-05-07 v15.13)stack avatar 模式傳 0\n visibleCountOverride?: number, // 2026-05-15 Bug 3 fix:override DOM measurement(PeoplePicker stack 走 formula primitive)\n): { visibleCount: number; ready: boolean } {\n const [state, setState] = React.useState({ visibleCount: totalCount, ready: !enabled })\n // 2026-05-18 Round 6 fix(per Codex M31 Round 6 H7 verdict + Step 5 共識):\n // `ofEl.offsetWidth` 在 expanded state(visibleCount === totalCount → overflow=0 →\n // `OverflowIndicator` count≤0 早退 `return null` → ofEl wrapper empty)= 0,fallback 60;\n // 在 collapsed state(+N rendered)= 真實寬(~28-32px)。同 `available` 在兩 state 給\n // 不同 verdict → 臨界值區 `max(B+g+Q, B+g+O) ≤ available < B+g+F` 振盪。Cache last\n // non-zero measurement → measurement state-independent → oscillation 收斂。\n // 初始 60 沿用舊 fallback(無 measure 史 ok-ish over-estimate)。\n const lastOverflowWRef = React.useRef<number>(60)\n\n // 2026-05-16 RACE FIX(user 抓「逐個 click 滿 6」vs「取消全選→再全選」same length 不同 visible):\n //\n // 原 useEffect + 雙 rAF 沒 capture rAF IDs → cleanup 不 cancel pending rAFs。\n // Path B(length=6→0→6):length=0 時 override=undefined 走 internal calc 排 rAF,\n // 然後 length=6 + override=N → deps change → cleanup 跑(disconnect ResizeObserver 但\n // 不 cancel rAF)→ 新 useEffect 跑 override 寫 el.hidden → 舊 rAF 仍 fire → 跑舊\n // internal calc → 覆寫 el.hidden 用 internal measurement(不一致於 override formula)。\n //\n // Fix:\n // 1. useEffect → useLayoutEffect:tighter timing,measurement 在 paint 前 sync\n // 2. Capture rAF IDs,cancel on cleanup\n // 3. scheduleCalc 函式包裝,cancel in-flight rAF 才排新一輪(避免 ResizeObserver\n // re-fire 堆 rAF)\n //\n // 對齊 2026-05-14 I3 fix comment「user 抓『全選 vs 逐個勾 result 不同』」 — 當時 fix\n // 只加 double-rAF 但漏 cancel,本次補完 race close。\n // 2026-05-18 Round 5 fix(per visual test probe):useLayoutEffect 在 nested component 場景\n // 會在 parent ref attach 前 fire(child layout effect 先於 parent ref attach)→ containerRef.current\n // null → early return → calc never runs → setProperty never called → CSS var unset → tag overflow。\n // 改 useEffect:fires AFTER paint,所有 refs 都 attach。double-rAF guard ensures layout done。\n // Trade-off:可能 1-2 frame flicker,但 functional setState guard + paint target measurement 已 cover。\n React.useEffect(() => {\n /**\n * 這次量測可不可信:容器與所有標籤都量到非零寬度才算數。\n *\n * 雙 rAF 的 fallback(2026-05-14 I3)當初是為了「批次渲染場景 tag 還 0-width」——\n * 那個條件在同步這一趟就量得出來,不必無條件再跑一次。實測(2026-09-10,DataTable\n * roadmap 全功能範例、40 步滾輪):每個掛載固定跑兩趟 calc,一次手勢 180 趟、\n * 1080 次幾何讀取,其中第二趟幾乎總是得到相同結果。改成「不可信才補跑」。\n */\n let trustworthy = false\n if (!enabled || totalCount === 0) { setState({ visibleCount: totalCount, ready: true }); return }\n if (visibleCountOverride !== undefined) {\n for (let i = 0; i < tagEls.current.length; i++) {\n const el = tagEls.current[i]\n if (el) el.hidden = i >= visibleCountOverride\n }\n const ofEl = overflowEl.current\n if (ofEl) ofEl.hidden = visibleCountOverride >= totalCount\n setState({ visibleCount: visibleCountOverride, ready: true }); return\n }\n // totalCount=1 fast path:single-tag case 直接 visible 不跑 measurement loop。\n // (歷史:c90d029 曾移除此 bypass,後復原 — 移除會造成 narrow cell 1-selected 跑 unbounded Tag\n // measurement 後 visibleCount=0 → 顯 +1 indicator 而非 single tag,違反 PeoplePicker length===1\n // 走 PersonDisplay SSOT。)\n // 2026-05-16 Round 5 codex edge case fix:explicit unhide DOM nodes(對齊 override branch)。\n // 原 fast-path 只設 React state 不動 `el.hidden`,如 wrappers 之前 hidden 殘留(從 length>1 降到 1)\n // 可能視覺漏顯。Override branch L78-80 同 contract 對齊。\n if (totalCount === 1) {\n for (let i = 0; i < tagEls.current.length; i++) {\n const el = tagEls.current[i]\n if (el) el.hidden = i >= 1\n }\n const ofEl = overflowEl.current\n if (ofEl) ofEl.hidden = true\n trustworthy = true\n setState({ visibleCount: 1, ready: true }); return\n }\n const container = containerRef.current\n if (!container) return\n\n const calc = () => {\n trustworthy = false\n const cs = getComputedStyle(container)\n const available = container.clientWidth - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0)\n // 2026-05-18 Round 5 fix(per user 拍板「那就開始做」+ Codex M31 Round 5 verdict):\n // inject available 成 CSS var,Tag 用 explicit length 而非 cyclic percentage(避 CSS Sizing 3\n // §5.2.1 cyclic percentage 退化問題)。\n container.style.setProperty('--combobox-tag-area-inline-size', `${available}px`)\n for (const el of tagEls.current) if (el) el.hidden = false\n const ofEl = overflowEl.current\n if (ofEl) ofEl.hidden = false\n // 2026-05-18 Round 6 fix:cache last non-zero ofEl width 破 expanded/collapsed state\n // 量測二態(expanded → ofEl 空 offsetWidth=0 / collapsed → real ~28-32px)。沒 cache\n // 之前同 `available` 在兩 state 給不同 verdict → 永動。詳本 hook 頂部 ref 註解。\n const measuredOverflowW = ofEl?.offsetWidth || 0\n if (measuredOverflowW > 0) lastOverflowWRef.current = measuredOverflowW\n const overflowW = lastOverflowWRef.current\n // **#3 fix(2026-05-04)**:width-check 先於 count++,並處理 i=0 邊界(1 tag 自身就太寬 → 全 hidden 顯 +N)\n // 之前 bug:greedy `count++` 永遠至少 = 1,1-tag-too-wide case 視覺呈半個 tag clipped + +N(錯)\n // 修後:1 tag 太寬時 count = 0,全 N tags 走 +N 顯 indicator\n // 2026-05-18 Round 5:量 paint target `[data-tag-root]` 而非 wrapper(per codex Round 5 verdict)。\n // wrapper basis:auto 自由 grow,offsetWidth ≠ Tag actual paint width。\n let used = 0, count = 0\n let anyZero = available <= 0\n for (let i = 0; i < totalCount; i++) {\n const el = tagEls.current[i]\n if (!el) continue\n const tagRoot = el.querySelector('[data-tag-root]') as HTMLElement | null\n const w = tagRoot ? tagRoot.getBoundingClientRect().width : el.offsetWidth\n if (w <= 0) anyZero = true\n const next = used + (count > 0 ? gap : 0) + w\n const remaining = totalCount - count - 1\n // width check FIRST(無 `count > 0` 短路):任何超寬都 break,包含 i=0 case\n if (remaining > 0 && next + gap + overflowW > available) break\n if (remaining === 0 && next > available) break\n used = next; count++\n }\n for (let i = 0; i < tagEls.current.length; i++) { const el = tagEls.current[i]; if (el) el.hidden = i >= count }\n if (ofEl) ofEl.hidden = count >= totalCount\n // 2026-05-18 Round 5 last guard(per Codex Round 5 verdict):safety net 防 measurement drift\n // (sub-pixel / rounding)。verify last visible tag rect.right ≤ container right,超出遞減 count。\n const containerRect = container.getBoundingClientRect()\n while (count > 0) {\n const lastEl = tagEls.current[count - 1]\n const tagRoot = lastEl?.querySelector('[data-tag-root]') as HTMLElement | null\n if (!tagRoot) break\n const tagRect = tagRoot.getBoundingClientRect()\n if (tagRect.right <= containerRect.right + 0.5) break\n count--\n if (lastEl) lastEl.hidden = true\n }\n if (ofEl) ofEl.hidden = count >= totalCount\n // 2026-09-08:標籤列是 `flex-1 min-w-0`,容器夠窄時它會被壓到 clientWidth = 0,\n // 而「+N」本身**在裁切容器內**,於是連它一起被裁掉 —— 使用者看不到「還有幾個」,\n // 那正是空間不足時唯一還帶資訊的元素。(實測 DataTable 篩選面板:標籤區寬度隨容器\n // 180 → 148 → 68 → 0;420px 時「+3」超出裁切祖先 28.4px,完全不可見。)\n // 給容器一個等於「+N」寬度的下限:它是最後才被放棄的東西。\n // 條件用 totalCount 而不是 `!ofEl.hidden`,是為了避免震盪 —— 後者會讓\n // 「設下限 → 空間變夠 → 一個 tag 塞得下 → +N 收起 → 下限撤掉 → 空間又不夠」來回跑。\n container.style.minInlineSize = totalCount > 0 ? `${overflowW}px` : ''\n // 2026-05-18 A' fix functional setState value-equal guard(per Codex Round 3 verdict):\n // effect 內 calc 直跑 + ResizeObserver re-fire 同時跑 → 若每次都 new object setState\n // 觸發 re-render 即使值沒變,可能 cascade。回 prev 不更新 = avoid 抖動。\n trustworthy = !anyZero\n setState(prev => (prev.visibleCount === count && prev.ready) ? prev : { visibleCount: count, ready: true })\n }\n\n // 2026-05-14 I3 fix(per codex M31 verdict + user 抓「全選 vs 逐個勾 result 不同」):\n // double-rAF ensures layout 完成 before measurement(原 single rAF 在 batched render\n // 場景 tag 還 0-width)。Plus observe per-item ResizeObserver — 任何 tag width 變動\n // 都 trigger recalc(deterministic regardless of commit order)。\n //\n // 2026-05-16 Race close:capture rAF IDs + cancel on cleanup(原版 race I3 沒 close\n // 完;user 抓 path A 逐個 click vs path B 取消全選再全選 same length 不同 visible)。\n // 2026-05-18 A' fix(per Codex Round 3 共識,user 拍板「執行」)— effect fire 時 calc() 直跑\n // 完成 `el.hidden` 設定 + functional setState guard(value-equal 不更新 = 避免 ResizeObserver\n // 抖動 cascade rerender)。double-rAF 為 fallback path(ResizeObserver / async update path)。\n // 解 user verbatim「tag 過長 / 過多會先全顯再變 +N 閃動」root cause(per codex Round 3 cite\n // 「render 沒設 hidden + calc imperative 寫 DOM」)。\n // 註:Round 3 原以 useLayoutEffect sync calc(paint 前設 hidden)實作;2026-05-18 Round 5\n // 已改 React.useEffect after-paint(nested 場景 parent ref attach 時序,詳上方 Round 5 註解)。\n calc()\n let rafId1 = 0, rafId2 = 0\n const scheduleCalc = () => {\n if (rafId1) { cancelAnimationFrame(rafId1); rafId1 = 0 }\n if (rafId2) { cancelAnimationFrame(rafId2); rafId2 = 0 }\n rafId1 = requestAnimationFrame(() => {\n rafId1 = 0\n rafId2 = requestAnimationFrame(() => {\n rafId2 = 0\n calc()\n })\n })\n }\n // 同步那趟量到 0 寬(批次渲染 / 尚未版面配置)才補跑雙 rAF;量得準就不再跑第二趟。\n if (!trustworthy) scheduleCalc()\n /**\n * ResizeObserver 在 `observe()` 之後一定會先送一發「初始觀測」,那一發回報的尺寸\n * 就是上面同步 calc 剛量過的同一個版面 —— 拿它再跑一次是純白工。每個 observer\n * 各自吞掉自己的第一發,之後的每一發都是真的尺寸變了,照常重算。\n */\n const skipFirst = (fn: () => void) => { let primed = false; return () => { if (!primed) { primed = true; return } fn() } }\n const containerObs = new ResizeObserver(skipFirst(scheduleCalc))\n containerObs.observe(container)\n const itemObs = new ResizeObserver(skipFirst(scheduleCalc))\n for (const el of tagEls.current) {\n if (el) itemObs.observe(el)\n }\n return () => {\n if (rafId1) cancelAnimationFrame(rafId1)\n if (rafId2) cancelAnimationFrame(rafId2)\n containerObs.disconnect()\n itemObs.disconnect()\n }\n // 2026-05-15 Bug 3 fix:visibleCountOverride 入 deps,override 改 trigger recalc。\n // 2026-09-29 exhaustive-deps:tagEls / overflowEl 是呼叫端 useRef 出來的 ref 物件(唯一呼叫端 OverflowTagList),\n // 身分整個生命週期不變,列進來不會多跑 —— 跟 containerRef 同一種東西、同一種待遇;規則看不穿函式參數才要求明列。\n }, [containerRef, tagEls, overflowEl, totalCount, enabled, gap, visibleCountOverride])\n\n return state\n}\n\n// ── OverflowTagList (unchanged) ──────────────────────────────────────────────\n\ntype ComboboxOverflowShape = 'circle' | 'tag'\n\n// 2026-05-16 fix:overflow chip wrapper 必能跟 tag wrapper 套同 overlap class\n// (per user 物理模型「avatar 和 +N 都是同尺寸圓形 + 同 step」)。原 chip wrapper\n// 只有 `shrink-0`,在 stack 模式 -ml-0.5 不 apply → chip 不 overlap → 視覺多 22px\n// 額外空間 → length=4→4 / length=5→2+3 saw bug 物理根因。\n// PeoplePicker stack mode pass `'-ml-0.5 first:ml-0 relative inline-flex'` 對齊。\ninterface OverflowTagListProps {\n containerRef: React.RefObject<HTMLDivElement | null>\n items: { value: string; label: string }[]\n size: 'sm' | 'md' | 'lg'\n wrap: boolean\n renderTag: (item: { value: string; label: string }, index: number) => React.ReactNode\n /**\n * 2026-05-14 I4 fix(per codex M31 verdict + user 抓「display overflow 有 avatar / edit 無」):\n * Optional renderer for hidden items in `+N` overflow popover。Default fallback = `<Tag>{label}</Tag>`\n * (純文字 chip,backward-compat)。Consumer pass 此 prop 讓 hidden items 顯示同 avatar 視覺\n * (對齊 view path MultiPersonDisplay overflow popover Tag avatar SSOT)。\n */\n renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode\n onRemove?: (value: string) => void\n trailing?: React.ReactNode\n /** Tag area gap in px(default 4)。Stack mode 傳 0 讓 negative margin 生效 */\n gap?: number\n /**\n * Optional class merged into each tag's outer measurement wrapper `<div className=\"shrink-0\">`.\n * (2026-05-07 v15.13)為 PeoplePicker stack mode 提供 hook point — 讓 stack avatar 走\n * `-ml-0.5 first:ml-0 relative inline-flex group/avatar` 達成 overlap + dismiss group selector,\n * 同時保留 `useOverflowCount` 量測 wrapper(必要,不可移除)。\n *\n * **Caveat(Q2 known tradeoff)**:`-ml-0.5` 負 margin 不改 each wrapper 的 `offsetWidth` →\n * `useOverflowCount` 累加按完整寬計算 → 視覺實際塞得進的 tag 數 > 量測判定能塞的數 →\n * **+N indicator 偏保守**(視覺還有空間但已顯 `+N`)。當前 v1 接受此 tradeoff;若窄 trigger\n * + 多人場景明顯不對,future 可加 `overlapPx` prop 讓量測補償。\n */\n tagWrapperClassName?: string\n /** 2026-05-16 fix:overflow chip 圓形 wrapper 套此 class(stack 模式套 `-ml-0.5` overlap),\n * 讓 chip 跟 avatar 同 step 物理 — 避免「chip 多 24px 額外空間」造成 saw transition。*/\n overflowWrapperClassName?: string\n /**\n * Overflow indicator(+N)形狀(2026-05-12 Round 7 fix,user 抓 PeoplePicker stack +N 該圓形):\n * - `'tag'`(default,backward-compat)— 矩形 chip(對齊 Combobox 文字 tag)\n * - `'circle'`(opt-in for avatar stack consumers)— 圓形 avatar-shape +N(對齊 GitHub picker idiom)\n * PeoplePicker stack mode pass `'circle'`,Combobox 文字 tag 自走 `'tag'`。\n */\n overflowShape?: ComboboxOverflowShape\n /**\n * 2026-05-15 Bug 3 fix:override visible count via formula-based primitive(PeoplePicker stack\n * 用 `avatar-stack-overflow` primitive deterministic formula 計算 visible,bypass DOM offsetWidth\n * measurement)。對齊 user SSOT「同 cell width 同 overflow 判斷」。\n */\n visibleCountOverride?: number\n}\n\nfunction OverflowTagList({ containerRef, items, size, wrap, renderTag, renderHiddenTag, onRemove, trailing, tagWrapperClassName, overflowWrapperClassName, gap = GAP, overflowShape = 'tag', visibleCountOverride }: OverflowTagListProps) {\n const tagEls = React.useRef<(HTMLDivElement | null)[]>([])\n const overflowEl = React.useRef<HTMLDivElement>(null)\n const { visibleCount, ready } = useOverflowCount(containerRef, tagEls, overflowEl, items.length, !wrap, gap, visibleCountOverride)\n tagEls.current.length = items.length\n\n if (wrap) return <>{items.map((item, i) => renderTag(item, i))}{trailing}</>\n\n const overflow = items.length - visibleCount\n const hiddenItems = items.slice(visibleCount)\n\n // 2026-05-18 A' fix(per Codex Round 3 共識,user 拍板「執行」)— 撤掉舊的 `style={{ opacity: ready ? 1 : 0 }}`\n // gate(掛在 `<span className=\"contents\">` 上,但 CSS Display 3 spec 規定 `display:contents` 元素不產生 box,\n // parent opacity 對 children 無效 → gate 從沒生效是 dead code)。Flicker 由 `useOverflowCount` effect 內\n // `calc()` 直跑(現 L190;2026-05-18 Round 5 改 useEffect after-paint + double-rAF guard,詳該 hook 註解)解。\n // `ready` state 保留供未來 instrumentation / debug,不再當 visual gate。\n // 保留 `<span className=\"contents\">` 維持 fragment-like rendering(parent JSX 期望 single child)。\n void ready // intentional: ready 留供 future debug,目前無 consumer\n // **量測 wrapper 必須是 flex 容器,不能是區塊盒**(2026-09-15 user 抓「sm 的 tag 沒垂直置中」,像素實測):\n // 區塊盒的高度由繼承的字型行高決定(欄位 text-body = 21px),sm 的 Tag 只有 20px(h-5),行內的 Tag 對齊\n // 行盒基線、沉到底部 → tag 區 21.8px、tag 上隙 3.9 / 下隙 2.1。md/lg 的 Tag 是 24px ≥ 21,盒子被撐滿才看不出來。\n // flex 容器沒有行盒:高度 = Tag 高度,wrapper `items-center` 直接對 Tag 的盒子置中(sm 3/3、md 3/3、lg 5/5)。\n // Select 的 tag 模式沒有這層 wrapper,一直是正的 —— 這層 wrapper 是 useOverflowCount 量寬用的,寬度量法不變\n //(flex 容器在 flex row 裡 shrink-0 的 max-content 寬 = 內容寬,跟區塊盒相同)。閘:`scripts/tag-field-vertical-inset.mjs`。\n return (\n <span className=\"contents\">\n {items.map((item, i) => (\n // 2026-05-14 I5 fix(per codex M31 verdict + user 抓「avatar stack 堆疊方向不一致」):\n // 加 z-index per-index — 前 item z 高(對齊 MultiPersonDisplay zIndex: visible.length - i\n // canonical + MUI AvatarGroup surplus pattern)。view + edit stack 堆疊方向統一。\n // 2026-09-26:疊放順序改走 CSS 變數,裡面有東西拿到鍵盤焦點時整項升到最上層 —— 焦點框往外畫,不升的話\n // 左半圈會被前一項蓋住(同 avatar.tsx AVATAR_STACK_ITEM_CLASS 的理由;頭像堆疊只在 PeoplePicker 會重疊,一般 Tag 不重疊、升層無副作用)\n <div key={item.value} ref={el => { tagEls.current[i] = el }}\n className={cn('shrink-0 max-w-full flex z-[var(--tag-stack-z)] has-[:focus-visible]:z-[var(--tag-stack-z-focus)]', tagWrapperClassName)}\n style={{ ['--tag-stack-z' as string]: items.length - i, ['--tag-stack-z-focus' as string]: items.length + 1 }}>{renderTag(item, i)}</div>\n ))}\n <div ref={overflowEl}\n className={cn('shrink-0 flex has-[:focus-visible]:z-[var(--tag-stack-z-focus)]', overflowWrapperClassName)}\n style={{ ['--tag-stack-z-focus' as string]: items.length + 1 }}>\n <OverflowIndicator count={overflow} shape={overflowShape} size={size}>\n {hiddenItems.map(item => (\n renderHiddenTag\n ? <React.Fragment key={item.value}>{renderHiddenTag(item)}</React.Fragment>\n : <Tag key={item.value} size=\"sm\" onRemove={onRemove ? () => onRemove(item.value) : undefined}>\n {item.label}\n </Tag>\n ))}\n </OverflowIndicator>\n </div>\n {trailing}\n </span>\n )\n}\n\n// ── Internal tag-stack renderer (consumed by ReadonlyMultiSelect / mode='view') ───\n//\n// Phase B2(2026-05-05):原 ComboboxDisplay sub-component 已 retire,改 inline `<Combobox mode=\"view\">`。\n// 本 helper 只負責 tag-stack 內容渲染(OverflowTagList 消費),不包 Field wrapper。\nfunction ComboboxTagStack({\n value, options, tagSize = 'md', wrap = false, containerRef: externalRef, disabled = false,\n}: {\n value?: string[] | null; options?: ComboboxOption[]; tagSize?: 'sm' | 'md' | 'lg'\n wrap?: boolean; containerRef?: React.RefObject<HTMLDivElement | null>; disabled?: boolean\n}) {\n const emptyDisplay = useFieldEmptyDisplay()\n const ownRef = React.useRef<HTMLDivElement>(null)\n if (!value || value.length === 0) return <span className={fieldEmptyColorClass(disabled ? 'disabled' : 'view')}>{emptyDisplay}</span>\n const items = value.map(v => ({ value: v, label: options?.find(o => o.value === v)?.label ?? v }))\n const disabledClass = disabled ? 'bg-disabled text-fg-disabled' : undefined\n\n const content = (\n <OverflowTagList containerRef={externalRef ?? ownRef} items={items} size={tagSize} wrap={wrap}\n // 2026-05-18 7B' fix(per user 拍板「執行」+ Codex Round 3 共識)— 移除 `unbounded`,Tag 回預設\n // `max-w-40` cap(160px)+ 內建 `[data-tag-text] truncate min-w-0` 自帶 ellipsis。原 unbounded 是\n // 「cell-as-input narrow cell < 160px」設計(`tag.tsx:85-90`),但 generic Combobox tag display\n // 應走 Tag canonical cap-with-ellipsis(per `data-table.spec.md:235`「Tag 文字內部 truncate;\n // multiSelect 動態 +N」+ `data-table.spec.md:467`「Tag 不可被外層 overflow-hidden 裁掉邊框」)。\n // Trade-off:長 tag 觸發 +N 提前(160 + gap + overflowW > available 較 quick)— acceptable per user。\n // Round 2 dynamic slot maxWidth 提案經 user + codex 共識撤回(3 chicken-and-egg fatal,KISS 勝)。\n renderTag={(item) => <Tag size={tagSize} className={cn('shrink-0', disabledClass)}>{item.label}</Tag>} />\n )\n\n if (externalRef) return content\n // 2026-05-05 v9 fix(Bug 4):view path 內 wrapper 必須 `flex-1 min-w-0`,否則在 cell flex\n // parent 下不認領完整可用寬度 → OverflowTagList 量得寬度小於 edit path → 顯 `+N` 多於 edit。\n // edit path tagAreaRef wrapper 已是 `flex-1 min-w-0`(CustomCombobox),\n // view 必對稱才 SSOT。\n // 2026-05-15 F1 Q3 fix(per user round 3 verbatim「單人選取時 Tag 越界蓋 indicator」):\n // `overflow-visible` → `overflow-hidden` 讓 narrow cell width 強制 clip(Tag 內建 truncate\n // 處理 text ellipsis,stack `-ml-0.5` 負 margin 在 wrapper 內不受影響)。對齊\n // `data-table.spec.md:233`「禁硬裁無 ellipsis」+ MUI X / Ant Table column.ellipsis 共識。\n // (2026-05-14 nakedCellRowModeAlign 同保留 — autoRowHeight cell first-line align canonical。)\n return (\n <div ref={ownRef} className={cn('flex-1 min-w-0 flex items-center', nakedCellRowModeAlign, wrap ? 'flex-wrap' : tagRowOverflowClass)} style={{ gap: GAP }}>\n {content}\n </div>\n )\n}\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\nexport interface ComboboxProps {\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: ComboboxOption[]\n value?: string[]\n onChange?: (value: string[]) => void\n placeholder?: string\n className?: string\n disabled?: boolean\n wrap?: boolean\n clearable?: boolean\n /** 啟用搜尋 */\n searchable?: boolean\n /** 「這個值」在讀取 / 驗證 / 儲存(Field 家族 `loading` SSOT,`field-controls.spec.md`「Loading state」;2026-09-09 user 拍板\n * 收窄語意,與 Input `loading` 同義):觸發點右側、ChevronDown 左邊放列圖示尺寸的 CircularProgress(react-select / Atlassian\n * 的順序:清除 → 轉圈 → 箭頭)+ 觸發點 `aria-busy`;選單照常可開、可選。**不是**選項載入 —— 選項載入用 `optionsLoading`。 */\n loading?: boolean\n /** 選項清單載入中(2026-09-09 user 拍板改名自 `loading`)。Forward 給 SelectMenu SSOT:指示**只在選單內**(沒有可顯示選項時\n * 一列「載入選項中」訊息列 + listbox `aria-busy`),觸發點 / 搜尋列不轉圈;本機過濾已有選項時保留、遠端搜尋抓資料中舊選項\n * 不顯示(`select-menu.spec.md`「Loading」「遠端搜尋」)。 */\n optionsLoading?: boolean\n /** 搜尋框位置:menu(浮層內,預設)或 trigger(inline input) */\n searchIn?: 'menu' | 'trigger'\n /** 遠端搜尋時傳 `false`:不在本機用搜尋字過濾(trigger 模式與浮層模式都不過濾)、伺服器回什麼列什麼;抓資料中(`optionsLoading`)\n * 舊結果不顯示、關鍵字空時顯示 `suggestions`;SSOT select-menu.spec.md「遠端搜尋」。 */\n filterOption?: boolean\n /** 搜尋字改變時回呼(含清空);遠端搜尋搭配 `filterOption={false}` + `optionsLoading`。trigger / menu 兩種搜尋位置都會回呼。 */\n onSearchChange?: (value: string) => void\n /** 遠端搜尋、關鍵字空時顯示的建議清單(部分選項;DS 自動包成「建議」群組,讓使用者知道選項不只這幾筆)。只在 `filterOption={false}`\n * 生效;SSOT `select-menu.spec.md`「Suggestions」。 */\n suggestions?: ComboboxOption[]\n /** 建議群組標題(預設「建議」;forward 給 SelectMenu) */\n suggestionsLabel?: string\n /** 遠端搜尋、關鍵字空、沒有建議也沒在載入時的提示列文案(預設「輸入關鍵字搜尋」;forward 給 SelectMenu) */\n searchHintText?: string\n /** 搜尋框 placeholder(未有選項時顯示)。Default: 「搜尋…」 */\n searchPlaceholder?: string\n /** 搜尋框 ARIA label。Default: 「搜尋選項」 */\n searchAriaLabel?: string\n /** Empty-selection placeholder text。Default: 「選擇…」 */\n emptyPlaceholder?: string\n /** 搜尋無結果提示(2026-07-04 Q4 拍板接線)— forward SelectMenu primitive SSOT(default「沒有符合的選項」) */\n emptyText?: string\n /** 多選 footer 全選按鈕文字 —— 還沒全選時(2026-09-17 補轉發:原本 SelectMenu 有這個 prop 但沒有任何 wrapper 傳下去,\n * 等於 Combobox / PeoplePicker / DataTable 的使用者永遠改不了文案);default「全選」 */\n selectAllLabel?: string\n /** 多選 footer 全選按鈕文字 —— 已全選時,點下去清空;default「取消全選」 */\n deselectAllLabel?: string\n /**\n * 多選:在清單最上面加一列「不限」。**預設關**,由消費端自行開啟(轉發給 `SelectMenu`,\n * 完整語意與「何時該開」見 `../SelectMenu/select-menu.spec.md`)。\n * 只選「不限」時,欄位不渲 Tag,改走**一般已填值**的純文字路徑(與單選欄位同一種樣式)。\n */\n unrestricted?: boolean\n /** 「不限」那一列與欄位上顯示的文字(同一個來源)。預設「不限」。 */\n unrestrictedLabel?: string\n /** 「不限」在 value 陣列裡的保留值。預設 `__unrestricted__`。 */\n unrestrictedValue?: string\n /** 可建立新選項(creatable tag,2026-07-18 user 拍板 forward)—— 搜尋非空且無完全同名既有選項時,\n * dropdown 顯 create row(Plus + `createLabel`);forward 給底層 SelectMenu(邏輯/顯示/互動 SSOT 住在 SelectMenu)。\n * 僅 searchable 桌機路徑生效(需打字);native mobile 路徑不支援。對齊 Ant tags / react-select Creatable。 */\n creatable?: boolean\n /** 建立新選項 callback(forward SelectMenu `onCreate`)。 */\n onCreate?: (value: string) => void\n /** create row 文字格式(forward SelectMenu `createLabel`,預設「直接使用「{query}」」)。 */\n createLabel?: (query: string) => string\n /** a11y:無 Field wrapper 時提供 role='combobox' 的 accessible name(axe aria-input-field-name) */\n 'aria-label'?: string\n /** Initial open state(uncontrolled)— 對齊 Select.defaultOpen / Radix Popover canonical。\n * DataTable cell-as-input 1-step open 用 */\n defaultOpen?: boolean\n /** open state 變更 callback。DataTable cell-as-input 用:open=false → cell exit edit */\n onOpenChange?: (open: boolean) => void\n /**\n * Selected tag pill 客製 render(2026-05-07 v15.5)。\n *\n * 設了 → 每個 selected tag pill 走 consumer 提供的 ReactNode(收 item={value, label}\n * + onRemove,consumer 自己組 onRemove);沒設 → 走預設 `<Tag>` text-only pill。\n *\n * 用例:PeoplePicker(multi)用此 slot 把 selected tag 換成 avatar + name pill,而非\n * 純文字 Tag。對齊 PeoplePicker = Combobox wrapper SSOT。\n */\n tagRenderer?: (item: { value: string; label: string }, onRemove: () => void) => React.ReactNode\n /**\n * 2026-05-14 I4 fix:Optional renderer for hidden items in `+N` overflow popover\n * (對齊 view path MultiPersonDisplay overflow popover 含 avatar SSOT)。PeoplePicker stack\n * pass 此 prop 讓 hidden items 顯 avatar + name(同 view path)。Default fallback\n * `<Tag>{label}</Tag>` 純文字 backward-compat。\n */\n renderHiddenTag?: (item: { value: string; label: string }) => React.ReactNode\n /**\n * @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer hook)。\n *\n * Optional class merged into each tag's outer measurement wrapper (2026-05-07 v15.13)。\n * Stack avatar 模式用此 hook point 達成 sibling-level overlap (`-ml-0.5`) + group selector\n * (`group/avatar`)— 既保留 Combobox 必要 measurement wrapper,又讓 dismiss/overlap 視覺生效。\n */\n tagWrapperClassName?: string\n /** @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer hook)。\n * 2026-05-16:overflow chip wrapper 套此 class(對齊 tagWrapperClassName)。Stack 模式\n * pass `-ml-0.5 first:ml-0` 讓 chip 跟 avatar 同 overlap step,物理上 chip = 1 個 slot 不\n * 外加 24px。Default undefined = chip 不 overlap(text-tag mode 等)。*/\n overflowWrapperClassName?: string\n /**\n * Tag area gap in px (2026-05-07 v15.13)。預設 4(pill mode 標準 spacing)。\n * Stack avatar 模式傳 0,讓 `tagWrapperClassName` 的 `-ml-[var(--avatar-stack-overlap)]` negative margin 生效\n * (CSS `gap` 套在 flex container 上會強制 sibling spacing,蓋過 negative margin)。\n * **Q2 known tradeoff**:0 後 useOverflowCount 仍按 wrapper.offsetWidth 累加(不含 overlap\n * 補償)→ +N 偏保守。當前接受;若需精準可 future 加 `overlapPx` 補償邏輯。\n *\n * @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer hook)。\n */\n tagAreaGapPx?: number\n /**\n * tagAreaRef container 左 paddingLeft(px,2026-05-12 加,for PeoplePicker Avatar inset)。\n * Default undefined = no extra padding(Field wrapper `tagPadding[size]` calc 公式自然 inset)。\n * 設值時 tagAreaRef 增 `style.paddingLeft`,**useOverflowCount 的 `available = clientWidth -\n * paddingLeft - paddingRight` 自動 include**(`parseFloat(cs.paddingLeft)` 從 container CSS 抓)\n * → width calc 不漂移,無 side-effect。\n *\n * @internal PeoplePicker stack wrapper 內部協議 — 目前無 active consumer(PeoplePicker 傳 undefined),保留供未來精準 padding;新 consumer 請先評估。\n *\n * **2026-05-13 v2 deprecate path**:原 PeoplePicker pass `{8}` 假設「Combobox tagPadding=4px,4+8=12」\n * 但 `tagPadding[size]` 是 density-dependent calc `(field-height − 2px − tag-height) / 2`(3/3/5;SSOT field-wrapper.tsx fieldTagInsetX,2026-09-15 更正:舊註解寫 icon-size 是錯的),只在 md size +\n * default density 才 = 4px;其他 size/density 漂 6/8px → 4+8=12 公式破。改 PeoplePicker 直接 inject\n * `!px-[var(--field-px)]` className 到 Combobox Field wrapper(per people-picker.spec.md:94 v2),`tagAreaPaddingLeftPx`\n * 走 undefined。Future 仍保留此 prop 給其他 consumer 精準調整 padding,但 PeoplePicker 已不再用。\n */\n tagAreaPaddingLeftPx?: number\n /**\n * Overflow indicator (+N) 形狀(2026-05-12 Round 7,opt-in 給 avatar stack consumer):\n * - `'tag'`(default)— 矩形 chip(Combobox 文字 tag default)\n * - `'circle'`(opt-in)— 圓形 avatar-shape(PeoplePicker stack 用)\n */\n overflowShape?: ComboboxOverflowShape\n /**\n * @internal PeoplePicker stack wrapper 內部協議 — end-user 勿用(measurement-layer override)。\n *\n * 2026-05-15 Bug 3 fix:override visible count via formula-based primitive(opt-in;default 走\n * DOM-based `useOverflowCount`)。PeoplePicker stack mode 用 `avatar-stack-overflow` primitive\n * deterministic formula 計算 visible count,forward 給 Combobox bypass DOM offsetWidth\n * measurement,避免 dual-algorithm drift。對齊 user SSOT「同 cell width 同 overflow 判斷」。\n */\n visibleCountOverride?: number\n /**\n * Display 是否渲 ChevronDown + Field naked wrapper(D-path opt-in,2026-05-08)\n * — DataTable cell view↔edit 像素級對齊用。預設 false(裸 tag stack,backward compat)。\n * 設 true 時 view 走 fieldWrapperStyles(naked variant)+ ItemSuffix ChevronDown,\n * 與 edit 同 DOM 結構,消除 Layer-B padding mismatch。\n */\n showDisplayEndIcon?: boolean\n}\n\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 readonly/disabled/view render ─────────────────────────────────\n\nfunction ReadonlyMultiSelect({\n mode, variant: variantProp, width, size, options, value, wrap, className, showDisplayEndIcon = false,\n unrestricted = false, unrestrictedLabel = '不限', unrestrictedValue = '__unrestricted__', // i18n-allow: DS default(與 SelectMenu 同源)\n}: Pick<ComboboxProps, 'mode' | 'width' | 'size' | 'options' | 'value' | 'wrap' | 'className' | 'showDisplayEndIcon' | 'unrestricted' | 'unrestrictedLabel' | 'unrestrictedValue'> & {\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 = sz === 'lg' ? 20 : 16\n const tagHeight = TAG_HEIGHT_PX[sz]\n const containerRef = React.useRef<HTMLDivElement>(null)\n // 只選了「不限」時不渲 Tag —— 走**一般已填值**那條純文字路徑(2026-09-18 user 拍板)。\n // 互斥保證它只會單獨存在,所以判斷就是「陣列裡只有它」。\n const isUnrestrictedOnly = unrestricted && (value?.length ?? 0) === 1 && value?.[0] === unrestrictedValue\n const hasTags = (value?.length ?? 0) > 0 && !isUnrestrictedOnly\n\n // mode='view'(Phase B2 2026-05-05):純內容輸出 — tag stack 不包 Field wrapper / 不 reserve 高度。\n // 對齊原 ComboboxDisplay sub-component(retired)。\n // Opt-in(showDisplayEndIcon=true,2026-05-08 D-path):Field naked wrapper + ItemSuffix ChevronDown,\n // 與 edit 同結構消除 cell view↔edit 像素偏移(Layer-B padding mismatch)。\n if (resolvedMode === 'view') {\n if (!showDisplayEndIcon) {\n // 2026-05-14 I2 fix(spec contract (e) view typography canonical):empty bare span 套\n // `fieldDisplayTextClass(sz)`(sm/md→text-body,lg→text-body-lg)— 對齊跨 Field family 統一。\n // 「不限」與 placeholder 共用同一顆 span、同一個字級與位置,**唯一差別是不套那層灰**\n // (`Select` 單選欄位就是這樣寫的,select.tsx:352-353;字級 SSOT `field-wrapper.tsx:387`)。\n if (isUnrestrictedOnly) return <span className={cn(fieldDisplayTextClass(sz), className)}>{unrestrictedLabel}</span>\n if (!hasTags) return <span className={cn(fieldDisplayTextClass(sz), fieldEmptyColorClass(resolvedMode), className)}>{emptyDisplay}</span>\n return (\n <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap} />\n )\n }\n return (\n <div\n className={cn(fieldWrapperStyles({ mode: 'view', variant, width, size: sz }), hasTags && tagPadding[sz],\n // wrap 幾何跟 edit / readonly / disabled 全 mode 一致(2026-09-15 補漏):items-start + 同一個內距公式 + 高度放開,\n // 否則 view 態 wrap 的 tag 會被固定的 h-field-* 裁掉;第一行 y 仍 = 單行 y(field.spec.md:147 中線錨在 field-height/2)。\n hasTags && wrap && cn('items-start', tagPaddingY[sz]), className)}\n style={hasTags ? { paddingRight: 'var(--field-px)', ...(wrap ? { height: 'auto' } : undefined) } : undefined}\n data-field-mode=\"view\"\n >\n {hasTags ? (\n <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap} />\n ) : (\n isUnrestrictedOnly\n ? <span className={cn('flex-1 min-w-0', fieldDisplayTextClass(sz))}>{unrestrictedLabel}</span>\n : <span className={cn('flex-1 min-w-0', fieldEmptyColorClass(resolvedMode))}>{emptyDisplay}</span>\n )}\n {/* wrap 時 chevron 鎖第一行 tag 中線,跟 readonly(:628)/ edit 同一招(field-controls.spec.md:280) */}\n <ItemSuffix className={cn('pointer-events-none', wrap && 'self-start')} style={wrap ? { height: tagHeight } : undefined}>\n <ChevronDown size={iconSize} className=\"shrink-0 text-fg-muted\" aria-hidden />\n </ItemSuffix>\n </div>\n )\n }\n\n return (\n <div ref={containerRef}\n className={cn(fieldWrapperStyles({ mode: resolvedMode, variant, width, size: sz }), hasTags && tagPadding[sz],\n // 2026-05-18 #6A Round 1 Step 1/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:451):\n // readonly/disabled path 對齊 L293 view wrapper 已 ship 的 overflow-hidden fix。\n // M10 propagation:原 overflow-visible 讓 readonly tag 越界蓋 indicator,跟 view 不對稱。\n // 2026-06-27 對齊 edit path(L598-617):wrap 時 items-start + chevron self-start/tagHeight 鎖第一行;\n // paddingRight: var(--field-px) re-assert 右緣 12px(tagPadding 對稱 calc 會吃掉右緣,跟 edit 一致)。\n wrap ? cn('flex-wrap items-start', tagPaddingY[sz]) : tagRowOverflowClass,\n // 停用:外框是 cursor-not-allowed(fieldWrapperStyles disabled compound),但裡面的 Tag 自帶 cursor-text,指到 tag 上就變回文字游標\n //(2026-09-29 全站掃出);停用的欄位整塊都是禁止符號(field-controls.spec.md「游標指引」disabled → cursor-not-allowed)\n resolvedMode === 'disabled' && '[&_*]:cursor-not-allowed',\n className)}\n style={{ gap: GAP, paddingRight: 'var(--field-px)', ...(wrap ? { height: 'auto' } : undefined) }} data-field-mode={resolvedMode}\n aria-disabled={resolvedMode === 'disabled' ? true : undefined}>\n {hasTags ? (\n <ComboboxTagStack value={value} options={options} tagSize={sz} wrap={wrap}\n containerRef={containerRef} disabled={resolvedMode === 'disabled'} />\n ) : (\n isUnrestrictedOnly\n ? <span className={fieldDisplayTextClass(sz)}>{unrestrictedLabel}</span>\n : <span className={fieldEmptyColorClass(resolvedMode)}>{emptyDisplay}</span>\n )}\n {/* 2026-06-26 類型身份 indicator:edit 顯示 / readonly 不顯示(純值、不可開下拉) / disabled 保留(fg-disabled,對齊原生 <select disabled>);naked cell 依 showDisplayEndIcon */}\n {(variant === 'naked' ? !!showDisplayEndIcon : resolvedMode === 'disabled') && (\n <ItemSuffix className={cn('pointer-events-none', wrap && 'self-start')} style={wrap ? { height: tagHeight } : undefined}>\n <ChevronDown size={iconSize} className={cn('shrink-0', resolvedMode === 'disabled' ? 'text-fg-disabled' : 'text-fg-muted')} aria-hidden />\n </ItemSuffix>\n )}\n </div>\n )\n}\n\n// ── Native Combobox (mobile) ────────────────────────────────────────\n\n// 2026-05-16 Bug A root cause fix(Claude+Codex M31 Step 5 比稿 consensus,user verbatim\n// 「圖二/圖三 同 180px 不同 length 不同 visible — 跟 user 一開始抓的問題一模一樣」):\n// 公開 `Combobox.forwardRef` 之前用 `(props, _ref)` 把 ref drop,內部 `CustomCombobox`\n// 從未拿 ref → PeoplePicker `stackContainerRef.current` 永遠 null →\n// `useLayoutEffect` early return → `visibleCountOverride` 永遠 undefined →\n// Combobox 走原 internal `useOverflowCount` 60px chip fallback bug → drift。\n// Fix:internal `__triggerRef` prop(underscore = internal-only)attach root div;\n// 公開 `Combobox.forwardRef` 把 `ref` forward 為 `__triggerRef`。對齊 codex DS-wide iceberg\n// audit:`SelectMenu` / `DateGrid` / `Toast` 的 `_ref` 是 intentional documented(no DOM\n// target);唯本處 actionable drop。\ntype ComboboxInternalProps = ComboboxProps & { __triggerRef?: React.Ref<HTMLDivElement> }\n\nfunction focusAfterTagRemoval(container: HTMLElement | null, owner: HTMLElement | null) {\n const active = document.activeElement\n const buttons = container\n ? Array.from(container.querySelectorAll<HTMLButtonElement>('[data-collection-remove]'))\n .filter((button) => button.getClientRects().length > 0)\n : []\n const index = buttons.indexOf(active as HTMLButtonElement)\n const next = index >= 0 ? buttons[index + 1] ?? buttons[index - 1] : undefined\n const fallback = owner ?? container?.closest<HTMLElement>('[role=\"combobox\"]')\n ;(next ?? fallback)?.focus()\n\n // Some renderers intentionally change anatomy at collection length 1 (PeoplePicker stack:\n // avatar stack → avatar + name). That remounts the button focused above. Re-apply the same\n // next→previous→owner policy after React commits so focus cannot fall back to body.\n const preferredIndex = index >= 0\n ? (buttons[index + 1] ? index : buttons[index - 1] ? index - 1 : -1)\n : -1\n window.requestAnimationFrame(() => {\n const updatedButtons = container\n ? Array.from(container.querySelectorAll<HTMLButtonElement>('[data-collection-remove]'))\n .filter((button) => button.getClientRects().length > 0)\n : []\n const updatedTarget = preferredIndex >= 0 ? updatedButtons[preferredIndex] : undefined\n ;(updatedTarget ?? fallback)?.focus()\n })\n}\n\n// 轉換 ComboboxOption → SelectMenuOption:同一份 mapping 給 options 與 suggestions(2026-09-09 建議清單),不複製第二份。\n// 2026-05-10 post-Issue-4 follow-up:forward 全 SelectMenuOption surface(avatar / description / disabled / icon / group)。\nconst toMenuOption = (opt: ComboboxOption): SelectMenuOption => ({\n value: opt.value,\n label: opt.label,\n icon: opt.icon,\n avatar: opt.avatar,\n description: opt.description,\n disabled: opt.disabled,\n group: opt.group,\n})\n\n// ── Custom Combobox (desktop — consumes SelectMenu) ───────────────────\n\nfunction CustomCombobox({\n mode, variant: variantProp, width, error: errorProp = false, size = 'md', options, value = [], onChange, placeholder,\n className, disabled: disabledProp, wrap = false, clearable = false, searchable = false, loading, optionsLoading, searchIn = 'menu', filterOption = true, onSearchChange,\n suggestions, suggestionsLabel, searchHintText,\n searchPlaceholder = '搜尋…', // i18n-allow: DS default\n searchAriaLabel = '搜尋選項', // i18n-allow: DS default\n emptyPlaceholder = '選擇…', // i18n-allow: DS default\n emptyText,\n selectAllLabel,\n deselectAllLabel,\n unrestricted = false,\n unrestrictedLabel = '不限', // i18n-allow: DS default; consumer override via unrestrictedLabel prop\n unrestrictedValue = '__unrestricted__',\n creatable = false,\n onCreate,\n createLabel,\n defaultOpen = false,\n onOpenChange,\n __triggerRef,\n tagRenderer,\n renderHiddenTag,\n tagWrapperClassName,\n overflowWrapperClassName,\n tagAreaGapPx,\n visibleCountOverride,\n tagAreaPaddingLeftPx,\n overflowShape,\n showDisplayEndIcon = false,\n 'aria-label': ariaLabel,\n}: ComboboxInternalProps) {\n const tagAreaGap = tagAreaGapPx ?? GAP\n const fieldCtx = useFieldContext()\n const error = useResolvedFieldInvalid(errorProp)\n const disabled = useResolvedFieldDisabled(disabledProp)\n // 2026-06-08 SSOT:mode 經 useResolvedFieldMode;修 <Field mode=\"view\"> 漏 cascade\n const resolvedMode = useResolvedFieldMode({ mode, disabled })\n const variant: FieldVariantInternal = useResolvedFieldVariant(variantProp)\n const iconSize = getIconSize(size)\n const showClear = clearable && value.length > 0 && resolvedMode === 'edit'\n const [open, setOpen] = React.useState(defaultOpen)\n const [search, setSearchState] = React.useState('')\n // 2026-09-29 exhaustive-deps:`onSearchChange` 走 ref、`setSearch` 身分固定(同 hooks/use-controllable.ts:24 的 onChangeRef 寫法)。\n // 下面「關閉時清搜尋」的 effect 要把 setSearch 列進相依;若 setSearch 仍跟著 onSearchChange 換身分,consumer 用 inline 箭頭\n // (本檔 stories 的遠端搜尋範例就是)→ 每次父層重繪都換一個 → 關著的時候 effect 反覆跑 → onSearchChange('') 反覆呼叫 →\n // 範例裡 setOptions([]) 是新陣列不會 bail-out → 父層再重繪 → 無限迴圈。ref 讓 effect 只在 open 變動時跑,行為 Δ=0。\n const onSearchChangeRef = React.useRef(onSearchChange)\n onSearchChangeRef.current = onSearchChange\n const setSearch = React.useCallback((next: string) => { setSearchState(next); onSearchChangeRef.current?.(next) }, [])\n // 2026-05-12 Q3 fix:trigger 內 inline 搜尋 input ref,onOpenAutoFocus 時 explicit focus\n // 讓 user 看到 cursor 知道可 inline search(跟 Select inputRef SSOT 同模式)。\n const inputRef = React.useRef<HTMLInputElement>(null)\n // a11y: 為 listbox 容器(SelectMenu 內 PopoverContent)建立穩定 id,讓 trigger 的\n // aria-controls 能指向它(WAI-ARIA combobox pattern 要求)。React.useId 在 SSR/CSR 都穩定。\n const listboxId = React.useId()\n // a11y(2026-07-05 D4):追蹤 cmdk active item id → searchIn='trigger' 搜尋 input 綁 aria-activedescendant\n // (機制詳 select-menu.tsx useActiveDescendant docblock;必在 early return 前呼叫 — React #310 hook 順序)。\n const activeOptionId = useActiveDescendant(listboxId, open)\n\n // 關閉時清搜尋。setSearch 身分固定(見上方 ref 寫法),列進相依只是如實宣告,effect 仍只在 open 變動時跑。\n React.useEffect(() => { if (!open) setSearch('') }, [open, setSearch])\n\n // React #310 fix(對齊 select.tsx):以下 hooks(useMemo/useRef)必在 conditional early-return 前\n // 無條件呼叫。resolvedMode 在 edit↔非edit 切換時 hook 數量不可變動,否則 Rules of Hooks\n // violation → React #310 「rendered fewer/more hooks」crash(ReadonlyMultiSelect 用不到這些值,\n // 多算無害,對齊 select.tsx hoist pattern)。\n // 已選值的 label:先查 options,再查 suggestions(2026-09-09:從建議群組選的值不在 options 裡),最後查「看過的選項」\n // (hooks/use-known-options.ts;遠端搜尋關閉後結果被清掉、值還在 → 不能退成 id)\n const findKnown = useKnownOptions([options, suggestions], (o) => o.value)\n const items = React.useMemo(\n () => value.map(v => ({ value: v, label: (options.find(o => o.value === v) ?? suggestions?.find(o => o.value === v) ?? findKnown(v))?.label ?? v })),\n [value, options, suggestions, findKnown]\n )\n // 只選了「不限」時,欄位不渲 Tag,改走一般已填值的純文字路徑(2026-09-18 user 拍板)。\n // 互斥保證它只會單獨存在;文字用 `unrestrictedLabel`,與選單那一列**同一個來源**。\n const isUnrestrictedOnly = unrestricted && value.length === 1 && value[0] === unrestrictedValue\n // **「有沒有 Tag」只准有這一個判斷式**(2026-09-18 user 抓到的漂移根因)。\n //\n // 依據逐字在 `../Field/field-controls.spec.md:298`:\n // 「tagPadding 只在有 Tag 時才套用。Placeholder/空值狀態使用 fieldWrapper 的標準\n // `--field-px`(`px-[var(--field-px)]`)padding,確保文字與邊框有足夠間距。」\n // `tagPadding`(= `fieldTagInsetX`,`(欄高 − 2px 邊框 − Tag 高) / 2`)的理由是**讓 Tag 四邊等距**\n //(`../Tag/tag.spec.md`「圓角與間距」+ 本 spec :279,2026-09-15 df463144),跟文字沒有關係——\n // 所以欄位裡**沒有 Tag** 的時候,它本來就不該套。\n //\n // 「只選『不限』」是第三種狀態:值非空、但不渲 Tag。上面那條規則按字面就涵蓋它(沒有 Tag)。\n // 出事的原因是這件事當時有**兩個判斷式**:唯讀路徑的內距看 `hasTags`、可編輯路徑看\n // `value.length > 0`;我新增第三種狀態時只改到渲染那一側 → 可編輯的「不限」字跑到 4px(少 9px)。\n const hasTags = value.length > 0 && !isUnrestrictedOnly\n // 唯讀 / 檢視 / 停用分支只拿得到 options:把已選但不在 options 裡的項補上\n const optionsForDisplay = React.useMemo(() => {\n const missing = value.map(v => (options.some(o => o.value === v) ? undefined : (suggestions?.find(o => o.value === v) ?? findKnown(v)))).filter((o): o is ComboboxOption => !!o)\n return missing.length ? [...options, ...missing] : options\n }, [options, suggestions, value, findKnown])\n const tagAreaRef = React.useRef<HTMLDivElement>(null)\n const tagHeight = TAG_HEIGHT_PX[size]\n\n const handleRemove = (v: string) => {\n focusAfterTagRemoval(tagAreaRef.current, inputRef.current)\n onChange?.(value.filter(x => x !== v))\n }\n\n // searchIn='trigger' 時由 trigger input 過濾,不走 SelectMenu 內建搜尋\n const filteredOptions = React.useMemo(\n () => (searchable && searchIn === 'trigger' && filterOption && search\n ? options.filter(o => o.label.toLowerCase().includes(search.toLowerCase()))\n : options),\n [searchable, searchIn, filterOption, search, options]\n )\n\n // 轉換 ComboboxOption → SelectMenuOption\n // 2026-05-10 post-Issue-4 follow-up:forward 全 SelectMenuOption surface(avatar / description /\n // disabled / icon / group)— 修先前 PeoplePicker multi-mode dropdown 漏 avatar drift bug。\n const menuOptions: SelectMenuOption[] = React.useMemo(\n () => filteredOptions.map(toMenuOption),\n [filteredOptions]\n )\n const menuSuggestions: SelectMenuOption[] | undefined = React.useMemo(\n () => suggestions?.map(toMenuOption),\n [suggestions]\n )\n\n if (resolvedMode !== 'edit') {\n return <ReadonlyMultiSelect mode={resolvedMode} variant={variant} width={width} size={size} options={optionsForDisplay} value={value} wrap={wrap} className={className} showDisplayEndIcon={showDisplayEndIcon} unrestricted={unrestricted} unrestrictedLabel={unrestrictedLabel} unrestrictedValue={unrestrictedValue} />\n }\n\n // 值處理中的轉圈(Field 家族 loading,2026-09-09 user 拍板收窄):觸發點右側、箭頭左邊(react-select / Atlassian 順序:清除 → 轉圈 → 箭頭),\n // 跟 Input 的 endAction 槽同義 —— 與選單開關、選項多寡無關;選項載入的指示在選單內(optionsLoading → SelectMenu)\n const chevronEl = (\n <>\n {loading && <CircularProgress size={iconSize} className=\"shrink-0\" />}\n <ChevronDown size={iconSize} className={cn('shrink-0 text-fg-muted transition-transform motion-reduce:duration-0', open && 'rotate-180')} aria-hidden />\n </>\n )\n\n const trigger = (\n <div\n ref={__triggerRef}\n id={fieldCtx?.id}\n role=\"combobox\" aria-expanded={open} aria-controls={listboxId} tabIndex={0}\n // 2026-09-25 待辦總帳 B11「多選下拉(有全選)行為不變、只改宣告」:宣告的彈出型別 = 焦點實際去哪。\n // 搜尋框在觸發欄位內(searchIn='trigger')→ 焦點留在欄位、清單用 aria-activedescendant = listbox;\n // 其餘(浮層內搜尋框 / 不可打字)焦點進到浮層、Tab 在面板裡繞圈 = dialog。與下方 onOpenAutoFocus 同一個條件。\n // W3C:popup 不是 listbox 時 aria-haspopup 要寫出型別(https://github.com/w3c/aria-practices/blob/3f094fde1c81b25dfa69162563bf28d093f854d4/content/patterns/combobox/combobox-pattern.html#L410-L411),\n // dialog 型「DOM focus moves into the dialog」(同檔 #L395)\n aria-haspopup={searchIn === 'trigger' ? 'listbox' : 'dialog'}\n aria-label={ariaLabel}\n // a11y(2026-07-14 dim-10):div-based role=combobox 的 <label for> 無效,接 FieldLabel labelId\n // (field-context.ts labelId jsDoc);consumer aria-label 優先 — 與 sibling select.tsx:705 同款 guard。\n aria-labelledby={ariaLabel ? undefined : fieldCtx?.labelId}\n aria-invalid={error || undefined}\n // 值處理中(Field 家族 loading):跟 Input wrapper 同樣標 aria-busy(field-controls.spec.md「Loading state」)\n aria-busy={loading || undefined}\n aria-required={fieldCtx?.required || undefined}\n aria-describedby={fieldCtx?.descriptionId}\n aria-errormessage={error ? fieldCtx?.errorId : undefined}\n // 2026-09-07:本元件是 Field 家族的「單一狀態控制項」——依 focus-canonical 規則二第三列,\n // 滑鼠與鍵盤**共用同一套 focus 樣式**,而 Field 的那一套就是邊框轉 primary\n // (field-wrapper.tsx `focus-within:!border-primary`)。所以這裡要抑制全域外描邊,\n // 跟 DatePicker(:608)/ TimePicker(:378)一致 —— 否則同一顆控件會有兩個焦點指示。\n // **本行不是新增抑制,是補上一直漏掉的那個**:遷移前這顆沒寫 outline-none,\n // 於是全域外描邊一直畫在它上面,是全家族唯一的例外(user 2026-09-07 抓到)。\n // @focus-suppress C — 這一行的元素**就是**那圈欄位外框;承擔者:自己(fieldWrapperStyles 的 focus-within:!border-primary,field-wrapper.tsx:57)\n className={cn(fieldWrapperStyles({ mode: 'edit', variant: variant, width, size, error }), 'focus-visible:outline-none', hasTags && tagPadding[size], 'relative cursor-pointer',\n wrap && cn('items-start', tagPaddingY[size]),\n // 2026-05-06 v13.3 SSOT retire:per-control `open && 'border-primary'` 移除。Field default\n // 統一處理 — open=灰深(data-state)/ focus=藍;2026-07-04 Q1:error 亦收進 error variant。\n className)}\n style={{ paddingRight: 'var(--field-px)', ...(wrap ? { height: 'auto' } : undefined) }}\n data-field-mode=\"edit\" data-error={error ? '' : undefined}\n // WAI-ARIA APG combobox 鍵盤開啟語意 — 對齊 sibling Select(select.tsx:593-598)。\n // <div role=combobox> 不像 native <button> 自動 synthesize Enter/Space click,故顯式補:\n // Enter/Space → 開(searchable 時不攔,讓 inline search input 自行處理打字);\n // Escape → 關;ArrowDown → 開(APG required combobox 展開鍵,僅在 closed 時攔,\n // open 後不 preventDefault 讓方向鍵自由流向選單導覽)。\n // 純 additive:此 trigger 原無 onKeyDown,不覆寫既有 handler;open 邏輯仍走 setOpen SSOT。\n onKeyDown={(e) => {\n // a11y(2026-07-14 dim-10):Enter/Space 來自 descendant 互動元素(Tag 移除 / clear 按鈕)\n // 時直接放行 —— 否則下方 preventDefault 會取消 native button activation(鍵盤永遠按不動\n // 按鈕)。guard 限 Enter/Space + button 類:search input 的 Enter 仍走 cmdk 選項選取\n // (forwardKeyToListbox),Escape / 方向鍵仍走 combobox 導覽。\n if (\n (e.key === 'Enter' || e.key === ' ') &&\n e.target !== e.currentTarget &&\n (e.target as HTMLElement).closest?.('button, a, [role=\"button\"]')\n ) return\n // 2026-07-05 D4 P0:open 後 ArrowUp/Down/Enter 轉送 cmdk root(select-menu.tsx forwardKeyToListbox)\n if (open && forwardKeyToListbox(listboxId, e)) return\n if (e.key === 'Enter' || e.key === ' ') {\n // 2026-06-11 P0 a11y(R2,同 select.tsx 修):Combobox 恆 searchable → 原 `!searchable`\n // guard 使 Enter/Space 永遠開不了(僅 ArrowDown 可)。正確 guard = !open。\n if (!open) { e.preventDefault(); setOpen(true) }\n }\n if (e.key === 'ArrowDown' && !open) { e.preventDefault(); setOpen(true) }\n if (e.key === 'Escape') setOpen(false)\n }}>\n {/* 2026-05-18 #6A Round 1 Step 2/4(per user 拍板「決策6選a」+ codex M31 Step 5 verdict cite combobox.tsx:648):\n CustomCombobox edit non-wrap tagArea 對齊 L293 view + L451 readonly + L518 native edit 已 ship 的 overflow-hidden fix。\n 原 overflow-visible 讓 tag 越界蓋 chevron / +N indicator(user 圖三)。M10 propagation 完整 4-path align。 */}\n {/* `isolate`:標籤 wrapper 的疊放順序(`--tag-stack-z`,頭像堆疊用)只在這一列裡比,不跟頁面上其他層比 ——\n 與 avatar.tsx AVATAR_STACK_CLASS(檢視態的堆疊列)同一件事,編輯態這裡就是那一列(2026-09-26 補,M17) */}\n <div ref={tagAreaRef} className={cn('flex-1 min-w-0 flex items-center relative isolate', nakedCellRowModeAlign, wrap ? 'flex-wrap' : tagRowOverflowClass)} style={{ gap: tagAreaGap, paddingLeft: tagAreaPaddingLeftPx }}>\n {/* 有 Tag / 只選「不限」(純文字,同 placeholder 的盒與字級,只是不套灰)/ 空(placeholder)。\n 三選一的第一個條件就是上面那個 `hasTags`,與欄位內距**同一個判斷式**。*/}\n {hasTags ? (\n <OverflowTagList containerRef={tagAreaRef} items={items} size={size} wrap={wrap}\n tagWrapperClassName={tagWrapperClassName}\n overflowWrapperClassName={overflowWrapperClassName}\n gap={tagAreaGap}\n overflowShape={overflowShape}\n visibleCountOverride={visibleCountOverride}\n renderTag={(item) => (\n tagRenderer\n ? tagRenderer(item, () => handleRemove(item.value))\n : <Tag size={size} className=\"shrink-0 relative z-10\"\n onRemove={() => handleRemove(item.value)}>{item.label}</Tag>\n )}\n renderHiddenTag={renderHiddenTag}\n onRemove={handleRemove}\n trailing={searchable && searchIn === 'trigger' ? (\n <input ref={inputRef} value={search} onChange={(e) => setSearch(e.target.value)}\n // 2026-05-15 Drift A fix(per user verbatim SSOT clarification「未選 → placeholder 顯示請選擇之類」):\n // items.length === 0(empty selection)→ 用 `placeholder` trigger empty prop(「請選擇…」),\n // **不**用 `searchPlaceholder`(「搜尋…」);後者僅在 panel-top search input 場景才合理。\n // items.length > 0(已選)→ no placeholder,純 cursor(對齊 Combobox empty cursor SSOT)。\n // SSOT 對齊 select.tsx:185 `placeholder={selectedLabel || placeholder || '搜尋…'}`\n // empty-state fallback to trigger placeholder canonical。\n placeholder={items.length === 0 ? placeholder : ''} onClick={(e) => { e.stopPropagation(); setOpen(true) }}\n aria-label={searchAriaLabel}\n // a11y(2026-07-05 D4):cmdk active item id(useActiveDescendant)→ SR 播報方向鍵導覽中的 option\n aria-activedescendant={activeOptionId}\n // @focus-suppress B — B Field 家族輸入控件;承擔者:裸 input;指示器是 wrapper 邊框\n className=\"flex-1 min-w-[60px] bg-transparent outline-none text-body leading-compact relative z-10\" />\n ) : undefined} />\n ) : isUnrestrictedOnly ? (\n /* 只選「不限」→ 一般已填值的純文字:與下面 placeholder **同一顆 span 的盒**,\n 唯一差別是不套那層灰(對齊單選欄位 select.tsx:352-353)。\n 左緣靠上面 `hasTags` 讓欄位退回 `--field-px`,不是在這裡另外補位移。 */\n <span className={cn('flex-1 min-w-0 truncate', fieldDisplayTextClass(size))}>{unrestrictedLabel}</span>\n ) : (\n /* 2026-05-12 Stream C Issue 3 fix(codex Q3 Cluster C):placeholder span 必 flex-1 min-w-0\n truncate,narrow container 時單行省略(對齊 Combobox text-tag truncate canonical)。\n 原 hardcode wraps in narrow trigger → user 抓「placeholder 文字 wrap multi-line」。 */\n <span className=\"flex-1 min-w-0 truncate text-fg-muted\">{placeholder ?? emptyPlaceholder}</span>\n )}\n </div>\n <ItemSuffix className={cn('relative z-10 pointer-events-none', wrap && 'self-start')}\n style={wrap ? { height: tagHeight } : undefined}>\n {showClear && (\n <span className=\"pointer-events-auto\">\n <ItemInlineAction\n size={size ?? 'md'}\n action={{\n icon: X,\n label: '清除全部', // i18n-allow: DS default inline-action label\n onClick: (e) => { e?.stopPropagation(); onChange?.([]) },\n }}\n />\n </span>\n )}\n {chevronEl}\n </ItemSuffix>\n </div>\n )\n\n return (\n <SelectMenu\n optionsLoading={optionsLoading}\n filterOption={filterOption}\n // 搜尋在觸發點時把搜尋字交給 SelectMenu(受控;對齊 select.tsx):遠端模式要靠它分辨「關鍵字空 → 建議 / 提示」與\n // 「抓資料中 → 清舊清單」,creatable 的建立列也依它顯隱(2026-09-09 之前 trigger 模式沒傳,建立列永遠不出現)。\n search={searchIn === 'trigger' ? search : undefined}\n onSearchChange={searchIn === 'menu' ? onSearchChange : setSearch}\n suggestions={menuSuggestions}\n suggestionsLabel={suggestionsLabel}\n searchHintText={searchHintText}\n emptyText={emptyText}\n selectAllLabel={selectAllLabel}\n deselectAllLabel={deselectAllLabel}\n // 「不限」轉發(2026-09-18):Combobox 是恆多選的消費者,開關與文字都由產品端決定。\n unrestricted={unrestricted}\n unrestrictedLabel={unrestrictedLabel}\n unrestrictedValue={unrestrictedValue}\n options={menuOptions}\n value={value}\n onValueChange={onChange as (value: string | string[]) => void}\n multiple\n creatable={creatable}\n onCreate={onCreate}\n createLabel={createLabel}\n searchable={searchable && searchIn === 'menu'}\n searchPlaceholder={searchPlaceholder}\n searchAriaLabel={searchAriaLabel}\n size={size}\n open={open}\n onOpenChange={(o) => { setOpen(o); onOpenChange?.(o) }}\n // 2026-05-12 Q3 fix(user 抓「inline-searchable 開浮層應出現 cursor」)— 跟 Select line 550\n // 同 SSOT pattern:preventDefault Radix default focus + 顯式 focus inline input → 開時\n // cursor 直接 visible,user 知道可 inline search。\n onOpenAutoFocus={searchIn === 'trigger' ? (e) => { e.preventDefault(); inputRef.current?.focus() } : undefined}\n contentId={listboxId}\n >\n {trigger}\n </SelectMenu>\n )\n}\n\n// ── Public component ────────────────────────────────────────────────────────\n\nconst Combobox = React.forwardRef<HTMLDivElement, ComboboxProps>(\n ({ size: sizeProp, ...props }, ref) => {\n // B 組 cascade fix:public wrapper 一處 resolve size(prop>Field>surface>md)後 forward 給內層,\n // 讓 <Field size> / DataTable cell surface-size 對 Combobox 生效(內層默認 'md' 被此顯式 size 覆蓋)。\n const size = useResolvedFieldSize(sizeProp)\n // 2026-05-16 真 root cause fix:之前用 `_ref` drop ref。修為 forward 給 internal\n // `__triggerRef`,讓 PeoplePicker stack 透過 ref 量 trigger DOM(visibleCountOverride\n // 才生效)。對齊 React forwardRef public-API canonical(MUI Autocomplete / Radix\n // Popover.Trigger 共識)+ codex M31 Step 5 比稿 verdict + DS-wide ref-drop iceberg audit。\n // 2026-09-18 user 拍板:**手機與桌機同一套**,不為裝置分流。\n // 「我完全不想要為了手機客製化元件,我希望就是 SSOT,直接用桌機版的,什麼都完全不動,\n // 就只是讓手機跟桌機同步而已」。\n // 原本觸控會走一個隱藏原生 `<select>` 的 NativeCombobox。移除的理由是**證據**不是偏好:\n // (a) 原生 `<select multiple>` 在任何裝置上都不是下拉(加了 multiple 瀏覽器改渲染成常駐\n // 清單、沒有展開收合),所以那條路徑只能用單選 select「一次加一個」繞,先天做不到多選選單;\n // (b) 它靜默丟棄 20 個 prop(沒有 rest-spread、TypeScript 不報錯、零 warning),\n // 搜尋 / 全選 / 分組 / 遠端搜尋 / 可建立 / 不限 在觸控上全部無效,而 36 個呼叫點正在傳;\n // (c) 它宣稱的 a11y 好處沒有兌現 —— 那顆 `<select>` 的 value 恆為空字串、也沒有 multiple,\n // 輔助科技從被命名的控件上讀不到已選了什麼;\n // (d) 世界級沒有一家為手機換一套多選 UI(Base UI 明文「同一元件 + multiple,觸控只調定位」/\n // Apple HIG pop-up button「iOS 無額外考量」/ Polaris / Atlassian / Radix / react-select\n // 文件對裝置零分支)。\n // 量過:390px 寬下浮層 356px、不溢出、高度放得下;列高 32px 高於 DS 自己的 24px 地板\n // (owner = tokens/uiSize/uiSize.spec.md「元件高度地板」:169)。**刻意不為觸控加大尺寸** ——\n // 那會變成第二套規格,正是這次要消滅的東西。**不拿觸控尺寸建議當依據**:先前這裡寫的\n // 「過 WCAG 2.2 AA(24×24)」已於 2026-09-24 撤回(本 DS 以滑鼠精度為前提,見\n // ds-canonical/references/hit-area-canonical.md「本 DS 不採納觸控尺寸建議」);\n // 同時把 24 門檻的出處從 overlay-surface.spec.md:431(該段 2026-09-27 起住 overlay-chrome-sizing.spec.md「為什麼用負 margin 而非 fixed wrapper / size=\"xs\"」)改指真正的 owner(上一行)。\n return <CustomCombobox {...props} size={size} __triggerRef={ref} />\n }\n)\nCombobox.displayName = 'Combobox'\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 comboboxMeta = {\n component: 'Combobox',\n family: 4,\n variants: {\n\n },\n sizes: {\n\n },\n // 'active' 移除 — trigger 走 Field chrome(field-wrapper 無按壓態)、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: ['bg-disabled', 'bg-transparent'],\n fg: ['text-fg-disabled', 'text-fg-muted'],\n ring: [],\n },\n} as const\n\nexport { Combobox }\n"],"names":["_a"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/components/Command/command.tsx"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAmB,MAAM,MAAM,CAAA;AAKnE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,2CAA2C,CAAA;AAenG,KAAK,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAqGrC,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;WAEwD,WAAW;wCAqD9E,CAAA;AAGF;;;;;;;GAOG;AACH,QAAA,MAAM,aAAa,GAAI,sCAAwD,WAAW,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,4CAc9H,CAAA;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,YAAY;;;;;;;;WAGP,WAAW;0CA+BpB,CAAA;AAIF;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,WAAW;;;;;;;;sFAiBf,CAAA;AAIF;;;;;;;;GAQG;AACH,QAAA,MAAM,YAAY;;;;;;;WAEyD,WAAW;wCAoBpF,CAAA;AAIF;;;;;;GAMG;AACH,iBAAS,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAA;CAAE,2CAOvF;AASD,wBAAgB,kBAAkB,CAAC,EAAE,OAAe,EAAE,IAAI,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,2CAOhG;AAGD;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,YAAY;;;;;;;;;;sFAuBhB,CAAA;AAIF,QAAA,MAAM,gBAAgB;;;;;;sFAYpB,CAAA;AAGF,KAAK,oBAAoB,GAAG,IAAI,CAAC,aAAa,EAC5C,MAAM,GAAG,WAAW,GAAG,oBAAoB,GAAG,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,KAAK,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC,CAAA;AACvJ,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,GAAG,oBAAoB,GAAG;IACnH,wGAAwG;IACxG,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,CAAA;AAED;;;;;;GAMG;AACH,QAAA,MAAM,WAAW;;;;;;;;;;;;;IAXf,wGAAwG;eAC7F,KAAK,CAAC,SAAS;wCA+E1B,CAAA;AAIF,QAAA,MAAM,eAAe;8BAGlB,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;;CAUvC,CAAA;AAKD,eAAO,MAAM,WAAW;;;;;;;;;;;CAgBd,CAAA;AAEV,OAAO,EACL,OAAO,EACP,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,WAAW,EACX,eAAe,EACf,gBAAgB,GACjB,CAAA"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/components/Command/command.tsx"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAmB,MAAM,MAAM,CAAA;AAKnE,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,2CAA2C,CAAA;AAenG,KAAK,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAqGrC,QAAA,MAAM,OAAO;;;;;;;;;;;;;;;;;WAEwD,WAAW;wCAqD9E,CAAA;AAGF;;;;;;;GAOG;AACH,QAAA,MAAM,aAAa,GAAI,sCAAwD,WAAW,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,4CAc9H,CAAA;AAED;;;;;;;GAOG;AACH,QAAA,MAAM,YAAY;;;;;;;;WAGP,WAAW;0CAgCpB,CAAA;AAIF;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,WAAW;;;;;;;;sFAiBf,CAAA;AAIF;;;;;;;;GAQG;AACH,QAAA,MAAM,YAAY;;;;;;;WAEyD,WAAW;wCAqBpF,CAAA;AAIF;;;;;;GAMG;AACH,iBAAS,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,WAAW,CAAA;CAAE,2CAQvF;AASD,wBAAgB,kBAAkB,CAAC,EAAE,OAAe,EAAE,IAAI,EAAE,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,2CAOhG;AAGD;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,YAAY;;;;;;;;;;sFAuBhB,CAAA;AAIF,QAAA,MAAM,gBAAgB;;;;;;sFAYpB,CAAA;AAGF,KAAK,oBAAoB,GAAG,IAAI,CAAC,aAAa,EAC5C,MAAM,GAAG,WAAW,GAAG,oBAAoB,GAAG,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,KAAK,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC,CAAA;AACvJ,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,wBAAwB,CAAC,OAAO,gBAAgB,CAAC,IAAI,CAAC,GAAG,oBAAoB,GAAG;IACnH,wGAAwG;IACxG,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B,CAAA;AAED;;;;;;GAMG;AACH,QAAA,MAAM,WAAW;;;;;;;;;;;;;IAXf,wGAAwG;eAC7F,KAAK,CAAC,SAAS;wCAgF1B,CAAA;AAIF,QAAA,MAAM,eAAe;8BAGlB,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC;;CAUvC,CAAA;AAKD,eAAO,MAAM,WAAW;;;;;;;;;;;CAgBd,CAAA;AAEV,OAAO,EACL,OAAO,EACP,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,WAAW,EACX,eAAe,EACf,gBAAgB,GACjB,CAAA"}
@@ -123,7 +123,8 @@ const CommandDialog = ({ children, title = "指令面板", label = "搜尋指令
123
123
  ] }) });
124
124
  };
125
125
  const CommandInput = React.forwardRef(({ className, size: sizeProp, ...props }, ref) => {
126
- const size = sizeProp ?? useRowSize("md");
126
+ const inherited = useRowSize("md");
127
+ const size = sizeProp ?? inherited;
127
128
  return /* @__PURE__ */ jsxs(
128
129
  "div",
129
130
  {
@@ -157,7 +158,7 @@ CommandInput.displayName = Command$1.Input.displayName;
157
158
  const CommandList = React.forwardRef(({ className, label = "選項", ...props }, ref) => (
158
159
  // i18n-allow: DS 預設 listbox 名稱(cmdk 預設是英文 Suggestions)
159
160
  /* @story-baseline: overlay-surface.spec.md#Viewport-aware-scroll-chain-invariant(M25 SSOT owner)
160
- owner spec: overlay-surface.spec.md:34/53/347-362 —— 「浮層 body 永遠 flex-1 min-h-0 overflow-y-auto;
161
+ owner spec: overlay-surface.spec.md「SurfaceBody」+ overlay-chrome-sizing.spec.md「為什麼 SurfaceHeader 是 padding-based」(2026-09-27 拆檔前 = overlay-surface.spec.md:34/53/347-362)—— 「浮層 body 永遠 flex-1 min-h-0 overflow-y-auto;
161
162
  中間 wrapper 都必 flex flex-col h-full min-h-0;viewport 太小 body 內壓縮捲動」。
162
163
  conflicting code(修前): 本 ScrollArea 固定 max-h-300 無 flex-1 → 在夾住的 SelectMenu PopoverContent
163
164
  (max-h=available-height)內撐破外殼、底部選項被裁(320px viewport 實測 bottom 425 > 320 溢出)。
@@ -167,7 +168,8 @@ const CommandList = React.forwardRef(({ className, label = "選項", ...props },
167
168
  ));
168
169
  CommandList.displayName = Command$1.List.displayName;
169
170
  const CommandEmpty = React.forwardRef(({ className, children, size: sizeProp, ...props }, ref) => {
170
- const size = sizeProp ?? useRowSize("md");
171
+ const inherited = useRowSize("md");
172
+ const size = sizeProp ?? inherited;
171
173
  const setEmptyText = React.useContext(EmptyTextContext);
172
174
  const text = typeof children === "string" || typeof children === "number" ? String(children) : null;
173
175
  React.useEffect(() => {
@@ -178,7 +180,8 @@ const CommandEmpty = React.forwardRef(({ className, children, size: sizeProp, ..
178
180
  });
179
181
  CommandEmpty.displayName = Command$1.Empty.displayName;
180
182
  function CommandLoading({ label, size: sizeProp }) {
181
- const size = sizeProp ?? useRowSize("md");
183
+ const inherited = useRowSize("md");
184
+ const size = sizeProp ?? inherited;
182
185
  return /* @__PURE__ */ jsx(MenuItem, { size, message: true, role: "status", startContent: /* @__PURE__ */ jsx(CircularProgress, { size: ICON_SIZE[size] }), children: label });
183
186
  }
184
187
  function CommandEmptyStatus({ loading = false, text }) {
@@ -217,7 +220,8 @@ const CommandSeparator = React.forwardRef(({ className, ...props }, ref) => /* @
217
220
  ));
218
221
  CommandSeparator.displayName = Command$1.Separator.displayName;
219
222
  const CommandItem = React.forwardRef(({ className, children, size: sizeProp, startIcon, startIconClassName, avatar, startContent, description, tag, endContent, shortcut, selected, checkbox, checked, disabled, ...props }, ref) => {
220
- const size = sizeProp ?? useRowSize("md");
223
+ const inherited = useRowSize("md");
224
+ const size = sizeProp ?? inherited;
221
225
  const cursorByKeyboard = useCursorMover() === "keyboard";
222
226
  const childIsMenuItem = React.isValidElement(children) && children.type === MenuItem;
223
227
  const end = shortcut != null ? /* @__PURE__ */ jsx(CommandShortcut, { children: shortcut }) : endContent;