@fluentui/react-combobox 9.0.0-beta.9 → 9.0.0

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 (302) hide show
  1. package/CHANGELOG.json +848 -1
  2. package/CHANGELOG.md +248 -2
  3. package/README.md +1 -3
  4. package/dist/index.d.ts +62 -11
  5. package/lib/Combobox.js.map +1 -1
  6. package/lib/ComboboxField.js +2 -0
  7. package/lib/ComboboxField.js.map +1 -0
  8. package/lib/Dropdown.js.map +1 -1
  9. package/lib/Listbox.js.map +1 -1
  10. package/lib/Option.js.map +1 -1
  11. package/lib/OptionGroup.js.map +1 -1
  12. package/lib/components/Combobox/Combobox.js +0 -1
  13. package/lib/components/Combobox/Combobox.js.map +1 -1
  14. package/lib/components/Combobox/Combobox.types.js.map +1 -1
  15. package/lib/components/Combobox/index.js.map +1 -1
  16. package/lib/components/Combobox/renderCombobox.js +10 -6
  17. package/lib/components/Combobox/renderCombobox.js.map +1 -1
  18. package/lib/components/Combobox/useCombobox.js +107 -70
  19. package/lib/components/Combobox/useCombobox.js.map +1 -1
  20. package/lib/components/Combobox/useComboboxStyles.js +246 -185
  21. package/lib/components/Combobox/useComboboxStyles.js.map +1 -1
  22. package/lib/components/ComboboxField/ComboboxField.js +8 -0
  23. package/lib/components/ComboboxField/ComboboxField.js.map +1 -0
  24. package/lib/components/ComboboxField/index.js +2 -0
  25. package/lib/components/ComboboxField/index.js.map +1 -0
  26. package/lib/components/Dropdown/Dropdown.js +0 -1
  27. package/lib/components/Dropdown/Dropdown.js.map +1 -1
  28. package/lib/components/Dropdown/Dropdown.types.js.map +1 -1
  29. package/lib/components/Dropdown/index.js.map +1 -1
  30. package/lib/components/Dropdown/renderDropdown.js +10 -6
  31. package/lib/components/Dropdown/renderDropdown.js.map +1 -1
  32. package/lib/components/Dropdown/useDropdown.js +25 -36
  33. package/lib/components/Dropdown/useDropdown.js.map +1 -1
  34. package/lib/components/Dropdown/useDropdownStyles.js +236 -176
  35. package/lib/components/Dropdown/useDropdownStyles.js.map +1 -1
  36. package/lib/components/Listbox/Listbox.js +0 -1
  37. package/lib/components/Listbox/Listbox.js.map +1 -1
  38. package/lib/components/Listbox/Listbox.types.js.map +1 -1
  39. package/lib/components/Listbox/index.js.map +1 -1
  40. package/lib/components/Listbox/renderListbox.js +2 -2
  41. package/lib/components/Listbox/renderListbox.js.map +1 -1
  42. package/lib/components/Listbox/useListbox.js +15 -17
  43. package/lib/components/Listbox/useListbox.js.map +1 -1
  44. package/lib/components/Listbox/useListboxStyles.js +16 -20
  45. package/lib/components/Listbox/useListboxStyles.js.map +1 -1
  46. package/lib/components/Option/Option.js +0 -1
  47. package/lib/components/Option/Option.js.map +1 -1
  48. package/lib/components/Option/Option.types.js.map +1 -1
  49. package/lib/components/Option/index.js.map +1 -1
  50. package/lib/components/Option/renderOption.js +4 -3
  51. package/lib/components/Option/renderOption.js.map +1 -1
  52. package/lib/components/Option/useOption.js +46 -39
  53. package/lib/components/Option/useOption.js.map +1 -1
  54. package/lib/components/Option/useOptionStyles.js +101 -79
  55. package/lib/components/Option/useOptionStyles.js.map +1 -1
  56. package/lib/components/OptionGroup/OptionGroup.js +0 -1
  57. package/lib/components/OptionGroup/OptionGroup.js.map +1 -1
  58. package/lib/components/OptionGroup/OptionGroup.types.js.map +1 -1
  59. package/lib/components/OptionGroup/index.js.map +1 -1
  60. package/lib/components/OptionGroup/renderOptionGroup.js +4 -3
  61. package/lib/components/OptionGroup/renderOptionGroup.js.map +1 -1
  62. package/lib/components/OptionGroup/useOptionGroup.js +0 -1
  63. package/lib/components/OptionGroup/useOptionGroup.js.map +1 -1
  64. package/lib/components/OptionGroup/useOptionGroupStyles.js +29 -34
  65. package/lib/components/OptionGroup/useOptionGroupStyles.js.map +1 -1
  66. package/lib/contexts/ComboboxContext.js +9 -11
  67. package/lib/contexts/ComboboxContext.js.map +1 -1
  68. package/lib/contexts/ListboxContext.js +7 -9
  69. package/lib/contexts/ListboxContext.js.map +1 -1
  70. package/lib/contexts/useComboboxContextValues.js.map +1 -1
  71. package/lib/contexts/useListboxContextValues.js +2 -2
  72. package/lib/contexts/useListboxContextValues.js.map +1 -1
  73. package/lib/index.js +6 -0
  74. package/lib/index.js.map +1 -1
  75. package/lib/utils/ComboboxBase.types.js.map +1 -1
  76. package/lib/utils/OptionCollection.types.js.map +1 -1
  77. package/lib/utils/Selection.types.js.map +1 -1
  78. package/lib/utils/dropdownKeyActions.js +12 -33
  79. package/lib/utils/dropdownKeyActions.js.map +1 -1
  80. package/lib/utils/internalTokens.js.map +1 -1
  81. package/lib/utils/useComboboxBaseState.js +29 -30
  82. package/lib/utils/useComboboxBaseState.js.map +1 -1
  83. package/lib/utils/useComboboxPopup.js +6 -4
  84. package/lib/utils/useComboboxPopup.js.map +1 -1
  85. package/lib/utils/useOptionCollection.js +13 -23
  86. package/lib/utils/useOptionCollection.js.map +1 -1
  87. package/lib/utils/useScrollOptionsIntoView.js +36 -0
  88. package/lib/utils/useScrollOptionsIntoView.js.map +1 -0
  89. package/lib/utils/useSelection.js +9 -12
  90. package/lib/utils/useSelection.js.map +1 -1
  91. package/lib/utils/useTriggerListboxSlots.js +34 -40
  92. package/lib/utils/useTriggerListboxSlots.js.map +1 -1
  93. package/lib-amd/Combobox.js +6 -0
  94. package/lib-amd/Combobox.js.map +1 -0
  95. package/lib-amd/ComboboxField.js +6 -0
  96. package/lib-amd/ComboboxField.js.map +1 -0
  97. package/lib-amd/Dropdown.js +6 -0
  98. package/lib-amd/Dropdown.js.map +1 -0
  99. package/lib-amd/Listbox.js +6 -0
  100. package/lib-amd/Listbox.js.map +1 -0
  101. package/lib-amd/Option.js +6 -0
  102. package/lib-amd/Option.js.map +1 -0
  103. package/lib-amd/OptionGroup.js +6 -0
  104. package/lib-amd/OptionGroup.js.map +1 -0
  105. package/lib-amd/components/Combobox/Combobox.js +16 -0
  106. package/lib-amd/components/Combobox/Combobox.js.map +1 -0
  107. package/lib-amd/components/Combobox/Combobox.types.js +5 -0
  108. package/lib-amd/components/Combobox/Combobox.types.js.map +1 -0
  109. package/lib-amd/components/Combobox/index.js +10 -0
  110. package/lib-amd/components/Combobox/index.js.map +1 -0
  111. package/lib-amd/components/Combobox/renderCombobox.js +20 -0
  112. package/lib-amd/components/Combobox/renderCombobox.js.map +1 -0
  113. package/lib-amd/components/Combobox/useCombobox.js +206 -0
  114. package/lib-amd/components/Combobox/useCombobox.js.map +1 -0
  115. package/lib-amd/components/Combobox/useComboboxStyles.js +152 -0
  116. package/lib-amd/components/Combobox/useComboboxStyles.js.map +1 -0
  117. package/lib-amd/components/ComboboxField/ComboboxField.js +10 -0
  118. package/lib-amd/components/ComboboxField/ComboboxField.js.map +1 -0
  119. package/lib-amd/components/ComboboxField/index.js +6 -0
  120. package/lib-amd/components/ComboboxField/index.js.map +1 -0
  121. package/lib-amd/components/Dropdown/Dropdown.js +16 -0
  122. package/lib-amd/components/Dropdown/Dropdown.js.map +1 -0
  123. package/lib-amd/components/Dropdown/Dropdown.types.js +5 -0
  124. package/lib-amd/components/Dropdown/Dropdown.types.js.map +1 -0
  125. package/lib-amd/components/Dropdown/index.js +10 -0
  126. package/lib-amd/components/Dropdown/index.js.map +1 -0
  127. package/lib-amd/components/Dropdown/renderDropdown.js +21 -0
  128. package/lib-amd/components/Dropdown/renderDropdown.js.map +1 -0
  129. package/lib-amd/components/Dropdown/useDropdown.js +121 -0
  130. package/lib-amd/components/Dropdown/useDropdown.js.map +1 -0
  131. package/lib-amd/components/Dropdown/useDropdownStyles.js +127 -0
  132. package/lib-amd/components/Dropdown/useDropdownStyles.js.map +1 -0
  133. package/lib-amd/components/Listbox/Listbox.js +16 -0
  134. package/lib-amd/components/Listbox/Listbox.js.map +1 -0
  135. package/lib-amd/components/Listbox/Listbox.types.js +5 -0
  136. package/lib-amd/components/Listbox/Listbox.types.js.map +1 -0
  137. package/lib-amd/components/Listbox/index.js +10 -0
  138. package/lib-amd/components/Listbox/index.js.map +1 -0
  139. package/lib-amd/components/Listbox/renderListbox.js +15 -0
  140. package/lib-amd/components/Listbox/renderListbox.js.map +1 -0
  141. package/lib-amd/components/Listbox/useListbox.js +80 -0
  142. package/lib-amd/components/Listbox/useListbox.js.map +1 -0
  143. package/lib-amd/components/Listbox/useListboxStyles.js +24 -0
  144. package/lib-amd/components/Listbox/useListboxStyles.js.map +1 -0
  145. package/lib-amd/components/Option/Option.js +15 -0
  146. package/lib-amd/components/Option/Option.js.map +1 -0
  147. package/lib-amd/components/Option/Option.types.js +5 -0
  148. package/lib-amd/components/Option/Option.types.js.map +1 -0
  149. package/lib-amd/components/Option/index.js +10 -0
  150. package/lib-amd/components/Option/index.js.map +1 -0
  151. package/lib-amd/components/Option/renderOption.js +16 -0
  152. package/lib-amd/components/Option/renderOption.js.map +1 -0
  153. package/lib-amd/components/Option/useOption.js +117 -0
  154. package/lib-amd/components/Option/useOption.js.map +1 -0
  155. package/lib-amd/components/Option/useOptionStyles.js +73 -0
  156. package/lib-amd/components/Option/useOptionStyles.js.map +1 -0
  157. package/lib-amd/components/OptionGroup/OptionGroup.js +15 -0
  158. package/lib-amd/components/OptionGroup/OptionGroup.js.map +1 -0
  159. package/lib-amd/components/OptionGroup/OptionGroup.types.js +5 -0
  160. package/lib-amd/components/OptionGroup/OptionGroup.types.js.map +1 -0
  161. package/lib-amd/components/OptionGroup/index.js +10 -0
  162. package/lib-amd/components/OptionGroup/index.js.map +1 -0
  163. package/lib-amd/components/OptionGroup/renderOptionGroup.js +16 -0
  164. package/lib-amd/components/OptionGroup/renderOptionGroup.js.map +1 -0
  165. package/lib-amd/components/OptionGroup/useOptionGroup.js +33 -0
  166. package/lib-amd/components/OptionGroup/useOptionGroup.js.map +1 -0
  167. package/lib-amd/components/OptionGroup/useOptionGroupStyles.js +34 -0
  168. package/lib-amd/components/OptionGroup/useOptionGroupStyles.js.map +1 -0
  169. package/lib-amd/contexts/ComboboxContext.js +28 -0
  170. package/lib-amd/contexts/ComboboxContext.js.map +1 -0
  171. package/lib-amd/contexts/ListboxContext.js +23 -0
  172. package/lib-amd/contexts/ListboxContext.js.map +1 -0
  173. package/lib-amd/contexts/useComboboxContextValues.js +23 -0
  174. package/lib-amd/contexts/useComboboxContextValues.js.map +1 -0
  175. package/lib-amd/contexts/useListboxContextValues.js +24 -0
  176. package/lib-amd/contexts/useListboxContextValues.js.map +1 -0
  177. package/lib-amd/index.js +37 -0
  178. package/lib-amd/index.js.map +1 -0
  179. package/lib-amd/utils/ComboboxBase.types.js +5 -0
  180. package/lib-amd/utils/ComboboxBase.types.js.map +1 -0
  181. package/lib-amd/utils/OptionCollection.types.js +5 -0
  182. package/lib-amd/utils/OptionCollection.types.js.map +1 -0
  183. package/lib-amd/utils/Selection.types.js +5 -0
  184. package/lib-amd/utils/Selection.types.js.map +1 -0
  185. package/lib-amd/utils/dropdownKeyActions.js +85 -0
  186. package/lib-amd/utils/dropdownKeyActions.js.map +1 -0
  187. package/lib-amd/utils/internalTokens.js +11 -0
  188. package/lib-amd/utils/internalTokens.js.map +1 -0
  189. package/lib-amd/utils/useComboboxBaseState.js +76 -0
  190. package/lib-amd/utils/useComboboxBaseState.js.map +1 -0
  191. package/lib-amd/utils/useComboboxPopup.js +16 -0
  192. package/lib-amd/utils/useComboboxPopup.js.map +1 -0
  193. package/lib-amd/utils/useOptionCollection.js +65 -0
  194. package/lib-amd/utils/useOptionCollection.js.map +1 -0
  195. package/lib-amd/utils/useScrollOptionsIntoView.js +33 -0
  196. package/lib-amd/utils/useScrollOptionsIntoView.js.map +1 -0
  197. package/lib-amd/utils/useSelection.js +42 -0
  198. package/lib-amd/utils/useSelection.js.map +1 -0
  199. package/lib-amd/utils/useTriggerListboxSlots.js +104 -0
  200. package/lib-amd/utils/useTriggerListboxSlots.js.map +1 -0
  201. package/lib-commonjs/Combobox.js +0 -2
  202. package/lib-commonjs/Combobox.js.map +1 -1
  203. package/lib-commonjs/ComboboxField.js +8 -0
  204. package/lib-commonjs/ComboboxField.js.map +1 -0
  205. package/lib-commonjs/Dropdown.js +0 -2
  206. package/lib-commonjs/Dropdown.js.map +1 -1
  207. package/lib-commonjs/Listbox.js +0 -2
  208. package/lib-commonjs/Listbox.js.map +1 -1
  209. package/lib-commonjs/Option.js +0 -2
  210. package/lib-commonjs/Option.js.map +1 -1
  211. package/lib-commonjs/OptionGroup.js +0 -2
  212. package/lib-commonjs/OptionGroup.js.map +1 -1
  213. package/lib-commonjs/components/Combobox/Combobox.js +0 -7
  214. package/lib-commonjs/components/Combobox/Combobox.js.map +1 -1
  215. package/lib-commonjs/components/Combobox/Combobox.types.js.map +1 -1
  216. package/lib-commonjs/components/Combobox/index.js +0 -6
  217. package/lib-commonjs/components/Combobox/index.js.map +1 -1
  218. package/lib-commonjs/components/Combobox/renderCombobox.js +10 -12
  219. package/lib-commonjs/components/Combobox/renderCombobox.js.map +1 -1
  220. package/lib-commonjs/components/Combobox/useCombobox.js +106 -78
  221. package/lib-commonjs/components/Combobox/useCombobox.js.map +1 -1
  222. package/lib-commonjs/components/Combobox/useComboboxStyles.js +245 -189
  223. package/lib-commonjs/components/Combobox/useComboboxStyles.js.map +1 -1
  224. package/lib-commonjs/components/ComboboxField/ComboboxField.js +14 -0
  225. package/lib-commonjs/components/ComboboxField/ComboboxField.js.map +1 -0
  226. package/lib-commonjs/components/ComboboxField/index.js +8 -0
  227. package/lib-commonjs/components/ComboboxField/index.js.map +1 -0
  228. package/lib-commonjs/components/Dropdown/Dropdown.js +0 -7
  229. package/lib-commonjs/components/Dropdown/Dropdown.js.map +1 -1
  230. package/lib-commonjs/components/Dropdown/Dropdown.types.js.map +1 -1
  231. package/lib-commonjs/components/Dropdown/index.js +0 -6
  232. package/lib-commonjs/components/Dropdown/index.js.map +1 -1
  233. package/lib-commonjs/components/Dropdown/renderDropdown.js +10 -12
  234. package/lib-commonjs/components/Dropdown/renderDropdown.js.map +1 -1
  235. package/lib-commonjs/components/Dropdown/useDropdown.js +25 -47
  236. package/lib-commonjs/components/Dropdown/useDropdown.js.map +1 -1
  237. package/lib-commonjs/components/Dropdown/useDropdownStyles.js +235 -180
  238. package/lib-commonjs/components/Dropdown/useDropdownStyles.js.map +1 -1
  239. package/lib-commonjs/components/Listbox/Listbox.js +0 -7
  240. package/lib-commonjs/components/Listbox/Listbox.js.map +1 -1
  241. package/lib-commonjs/components/Listbox/Listbox.types.js.map +1 -1
  242. package/lib-commonjs/components/Listbox/index.js +0 -6
  243. package/lib-commonjs/components/Listbox/index.js.map +1 -1
  244. package/lib-commonjs/components/Listbox/renderListbox.js +2 -7
  245. package/lib-commonjs/components/Listbox/renderListbox.js.map +1 -1
  246. package/lib-commonjs/components/Listbox/useListbox.js +14 -25
  247. package/lib-commonjs/components/Listbox/useListbox.js.map +1 -1
  248. package/lib-commonjs/components/Listbox/useListboxStyles.js +16 -24
  249. package/lib-commonjs/components/Listbox/useListboxStyles.js.map +1 -1
  250. package/lib-commonjs/components/Option/Option.js +0 -6
  251. package/lib-commonjs/components/Option/Option.js.map +1 -1
  252. package/lib-commonjs/components/Option/Option.types.js.map +1 -1
  253. package/lib-commonjs/components/Option/index.js +0 -6
  254. package/lib-commonjs/components/Option/index.js.map +1 -1
  255. package/lib-commonjs/components/Option/renderOption.js +4 -7
  256. package/lib-commonjs/components/Option/renderOption.js.map +1 -1
  257. package/lib-commonjs/components/Option/useOption.js +45 -45
  258. package/lib-commonjs/components/Option/useOption.js.map +1 -1
  259. package/lib-commonjs/components/Option/useOptionStyles.js +101 -83
  260. package/lib-commonjs/components/Option/useOptionStyles.js.map +1 -1
  261. package/lib-commonjs/components/OptionGroup/OptionGroup.js +0 -6
  262. package/lib-commonjs/components/OptionGroup/OptionGroup.js.map +1 -1
  263. package/lib-commonjs/components/OptionGroup/OptionGroup.types.js.map +1 -1
  264. package/lib-commonjs/components/OptionGroup/index.js +0 -6
  265. package/lib-commonjs/components/OptionGroup/index.js.map +1 -1
  266. package/lib-commonjs/components/OptionGroup/renderOptionGroup.js +4 -7
  267. package/lib-commonjs/components/OptionGroup/renderOptionGroup.js.map +1 -1
  268. package/lib-commonjs/components/OptionGroup/useOptionGroup.js +0 -4
  269. package/lib-commonjs/components/OptionGroup/useOptionGroup.js.map +1 -1
  270. package/lib-commonjs/components/OptionGroup/useOptionGroupStyles.js +29 -38
  271. package/lib-commonjs/components/OptionGroup/useOptionGroupStyles.js.map +1 -1
  272. package/lib-commonjs/contexts/ComboboxContext.js +10 -14
  273. package/lib-commonjs/contexts/ComboboxContext.js.map +1 -1
  274. package/lib-commonjs/contexts/ListboxContext.js +8 -12
  275. package/lib-commonjs/contexts/ListboxContext.js.map +1 -1
  276. package/lib-commonjs/contexts/useComboboxContextValues.js +0 -2
  277. package/lib-commonjs/contexts/useComboboxContextValues.js.map +1 -1
  278. package/lib-commonjs/contexts/useListboxContextValues.js +2 -6
  279. package/lib-commonjs/contexts/useListboxContextValues.js.map +1 -1
  280. package/lib-commonjs/index.js +43 -11
  281. package/lib-commonjs/index.js.map +1 -1
  282. package/lib-commonjs/utils/ComboboxBase.types.js.map +1 -1
  283. package/lib-commonjs/utils/OptionCollection.types.js.map +1 -1
  284. package/lib-commonjs/utils/Selection.types.js.map +1 -1
  285. package/lib-commonjs/utils/dropdownKeyActions.js +12 -37
  286. package/lib-commonjs/utils/dropdownKeyActions.js.map +1 -1
  287. package/lib-commonjs/utils/internalTokens.js.map +1 -1
  288. package/lib-commonjs/utils/useComboboxBaseState.js +29 -36
  289. package/lib-commonjs/utils/useComboboxBaseState.js.map +1 -1
  290. package/lib-commonjs/utils/useComboboxPopup.js +6 -8
  291. package/lib-commonjs/utils/useComboboxPopup.js.map +1 -1
  292. package/lib-commonjs/utils/useOptionCollection.js +13 -26
  293. package/lib-commonjs/utils/useOptionCollection.js.map +1 -1
  294. package/lib-commonjs/utils/useScrollOptionsIntoView.js +43 -0
  295. package/lib-commonjs/utils/useScrollOptionsIntoView.js.map +1 -0
  296. package/lib-commonjs/utils/useSelection.js +9 -15
  297. package/lib-commonjs/utils/useSelection.js.map +1 -1
  298. package/lib-commonjs/utils/useTriggerListboxSlots.js +33 -44
  299. package/lib-commonjs/utils/useTriggerListboxSlots.js.map +1 -1
  300. package/package.json +23 -22
  301. package/Spec-migration.md +0 -13
  302. package/Spec.md +0 -520
@@ -1,9 +1,11 @@
1
1
  import * as React from 'react';
2
+ import { ArrowLeft, ArrowRight } from '@fluentui/keyboard-keys';
2
3
  import { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';
3
- import { getPartitionedNativeProps, resolveShorthand, mergeCallbacks, useEventCallback, useMergedRefs } from '@fluentui/react-utilities';
4
+ import { getPartitionedNativeProps, resolveShorthand, mergeCallbacks, useEventCallback, useId, useMergedRefs } from '@fluentui/react-utilities';
5
+ import { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';
4
6
  import { useComboboxBaseState } from '../../utils/useComboboxBaseState';
5
- import { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';
6
7
  import { useComboboxPopup } from '../../utils/useComboboxPopup';
8
+ import { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';
7
9
  import { Listbox } from '../Listbox/Listbox';
8
10
  /**
9
11
  * Create the state required to render Combobox.
@@ -14,16 +16,17 @@ import { Listbox } from '../Listbox/Listbox';
14
16
  * @param props - props from this instance of Combobox
15
17
  * @param ref - reference to root HTMLElement of Combobox
16
18
  */
17
-
18
19
  export const useCombobox_unstable = (props, ref) => {
19
- var _a;
20
-
21
- const baseState = useComboboxBaseState(props);
20
+ var _a, _b;
21
+ const baseState = useComboboxBaseState({
22
+ ...props,
23
+ editable: true
24
+ });
22
25
  const {
23
26
  activeOption,
24
27
  clearSelection,
25
28
  getIndexOfId,
26
- getOptionsMatchingValue,
29
+ getOptionsMatchingText,
27
30
  hasFocus,
28
31
  open,
29
32
  selectOption,
@@ -35,9 +38,12 @@ export const useCombobox_unstable = (props, ref) => {
35
38
  value
36
39
  } = baseState;
37
40
  const {
41
+ disabled,
38
42
  freeform,
43
+ inlinePopup,
39
44
  multiselect
40
45
  } = props;
46
+ const comboId = useId('combobox-');
41
47
  const {
42
48
  primary: triggerNativeProps,
43
49
  root: rootNativeProps
@@ -47,90 +53,95 @@ export const useCombobox_unstable = (props, ref) => {
47
53
  excludedPropNames: ['children', 'size']
48
54
  });
49
55
  const rootRef = React.useRef(null);
50
- const triggerRef = React.useRef(null); // calculate listbox width style based on trigger width
51
-
52
- const [popupWidth, setPopupWidth] = React.useState();
56
+ const triggerRef = React.useRef(null);
57
+ // NVDA and JAWS have bugs that suppress reading the input value text when aria-activedescendant is set
58
+ // To prevent this, we clear the HTML attribute (but save the state) when a user presses left/right arrows
59
+ // ref: https://github.com/microsoft/fluentui/issues/26359#issuecomment-1397759888
60
+ const [hideActiveDescendant, setHideActiveDescendant] = React.useState(false);
61
+ // calculate listbox width style based on trigger width
62
+ const [popupDimensions, setPopupDimensions] = React.useState();
53
63
  React.useEffect(() => {
54
64
  var _a;
55
-
56
- const width = open ? `${(_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth}px` : undefined;
57
- setPopupWidth(width);
58
- }, [open]); // handle input type-to-select
59
-
60
- const getSearchString = inputValue => {
61
- // if there are commas in the value string, take the text after the last comma
62
- const searchString = inputValue.split(',').pop();
63
- return (searchString === null || searchString === void 0 ? void 0 : searchString.trim().toLowerCase()) || '';
64
- }; // set active option and selection based on typing
65
-
66
-
65
+ // only recalculate width when opening
66
+ if (open) {
67
+ const width = `${(_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth}px`;
68
+ if (width !== (popupDimensions === null || popupDimensions === void 0 ? void 0 : popupDimensions.width)) {
69
+ setPopupDimensions({
70
+ width
71
+ });
72
+ }
73
+ }
74
+ }, [open, popupDimensions]);
75
+ // set active option and selection based on typing
67
76
  const getOptionFromInput = inputValue => {
68
77
  var _a;
69
-
70
- const searchString = getSearchString(inputValue);
71
-
72
- if (searchString.length === 0) {
78
+ const searchString = inputValue === null || inputValue === void 0 ? void 0 : inputValue.trim().toLowerCase();
79
+ if (!searchString || searchString.length === 0) {
73
80
  return;
74
81
  }
75
-
76
- const matcher = optionValue => optionValue.toLowerCase().indexOf(searchString) === 0;
77
-
78
- const matches = getOptionsMatchingValue(matcher); // return first matching option after the current active option, looping back to the top
79
-
82
+ const matcher = optionText => optionText.toLowerCase().indexOf(searchString) === 0;
83
+ const matches = getOptionsMatchingText(matcher);
84
+ // return first matching option after the current active option, looping back to the top
80
85
  if (matches.length > 1 && activeOption) {
81
86
  const startIndex = getIndexOfId(activeOption.id);
82
87
  const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);
83
88
  return nextMatch !== null && nextMatch !== void 0 ? nextMatch : matches[0];
84
89
  }
85
-
86
90
  return (_a = matches[0]) !== null && _a !== void 0 ? _a : undefined;
87
91
  };
88
92
  /* Handle typed input */
89
93
  // reset any typed value when an option is selected
90
-
91
-
92
94
  baseState.selectOption = (ev, option) => {
93
95
  setValue(undefined);
94
96
  selectOption(ev, option);
95
97
  };
96
-
97
98
  const onTriggerBlur = ev => {
98
99
  // handle selection and updating value if freeform is false
99
100
  if (!baseState.open && !freeform) {
100
101
  // select matching option, if the value fully matches
101
- if (value && activeOption && getSearchString(value) === (activeOption === null || activeOption === void 0 ? void 0 : activeOption.value.toLowerCase())) {
102
+ if (value && activeOption && value.trim().toLowerCase() === (activeOption === null || activeOption === void 0 ? void 0 : activeOption.value.toLowerCase())) {
102
103
  baseState.selectOption(ev, activeOption);
103
- } // reset typed value when the input loses focus while collapsed, unless freeform is true
104
-
105
-
104
+ }
105
+ // reset typed value when the input loses focus while collapsed, unless freeform is true
106
106
  setValue(undefined);
107
107
  }
108
108
  };
109
-
110
109
  baseState.setOpen = (ev, newState) => {
110
+ if (disabled) {
111
+ return;
112
+ }
111
113
  if (!newState && !freeform) {
112
114
  setValue(undefined);
113
115
  }
114
-
115
116
  setOpen(ev, newState);
116
- }; // update value and active option based on input
117
-
118
-
117
+ };
118
+ // update value and active option based on input
119
119
  const onTriggerChange = ev => {
120
- const inputValue = ev.target.value; // update uncontrolled value
121
-
122
- baseState.setValue(inputValue); // handle updating active option based on input
123
-
120
+ const inputValue = ev.target.value;
121
+ // update uncontrolled value
122
+ baseState.setValue(inputValue);
123
+ // handle updating active option based on input
124
124
  const matchingOption = getOptionFromInput(inputValue);
125
125
  setActiveOption(matchingOption);
126
- setFocusVisible(true); // clear selection for single-select if the input value no longer matches the selection
127
-
126
+ setFocusVisible(true);
127
+ // clear selection for single-select if the input value no longer matches the selection
128
128
  if (!multiselect && selectedOptions.length === 1 && (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)) {
129
129
  clearSelection(ev);
130
130
  }
131
- }; // resolve input and listbox slot props
132
-
133
-
131
+ };
132
+ // open Combobox when typing
133
+ const onTriggerKeyDown = ev => {
134
+ if (!open && getDropdownActionFromKey(ev) === 'Type') {
135
+ baseState.setOpen(ev, true);
136
+ }
137
+ // clear activedescendant when moving the text insertion cursor
138
+ if (ev.key === ArrowLeft || ev.key === ArrowRight) {
139
+ setHideActiveDescendant(true);
140
+ } else {
141
+ setHideActiveDescendant(false);
142
+ }
143
+ };
144
+ // resolve input and listbox slot props
134
145
  let triggerSlot;
135
146
  let listboxSlot;
136
147
  triggerSlot = resolveShorthand(props.input, {
@@ -143,19 +154,21 @@ export const useCombobox_unstable = (props, ref) => {
143
154
  }
144
155
  });
145
156
  triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);
146
- triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur); // only resolve listbox slot if needed
147
-
157
+ triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);
158
+ triggerSlot.onKeyDown = mergeCallbacks(triggerSlot.onKeyDown, onTriggerKeyDown);
159
+ // only resolve listbox slot if needed
148
160
  listboxSlot = open || hasFocus ? resolveShorthand(props.listbox, {
149
161
  required: true,
150
162
  defaultProps: {
151
163
  children: props.children,
152
- style: {
153
- width: popupWidth
154
- }
164
+ style: popupDimensions
155
165
  }
156
166
  }) : undefined;
157
167
  [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);
158
168
  [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);
169
+ if (hideActiveDescendant) {
170
+ triggerSlot['aria-activedescendant'] = undefined;
171
+ }
159
172
  const state = {
160
173
  components: {
161
174
  root: 'div',
@@ -165,7 +178,9 @@ export const useCombobox_unstable = (props, ref) => {
165
178
  },
166
179
  root: resolveShorthand(props.root, {
167
180
  required: true,
168
- defaultProps: { ...rootNativeProps
181
+ defaultProps: {
182
+ 'aria-owns': !inlinePopup ? listboxSlot === null || listboxSlot === void 0 ? void 0 : listboxSlot.id : undefined,
183
+ ...rootNativeProps
169
184
  }
170
185
  }),
171
186
  input: triggerSlot,
@@ -173,36 +188,58 @@ export const useCombobox_unstable = (props, ref) => {
173
188
  expandIcon: resolveShorthand(props.expandIcon, {
174
189
  required: true,
175
190
  defaultProps: {
176
- children: /*#__PURE__*/React.createElement(ChevronDownIcon, null)
191
+ 'aria-expanded': open,
192
+ children: /*#__PURE__*/React.createElement(ChevronDownIcon, null),
193
+ role: 'button'
177
194
  }
178
195
  }),
179
- ...baseState,
180
- setOpen
196
+ ...baseState
181
197
  };
182
198
  state.root.ref = useMergedRefs(state.root.ref, rootRef);
183
199
  /* handle open/close + focus change when clicking expandIcon */
184
-
185
200
  const {
186
201
  onMouseDown: onIconMouseDown,
187
202
  onClick: onIconClick
188
203
  } = state.expandIcon || {};
189
204
  const onExpandIconMouseDown = useEventCallback(mergeCallbacks(onIconMouseDown, () => {
190
- // do not dismiss on blur when clicking the icon
191
- baseState.ignoreNextBlur.current = true;
205
+ // do not dismiss on blur when closing via clicking the icon
206
+ if (open) {
207
+ baseState.ignoreNextBlur.current = true;
208
+ }
192
209
  }));
193
210
  const onExpandIconClick = useEventCallback(mergeCallbacks(onIconClick, event => {
194
- var _a; // open and set focus
195
-
196
-
211
+ var _a;
212
+ // open and set focus
197
213
  state.setOpen(event, !state.open);
198
214
  (_a = triggerRef.current) === null || _a === void 0 ? void 0 : _a.focus();
215
+ // set focus visible=false, since this can only be done with the mouse/pointer
216
+ setFocusVisible(false);
199
217
  }));
200
-
201
218
  if (state.expandIcon) {
202
219
  state.expandIcon.onMouseDown = onExpandIconMouseDown;
203
220
  state.expandIcon.onClick = onExpandIconClick;
221
+ // If there is no explicit aria-label, calculate default accName attribute for expandIcon button,
222
+ // using the following steps:
223
+ // 1. If there is an aria-label, it is "Open [aria-label]"
224
+ // 2. If there is an aria-labelledby, it is "Open [aria-labelledby target]" (using aria-labelledby + ids)
225
+ // 3. If there is no aria-label/ledby attr, it falls back to "Open"
226
+ // We can't fall back to a label/htmlFor name because of https://github.com/w3c/accname/issues/179
227
+ const hasExpandLabel = state.expandIcon['aria-label'] || state.expandIcon['aria-labelledby'];
228
+ const defaultOpenString = 'Open'; // this is english-only since it is the fallback
229
+ if (!hasExpandLabel) {
230
+ if (props['aria-labelledby']) {
231
+ const chevronId = (_b = state.expandIcon.id) !== null && _b !== void 0 ? _b : `${comboId}-chevron`;
232
+ const chevronLabelledBy = `${chevronId} ${state.input['aria-labelledby']}`;
233
+ state.expandIcon['aria-label'] = defaultOpenString;
234
+ state.expandIcon.id = chevronId;
235
+ state.expandIcon['aria-labelledby'] = chevronLabelledBy;
236
+ } else if (props['aria-label']) {
237
+ state.expandIcon['aria-label'] = `${defaultOpenString} ${props['aria-label']}`;
238
+ } else {
239
+ state.expandIcon['aria-label'] = defaultOpenString;
240
+ }
241
+ }
204
242
  }
205
-
206
243
  return state;
207
244
  };
208
245
  //# sourceMappingURL=useCombobox.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["components/Combobox/useCombobox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAZ,MAAuB,OAAvB;AACA,SAAS,kBAAkB,IAAI,eAA/B,QAAsD,uBAAtD;AACA,SACE,yBADF,EAEE,gBAFF,EAGE,cAHF,EAIE,gBAJF,EAKE,aALF,QAMO,2BANP;AAOA,SAAS,oBAAT,QAAqC,kCAArC;AACA,SAAS,sBAAT,QAAuC,oCAAvC;AACA,SAAS,gBAAT,QAAiC,8BAAjC;AACA,SAAS,OAAT,QAAwB,oBAAxB;AAMA;;;;;;;;AAQG;;AACH,OAAO,MAAM,oBAAoB,GAAG,CAAC,KAAD,EAAuB,GAAvB,KAA0E;;;EAC5G,MAAM,SAAS,GAAG,oBAAoB,CAAC,KAAD,CAAtC;EACA,MAAM;IACJ,YADI;IAEJ,cAFI;IAGJ,YAHI;IAIJ,uBAJI;IAKJ,QALI;IAMJ,IANI;IAOJ,YAPI;IAQJ,eARI;IASJ,eATI;IAUJ,eAVI;IAWJ,OAXI;IAYJ,QAZI;IAaJ;EAbI,IAcF,SAdJ;EAeA,MAAM;IAAE,QAAF;IAAY;EAAZ,IAA4B,KAAlC;EAEA,MAAM;IAAE,OAAO,EAAE,kBAAX;IAA+B,IAAI,EAAE;EAArC,IAAyD,yBAAyB,CAAC;IACvF,KADuF;IAEvF,kBAAkB,EAAE,OAFmE;IAGvF,iBAAiB,EAAE,CAAC,UAAD,EAAa,MAAb;EAHoE,CAAD,CAAxF;EAMA,MAAM,OAAO,GAAG,KAAK,CAAC,MAAN,CAA6B,IAA7B,CAAhB;EACA,MAAM,UAAU,GAAG,KAAK,CAAC,MAAN,CAA+B,IAA/B,CAAnB,CA1B4G,CA4B5G;;EACA,MAAM,CAAC,UAAD,EAAa,aAAb,IAA8B,KAAK,CAAC,QAAN,EAApC;EACA,KAAK,CAAC,SAAN,CAAgB,MAAK;;;IACnB,MAAM,KAAK,GAAG,IAAI,GAAG,GAAG,CAAA,EAAA,GAAA,OAAO,CAAC,OAAR,MAAe,IAAf,IAAe,EAAA,KAAA,KAAA,CAAf,GAAe,KAAA,CAAf,GAAe,EAAA,CAAE,WAAW,IAAlC,GAAyC,SAA3D;IACA,aAAa,CAAC,KAAD,CAAb;EACD,CAHD,EAGG,CAAC,IAAD,CAHH,EA9B4G,CAmC5G;;EACA,MAAM,eAAe,GAAI,UAAD,IAA+B;IACrD;IACA,MAAM,YAAY,GAAG,UAAU,CAAC,KAAX,CAAiB,GAAjB,EAAsB,GAAtB,EAArB;IAEA,OAAO,CAAA,YAAY,KAAA,IAAZ,IAAA,YAAY,KAAA,KAAA,CAAZ,GAAY,KAAA,CAAZ,GAAA,YAAY,CAAE,IAAd,GAAqB,WAArB,EAAA,KAAsC,EAA7C;EACD,CALD,CApC4G,CA2C5G;;;EACA,MAAM,kBAAkB,GAAI,UAAD,IAAgD;;;IACzE,MAAM,YAAY,GAAG,eAAe,CAAC,UAAD,CAApC;;IAEA,IAAI,YAAY,CAAC,MAAb,KAAwB,CAA5B,EAA+B;MAC7B;IACD;;IAED,MAAM,OAAO,GAAI,WAAD,IAAyB,WAAW,CAAC,WAAZ,GAA0B,OAA1B,CAAkC,YAAlC,MAAoD,CAA7F;;IACA,MAAM,OAAO,GAAG,uBAAuB,CAAC,OAAD,CAAvC,CARyE,CAUzE;;IACA,IAAI,OAAO,CAAC,MAAR,GAAiB,CAAjB,IAAsB,YAA1B,EAAwC;MACtC,MAAM,UAAU,GAAG,YAAY,CAAC,YAAY,CAAC,EAAd,CAA/B;MACA,MAAM,SAAS,GAAG,OAAO,CAAC,IAAR,CAAa,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,EAAR,CAAZ,IAA2B,UAAlD,CAAlB;MACA,OAAO,SAAS,KAAA,IAAT,IAAA,SAAS,KAAA,KAAA,CAAT,GAAA,SAAA,GAAa,OAAO,CAAC,CAAD,CAA3B;IACD;;IAED,OAAO,CAAA,EAAA,GAAA,OAAO,CAAC,CAAD,CAAP,MAAU,IAAV,IAAU,EAAA,KAAA,KAAA,CAAV,GAAU,EAAV,GAAc,SAArB;EACD,CAlBD;EAoBA;EAEA;;;EACA,SAAS,CAAC,YAAV,GAAyB,CAAC,EAAD,EAAsB,MAAtB,KAA6C;IACpE,QAAQ,CAAC,SAAD,CAAR;IACA,YAAY,CAAC,EAAD,EAAK,MAAL,CAAZ;EACD,CAHD;;EAKA,MAAM,aAAa,GAAI,EAAD,IAA2C;IAC/D;IACA,IAAI,CAAC,SAAS,CAAC,IAAX,IAAmB,CAAC,QAAxB,EAAkC;MAChC;MACA,IAAI,KAAK,IAAI,YAAT,IAAyB,eAAe,CAAC,KAAD,CAAf,MAA2B,YAAY,KAAA,IAAZ,IAAA,YAAY,KAAA,KAAA,CAAZ,GAAY,KAAA,CAAZ,GAAA,YAAY,CAAE,KAAd,CAAoB,WAApB,EAA3B,CAA7B,EAA2F;QACzF,SAAS,CAAC,YAAV,CAAuB,EAAvB,EAA2B,YAA3B;MACD,CAJ+B,CAMhC;;;MACA,QAAQ,CAAC,SAAD,CAAR;IACD;EACF,CAXD;;EAaA,SAAS,CAAC,OAAV,GAAoB,CAAC,EAAD,EAAK,QAAL,KAA0B;IAC5C,IAAI,CAAC,QAAD,IAAa,CAAC,QAAlB,EAA4B;MAC1B,QAAQ,CAAC,SAAD,CAAR;IACD;;IAED,OAAO,CAAC,EAAD,EAAK,QAAL,CAAP;EACD,CAND,CArF4G,CA6F5G;;;EACA,MAAM,eAAe,GAAI,EAAD,IAA4C;IAClE,MAAM,UAAU,GAAG,EAAE,CAAC,MAAH,CAAU,KAA7B,CADkE,CAElE;;IACA,SAAS,CAAC,QAAV,CAAmB,UAAnB,EAHkE,CAKlE;;IACA,MAAM,cAAc,GAAG,kBAAkB,CAAC,UAAD,CAAzC;IACA,eAAe,CAAC,cAAD,CAAf;IAEA,eAAe,CAAC,IAAD,CAAf,CATkE,CAWlE;;IACA,IACE,CAAC,WAAD,IACA,eAAe,CAAC,MAAhB,KAA2B,CAD3B,KAEC,UAAU,CAAC,MAAX,GAAoB,CAApB,IAAyB,eAAe,CAAC,CAAD,CAAf,CAAmB,OAAnB,CAA2B,UAA3B,MAA2C,CAFrE,CADF,EAIE;MACA,cAAc,CAAC,EAAD,CAAd;IACD;EACF,CAnBD,CA9F4G,CAmH5G;;;EACA,IAAI,WAAJ;EACA,IAAI,WAAJ;EAEA,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,KAAP,EAAc;IAC1C,QAAQ,EAAE,IADgC;IAE1C,YAAY,EAAE;MACZ,GAAG,EAAE,aAAa,CAAC,CAAA,EAAA,GAAA,KAAK,CAAC,KAAN,MAAW,IAAX,IAAW,EAAA,KAAA,KAAA,CAAX,GAAW,KAAA,CAAX,GAAW,EAAA,CAAE,GAAd,EAAmB,UAAnB,CADN;MAEZ,IAAI,EAAE,MAFM;MAGZ,KAAK,EAAE,KAAK,KAAA,IAAL,IAAA,KAAK,KAAA,KAAA,CAAL,GAAA,KAAA,GAAS,EAHJ;MAIZ,GAAG;IAJS;EAF4B,CAAd,CAA9B;EAUA,WAAW,CAAC,QAAZ,GAAuB,cAAc,CAAC,WAAW,CAAC,QAAb,EAAuB,eAAvB,CAArC;EACA,WAAW,CAAC,MAAZ,GAAqB,cAAc,CAAC,WAAW,CAAC,MAAb,EAAqB,aAArB,CAAnC,CAlI4G,CAoI5G;;EACA,WAAW,GACT,IAAI,IAAI,QAAR,GACI,gBAAgB,CAAC,KAAK,CAAC,OAAP,EAAgB;IAC9B,QAAQ,EAAE,IADoB;IAE9B,YAAY,EAAE;MACZ,QAAQ,EAAE,KAAK,CAAC,QADJ;MAEZ,KAAK,EAAE;QAAE,KAAK,EAAE;MAAT;IAFK;EAFgB,CAAhB,CADpB,GAQI,SATN;EAWA,CAAC,WAAD,EAAc,WAAd,IAA6B,gBAAgB,CAAC,KAAD,EAAQ,WAAR,EAAqB,WAArB,CAA7C;EACA,CAAC,WAAD,EAAc,WAAd,IAA6B,sBAAsB,CAAC,KAAD,EAAQ,SAAR,EAAmB,GAAnB,EAAwB,WAAxB,EAAqC,WAArC,CAAnD;EAEA,MAAM,KAAK,GAAkB;IAC3B,UAAU,EAAE;MACV,IAAI,EAAE,KADI;MAEV,KAAK,EAAE,OAFG;MAGV,UAAU,EAAE,MAHF;MAIV,OAAO,EAAE;IAJC,CADe;IAO3B,IAAI,EAAE,gBAAgB,CAAC,KAAK,CAAC,IAAP,EAAa;MACjC,QAAQ,EAAE,IADuB;MAEjC,YAAY,EAAE,EACZ,GAAG;MADS;IAFmB,CAAb,CAPK;IAa3B,KAAK,EAAE,WAboB;IAc3B,OAAO,EAAE,WAdkB;IAe3B,UAAU,EAAE,gBAAgB,CAAC,KAAK,CAAC,UAAP,EAAmB;MAC7C,QAAQ,EAAE,IADmC;MAE7C,YAAY,EAAE;QACZ,QAAQ,eAAE,KAAA,CAAA,aAAA,CAAC,eAAD,EAAgB,IAAhB;MADE;IAF+B,CAAnB,CAfD;IAqB3B,GAAG,SArBwB;IAsB3B;EAtB2B,CAA7B;EAyBA,KAAK,CAAC,IAAN,CAAW,GAAX,GAAiB,aAAa,CAAC,KAAK,CAAC,IAAN,CAAW,GAAZ,EAAiB,OAAjB,CAA9B;EAEA;;EACA,MAAM;IAAE,WAAW,EAAE,eAAf;IAAgC,OAAO,EAAE;EAAzC,IAAyD,KAAK,CAAC,UAAN,IAAoB,EAAnF;EACA,MAAM,qBAAqB,GAAG,gBAAgB,CAC5C,cAAc,CAAC,eAAD,EAAkB,MAAK;IACnC;IACA,SAAS,CAAC,cAAV,CAAyB,OAAzB,GAAmC,IAAnC;EACD,CAHa,CAD8B,CAA9C;EAOA,MAAM,iBAAiB,GAAG,gBAAgB,CACxC,cAAc,CAAC,WAAD,EAAe,KAAD,IAA6C;WAAA,CACvE;;;IACA,KAAK,CAAC,OAAN,CAAc,KAAd,EAAqB,CAAC,KAAK,CAAC,IAA5B;IACA,CAAA,EAAA,GAAA,UAAU,CAAC,OAAX,MAAkB,IAAlB,IAAkB,EAAA,KAAA,KAAA,CAAlB,GAAkB,KAAA,CAAlB,GAAkB,EAAA,CAAE,KAAF,EAAlB;EACD,CAJa,CAD0B,CAA1C;;EAQA,IAAI,KAAK,CAAC,UAAV,EAAsB;IACpB,KAAK,CAAC,UAAN,CAAiB,WAAjB,GAA+B,qBAA/B;IACA,KAAK,CAAC,UAAN,CAAiB,OAAjB,GAA2B,iBAA3B;EACD;;EAED,OAAO,KAAP;AACD,CArMM","sourcesContent":["import * as React from 'react';\nimport { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n resolveShorthand,\n mergeCallbacks,\n useEventCallback,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';\nimport { useComboboxPopup } from '../../utils/useComboboxPopup';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { Slot } from '@fluentui/react-utilities';\nimport type { SelectionEvents } from '../../utils/Selection.types';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport type { ComboboxProps, ComboboxState } from './Combobox.types';\n\n/**\n * Create the state required to render Combobox.\n *\n * The returned state can be modified with hooks such as useComboboxStyles_unstable,\n * before being passed to renderCombobox_unstable.\n *\n * @param props - props from this instance of Combobox\n * @param ref - reference to root HTMLElement of Combobox\n */\nexport const useCombobox_unstable = (props: ComboboxProps, ref: React.Ref<HTMLInputElement>): ComboboxState => {\n const baseState = useComboboxBaseState(props);\n const {\n activeOption,\n clearSelection,\n getIndexOfId,\n getOptionsMatchingValue,\n hasFocus,\n open,\n selectOption,\n selectedOptions,\n setActiveOption,\n setFocusVisible,\n setOpen,\n setValue,\n value,\n } = baseState;\n const { freeform, multiselect } = props;\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'input',\n excludedPropNames: ['children', 'size'],\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLInputElement>(null);\n\n // calculate listbox width style based on trigger width\n const [popupWidth, setPopupWidth] = React.useState<string>();\n React.useEffect(() => {\n const width = open ? `${rootRef.current?.clientWidth}px` : undefined;\n setPopupWidth(width);\n }, [open]);\n\n // handle input type-to-select\n const getSearchString = (inputValue: string): string => {\n // if there are commas in the value string, take the text after the last comma\n const searchString = inputValue.split(',').pop();\n\n return searchString?.trim().toLowerCase() || '';\n };\n\n // set active option and selection based on typing\n const getOptionFromInput = (inputValue: string): OptionValue | undefined => {\n const searchString = getSearchString(inputValue);\n\n if (searchString.length === 0) {\n return;\n }\n\n const matcher = (optionValue: string) => optionValue.toLowerCase().indexOf(searchString) === 0;\n const matches = getOptionsMatchingValue(matcher);\n\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\n const startIndex = getIndexOfId(activeOption.id);\n const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);\n return nextMatch ?? matches[0];\n }\n\n return matches[0] ?? undefined;\n };\n\n /* Handle typed input */\n\n // reset any typed value when an option is selected\n baseState.selectOption = (ev: SelectionEvents, option: OptionValue) => {\n setValue(undefined);\n selectOption(ev, option);\n };\n\n const onTriggerBlur = (ev: React.FocusEvent<HTMLInputElement>) => {\n // handle selection and updating value if freeform is false\n if (!baseState.open && !freeform) {\n // select matching option, if the value fully matches\n if (value && activeOption && getSearchString(value) === activeOption?.value.toLowerCase()) {\n baseState.selectOption(ev, activeOption);\n }\n\n // reset typed value when the input loses focus while collapsed, unless freeform is true\n setValue(undefined);\n }\n };\n\n baseState.setOpen = (ev, newState: boolean) => {\n if (!newState && !freeform) {\n setValue(undefined);\n }\n\n setOpen(ev, newState);\n };\n\n // update value and active option based on input\n const onTriggerChange = (ev: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = ev.target.value;\n // update uncontrolled value\n baseState.setValue(inputValue);\n\n // handle updating active option based on input\n const matchingOption = getOptionFromInput(inputValue);\n setActiveOption(matchingOption);\n\n setFocusVisible(true);\n\n // clear selection for single-select if the input value no longer matches the selection\n if (\n !multiselect &&\n selectedOptions.length === 1 &&\n (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)\n ) {\n clearSelection(ev);\n }\n };\n\n // resolve input and listbox slot props\n let triggerSlot: Slot<'input'>;\n let listboxSlot: Slot<typeof Listbox> | undefined;\n\n triggerSlot = resolveShorthand(props.input, {\n required: true,\n defaultProps: {\n ref: useMergedRefs(props.input?.ref, triggerRef),\n type: 'text',\n value: value ?? '',\n ...triggerNativeProps,\n },\n });\n\n triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);\n triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);\n\n // only resolve listbox slot if needed\n listboxSlot =\n open || hasFocus\n ? resolveShorthand(props.listbox, {\n required: true,\n defaultProps: {\n children: props.children,\n style: { width: popupWidth },\n },\n })\n : undefined;\n\n [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);\n [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);\n\n const state: ComboboxState = {\n components: {\n root: 'div',\n input: 'input',\n expandIcon: 'span',\n listbox: Listbox,\n },\n root: resolveShorthand(props.root, {\n required: true,\n defaultProps: {\n ...rootNativeProps,\n },\n }),\n input: triggerSlot,\n listbox: listboxSlot,\n expandIcon: resolveShorthand(props.expandIcon, {\n required: true,\n defaultProps: {\n children: <ChevronDownIcon />,\n },\n }),\n ...baseState,\n setOpen,\n };\n\n state.root.ref = useMergedRefs(state.root.ref, rootRef);\n\n /* handle open/close + focus change when clicking expandIcon */\n const { onMouseDown: onIconMouseDown, onClick: onIconClick } = state.expandIcon || {};\n const onExpandIconMouseDown = useEventCallback(\n mergeCallbacks(onIconMouseDown, () => {\n // do not dismiss on blur when clicking the icon\n baseState.ignoreNextBlur.current = true;\n }),\n );\n\n const onExpandIconClick = useEventCallback(\n mergeCallbacks(onIconClick, (event: React.MouseEvent<HTMLSpanElement>) => {\n // open and set focus\n state.setOpen(event, !state.open);\n triggerRef.current?.focus();\n }),\n );\n\n if (state.expandIcon) {\n state.expandIcon.onMouseDown = onExpandIconMouseDown;\n state.expandIcon.onClick = onExpandIconClick;\n }\n\n return state;\n};\n"],"sourceRoot":"../src/"}
1
+ {"version":3,"mappings":"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","names":["React","ArrowLeft","ArrowRight","ChevronDownRegular","ChevronDownIcon","getPartitionedNativeProps","resolveShorthand","mergeCallbacks","useEventCallback","useId","useMergedRefs","getDropdownActionFromKey","useComboboxBaseState","useComboboxPopup","useTriggerListboxSlots","Listbox","useCombobox_unstable","props","ref","baseState","editable","activeOption","clearSelection","getIndexOfId","getOptionsMatchingText","hasFocus","open","selectOption","selectedOptions","setActiveOption","setFocusVisible","setOpen","setValue","value","disabled","freeform","inlinePopup","multiselect","comboId","primary","triggerNativeProps","root","rootNativeProps","primarySlotTagName","excludedPropNames","rootRef","useRef","triggerRef","hideActiveDescendant","setHideActiveDescendant","useState","popupDimensions","setPopupDimensions","useEffect","width","current","clientWidth","getOptionFromInput","inputValue","searchString","trim","toLowerCase","length","matcher","optionText","indexOf","matches","startIndex","id","nextMatch","find","option","undefined","ev","onTriggerBlur","newState","onTriggerChange","target","matchingOption","onTriggerKeyDown","key","triggerSlot","listboxSlot","input","required","defaultProps","type","onChange","onBlur","onKeyDown","listbox","children","style","state","components","expandIcon","role","onMouseDown","onIconMouseDown","onClick","onIconClick","onExpandIconMouseDown","ignoreNextBlur","onExpandIconClick","event","focus","hasExpandLabel","defaultOpenString","chevronId","chevronLabelledBy"],"sourceRoot":"../src/","sources":["packages/react-components/react-combobox/src/components/Combobox/useCombobox.tsx"],"sourcesContent":["import * as React from 'react';\nimport { ArrowLeft, ArrowRight } from '@fluentui/keyboard-keys';\nimport { ChevronDownRegular as ChevronDownIcon } from '@fluentui/react-icons';\nimport {\n getPartitionedNativeProps,\n resolveShorthand,\n mergeCallbacks,\n useEventCallback,\n useId,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport { getDropdownActionFromKey } from '../../utils/dropdownKeyActions';\nimport { useComboboxBaseState } from '../../utils/useComboboxBaseState';\nimport { useComboboxPopup } from '../../utils/useComboboxPopup';\nimport { useTriggerListboxSlots } from '../../utils/useTriggerListboxSlots';\nimport { Listbox } from '../Listbox/Listbox';\nimport type { Slot } from '@fluentui/react-utilities';\nimport type { SelectionEvents } from '../../utils/Selection.types';\nimport type { OptionValue } from '../../utils/OptionCollection.types';\nimport type { ComboboxProps, ComboboxState } from './Combobox.types';\n\n/**\n * Create the state required to render Combobox.\n *\n * The returned state can be modified with hooks such as useComboboxStyles_unstable,\n * before being passed to renderCombobox_unstable.\n *\n * @param props - props from this instance of Combobox\n * @param ref - reference to root HTMLElement of Combobox\n */\nexport const useCombobox_unstable = (props: ComboboxProps, ref: React.Ref<HTMLInputElement>): ComboboxState => {\n const baseState = useComboboxBaseState({ ...props, editable: true });\n const {\n activeOption,\n clearSelection,\n getIndexOfId,\n getOptionsMatchingText,\n hasFocus,\n open,\n selectOption,\n selectedOptions,\n setActiveOption,\n setFocusVisible,\n setOpen,\n setValue,\n value,\n } = baseState;\n const { disabled, freeform, inlinePopup, multiselect } = props;\n const comboId = useId('combobox-');\n\n const { primary: triggerNativeProps, root: rootNativeProps } = getPartitionedNativeProps({\n props,\n primarySlotTagName: 'input',\n excludedPropNames: ['children', 'size'],\n });\n\n const rootRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLInputElement>(null);\n\n // NVDA and JAWS have bugs that suppress reading the input value text when aria-activedescendant is set\n // To prevent this, we clear the HTML attribute (but save the state) when a user presses left/right arrows\n // ref: https://github.com/microsoft/fluentui/issues/26359#issuecomment-1397759888\n const [hideActiveDescendant, setHideActiveDescendant] = React.useState(false);\n\n // calculate listbox width style based on trigger width\n const [popupDimensions, setPopupDimensions] = React.useState<{ width: string }>();\n React.useEffect(() => {\n // only recalculate width when opening\n if (open) {\n const width = `${rootRef.current?.clientWidth}px`;\n if (width !== popupDimensions?.width) {\n setPopupDimensions({ width });\n }\n }\n }, [open, popupDimensions]);\n\n // set active option and selection based on typing\n const getOptionFromInput = (inputValue: string): OptionValue | undefined => {\n const searchString = inputValue?.trim().toLowerCase();\n\n if (!searchString || searchString.length === 0) {\n return;\n }\n\n const matcher = (optionText: string) => optionText.toLowerCase().indexOf(searchString) === 0;\n const matches = getOptionsMatchingText(matcher);\n\n // return first matching option after the current active option, looping back to the top\n if (matches.length > 1 && activeOption) {\n const startIndex = getIndexOfId(activeOption.id);\n const nextMatch = matches.find(option => getIndexOfId(option.id) >= startIndex);\n return nextMatch ?? matches[0];\n }\n\n return matches[0] ?? undefined;\n };\n\n /* Handle typed input */\n\n // reset any typed value when an option is selected\n baseState.selectOption = (ev: SelectionEvents, option: OptionValue) => {\n setValue(undefined);\n selectOption(ev, option);\n };\n\n const onTriggerBlur = (ev: React.FocusEvent<HTMLInputElement>) => {\n // handle selection and updating value if freeform is false\n if (!baseState.open && !freeform) {\n // select matching option, if the value fully matches\n if (value && activeOption && value.trim().toLowerCase() === activeOption?.value.toLowerCase()) {\n baseState.selectOption(ev, activeOption);\n }\n\n // reset typed value when the input loses focus while collapsed, unless freeform is true\n setValue(undefined);\n }\n };\n\n baseState.setOpen = (ev, newState: boolean) => {\n if (disabled) {\n return;\n }\n\n if (!newState && !freeform) {\n setValue(undefined);\n }\n\n setOpen(ev, newState);\n };\n\n // update value and active option based on input\n const onTriggerChange = (ev: React.ChangeEvent<HTMLInputElement>) => {\n const inputValue = ev.target.value;\n // update uncontrolled value\n baseState.setValue(inputValue);\n\n // handle updating active option based on input\n const matchingOption = getOptionFromInput(inputValue);\n setActiveOption(matchingOption);\n\n setFocusVisible(true);\n\n // clear selection for single-select if the input value no longer matches the selection\n if (\n !multiselect &&\n selectedOptions.length === 1 &&\n (inputValue.length < 1 || selectedOptions[0].indexOf(inputValue) !== 0)\n ) {\n clearSelection(ev);\n }\n };\n\n // open Combobox when typing\n const onTriggerKeyDown = (ev: React.KeyboardEvent<HTMLInputElement>) => {\n if (!open && getDropdownActionFromKey(ev) === 'Type') {\n baseState.setOpen(ev, true);\n }\n\n // clear activedescendant when moving the text insertion cursor\n if (ev.key === ArrowLeft || ev.key === ArrowRight) {\n setHideActiveDescendant(true);\n } else {\n setHideActiveDescendant(false);\n }\n };\n\n // resolve input and listbox slot props\n let triggerSlot: Slot<'input'>;\n let listboxSlot: Slot<typeof Listbox> | undefined;\n\n triggerSlot = resolveShorthand(props.input, {\n required: true,\n defaultProps: {\n ref: useMergedRefs(props.input?.ref, triggerRef),\n type: 'text',\n value: value ?? '',\n ...triggerNativeProps,\n },\n });\n\n triggerSlot.onChange = mergeCallbacks(triggerSlot.onChange, onTriggerChange);\n triggerSlot.onBlur = mergeCallbacks(triggerSlot.onBlur, onTriggerBlur);\n triggerSlot.onKeyDown = mergeCallbacks(triggerSlot.onKeyDown, onTriggerKeyDown);\n\n // only resolve listbox slot if needed\n listboxSlot =\n open || hasFocus\n ? resolveShorthand(props.listbox, {\n required: true,\n defaultProps: {\n children: props.children,\n style: popupDimensions,\n },\n })\n : undefined;\n\n [triggerSlot, listboxSlot] = useComboboxPopup(props, triggerSlot, listboxSlot);\n [triggerSlot, listboxSlot] = useTriggerListboxSlots(props, baseState, ref, triggerSlot, listboxSlot);\n\n if (hideActiveDescendant) {\n triggerSlot['aria-activedescendant'] = undefined;\n }\n\n const state: ComboboxState = {\n components: {\n root: 'div',\n input: 'input',\n expandIcon: 'span',\n listbox: Listbox,\n },\n root: resolveShorthand(props.root, {\n required: true,\n defaultProps: {\n 'aria-owns': !inlinePopup ? listboxSlot?.id : undefined,\n ...rootNativeProps,\n },\n }),\n input: triggerSlot,\n listbox: listboxSlot,\n expandIcon: resolveShorthand(props.expandIcon, {\n required: true,\n defaultProps: {\n 'aria-expanded': open,\n children: <ChevronDownIcon />,\n role: 'button',\n },\n }),\n ...baseState,\n };\n\n state.root.ref = useMergedRefs(state.root.ref, rootRef);\n\n /* handle open/close + focus change when clicking expandIcon */\n const { onMouseDown: onIconMouseDown, onClick: onIconClick } = state.expandIcon || {};\n const onExpandIconMouseDown = useEventCallback(\n mergeCallbacks(onIconMouseDown, () => {\n // do not dismiss on blur when closing via clicking the icon\n if (open) {\n baseState.ignoreNextBlur.current = true;\n }\n }),\n );\n\n const onExpandIconClick = useEventCallback(\n mergeCallbacks(onIconClick, (event: React.MouseEvent<HTMLSpanElement>) => {\n // open and set focus\n state.setOpen(event, !state.open);\n triggerRef.current?.focus();\n\n // set focus visible=false, since this can only be done with the mouse/pointer\n setFocusVisible(false);\n }),\n );\n\n if (state.expandIcon) {\n state.expandIcon.onMouseDown = onExpandIconMouseDown;\n state.expandIcon.onClick = onExpandIconClick;\n\n // If there is no explicit aria-label, calculate default accName attribute for expandIcon button,\n // using the following steps:\n // 1. If there is an aria-label, it is \"Open [aria-label]\"\n // 2. If there is an aria-labelledby, it is \"Open [aria-labelledby target]\" (using aria-labelledby + ids)\n // 3. If there is no aria-label/ledby attr, it falls back to \"Open\"\n // We can't fall back to a label/htmlFor name because of https://github.com/w3c/accname/issues/179\n const hasExpandLabel = state.expandIcon['aria-label'] || state.expandIcon['aria-labelledby'];\n const defaultOpenString = 'Open'; // this is english-only since it is the fallback\n if (!hasExpandLabel) {\n if (props['aria-labelledby']) {\n const chevronId = state.expandIcon.id ?? `${comboId}-chevron`;\n const chevronLabelledBy = `${chevronId} ${state.input['aria-labelledby']}`;\n\n state.expandIcon['aria-label'] = defaultOpenString;\n state.expandIcon.id = chevronId;\n state.expandIcon['aria-labelledby'] = chevronLabelledBy;\n } else if (props['aria-label']) {\n state.expandIcon['aria-label'] = `${defaultOpenString} ${props['aria-label']}`;\n } else {\n state.expandIcon['aria-label'] = defaultOpenString;\n }\n }\n }\n\n return state;\n};\n"]}